Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Avoiding screen flicker when updating TImage 3

Status
Not open for further replies.

biot023

Programmer
Nov 8, 2001
403
GB
Hallo - I have a program that constantly updates a bitmap to a TImage.
I know there is some technique for avoiding the flicker (at least, I think I know there is), but I'm damn'ed if I can think of it!
Can anyone help?
Cheers,
DJL

Common sense is what tells you the world is flat.
 
look into the help section for "DoubleBuffered".
Should help you reduce the flicker
 
I'm not sure if you're copying a completed bitmap into your TImage or if you're actually processing the bitmap as you're drawing into the TImage.

So I'll just leave you a few tips.

First, you say you're using a TImage. That isn't a descendant from TWinControl so you shouldn't get that much flicker anyways. Components that are descendants from TWinControl (like TPanel and TButton) should override the WM_ERASEBKGND message so that it doesn't erase the background. This is the usual cause of flicker. But with TImage, this doesn't happen.

Flicker also happens when you're drawing onto the screen and the video beam crosses where you are drawing showing part of the new image and part of the old one until the next frame.

So either you're drawing too slow or you're drawing way too fast. You should only draw 1 image per video frame (around 70-80 fps on monitors). You should try to set a more consistant timing to your drawing. Or you can go the real complicated way and create a DirectX window. This way, you can be told when a new frame is starting and draw then when the beam is off the screen thus eliminating flicker completely. But you have to draw fast enough that the beam doesn't catch up to your window while you're drawing in it.

So it's up to you how much work you want to put into it.

I would time how long it takes you to draw into the TImage. My guess is that you're either too slow (more than 1/70th of a second) or too fast (you're drawing more than 30-60 images per second). However, for normal Windows apps, you're gonna get flicker no matter what if you don't time it and you have any significant amount of animation.

Sorry for the long rant, but I hope it gives you some insight on the problem.

I just thought of something. Are you using a transparent image? If so, the background window will have to be redrawn and cause serious flicker.

Good luck


A programmer is a device for converting Coke into software.
 
Hi :)

First try setting the Stretch property to true, if some reason your requirement is not to do so then try placing the TImage onto a TPanel, then set

Panel1->DoubleBuffered=true;

You could set it for the whole form

Form1->DoubleBuffered=true;

but rather set this for the panel only.

 
All new information, thanks!
I kind of cheated & just drew to the form's canvas, but I'll be able to be a little more sophisticated, now.
Thanks again,
DJL

PS - happy new year!

Common sense is what tells you the world is flat.
 
As a suggestion, most people aren't going to acknowledge an update of something simple, i.e. a graph or chart, more than twice a second. If you are wanting to animate using a TImage by drawing to the Canvas, I recommend using a TAnimate instead if possible.

Note that the reason the TImage flickers is because of the erase_background being forced to true by the compiler. Borland likes to hide a lot of the inner workings to make things easier, but this is one of the biggest causes of flicker that gets most native Borland programmers (who never wrote applications with MSVC where you had to decide each time you validate a window whether to erase it's background or not).

See, when the TImage erases the background, it goes ahead and draws it erased if the vertical refresh is up. The vertical refresh is when the electron beam in the monitor has drawn the whole screen but has to return from one corner back to the opposite corner. During this time is when most memory on the device is updated. What happens is that the memory receives the "Erase" data (which is probably just the background color), then the vertical refresh occurs and the memory is locked, the image is drawn to screen, and your code was interrupted before it could draw the next portion of the TImage. Hence, your image disappears for a frame once in a while.

This is where double buffering comes into play. This was a common problem with old games, so they would create 2 buffers of memory on the video card and begin displaying buffer 1 (called the primary buffer) by setting a register or memory location in the video card indicating the address of the buffer to display (the address of buffer 1). They would then take as long as they needed to copy the image data to buffer 2 (secondary buffer), then change the register in the video card to reflect the address of buffer 2. Now buffer 2 is the primary buffer and is being displayed, and the program starts the next frame off by updating buffer 1 (the secondary buffer). Each frame, they would flip the buffers, hence double buffering and the prevention of "tearing" of the image on screen.

You can create a new component, based on TGraphicControl. Update the OnPaint event handler to do the following:

What you want to do is create a static Graphics::TBitmap *Buffer at program startup. Every frame (say we choose 2 Hz), you update the Buffer with all of the drawing that needs to take place. At the end of the frame, you say "Canvas->Draw(0, 0, Buffer);"

Using a simple bar graph as an example, which can get pretty complicated and time consuming redrawing every part, you could create a Buffer for each part of the graph. The background would be a Buffer. That might contain just the background color, a rectangle, the numbers, and marks out to the side of the graph. Then you might have another Buffer for the bars, which may be constantly changing but require much less time to process, since you're just drawing rectangles. At the end of every frame, you would call:

Buffer->Draw(0, 0, BackBuffer);
Buffer->Draw(0, 0, BarBuffer);
Canvas->Draw(0, 0, Buffer);

Just keep in mind that all of the canvases must be the same width and height to prevent distortion. Also note that the Canvas->Draw...that Canvas is the main canvas of the component you are creating.

Hope this helps,
Chris
 
Oh, one other thing. When you want to "Update" the component's image, don't call Update or Refresh or Repaint. Call Paint directly. This prevents the erasing of the background that gets done in the call to Update.
 
Supernat03

Any chance you would put you tips on graphics stuff in a doc so I/We could download them. I wondered why builder produced flickering graphics. Nice reply.

Mike



 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top