How to eliminate flicker?

rws

Member
Joined
Apr 24, 2003
Messages
12
Location
Vermont, USA
Apologies if this is obvious...

Im using VB in VS.NET Pro.

I want to update a plot of data as the data comes in the serial port.

I maintain a Bitmap on which I plot the data. Every time a new point comes in, I update the Bitmap and invalidate the control (a Panel).

During the Panels Paint event, I grab the graphics object and draw
the entire Bitmap image.

It works, but the Panel flickers annoyingly as the entire Bitmap is redrawn. My PC runs at 2.4GHz.

Is there a way to draw just the new data, without redrawing the old data (axes, tick marks, previous points)?

Thanks.

P.S. I did try using a Metafile instead of a Bitmap, but I was unsuccessful at appending data to an existing Metafile.
 
You can use the method youre currently using to draw a particular section directly to screen, but its often preferrable to use a backbuffer.

To implement a backbuffer, create an image in memory (to which you can grab a handle), draw directly to that, and then draw the entire thing onto your Panel. Im not too familiar with the Panel control, but the PictureBox control may provide you with a little more flexibility in terms of drawing functionality.

Good luck!
 
Thanks for responding...

Originally posted by steved
You can use the method youre currently using to draw a particular section directly to screen, ...

Id like to know how to do that.

The Paint event, it seems, can be used to paint everything only, not a subset. I did try to draw just a rectangle surrounding the new data, and it did that, but the rest of the Panel was blanked.

I dont think a PictureBox would help, since it doesnt support the DrawImage method. By the way, I did this once before in VB6, in which the PictureBox control DOES support DrawImage, and it worked beautifully. Put me down as one of the .NET skeptics.

Still stuck... :(
 
Similar to drawing to/from a buffer, youll need to get a handle to the Panel (or PictureBox) and perform a BitBlt directly onto that device context. Finding DCs and performing blt operations are all well-documented in MSDN, but if youre not sure where to start I can find some articles to point you in the right direction.

Sorry if any of this stuff Im suggesting is out of date, Ive completely dropped VB.net in favor of C#, and I havent had much time to dabble in GDI+ yet - though I know what Im suggesting is still possible (even if it may not be the ".NET way").

If someone knows an easier way for rws to accomplish this, feel free to correct me. :)
 
BitBlt looks like a good approach, but I think it is out of VBs scope.

I found a solution: I created a new panel, sized to surround the new plot data, and I invalidate it instead of the entire Bitmap. The new panel roams around the larger original panel, which contains it.

Kind of clunky, but the flicker is eliminated. Im sure theres still a better way.

Thanks, steved!
 
BitBlt isnt out of VB6s scope, so Im sure its still around in GDI+ for use in VB.net. ;) It would certainly be perferable to moving controls around within other controls.

There might even be a better way than BitBlt, though. Poke around the System.Drawing namespace and see what you can find.
 
Draw the graphics to a bitmap in memory first, then apply it to your object. Thats what I do with my Mp3 players, ect.. that I create music visuals for. I used to get tons of flicker by applying it straight to the picturebox object. Now that I create it in memory first then apply to the object, I have zero flicker and tons of speed to go with it.


Jason
 
Camaro,

I think that you are describing what I tried originally. I kept a Bitmap in memory, and kept it up-to-date. Every time I updated the Bitmap, I invalidated the Panel. This would trigger the Paint event for the Panel. In the Paint event I would draw the Bitmap (DrawImage method). The result was a nice real-time graph of my data, with lots of annoying flicker.

My current strategy, as I described previously, is to do the same thing on a much smaller Panel (the panel containing the new data). The "big picture" flicker is eliminated.

Im still not happy with the results: there are other side-effects of my current strategy.

Im not quite sure what you mean by "apply it to your object." Your comments make sense to me from a VB6 point of view, but not from a .NET point of view.

Thanks for responding.
 
Code:
Public Class PlotArea

 Module-level declarations:
    Private BMap As Bitmap 
    Friend Pen As New Pen(Color.Black, 1)
    Friend WithEvents Window As Panel

Constructor:
Public Sub New (list of dimensional arguments)
...
        Window = New Panel()
        With Window
            .Left = whatever (derived from the dimensional arguments)
            .Width = ditto
            .Height =  ditto
            .Top = ditto
            .BorderStyle = BorderStyle.FixedSingle
        End With

        Create a bitmap image of the Windows graphics layer
        BMap = New Bitmap(Window.Width, Window.Height, Window.CreateGraphics())
...
End Sub

    Heres the method that does the actual plotting:
    Friend Overloads Sub Plot(ByVal x1 As Single, ByVal y1 As Single, ByVal x2 As Single, ByVal y2 As Single)
        Dim PlotGob As Graphics = Graphics.FromImage(BMap)
        Dim x1point, y1point, x2point, y2point As Integer

        x1point = xpixel(x1)   converts to pixels
        y1point = ypixel(y1)
        x2point = xpixel(x2)
        y2point = ypixel(y2)
        PlotGob.DrawLine(Pen, x1point, y1point, x2point, y2point)
        PlotGob.Dispose()
        Window.Invalidate()   triggers the paint event
    End Sub

The Window Paint Event:
    Private Sub Window_Paint(ByVal sender As Object, ByVal pe As System.Windows.Forms.PaintEventArgs) Handles Window.Paint
        Dim PaintGob As Graphics = pe.Graphics
        PaintGob.DrawImage(BMap, 0, 0)
        PaintGob.Dispose()
    End Sub

End Class
 
Double-buffering for flicker-free graphics is built in to the .NET framework. All you have to do it call SetStyle to enable the DoubleBuffer and AllPaintingInWmPaint styles for your control, and perform all your drawing in the Paint event, using the Graphics instance supplied. No offscreen bitmap is required, this is taken care of.
 
That sure sounds like what Ive been looking for!

However, Im having a little trouble calling the SetStyle method because it is Protected.

My understanding is that a Protected method is callable from a derived class. My object is a Panel, which is derived from Control.

What am I missing here?
 
Its not a method of a control. Just simply type:
Code:
SetStyle(chooseproperty,trueorfalse)
 
Protected means you can only call it from _within_ a derived class. So youll have to derive from Panel yourself and use SetStyle in the constructor, ideally.

Its also a good idea to wrap your existing drawing functionality in the class too, it promotes encapsulation of code.
 
Back
Top