I have an old program written开发者_运维知识库 in borland pascal and in Delphi if I use the Form1.Canvas.LineTo and MoveTo functions I get a flickering effect. Can anyone tell me how to get rid of the flickering?
Try to set DoubleBuffered
to true in Form.OnCreate
.
A general technique for reducing flicker in animated graphics operations is called double buffering. The idea is that you do all drawing to an offscreen bitmap, then when you've finished rendering the whole scene, copy the entire bitmap to the visible display.
The term also relates to hardware-supported techniques such as the ability to exchange the whole video display buffer with an alternate one, which is used in dedicated systems like console video games.
Although using double buffering is usually the best solution, it is not always the right solution, and definitely not the most memory saving solution. However if you only draw a part of the image, I'd go with that solution as well setting DoubleBuffered
to true
as mentioned in the other comments.
However if you fill the entire components area every time you draw anyway, you might want to choose a different approach. If you set the ControlStyle
to csOpaque
you'll avoid having the component erase the background, and thereby removing a source of the flickering, without having to double buffer. This of course requires you to draw on the entire component area, so the solution is only really suitable if you do.
In general however if memory consumption is of no importance, I'd go for the double buffering as well, I just wanted to supply you with an alternative. :)
Easy code sample on the double buffering.
Create Buffer ( TBitmap )
Draw on the Buffer canvas.
Draw the bitmap on the canvas. Form1.Canvas
for example.
Buffer := TBitmap.Create;
try
Buffer.Width:=Form1.Width;
Buffer.Height:=Form1.Height;
//clearBuffer
Buffer.Canvas.FillRect(Buffer.Canvas.ClipRect);
//draw Something
Buffer.Canvas.TextOut(0,0,'Hello World');
Buffer.Canvas.Rectangle(0,1,2,3);
//drawBuffer on canvas
Form1.Canvas.Draw(0,0,Buffer);
finally
Buffer.free
end;
Double Buffering is one way but not always sufficient. Imagine you paint a shape at runtime, it depends on your repaint method. Forces the control to repaint its image on the screen could be crucial.
Call Repaint to force the control to repaint its image immediately. If the ControlStyle property includes csOpaque, the control paints itself directly. So double buffering plus invalidate and [csOpaque] as controlstyle could be an improvement:
var Compass: TPaintBox;
procedure TForm1ForceRepaint(Sender: TObject);
{Called when display type or compass angle changes}
begin
compass.controlstyle:= [csOpaque];
while heading.value<0 do heading.Value:=heading.Value+360;
while heading.value>360 do heading.Value:=heading.Value-360;
compass.Invalidate;
end;
In my case, none of the above-mentioned solutions really worked. I have two graphics which are overlaying one on another. The change of the DoubleBuffered
property has solved the flickering problem, but the background graphics was not correctly rendered.
After a small research, I have found two alternative fixes described on page https://delphi-bar.blogspot.com/2012/11/prevent-screen-refresh-and-flickering.html.
LockWindowUpdate(Handle);
try
// Code goes here
finally
LockWindowUpdate(0);
end;
As discussed for example here, it is not always a recommended way. The second option, in my case, has fixed almost completely the flicker problem:
SendMessage(Handle, WM_SETREDRAW, WPARAM(False), 0);
try
// Code goes here
finally
SendMessage(Handle, WM_SETREDRAW, WPARAM(True), 0);
RedrawWindow(Handle, nil, 0, RDW_ERASE or RDW_FRAME or RDW_INVALIDATE or RDW_ALLCHILDREN);
end;
精彩评论