2011

2010

2009

2008

Les nouveautés de WPF 4.0

11 February 2010

Hello all,

A post in french :

Je relaie les informations postées par moi-même sur un autre blog : Blog expertease Alti

C'est en français !

 

How to scale around a specific point and not the center of the Element

11 October 2009

The problem


The most popular controls which has been brought by the Microsoft SDK is certainly the scatterView. Each item is positioned at a random place with a random orientation.
ExampleOfScatterView

You can then rotate, move or scale them with your fingers. Here we will focus on this last point : the scaling. This is a really nice feature and you may wants to put it in your application (it may also be replace my a mouse wheel or stylus events, etc.).

If an user wants to zoom-in on a specific part of the presented items, he wills do a 'scale manipulation' with it's fingers on the specific part.

Simple, will you think : we just have to change the width and the height of the control based on the scale delta ! But the problem is that, the control will grow but the specific part wanted by the user will no more be under it's fingers. A figure worth a thousand words :
Schema example



My solution

Here we are going to scale a scatterViewItem with the property 'CanMove' set to false. We do it because, the scatterView item does already what we wants and this is done by a translation.


Also we are going to use a Affine2DManipulationProcessor which will gives us the scale value for a manipulation done by multiple fingers. If some are catching stylus events, you could use a ManipulationProcessor from the multiTouch SDK (available here :http://www.microsoft.com/downloads/details.aspx?FamilyID=12100526-ed26-476b-8e20-69662b8546c1&displaylang=en).

The XAML :

<s:ScatterView VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
      <s:ScatterViewItem x:Name="_myObjectToScale" Orientation="0" CanRotate="False" 
            CanScale="False" CanMove="False"
            Center="512.0,384.0"  ShowsActivationEffects="False"
            PreviewContactDown="_myObjectToScale_ContactDown" 
            PreviewContactUp="_myObjectToScale_ContactUp">
         <Image Source="Resources/myself.jpg" />
      </s:ScatterViewItem>


The code :

private Affine2DManipulationProcessor _ourManipProc;
public Affine2DManipulationProcessor OurManipProc { 
   get { return _ourManipProc; } 
   set { _ourManipProc = value; }
 }
 
public SurfaceWindow1()
{
    InitializeComponent();
    DataContext = this;
    _ourManipProc = new Affine2DManipulationProcessor(Affine2DManipulations.Scale, this);
 
    //Catch the event from our manipulation processor
    OurManipProc.Affine2DManipulationDelta += OurManipProc_Affine2DManipulationDelta;
}
 
 
private void _myObjectToScale_ContactDown(object sender, ContactEventArgs e)
{
    //this contact is tracked by ou MP
    OurManipProc.BeginTrack(e.Contact);
}
 
private void _myObjectToScale_ContactUp(object sender, ContactEventArgs e)
{
    //this contact is no more tracked by ou MP
    OurManipProc.EndTrack(e.Contact);
}



Then the important part, the Affine2DManipulationDelta handler which will do what we wants, I will describe it below.

void OurManipProc_Affine2DManipulationDelta(object sender, Affine2DOperationDeltaEventArgs e)
{
    double scaleDelta = e.ScaleDelta;
    if (scaleDelta == 1.0) return;
 
 
    Point manipOrigin = e.ManipulationOrigin;
    Point oldCenter = new Point(_myObjectToScale.Center.X, _myObjectToScale.Center.Y);
 
    double oldHeight = _myObjectToScale.ActualHeight;
    double newHeight = _myObjectToScale.ActualHeight * scaleDelta;
 
    double oldWidth = _myObjectToScale.ActualWidth;
    double newWidth = _myObjectToScale.ActualWidth * scaleDelta;
 
    _myObjectToScale.Height = newHeight;
    _myObjectToScale.Width = newWidth;
 
    double ratioX = Math.Abs(manipOrigin.X - oldCenter.X) / (oldWidth / 2);
    double newCenterXD = ratioX
        * Math.Sign(oldCenter.X - manipOrigin.X) * (newWidth - oldWidth) / 2;
 
    double ratioY = Math.Abs(manipOrigin.Y - oldCenter.Y) / (oldHeight / 2);
    double newCenterYD = ratioY *
        Math.Sign(oldCenter.Y - manipOrigin.Y) * (newHeight - oldHeight) / 2;
 
    if (scaleDelta > 1.0)
        _myObjectToScale.Center += new Vector(newCenterXD, newCenterYD);
    else
        _myObjectToScale.Center += new Vector(newCenterXD, newCenterYD);
}



Explanation


First we need to calculate the new size of our control. This is done by multiplying it's actual size by the scaleDelta gived by our processor.

Then we store some interesting values as the old size, the old center position, etc.

Then we calculate the ration for X and for Y. What is it ? It's ratio of the aimed point (the point on top of which the manipulation is done) and the half of the control size. But why do we need it ? Because we wants the controls to grow on each side of the aimed point, not only the one near the center. If we does not calculate this, one side of the control would stay at the same position during our manipulation. algo explanation

Next we calculate the center delta which is the translation we must operate on our control for the focused point to stay under our fingers (or mouse pointer, or stylus, whatever you wants :D).



We finaly apply all this measure to our control. That's it !

kick it on DotNetKicks.com Shout it


 

I am a WPF Technology Specialist !

25 September 2009


Today I have earned my Microsoft Certified Technology Specialist: .NET Framework 3.5, Windows Presentation Foundation Applications certification !

Youpi I can't put this nice logo on my blog :-) !

Certifié WPF

 

Tips: increase performances when using D3DImage in WPF

17 September 2009

Hello,

Often when you read articles explaining how to use a D3DImage in your WPF application you use code which directly handle the CompositorTarget.Rendering event by updating the 3D world... This can lead to performance problems.

For example in my application, WPF refresh the display with a FPS of 160 : the handler which recreate the 3D image is then call 160 times a second. No need to refresh this often.


The solution I used is to create a Timer which will do it at the FPS I want. Let's say 30FPS for example :

public void createTheRenderingWithCorrectFPS(int whichFPS){
   DispatcherTimer _timer = new DispatcherTimer();
   _timer.Interval = new TimeSpan(1000 /whichFPS);
   _timer.Start();
   _timer.Tick += new EventHandler(_timer_Tick);
}
void _timer_Tick(object sender, EventArgs e)
{
   //Refresh the 3D scene
}



This enables your application to be really more reactive especially that you need to be on the main thread to update the 3D scene...



Do you know a better way ?



kick it on DotNetKicks.com Shout it



 

Ambient, diffuse, emissive and specular colors : some examples

24 July 2009

Introduction

When you defines a material in Ogre or in 3D engines in general, you can play with at least four differents parameters : Ambient color, diffuse color, emissive color and specular color.

In this post I will give you the definitions and show you some example for those who - like me - requires some visual example to understand better...

Definitions

Here are the definitions (found on the web...) :

Ambient color : Ambient color is the color of an object where it is in shadow. This color is what the object reflects when illuminated by ambient light rather than direct light.

Diffuse color :Diffuse color is the most instinctive meaning of the color of an object. It is that essential color that the object reveals under pure white light. It is perceived as the color of the object itself rather than a reflection of the light.

Emissive color : This is the self-illumination color an object has.

Specular color :Specular color is the color of the light of a specular reflection (specular reflection is the type of reflection that is characteristic of light reflected from a shiny surface).



All object material can so define these 4 parameters. The color will then depend on them but also of the light they receive.

Examples

All the example are done with a point light, placed at the position (350, 400, 800);
With this type of light you define two colors, the ambient one and the diffuse one.

First example

The light parameters are :

  • Ambient color : White
  • Difusse color : White



First example

Second example

The light parameters are :

  • Ambient color : Red
  • Difusse color : White



Second example

Third example

The light parameters are :

  • Ambient color : Red
  • Difusse color : Red



Third example

Conclusion


As a conclusion : nothing is better than experimentation !

kick it on DotNetKicks.com
 

GUI to NUI : representations and manipulation of OLAP data in 3D

21 July 2009

Hello,

Here is a little post to show you a little video presenting the project I have worked on during my 6 months of training. I am very proud of it :) :



The subject was to find the new way of representations and manipulations of OLAP Data without using a keyboard or a mouse.
This is done in 3D on the Microsoft Surface plateform.

The technologies involved are :

  1. Microsoft Surface for the NUI (Natural User Interface),
  2. (M)Ogre to create the 3D World,
  3. OLAP for the acquisition of datas.




Here are some links for those interested :

  1. What is OLAP ? (wikipedia)
  2. What are the NUI ? (wikipedia)
  3. What is Ogre the 3D engine ?
  4. What is Microsoft Surface ?
  5. What is the company in which I have done my training ?



People who worked on it :

  1. Development: Jonathan ANTOINE
  2. Supervision of the project : Elise DUPONT
  3. 3D Expert : Laurent TRUDU



Enjoy !


kick it on DotNetKicks.com


Shout it
 

CREATE, LAUNCH and CONTROL a WPF animation FROM CODE

7 July 2009

The problem

Sometimes you need to animate your specific object and for this purpose there is the WPF animation.

Here are the prerequireds :

  • The property you want to animate must be a DependencyProperty,
  • The property must so be a part of a DependencyObject,
  • Your object must implement IAnimatable to be able to launch the animation.


The difficulty resides in being able to create an animation, create a storyboard and set the corrects values for the attached properties - TargetName and TargetProperty - on the animation. All of this directly in the code.

You can then control the animation, the usual way than in XAML.

My solution/checklist

Here is how I did it, step by step.

First I make my business object derives from FrameWorkElement. Why ?
Because, this make my object a dependency object. Also, my object will implements IAnimatable ( FrameWorkElement heritate from UIElement which implements IAnimatable). And finally, it gets a NameScope which will be used later.
So here is my object:

public class Puppet: FrameworkElement {    }



Next I will had a DependencyProperty to be animated. Here I animate a value of type Point. I create all the usual things for the dependencyProperty and also add a storyboard (I will always use the same):

public class Puppet: FrameworkElement
{
   public static DependencyProperty ContactMovementProperty =
   DependencyProperty.Register("ContactMovement", typeof(Point), typeof(Puppet));
 
   public Point ContactMovement
   {
       get { return (Point)GetValue(SatelliteNavigator.ContactMovementProperty); }
       set { SetValue(SatelliteNavigator.ContactMovementProperty, value); }
    }
 
    private Storyboard stboard = new Storyboard();
}



Then, let's say I will create and launch the animation directly in the constructor. Here is the code added :

public class()
{
   //Maybe it was running before (if not set in the constructor)
   //stboard.Stop();
 
    double xFinal = 36;
    double yFinal = 36;
    PointAnimation animation = new PointAnimation();
 
    animation.From = ContactMovement;
    animation.To = new Point(xFinal , yFinal );
    animation.Duration = TimeSpan.FromMilliseconds(e.Velocity.Length*7 / deceleration);
    animation.AccelerationRatio = 0f;
    animation.DecelerationRatio = 0.4f;
    String puppetName= "puppet";
 
    NameScope nams = new NameScope();
    NameScope.SetNameScope(this, nams);
    this.RegisterName(puppetName, this);
 
    Storyboard.SetTargetName(animation, puppetName);
    Storyboard.SetTargetProperty(animation, new PropertyPath(Puppet.ContactMovementProperty));
 
    stboard.Children.Add(animation);
    stboard.Begin(this);
 
}


What is done ? First I create the animation with random values for our example.
Then I create a NameScope and set it to our object. Why ? Because it's not created by the runtime for our object and we need one. It will be used by the animation to retrieve the object to animate.

This is done by registering the Puppet object in the namescope and giving the same TargetName of the attachedProperty of the animation(Storyboard.SetTargetName).

Then we clear the children animation of the storyboard (maybe it was not empty) and launch the storyboard by giving it the Puppet (object in which the animated object is).



We can then use the usual methods on storyboard to control the play of the media. For example :

stboard.Stop();


Conclusion

As you can see this is not as easy as writing some XAML lines but it's not impossible !

Any questions ?

kick it on DotNetKicks.com


Shout it


 

XAML to PNG converter... (redirect)

25 June 2009

In fact the post is here ... ^^

 

XAML to PNG converter...

Hello,

Today a post about creating a PNG from a XAML file. Easy some will says but we will see some more tips :

  • How to create a screenshot from a control in the size you want (not the actual size).
  • How to load an external XAML file and display it inside your application.



How to load an external XAML

This snippet will use a XAMLReader, and create a visual from the XAML and the put it inside you application :

Microsoft.Win32|>.OpenFileDialog dialog = new Microsoft.Win32|>.OpenFileDialog();
         dialog.Title = "Select the XAML file.";
         dialog.AddExtension = true;
         dialog.CheckFileExists = true;
         dialog.DefaultExt = ".xaml";
         dialog.Filter = "Xaml files |*.xaml";
 
         if (dialog.ShowDialog() == true)
         {
            String path = dialog.FileName;
            UIElement visual = XamlReader.Load(System.Xml.XmlReader.Create(path)) as UIElement;
            if (visual != null)
            {
               _docker.Children.Add(visual);
            }
            else
            {
               MessageBox.Show("Cannot load the UiElement from the XAML.", "Error", MessageBoxButton.OK);
               this.Close();
            }
         }


Quite simple in fact.

How to create a screenshot in the size you want...

Then to create a sample from a control or anything which is a visual you will use a different syntax than the one presented sooner in this blog.

The tips is to create a brush from the visual, and fill a Rectangle in a drawingContext.

Here is the code :

Visual theVisual = _docker; //Put the aimed visual here.
 
         //Get the size you wants from the UI
         double width = Convert.ToDouble(_widthTextB.Text);
         double height = Convert.ToDouble(_heightTextB.Text);
 
         if (double.IsNaN(width) || double.IsNaN(height))
         {
            throw new FormatException("You need to indicate the Width and Height values of the UIElement.");
         }
         Size size = new Size(width, height);
 
         DrawingVisual drawingVisual = new DrawingVisual();
         VisualBrush vBrush = new VisualBrush(theVisual);
 
         using (DrawingContext dc = drawingVisual.RenderOpen())
         {
            dc.DrawRectangle(vBrush, null, new Rect(new Point(), size));
         }
 
         RenderTargetBitmap render = new RenderTargetBitmap(
               Convert.ToInt32(1900),
               Convert.ToInt32(1200),
               96,
               96,
               PixelFormats.Pbgra32);
         // Indicate which control to render in the image
         render.Render(drawingVisual);
         Stream oStream = new FileStream("out.png", FileMode.Create);
 
         PngBitmapEncoder encoder = new PngBitmapEncoder();
         encoder.Frames.Add(BitmapFrame.Create(render));
         encoder.Save(oStream);
         oStream.Flush();
         oStream.Close();



The resulting app

There is a little drawback: the xaml visual you load must be configured to stretch when putted inside a layout control...
Here is some screenShot of the app running :

Xaml To Png Exporter



The code source is attached to the post.

kick it on DotNetKicks.com
 

Write text inside an image: add a poster to add it in your Mogre Scene

28 May 2009

Introduction

To display informations into your scene you can use a billboard represented by the MovableText into (M)ogre but sometimes you just want to put some static text somewhere because it's more readable.

For example :

Create a poster to add it in your Mogre Scene

The code

Here is the code which use a lot of my last article .

The steps are :

  1. Create a bitmap with the text in it,
  2. Create a texture with this image, then a material,
  3. Create a poster (rectangle) and put the texture on it,
  4. Return the manualObject created.

The part which may be interest you is how to get the right size for the created bitmap based on the text...

Also the creation of the manualObject is not necessary but I think it may interest some people to see how to use it.

/// <summary>
/// Creates a 'poster' based on a text.
/// </summary>
/// <param name="Smgr">The scenemanager (necesary to create the manual object).</param>
/// <param name="text">The text to put on the poster.</param>
/// <author>Jonathan ANTOINE</author>
private static ManualObject createALabel(SceneManager Smgr, String text)
{
String textureName = Guid.NewGuid().ToString();
System.Drawing.Font font = new System.Drawing.Font("Calibri", 12, FontStyle.Bold);
Bitmap bitmap = new Bitmap(1, 1);
Graphics g = Graphics.FromImage(bitmap);
 
SizeF measureString = g.MeasureString(text, font);
bitmap = new Bitmap((int)measureString.Width, (int)measureString.Height);
g = Graphics.FromImage(bitmap);
g.FillRectangle(Brushes.Black, new System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height));
g.DrawString(text, font, new System.Drawing.SolidBrush(Color.White), new Point(3, 3));
 
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
 
Stream oStream = new MemoryStream();
g.Save();
bitmap.Save(oStream, ImageFormat.Png);
oStream.Flush();
 
//bitmap.Dispose();
//Back to the start of the stream
oStream.Position = 0;
 
//read all the stream
BinaryReader oBinaryReader = new BinaryReader(oStream);
byte[] pBuffer = oBinaryReader.ReadBytes((int)oBinaryReader.BaseStream.Length);
oStream.Close(); //No more needed
TextureManager.Singleton.Remove(textureName); //Remove eventually texture with the same name
unsafe
{
GCHandle handle = GCHandle.Alloc(pBuffer, GCHandleType.Pinned);
byte* pUnsafeByte = (byte*)handle.AddrOfPinnedObject();
void* pUnsafeBuffer = (void*)handle.AddrOfPinnedObject();
 
MemoryDataStream oMemoryStream = new MemoryDataStream(pUnsafeBuffer, (uint)pBuffer.Length);
DataStreamPtr oPtrDataStream = new DataStreamPtr(oMemoryStream);
 
Mogre.Image oMogreImage = new Mogre.Image().Load(oPtrDataStream, "png");
 
TextureManager.Singleton.LoadImageW(textureName, ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME, oMogreImage);
 
//handle.Free();
}
String matNam = Guid.NewGuid().ToString();
MaterialPtr _dynamicMaterial = MaterialManager.Singleton.Create(matNam, ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME);
Pass pass = _dynamicMaterial.GetTechnique(0).GetPass(0);
 
pass.ShadingMode = ShadeOptions.SO_PHONG;
 
TextureUnitState tus = pass.CreateTextureUnitState(textureName);
tus.SetTextureAddressingMode(TextureUnitState.TextureAddressingMode.TAM_CLAMP);
pass.AddTextureUnitState(tus);
 
_dynamicMaterial.Dispose(); //Dispose the pointer, not the material !
 
ManualObject manualObject = Smgr.CreateManualObject(Guid.NewGuid().ToString());
 
manualObject.EstimateIndexCount(6);
manualObject.EstimateVertexCount(6);
 
manualObject.Begin(matNam, RenderOperation.OperationTypes.OT_TRIANGLE_LIST);
 
//DESSUS
int yWidthVariable = bitmap.Width;
int xWidth = bitmap.Height;
 
manualObject.Position(new Vector3(0, 0, 0));
manualObject.TextureCoord(1, 0);
manualObject.Normal(Vector3.UNIT_Z);
 
manualObject.Position(new Vector3(0, -yWidthVariable, 0));
manualObject.TextureCoord(0, 0f);
manualObject.Normal(Vector3.UNIT_Z);
manualObject.Position(new Vector3(xWidth, 0, 0));
manualObject.TextureCoord(1f, 1);
manualObject.Normal(Vector3.UNIT_Z);
 
manualObject.Position(new Vector3(0, -yWidthVariable, 0));
manualObject.TextureCoord(0f, 0f);
manualObject.Normal(Vector3.UNIT_Z);
manualObject.Position(new Vector3(xWidth, -yWidthVariable, 0));
manualObject.TextureCoord(0f, 1.0f);
manualObject.Normal(Vector3.UNIT_Z);
manualObject.Position(new Vector3(xWidth, 0, 0));
manualObject.TextureCoord(1f, 1.0f);
manualObject.Normal(Vector3.UNIT_Z);
 
manualObject.End();
 
manualObject.CastShadows = false;
 
return manualObject;
}



Also you can get the size of the "poster" by using the boundingbox. An example of use :

manualObject.BoundingBox.Size.x * 0.5f * Vector3.UNIT_Y;

The code can be find as an attached file.

kick it on DotNetKicks.com
 

Use dataBinding and DependencyProperty with a non-WPF or extern object

10 April 2009

Today we are going to learn how we can uses the powerful data binding of WPF even on non-WPF objects.

The problem: when to use this solution ?

Sometimes you need to use the databinding with an object that you have not created and you can't use inheritance.

For example I wanted to use a Mogre Camera and build some WPF animation with it and I couldn't because :

  • WPF animation needed a DependencyProperty to manipulate,
  • I couldn't derive the Mogre.Camera class and add it the correct things because I got the camera from a factory object (the sceneManager).



Then I couldn't use the WPF animation to move my camera... next is how I solve it.

A solution: mine and surely not the best ;-)

Here is the solution i use:

  1. Create a proxy DependencyProperty inside a DependencyObject, for example your main windows.
  2. Override the OnPropertyChanged handler.
  3. Update the aimed attribute inside the handler.


To control my camera, I created this DependencyProperty inside my windows:

public static readonly DependencyProperty CameraPositionProperty = DependencyProperty.Register("CameraPosition", typeof(Point3D), typeof(SurfaceWindow1), new PropertyMetadata(new Point3D(0, 0, 0)));
 
      public Point3D CameraPosition
      {
         get
         {
            return (Point3D)GetValue(CameraPositionProperty);
         }
         set
         {
            SetValue(CameraPositionProperty, value);
         }
      }


Then I added this override :

protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
      {
         base.OnPropertyChanged(e);
         if (e.Property.Name.Equals("CameraPosition"))
         {
            _ogre.Camera.SetPosition((float)((Point3D)e.NewValue).X, (float)((Point3D)e.NewValue).Y, (float)((Point3D)e.NewValue).Z);
            _ogre.Camera.LookAt(Vector3.ZERO);
         }
      }



And my usual question :

Does someone have a better idea to perform the same ?



 

Calculate the real difference between two angles, keeping the correct sign

1 April 2009

When you build some animations with WPF, Surface or JavaFX you sometimes need to know how evolve an angle. For example, you have the new angle (orientation) of an object and you have store before the last measure of this orientation : how to calculate the evolution ?
calculateAnglesBetweenOrientationExemple1

A first solution

"This is simple" will you say, just do this :

double difference = secondAngle - firstAngle;

But this snippet leads to errors. This is because the orientation value given is relative to a certain initial value, and restart to 0° if you pass the 360°. Lets give you an example: if the object was oriented at 358° and the user turns it of 5° you will obtain a difference of (3-358=) -355° where you actually wants to find 5....

A better solution

A solution I propose is to consider that the methods is called enough frequently that if the object rotate to the left or to the right it has not enough time to rotate more than 180° (half a tour).

Based on this, we consider that the direction of the rotation is given by the "shortest way". If it shorter to turn to the left to go to the new angle, then we select the angle sign which tells we have turned to the left. It may be easiest to understand by looking atentivly to the image above.

An image is maybe better than word : calculateAnglesBetweenOrientationExemple2



We then have this method in C#:

private double calculateDifferenceBetweenAngles(double firstAngle, double secondAngle)
  {
        double difference = secondAngle - firstAngle;
        while (difference < -180) difference += 360;
        while (difference > 180) difference -= 360;
        return difference;
 }


A case of use

When do use it ? For example when you build a carousel: the user can click on a specific item and the carousel rotate so it is in front of you. You then need to have the correct angle. I found no other way to do it.

Does someone have a better way to proceed ?



Shout it
 

Use a screenshot of a WPF visual as a texture in Mogre.

25 March 2009

Hello, Here is my first post about WPF and Mogre, maybe it will helps some people... The subject of today is "How to use a screenshot of a WPF elements and put it as an texture on your Mogre object"...

Why ? Because WPF enable you to create very rich interface and so great image to place on you differents elements...



By the way, I let you follow the link at the end of the post to learn how to blend Mogre in WPF and how to take a screenShot of a WPF visual.

The steps to follow are these :

  1. Create a screenshot of the WPF visual (any visual can be used),
  2. Put the bitmap in a stream and then to a buffer,
  3. Use some unsafe code to create a Mogre MemoryStream and a mogre image,
  4. Use this image to create a texture,
  5. Use this texture in a material,
  6. Put it on the mesh of your choice



Create a screenshot of the WPF visual

The original code is from thomas lebrun and can be found in any good WPF book :

Visual theVisual = this ; //Put the aimed visual here.
double width = Convert.ToDouble(theVisual.GetValue(FrameworkElement.WidthProperty));
double height = Convert.ToDouble(theVisual.GetValue(FrameworkElement.HeightProperty));
if (double.IsNaN(width) || double.IsNaN(height))
{
throw new FormatException("You need to indicate the Width and Height values of the UIElement.");
}
RenderTargetBitmap render = new RenderTargetBitmap(
      Convert.ToInt32(width),
      Convert.ToInt32(this.GetValue(FrameworkElement.HeightProperty)),
      96,
      96,
      PixelFormats.Pbgra32);
// Indicate which control to render in the image
render.Render(this);
Stream oStream = new MemoryStream();
PngBitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(render));
encoder.Save(oStream);
oStream.Flush();

Put the bitmap in a stream and then to a buffer

//Back to the start of the stream
 oStream.Position = 0;
 
//read all the stream
BinaryReader oBinaryReader = new BinaryReader(oStream);
byte[] pBuffer = oBinaryReader.ReadBytes((int)oBinaryReader.BaseStream.Length);
oStream.Close(); //No more needed
TextureManager.Singleton.Remove(sName); //Remove eventually texture with the same name

Create the texture

unsafe
         {
            GCHandle handle = GCHandle.Alloc(pBuffer, GCHandleType.Pinned);
            byte* pUnsafeByte = (byte*)handle.AddrOfPinnedObject();
            void* pUnsafeBuffer = (void*)handle.AddrOfPinnedObject();
 
            MemoryDataStream oMemoryStream = new MemoryDataStream(pUnsafeBuffer, (uint)pBuffer.Length);
            DataStreamPtr oPtrDataStream = new DataStreamPtr(oMemoryStream);
            oMogreImage = oMogreImage.Load(oPtrDataStream, "png");
 
            TextureManager.Singleton.LoadImageW(sName, ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME, oMogreImage);
 
            //handle.Free();
         }

Use this texture in a material

Here is the code of how you can create a material with this texture:

_dynamicMaterial = MaterialManager.Singleton.Create(SCREENSHOT_MATERIAL_NAME, ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME);
Pass pass = _dynamicMaterial.GetTechnique(0).GetPass(0);
 
TextureUnitState tus = pass.CreateTextureUnitState(SCREENSHOT_TEXTURE_NAME);
_dynamicMaterial.GetTechnique(0).GetPass(0).AddTextureUnitState(tus);

Then you just have to use it as a normal texture...

An example:

Here is a little screenshot of the results. I display a cube with the face using as a texture a screenshot of the window in which it is.... WPF screenshot as a texture in Mogre



Link: how to blend Mogre in WPF

 

Some news !

8 February 2009

Hello,

 

Long time i didn’t post on this blog for some reasons :

  • I had a lot of projects to do for my school,
  • I have to find a place to do my training…

 

No it’s ok and i am back to post some entries on this blog again…

 

I am doing my training on WPF and Surface so I widen the scope of the blog…

+++

 

Create your VideoPlayer with JavaFX, part three(Add a control bar).

22 December 2008

Let's continue pur story about creating our own media player.

You can find a demo of the resulting videoPlayer on this page: demo of the videoPlayer - part 3.

What will we do in our third part ? :

  1. Add a control bar to the videoPlayer
  2. Display the progess of the video in this bar
  3. Add a play/pause button in this bar
  4. Enjoy ourselves!



Add a control bar to the videoPlayer

The goal is to display a control bar when the mouse is hover the video or when the media is paused.

The control bar will look like this : Video player how-to: the control bar.

First we create the gray rectangle which is behind the meta-information and the two differents text. We will add them to a group to ease the use of trigger to show/hide them.

/** ###########################################
    * The control bar
    *   ########################################### */
 
var controlBarBackGroundRect : Rectangle = Rectangle{
        x:x
        y: vidHeight + y - 40
        width:vidWith
        height: 40
        opacity:0.5
        fill:Color.DARKGRAY
    }
 
    var playPauseGroupWidth = 20 ;
    var pauseGroup : Group = Group{content:[]};
    var playGroup : Group = Group{content:[]};
    var progressNode  = Group{content:[]};
 
 
    var groupControlBar: Group = Group{
        content: [controlBarBackGroundRect,progressNode, pauseGroup, playGroup]
        cursor: Cursor.DEFAULT
        opacity: 0.0
}


Don't forget to add it in the returned Group of our component:

return Group{
            content: [mediaView,groupVidMETA, groupControlBar]
        }


What you can notice is that we have already prepare the differents things which will be putted in : the playButton, the pauseButton, the progressNode and the grayRectangle which is the bacground ofthe controlbar.

Display the progess of the video in this bar

To display the progress of the media we will create a Progress's node. To create this progress Node we will uses the james weaver's how-to which is on this page : Progress Indicator: Creating a JavaFX Custom Node and Binding to a Model but we will customize it a little to fits our specifications.

Here is a summary of the changes :

  • No more polygon for the progression but a good old Rectangle,
  • Add left, right and center text.

And here is the code :

/*
 *  ProgressNode.fx -
 *  A custom node that functions as a progress bar
 *  TODO: Add the ability to have an "infinite progress" look as well
 *
 *  Developed 2008 by James L. Weaver (jim.weaver at lat-inc.com)
 *  to demonstrate how to create custom nodes in JavaFX
 *
 *  Used and changed 2008 by Jonathan ANTOINE to use in his videoPlayer
 */
 
package fr.antoinej.tools;
 
import javafx.scene.CustomNode;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.paint.Color;
import javafx.scene.paint.LinearGradient;
import javafx.scene.paint.Paint;
import javafx.scene.paint.Stop;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
import javafx.scene.text.Text;
import javafx.scene.text.TextOrigin;
 
public class ProgressNode extends CustomNode {
 
    /*
    * A number from 0.0 to 1.0 that indicates the amount of progress
     */
    public var progress:Number;
 
    /*
    * The fill of the progress part of the progress bar.  Because
     * this is of type Paint, a Color or gradient may be used.
     */
    public-init var progressFill:Paint =   LinearGradient {
        startX: 0.0
        startY: 0.0
        endX: 0.0
        endY: 1.0
        stops: [
            Stop {
                offset: 0.0
                color: Color.rgb(0, 192, 255)
            },
            Stop {
                offset: 0.20
                color: Color.rgb(0, 172, 234)
            },
            Stop {
                offset: 1.0
                color: Color.rgb(0, 112, 174)
            },
        ]
    };
 
    /*
    * The fill of the bar part of the progress bar. Because
     * this is of type Paint, a Color or gradient may be used.
     */
    public-init  var barFill:Paint = LinearGradient {
        startX: 0.0
        startY: 0.0
        endX: 0.0
        endY: 1.0
        stops: [
            Stop {
                offset: 0.0
                color: Color.rgb(112, 112, 112)
            },
            Stop {
                offset: 1.0
                color: Color.rgb(88, 88, 88)
            },
        ]
    };
    /*
    * The color of the progress percent text on the progress bar
     */
    public-init var progressPercentColor:Color = Color.rgb(191, 223, 239);
 
    /*
    * The color of the progress text on the right side of the progress bar
     */
    public-init var progressTextColor:Color = Color.WHITE;
 
    /*
    * Determines the width, in pixels, of the progress bar
     */
    public-init var width:Integer = 200;
 
    public var leftStr : String = "";
    public var rightStr : String = "";
    public var centerStr : String = "";
 
    /*
    * Determines the height, in pixels, of the progress bar
     */
    public-init var height:Integer = 20;
 
    /**
    * Create the Node
     */
    public override function create():Node {
        var textRef:Text;
        var progBarFont =Font.font("Verdana", FontWeight.EXTRA_BOLD, 10);
        var leftAndRightFont =Font.font("Sans serif", FontWeight.EXTRA_BOLD, 10);
        return Group{
 
            content: [
                // The entire progress bar
                Rectangle {
                    x:0
                    y:0
                    width: bind width
                    height: bind height
                    fill: bind barFill
                },
                Rectangle {
                    x:0
                    y:0
                    width: bind progress * width
                    height: height
                    fill: bind progressFill
                }
              ,
                // The percent complete displayed on the progress bar
                textRef = Text {
                    translateX: width / 2 - 20
                    translateY: 5
                    textOrigin: TextOrigin.TOP
                    font: progBarFont
 
                    fill: bind progressPercentColor
                    content: bind "{centerStr}({progress * 100 as Integer}%)"
                },
                Text {
                    translateX: bind width  - rightStr.length() * 6
                    translateY: 5
                    textOrigin: TextOrigin.TOP
                    font: leftAndRightFont
                    fill: bind progressPercentColor
                    content: bind "{rightStr}"
                },
                Text {
                    translateX: 4
                    translateY: 5
                    textOrigin: TextOrigin.TOP
                    font: leftAndRightFont
                    fill: bind progressPercentColor
                    content: bind "{leftStr}"
                }
 
            ]
        }    
 
    }
 
 
}



Now we gonna add it to our videoPlayer changing the precedent progressNode declaration by this one :

var progressNode: ProgressNode =
    ProgressNode{
        translateX:controlBarBackGroundRect.x + 10 + playPauseGroupWidth
        translateY:controlBarBackGroundRect.y + 10
        progress: bind mediaPlayer.currentTime.toMillis() / media.duration.toMillis()
        centerStr: bind "{%tM mediaPlayer.currentTime.toDate()}:{%tS mediaPlayer.currentTime.toDate()}"
        height:20
        width: vidWith - 20 - playPauseGroupWidth
        leftStr:"0:00${media.duration}"
        rightStr: bind "{%tM media.duration.toDate()}:{%tS media.duration.toDate()}"
    };

Note that we bind the rightStr to fit the sun usages given on this page.



Add a play/pause button in this bar

Now we gonna add a play/pause button. To do this we are going to create two groups, a play group which will be visible when the video is paused and a pause group visible when the video is played.

To create this buttons we are using polygons whe re some may prefers image: that's our choice !


Here is the code :

var pauseGroup : Group = Group{
        var rect1 =Rectangle {
            x: controlBarBackGroundRect.x + 7
            y: controlBarBackGroundRect.y + 13
            width: 4
            height: 13
            fill: Color.WHITE
            } ;
        var rect2 = Rectangle {
            x: controlBarBackGroundRect.x + 14
            y: controlBarBackGroundRect.y + 13
            width: 4
            height: 13
            fill: Color.WHITE
            };
        content: [rect1,rect2 ,
            Rectangle {
                x: controlBarBackGroundRect.x + 4
                y: controlBarBackGroundRect.y + 11
                width: 17
                height: 16
                fill: Color.TRANSPARENT
            }
        ]
        cursor:Cursor.HAND
        //On left click, play or pause the video
        onMouseClicked: function(me: MouseEvent){
            //Only a left click play/pause the video
            if(me.button == MouseButton.PRIMARY) {
                mediaPlayer.pause();
            }
        }
        onMouseEntered: function(me: MouseEvent){
            Timeline {
                keyFrames: [
               at(0s) {
                    rect1.fill => rect1.fill  tween Interpolator.LINEAR;
                    rect2.fill => rect1.fill  tween Interpolator.LINEAR;
              }
                  at(800ms) {
                    rect1.fill => Color.RED  tween Interpolator.LINEAR;
                    rect2.fill => Color.RED tween Interpolator.LINEAR;
            }
                ]
            }.play();
 
        }
        onMouseExited: function(me: MouseEvent){
            Timeline {
                keyFrames: [
               at(0s) {
                    rect1.fill => rect1.fill  tween Interpolator.LINEAR;
                    rect2.fill => rect1.fill  tween Interpolator.LINEAR;
              }
                  at(800ms) {
                    rect1.fill => Color.WHITE  tween Interpolator.LINEAR;
                    rect2.fill => Color.WHITE  tween Interpolator.LINEAR;
            }
                ]
            }.play();
 
        }
 
        visible: bind (mediaPlayer.status == mediaPlayer.PLAYING)
}
 
    var playGroup : Group = Group{
        var polygon = Polygon {
            points: [
                    controlBarBackGroundRect.x + 7,controlBarBackGroundRect.y + 14 ,
                    controlBarBackGroundRect.x + 7,controlBarBackGroundRect.y + 27,
                    controlBarBackGroundRect.x + 20,controlBarBackGroundRect.y + 20 ]
            fill: Color.WHITE
           };
        content: [polygon ,
            Rectangle {
                x: controlBarBackGroundRect.x + 4
                y: controlBarBackGroundRect.y + 11
                width: 17
                height: 16
                fill: Color.TRANSPARENT
            }
        ]
        cursor:Cursor.HAND
        //On left click, play or pause the video
        onMouseClicked: function(me: MouseEvent){
            //Only a left click play/pause the video
            if(me.button == MouseButton.PRIMARY) {
                mediaPlayer.play();
            }
        }
        onMouseEntered: function(me: MouseEvent){
            Timeline {
                keyFrames: [
               at(0s) {
                    polygon.fill => polygon.fill  tween Interpolator.LINEAR;
                             }
                  at(800ms) {
                    polygon.fill => Color.RED  tween Interpolator.LINEAR;
                             }
                ]
            }.play();
 
        }
        onMouseExited: function(me: MouseEvent){
            Timeline {
                keyFrames: [
               at(0s) {
                    polygon.fill => polygon.fill  tween Interpolator.LINEAR;
                              }
                  at(800ms) {
                    polygon.fill => Color.WHITE  tween Interpolator.LINEAR;
                           }
                ]
            }.play();
 
        }
 
        visible: bind (mediaPlayer.status == mediaPlayer.PAUSED)
}



You can find our component source in this post and view a demo on this page: demo of the videoPlayer - part 3.

 

how do I detect double clic in JavaFX ?

14 December 2008

I am currently confronted to this problem: detect double clic in JavaFX.

What I want to do :

When you make a double click, you click twice, so this is what will occurs:

  • The first click will be catch and the simpleClickAction will be done (because clickCount != 2) ---> I don't want it : this is a double click and I want the simpleClick action to be perform only on single click !,
  • The second click will be catch and the double clickAction will be done --> This is what I want.


So what I want is :

  • To perform a simpleClick action on single click only (and not those which are part of a double click),
  • To perform a double click action on doubleClick only.


How I did it

In swing this is done by using timer. So why not do the same with a Timeline in JavaFX.


This is how I solve the problem (the code is also linked to this post) :

/*
 * Main.fx
 *
 * Created on 14 déc. 2008, 15:10:59
 */
 
package fr.antoinj.detectdoubleclick;
 
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.scene.Group;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.scene.Scene;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
import javafx.scene.text.Text;
import javafx.stage.Stage;
 
/**
 * @author Jonathan
 */
 
var textContent = "Nothing detected";
var clickInTheLastFewMoments: Boolean = false;
var lastLauchedTimeLine:Timeline ;
var clickedTimeLine: Timeline= Timeline {
    keyFrames: [KeyFrame {
            time: 0s
            action:function(){
                lastLauchedTimeLine.stop();
                clickInTheLastFewMoments=true;
            }
        }
        ,
        KeyFrame {
            time: 200ms
            action:function(){
                clickInTheLastFewMoments=false;
                simpleClick();
            }
        }
    ]
}
 
function simpleClick(){
    textContent="Simple click detected";
}
function doubleClick(){
    textContent="Double click detected";
}
Stage {
 
 
    title: "How I detect doubleClick in JavaFX"
    width: 400
    height: 80
    scene: Scene {
        content: Group{
            content: [Rectangle {
                    x: 75,
                    y: 0
                    width: 400,
                    height: 50
                    fill: Color.BLACK
                    onMouseClicked: function(me:MouseEvent){
                        if(clickInTheLastFewMoments){
                            clickInTheLastFewMoments=false;
                            clickedTimeLine.stop();
                            doubleClick();
                        }else {
                            clickedTimeLine.playFromStart();
                        }
                    }
                },
 
                Rectangle {
                    x: 0,
                    y: 0
                    width: 75
                    height: 50
                    fill: Color.ORANGERED
                    onMouseClicked: function(me:MouseEvent){
                        textContent="Nothing detected";
                    }
 
                },
                Text {
                    font: Font.font("Verdana",FontWeight.BOLD,12)
                    fill: Color.BLACK
                    x: 8
                    y: 25
                    content: "REFRESH"
                }
                ,
                Text {
                    font: Font.font("Verdana",FontWeight.MEDIUM,24)
                    fill:Color.PINK
                    x: 80
                    y: 30
                    content: bind textContent;
                }]
 
        }
 
    }
}

You can also see a demo of this javaFx apps here : link to the demo page or launch this JNLP : link to the JNLP



My question is : Do you have a better way to do this ?

 

Create your VideoPlayer with JavaFX, part two.

Let's continue pur story about creating our own media player

What will we do in our second part ? :

  1. Display the meta-information of our video.
  2. Create animation and triggers to show it in a non-disturbing way.
  3. Add some triggers to our video : play/pause on click.
  4. Double-clic to resume the video
  5. Enjoy ourselves!



Display the meta-informations in a non-disturbing way

We already have all the informations to display because we gived them to our component.
Now we will display them in an header: Videoplayer's metainformation header

First we create the gray rectangle which is behind the meta-information and the two differents text. We will add them to a group to ease the use of trigger to show/hide them.

/** ###########################################
    * The Top Rectangle of description
     *   ########################################### */
    var topRDescription : Rectangle = Rectangle{
        x:x
        y:y
        width:vidWith
        height: 40
        opacity:0.5
        fill:Color.DARKGRAY
}
 
    var titleText: Text =  Text{
        x:topRDescription.x + 10
        y: topRDescription.y + 25
        textOrigin: TextOrigin.BOTTOM
        content: bind vidTitle
        fill:Color.ORANGE
        font: Font.font("Verdana", FontWeight.EXTRA_BOLD, 18)
}
 
    var descriptionText: Text =  Text{
        x:topRDescription.x + 10
        y: topRDescription.y + 35
        content: bind vidDescription
        fill:Color.WHITE
        font: Font.font("Verdana", FontWeight.MEDIUM, 10)
}
 
    var groupVidMETA : Group = Group{
        content: [topRDescription,titleText,descriptionText]
        cursor: Cursor.DEFAULT
        opacity: 0.0
        visible: bind showInfoBar
}


Don't forget to add it in the returned Group of our component:

return Group{
            content: [mediaView,groupVidMETA]
        }


You can see that the visibility of our meta-information's bar is bind to a var showInfoBar. This is on this var that we will act to show/hide the bar. Sets this var to true and the informations will be displayed all the time... this is cool but quite boring when you want watch the movie which is behind. We will so add some animations to display it in a non disturbing way.

Create animation and triggers to show it in a non-disturbing way.

We will now display the bar only when the mouse is hover the video or when the video is paused.
To do this we will use the opacity of the bar and add animation in the MediaView's node triggers. Remember the MediaView is the node in which the media is displayed.
Resume of the things to do :

  • Add the onMouseEntered trigger to the MediaView,
  • Creates and play an animation in it which will set the groupVidMETA'opacity from it's current state to 1 in 500ms.
  • Add the onMouseExited trigger to the MediaView and add an animation to hide the meta's info only if the video is not paused.


The resulting mediaView var is then :

//The node displaying the video   
    var mediaView : MediaView = MediaView{
        x:x
        y:y
        mediaPlayer: bind mediaPlayer
        fitHeight:vidHeight
        fitWidth:vidWith
          //Show the informations in an animation.
        onMouseEntered: function(me: MouseEvent){
            Timeline {
                keyFrames: [
               at(0s) {
                    groupVidMETA.opacity =>    groupVidMETA.opacity tween Interpolator.LINEAR;
                    groupControlBar.opacity => groupControlBar.opacity  tween Interpolator.LINEAR;
                }
                  at(500ms) {
                    groupVidMETA.opacity => 1.0 tween Interpolator.LINEAR;
                    groupControlBar.opacity => 1.0 tween Interpolator.LINEAR;
            }
                ]
            }.play()
 
        }
        //Hide the informations in an animation if the video is not paused.
        onMouseExited: function(me: MouseEvent){
            if(mediaPlayer.status != MediaPlayer.PAUSED){
                Timeline {
                    keyFrames: [
               at(0s) {
                        groupVidMETA.opacity => groupVidMETA.opacity  tween Interpolator.LINEAR;
              }
                  at(500ms) {
                        groupVidMETA.opacity => 0.0 tween Interpolator.LINEAR;
            }
                    ]
                }.play();
 
            }
        }
};


We are abble to know if the video is paused by accessing the mediaPlayer's status and comparing it to it's PAUSED def.
Now that informations are displayed, we will add triggers to play or pause the video.

Add some triggers to our video : play/pause on click.

This is done by adding a onMouseClicked trigger to our mediaView Component. We will also check that it's the left button that is clicked to perform the play/pause and reserve the right button to maybe future functionnality.
Also we will set the cursor to the HAND def: tell our watcher that they can do something by clicking the video.
This is what we add to our mediaView component:

cursor:Cursor.HAND
 
        onMouseClicked: function(me: MouseEvent){
            //Only a left click play/pause the video
            if(me.button == MouseButton.PRIMARY ) {
 
                if(mediaPlayer.status == mediaPlayer.PAUSED){
                    mediaPlayer.play();
                }else {
                    mediaPlayer.pause();
                }
            }
        }


Enjoy ourselfs

You can find our component source in this post and view a demo on this page: demo of the videoPlayer - part 2.
It can be long to load... My server fault ...

 

How I resolve my "MediaUnavailableException"'s problem in JavaFX...

10 December 2008

hey,

In my first try to create a videoPlayer I always get an exception trying to play a media which are on my local hard disk.

The problem

I was trying to execute this media :

var mediaURL : String = "file://C:/tchou.flv";

But it generates me logs like this one :

FX Media Object caught Exception com.sun.media.jmc.MediaUnavailableException: Media unavailable:


I search on the web and I notice that I was not alone facing this problem : look at this post.
But nobody seems to find the answer to this problem...

The solution

Actually I finally manage to get ride of this exception and it was quite simple : we should use '/' instead of '//' when using the "file" protocol. You just have to use the code below and it will work :

/*
* Do not use this :
* var mediaURL : String = "file://C:/tchou.flv";
*/
var mediaURL : String = "file:/C:/tchou.flv";

Quite easy in fact !

 

Create your VideoPlayer with JavaFX, part one.

9 December 2008

I noticed in this post that the mediaComponent pointed out in the JavaFX demos was not still available and that we will so make our own...

Lets start !

What will we do in our first part ? :

  1. Create our custom node MyMediaComponent
  2. Add the video in our component
  3. Enjoy ourselfs!



Create our custom node: MyMediaComponent

The first thing to do is quite easy : create a new JavaFX class in Nebeans and make it extends the CustomNode class from the javafx.scene package. This class is provided to enable you making your own nodes.

You will then have to ovveride the "create():Node" method :

public override function create():Node{
        return Group{
            content: []
        }
    }

We will add more things in the content when we will build them.
First we will add some var to our class, They will contains some informations about our component :

/** X attribute of our component. */
 public var x : Integer = 0 ;
 /** Y attribute of our component. */
 public var y : Integer = 0 ;
 
/** A description of the video. */
public var vidDescription : String = "" ;
/** The title of the video. */
public var vidTitle : String = "" ;
/** Start volume of the video. */
public var startVolume : Number = 0.5;
/** Do where display the meta informations on the video */
public var showInfoBar : Boolean = true;
/** The url of the video. */
public var mediaURL : String ="" ;
/** The Width in wich where will make the video fit. */
public var vidWith : Integer = 384;
/** The height in wich where will make the video fit. */
public var vidHeight : Integer = 288 ;



Add the video in our component

We will add the video in our component. To add this features we will use three differents Object in the JavaFX API:

  • Media : contains the basic informations about our media, Note that it can be a video or an audio media...
  • MediaPlayer: this object is used to perform the differents actions on our video; play/pause. This component also contains the informations about the status of the current video: playing/paused/buffering, etc ... We give it the media.
  • MediaView: this object is the node in which the video is displayed. We give it the mediaPlayer.



Lets add it in our class and use the differents var we created just before :

var media:Media = Media{
        source: mediaURL
    };
    var mediaPlayer: MediaPlayer = MediaPlayer{
        media:media
        autoPlay:true
    };
 
    var mediaView : MediaView = MediaView{
        x:x
        y:y
        mediaPlayer: bind mediaPlayer
        fitHeight:vidHeight
        fitWidth:vidWith
      };

The autoPlay attribute tells that the video is played as soon as it can be by the player (when enough data is available when buffered).


Now that we have created the different component we will add the mediaView in the group returned by our create() function:

public override function create():Node{
        return Group{
            content: [mediaView ]
        }
    }


Now by adding our component in your application you will display the video and play it. This is a first step in the birth of our videoComponent: Video player, results of part one.


In the next part you will learn how to display the informations on the video currently played when hovering the video and how to add some triggers (play/pause the video by clicking on it).

+++

 

You could use the JavaFX Media Component.... Yes but where is it ?

8 December 2008

Have you been trying all the wonderful demo on on the JavaFX web site ? Yes ? Me too !

You can try the "Simple Video Player" for example :

Simple Video Player sample

It's great but when I tried to reproduce the video player i meet a little problem.

It tells "You could use the JavaFX Media Component, a prefabricated video player in the com.sun.fxmediacomponent package."... But where is it ? I Just cannot find it on the web...

You then have two solutions:

  1. Download the source code and use the jar file present in the lib folder,
  2. Reproduce this package by your own implementations...

I really prefere the second solutions and I will make a little How-To in a future posts to tell you how to do...

++

 

- page 3 of 4 -