Harald Mejlholm

Creating a program for controlling my model train I want to visualize the trains movement. I therefore have created a user control, which I move around on the form controlled by a timer. The graphics on the user control is simply a rectangle, and as the train moves around curved tracks, this rectangle changes it angle within the control. I.e. what the timer event does, is to change the angle property (if necessary) of the control, change it's Location and requests a repaint of the control.

When there is no change in angle, i.e. the train is running on a straight line, the repaint and movement of the control is very nice. But when the angle changes, the movement is seen as 2 steps: change of angle followed by change of location (or vica versa depending of what I do first) - making the movement look flickering.

By putting trace prints into the OnPaint method, I can see, that when no change of angle, OnPaint is called once per timer slot - and when there is a change in angle, OnPaint is called twice with few milliseconds interval. From the trace output I can also see, that the ClipRectangle of the PaintEventArgs parameter to OnPaint changes between the 2 calls. May be that's the reason for the 2 calls...

Is there anyway of avoiding the 2 calls or any other method for getting a smooter movement/turn of the control



Re: Windows Forms General Paint of UserControl

IsshouFuuraibou

On thing that you may want to do is to use SuspendLayout and ResumeLayout when making the changes so that both are drawn together. Alternatively, it might be best to instead of drawing to the control directly, draw to a bitmap and put the bitmap on the control.

What are you using the turn the control Are you using a different control for the tracks and the train

You may want to invest some time into learning more about GDI+ and specifically how it uses transformation matricies (TranslateTransform, RotateTransform, etc) for rotation and translation of GDI+ drawn object





Re: Windows Forms General Paint of UserControl

Harald Mejlholm

Thank you very much for your answer!

I am already using SuspendLayout and ResumeLayout, and I have also tried out some of the various SetStyle-options (DoubleBuffered, UserPaint etc.), but they have not solved the problem. Also I do "heavy" use of the various matrix transformations on graphics and graphicpaths.

To your question: Yes, every track has a control, and every train has one.

I have come across the suggestion of first drawing a bitmap and then put this on the control. But I am not sure, how to draw the bitmap - can I do this the same way, as I draw the graphics directly now Or is there other methods for doing this





Re: Windows Forms General Paint of UserControl

IsshouFuuraibou

You would use the same code, you just would need to get the graphics object from the bitmap by using bitmapName.CreateGraphics() then you can just draw to that graphics object.





Re: Windows Forms General Paint of UserControl

nobugz

A UserControl is just not the right way to do this. No amount of tinkering is going to avoid the double paint. And you'll get in trouble when you get ready to show the train on the rails. Just use the form's Paint event and call e.Graphics.DrawRectangle() to show the train. Use e.Graphics.TranslateTransform and RotateTransform() to get the rectangle in the right position and orientation. Don't give up too quick, you'll need to invest a bit of time to get the transforms to work the way you want them.





Re: Windows Forms General Paint of UserControl

Harald Mejlholm

I may be a little slow in understanding this : in Visual C# the CreateGraphics method is only defined for the Control class - not for the Bitmap class. Or am I completely misunderstanding your point





Re: Windows Forms General Paint of UserControl

nobugz

In the Paint event, you'd use e.Graphics





Re: Windows Forms General Paint of UserControl

Harald Mejlholm

Sorry, but you have to be a bit more specific. I'll show, what I'm doing:

override void OnPaint(PaintEventArgs e)

{

Graphics g = e.Graphics;

...

Here create a graphicpath _Path with the shape, I want and then:

g.FillPath(TrainBrush, _Path);

Add some other stuff to g and then at last:

this.Region = new System.Drawing.Region(_Path);

}

Question: where and how does the Bitmap get into play Please show som sample stmt's.





Re: Windows Forms General Paint of UserControl

IsshouFuuraibou

Code Snippet

override void OnPaint(PaintEventArgs e)
{

Bitmap bm = new Bitmap(); // I believe you need either a file or a memeory stream here
Graphics g = Graphic.FromImage(bm);// Note here
...
Here create a graphicpath _Path with the shape, I want and then:
g.FillPath(TrainBrush, _Path);
Add some other stuff to g and then at last:

e.Graphics.DrawBitmap( bm ); // draw the bitmap to the real control's graphic object
this.Region = new System.Drawing.Region(_Path);
}



Bitmap constructor

Alternatively you may want to look at the BufferedGraphics class (2.0+ only)
BufferedGraphics
This allows you to create your own buffer and not rely on the control to do your double buffering.





Re: Windows Forms General Paint of UserControl

nobugz

Don't be confused about the bitmap. Just use e.Graphics.FillRectangle().





Re: Windows Forms General Paint of UserControl

Harald Mejlholm

After a lot of "tinkering", as you write, time has come to realize, that you're right! Things got better by the various suggestions for improvement, but still: it's not a nice movement, and when the movement gets fast, there is a tail of "old paint" after the train.

Since adding the paint of the train in the forms OnPaint was not a good solution, because of all the other Windows controls, what I have done is to create a large usercontrol (as large as the area, the train has got to "travel") with fixed location = (0,0). In this controls OnPaint method I move and rotate the graphic as needed. Setting the controls region = the graphicspath of the trains graphic, only this is seen - not the whole control. This works fine. So the problem was not changing the position and angle of the graphics, but the movement of the control on the form.

Thanks to all for your help!





Re: Windows Forms General Paint of UserControl

Harald Mejlholm

Just in case others should be fighting with same or similar problems: Drop the concept with UserControls and instead use the WPF facilities, that has come with Visual Studio Express 2008. The combination of WPF's graphics and animation functions works just fine. You can either create real 3D figures or you can - as I have done so far - create 2D shapes and embed them in the combination of Viewport3D, Interactive3DDecorator and TrackballDecorator. If you Google a little, you'll find plenty of examples on how to do this - both in MSDN and elsewhere.