C# .NET - Scrolling windows without redrawing
Asked By Ryan Dawson on 07-Oct-09 05:47 PM
In the project I'm working on in MS Visual Studio, I have a form that contains a panel. The panel has a custom paint event that uses Graphics.DrawLine and similar functions to create an image based on a mathematical function -- in this case, it's drawing a timeline in the panel with little vertical ticks to note each hour.
This timeline panel is contained in a smaller panel and therefore may has a scrollbar that the user can use to look at the part of the timeline that's of interest. The problem is that the timeline goes all flickery whenever the user drags it, because each mouse move triggers a repaint and goes through the whole loop all over again, effectively redrawing everything from the right extent to the left.
I want the drag to be smooth. Actually, what I really want is to be able to draw the data once, store that in memory, and then just scroll back and forth among what I've already drawn. I'll know when it's time to repaint, such as if the user changes the timescale. (I tried making it draw only once, and that just breaks the scrolling ability -- scrolling leaves a big blank on whatever just came into view.)
Does this make sense? How would I accomplish it?
Hmm, why do you redraw it on move triggers?
Robbe Morris replied to Ryan Dawson on 07-Oct-09 09:00 PM
Why not draw the whole thing and let the scroll bars determine what is or isn't visible?
It's not on purpose.
Ryan Dawson replied to Robbe Morris on 07-Oct-09 10:02 PM
I'm not intentionally redrawing on mouse moves. I just plugged the "paint" event into my custom procedure, and windows (or C#?) triggers it every time a new pixel becomes visible on the screen.
Your question is my question -- how DO I draw the whole thing and so on?
As it is, if I disable that paint procedure by means of a menu option, newly exposed pixels are simply background-gray instead of showing what I drew in that window location earlier.
It is the plugging of it in the paint event that is causing your problem I believe
Robbe Morris replied to Ryan Dawson on 07-Oct-09 10:04 PM
Can you look at the structure of your code and not use that event?
I don't know, can I?
Ryan Dawson replied to Robbe Morris on 08-Oct-09 09:50 AM
If I do that, manually calling the painting procedure when I load up a new time segment, scrolling the time bar leaves big blanks rather than showing what I drew in the "off screen" portion of the bar.
That's the whole problem right there.
So what I have is a function that calls Graphics g = mpTimeline.CreateGraphics(); and then uses g.DrawLine and so on to create this graphic. That's the basis of the question -- IS there a way to do that draw once and have it retain the bits outside the edges of what's actually visible right this second?
I've done something like this in the past and I think I drew to a PictureBox
Robbe Morris replied to Ryan Dawson on 08-Oct-09 10:06 AM
that was loaded on a panel instead of the .Graphics element of a given control. I
just drew the whole image on the PictureBox and did not react to the paint event
of the PictureBox.
That doesn't seem to be working
Ryan Dawson replied to Robbe Morris on 08-Oct-09 10:38 AM
...but I'll keep working on it. I don't want to resort to drawing into a bitmap and displaying that, but I may have to.
Just for clarification
Ryan Dawson replied to Ryan Dawson on 08-Oct-09 10:39 AM
It seems to have the same behavior as a panel, scrolling to the edges leaves blank space unless I hit the repaint.
Or am I doing it wrong? Do I draw to something other than the picturebox's graphics object?
You draw to a BitMapImage and set the PictureBox Image/Source property to the bitmap
Robbe Morris replied to Ryan Dawson on 08-Oct-09 10:49 AM
I was hoping there was another way.
Ryan Dawson replied to Robbe Morris on 08-Oct-09 12:04 PM
Oh well. Gotta do it that way then.