Link to home
Start Free TrialLog in
Avatar of bmihura
bmihura

asked on

Why does the rubber band rectangle sometimes leave marks on my screen?

I used some example code from Microsoft to draw a rubber band rectangle when I drag my mouse:

http://support.microsoft.com/kb/314945

I modified that code so that when the rectangle is dragged over a small PictureBox in my form, the PictureBox is moved out of the way. When that happens, the rubber band rectangle leaves marks on my screen! The bigger my form is, the worse the problem is; so this problem might not be reproducible with a really good graphics card.

Here's my project written in Microsoft Visual Studio 2008 then zipped up if anybody would like to try it:

www.lctechnology.com/FocusRectangleProblem.zip

Avatar of Göran Andersson
Göran Andersson
Flag of Sweden image

The reversible frame is only reversible if nothing else is drawn on top of it. When you move the PictureBox you are most likely causing it to redraw part of the form, which will draw over the reversible frame.

There are two possible solutions:

1. Whenever you move the PictureBox, you have to first hide the reversible frame, change the location of the PictureBox, call DoEvents so that the form and PictureBox is redrawn, then you can show the reversible frame again.

2. Use the Paint event to draw the reversible frame (or a regular rectangle if you want that). This means that you never hide the reversible frame, you only draw it on top of the form as the last stage of repainting it. To update the rectangle you invalidate the current rectangle, change the coordinates and invalidate the new rectangle. This will cause repainting of the part of the form that is affected. Moving the PictureBox is not a problem, as the Paint event will redraw the part of the rectangle that is affected.

Either method will probably cause some flickering. I don't know which one causes less.
Avatar of bmihura
bmihura

ASKER

GreenGhost,

I tried possible solutions 1 and 2, and they both leave even more marks on my screen. Here are two Visual Studio 2008 projects that demonstrate these two attempts:

www.lctechnology.com/FocusRectangleProblem_Try_1.zip
www.lctechnology.com/FocusRectangleProblem_Try_2.zip

Method 2 also caused flickering.

Maybe there's another to get this done? Or maybe I coded something wrong.
The second method works with a few corrections. It flickers a lot, but it doesn't leave any residue.

The Invalidate method uses client coordinates, not screen coordinates:

private void InvalidateRectangle(Point p1, Point p2) {
      // Normalize the rectangle.
      rc = new Rectangle(Math.Min(p1.X, p2.X), Math.Min(p1.Y, p2.Y), Math.Abs(p2.X - p1.X), Math.Abs(p2.Y - p1.Y));
      this.Invalidate(rc);
}

The reversible frame uses screen coordinates, so you have to convert the rectangle location:

private void Form1_Paint(object sender, PaintEventArgs e) {
      e.Graphics.FillRectangle(Brushes.Green, ClientRectangle);
      ControlPaint.DrawReversibleFrame(new Rectangle(PointToScreen(rc.Location), rc.Size), Color.Black, FrameStyle.Dashed);
}
It flickers less if you use a regular rectangle instead:

e.Graphics.DrawRectangle(Pens.Yellow, rc.X, rc.Y, rc.Width - 1, rc.Height - 1);
Avatar of bmihura

ASKER

It does flicker less, but I've got to figure out a way to have no flicker since this will be a commercial app.

I also have to use the reversible rectangle, because the background will be an arbitrary screenshot that might accidentally match the rectangle's color.
ASKER CERTIFIED SOLUTION
Avatar of Göran Andersson
Göran Andersson
Flag of Sweden image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of bmihura

ASKER

Wow, that was amazing.
Avatar of bmihura

ASKER

Wow, nice solution.

Would you mind explaining your thought process as to why this.Update worked where  Applicaton.DoEvents did not?

Also, why was there no flicker, even with huge rectangles being dragged?

I could sure use just a small percentage of your programming knowledge!
The Update method does what I tried to do with the DoEvents method, i.e. handle all messages in the queue so that the form is redrawn. Perhaps because one message causes other messages, like when the message to change the location of the control will cause messages to invalidate the control and part of the form.

The reason that a refersible frame causes little flicker is that it's drawn in a way that it can be reversed. When you draw the frame again in the same location it reverses the effect of the first draw and the screen looked exactly as it did before. As you don't have to repaint any part of the form to remove the frame, the inside of the frame doesn't flicker.
Avatar of bmihura

ASKER

Got it, thanks!