rws Posted May 2, 2003 Posted May 2, 2003 Apologies if this is obvious... I'm 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 Panel's 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. Quote
steved Posted May 2, 2003 Posted May 2, 2003 You can use the method you're currently using to draw a particular section directly to screen, but it's 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. I'm 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! Quote zig?
rws Posted May 2, 2003 Author Posted May 2, 2003 Thanks for responding... You can use the method you're currently using to draw a particular section directly to screen, ... I'd 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 don't think a PictureBox would help, since it doesn't 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... :( Quote
steved Posted May 2, 2003 Posted May 2, 2003 Similar to drawing to/from a buffer, you'll need to get a handle to the Panel (or PictureBox) and perform a BitBlt directly onto that device context. Finding DC's and performing blt operations are all well-documented in MSDN, but if you're not sure where to start I can find some articles to point you in the right direction. Sorry if any of this stuff I'm suggesting is out of date, I've completely dropped VB.net in favor of C#, and I haven't had much time to dabble in GDI+ yet - though I know what I'm 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. :) Quote zig?
rws Posted May 9, 2003 Author Posted May 9, 2003 BitBlt looks like a good approach, but I think it is out of VB's 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. I'm sure there's still a better way. Thanks, steved! Quote
steved Posted May 9, 2003 Posted May 9, 2003 BitBlt isn't out of VB6's scope, so I'm sure it's 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. Quote zig?
Camaro Z28 Posted May 15, 2003 Posted May 15, 2003 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 Quote Visual Basic Code Source FREE Visual Basic Source Code
rws Posted May 15, 2003 Author Posted May 15, 2003 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. I'm still not happy with the results: there are other side-effects of my current strategy. I'm 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. Quote
Guest mutant Posted May 15, 2003 Posted May 15, 2003 What code are you using in Paint event that it is flickering? Quote
rws Posted May 16, 2003 Author Posted May 16, 2003 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 Window's graphics layer BMap = New Bitmap(Window.Width, Window.Height, Window.CreateGraphics()) '... End Sub ' ' 'Here's 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 Quote
*Gurus* divil Posted May 16, 2003 *Gurus* Posted May 16, 2003 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. Quote MVP, Visual Developer - .NET Now you see why evil will always triumph - because good is dumb. My free .NET Windows Forms Controls and Articles
rws Posted May 21, 2003 Author Posted May 21, 2003 That sure sounds like what I've been looking for! However, I'm 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? Quote
Guest mutant Posted May 21, 2003 Posted May 21, 2003 Its not a method of a control. Just simply type: SetStyle(chooseproperty,trueorfalse) Quote
*Gurus* divil Posted May 22, 2003 *Gurus* Posted May 22, 2003 Protected means you can only call it from _within_ a derived class. So you'll have to derive from Panel yourself and use SetStyle in the constructor, ideally. It's also a good idea to wrap your existing drawing functionality in the class too, it promotes encapsulation of code. Quote MVP, Visual Developer - .NET Now you see why evil will always triumph - because good is dumb. My free .NET Windows Forms Controls and Articles
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.