I need some help on canvas drawing. I am working on an app that has a large canvas used to plot data coming in from the serial port. When I initialize the canvas in the Paint Event, I draw a bunch of graduations and text, similar to an oscilloscope screen.
Now, I have data coming in from the serial port. I want to plot a point (few pixels or line) on the canvas. For the life of me, I can’t seem to find how to do this outside of the paint event of the canvas. I need some ideas.
My thought is I don’t want to “Re-Paint” the entire canvas every time I receive data just to draw a point as I suspect doing numerous updates a second will really cripple system resources. I’d like to do this outside the paint event.
Instead of using the paint event on a canvas, create a picture, and put your initial background stuff in there. Then apply that picture to the canvas.
When you want to update update it, draw the new stuff onto another picture. Then redraw everything on the mask layer of the new picture in black. Then merge the Canvas image with the new one, and replace the canvas image with it.
In addition to what’s described above, there’s another way to do this which will be reusable and self contained. The PlotCanvas class in this project is set up to raise a PaintBackground event only when it needs to (that is, when the picture that’s already rendered isn’t the right size), draws that as a picture, and then raises the Paint event for you. There’s also a ResetBackground method which will cause the background to be repainted the next time the canvas is refreshed.
Those are all great ideas and super helpful, thanks.
One concept that is lost on me is drawing the actual plotted values as they arrive. These are coming in at 10 samples per second. When I calculate my position in a method called by my DataAvailable event is it normal process to invalidate() the canvas and have to redraw all of the previous plotted samples every time? Or is there a way to simply draw a new line to the canvas, i.e. a single pixel?
I used to do this with the canvas class eons ago (circa 2010) using the canvas.graphics property, but it looks like that was deprecated.
Canvases are cleared every time they paint, but you certainly could cache them. If you’re planning on scrolling like an oscilloscope, I’d suggest two arrays for this, both with the number of values across that you need. Once you reach the “edge” you start adding values to the other array. When it comes to drawing, you draw from n to count-1 on the first array and 0 to n on the second. That way you don’t have to continually resize the array, which is very time consuming.
The suggestion of using the graduations as a backdrop on the canvas makes perfect sense.
My canvas is 2400 pixels wide. I do not need to scroll as it will auto stop. I am doing what Greg is suggesting and keeping an array of values (coordinates) as they are received. My confusion revolves around the most efficient way to plot those values.
I can refresh the canvas each time I receive a new value. But If the paint event wipes out the canvas and it has to be redrawn it would seem I need to replot the previous values each time by reconstructing it from the stored array. Is this correct? I wonder how efficient that is?
What I was hoping for is to simply “update” the canvas with the new value at the new coordinates, leaving the previous values untouched. I am not seeing an easy way to do this…
Well… I tried redrawing the entire trace from previous readings for each paint event and I really can’t believe how fast it is or that there is no flicker, so that is a nice surprise.
Does the canvas only update pixels that need to be changed when paint is called?