Spurious lines when scrolling a GDI+ object - c#

I am following a GDI+ tutorial, and in the section Drawing Shapes and Lines there's a simple example that draws a filled rectangle, filled ellipse and filled line in a scrolling window. It seems to work fine, but when I scroll down and back up it doesn't scroll properly as shown:
The OnPaint method is:
protected override void OnPaint(PaintEventArgs e)
{
Graphics dc = e.Graphics;
Point ScrollOffset = this.AutoScrollPosition;
dc.TranslateTransform(ScrollOffset.X, ScrollOffset.Y);
if (e.ClipRectangle.Top + ScrollOffset.X < 350 ||
e.ClipRectangle.Left + ScrollOffset.Y < 250)
{
dc.DrawRectangle(BluePen, rectangleBounds);
dc.FillRectangle(CrossBrush, rectangleBounds);
dc.DrawEllipse(RedPen, ellipseBounds);
dc.FillEllipse(SolidAzureBrush, ellipseBounds);
dc.DrawLine(BrickWidePen, rectangleBounds.Location, ellipseBounds.Location + ellipseBounds.Size);
}
base.OnPaint(e);
}
(The rest of the code can be seen at the page linked above, in case it matters).
If I minimise and restore it fixes the problem, so it looks as if the OnPaint method isn't getting called at the right time (is the window being scrolled between the OnPaint method being called and the paint actually occurring?). So how should I handle the paint so the scrolling doesn't corrupt the image?

Related

Create Form fade out transition

How could you - in WinForms - create a black area that (over time) loses/gains transparency and is redrawn constantly so a kind of transition is created? I dont want to create a seperate form, so this would be very helpful and I could rearrange my new items as soon as the black area reaches a transparency of 0.
Left: What i have what at the moment:
Right: What the program looks like on startup
What I would want: A totally black screen
Override the OnPaint method of the form, and fill a rectangle the size of the form with the desired transparency. In this example, transparency keeps increasing:
var transparency = 0;
protected override OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
// e.Graphics.DrawImage(Image, imageLeft, imageTop, imageWidth, imageHeight);
e.Graphics.FillRectangle(new SolidBrush(Color.FromArgb(transparency, Black)), this.ClientRectangle);
}
If you want to do this from a Timer event, inside the Tick event Invalidate the form to force the paint.
protected void MyTimer_Tick(object sender, eventArgs e) {
transparency++;
MyForm.Invalidate();
}
If you need to draw on top of the PictureBox, that presents a problem. One way to solve it is to get rid of the PictureBox and draw the image using Graphics.DrawImage before you draw the fade. If you want to show the image but have the black go up against the edges of your animal, then make it's background color of the PictureBox transparent and convert your image to use a PNG or GIF with all around the animal transparent in the original image.
For more complex effects, Check out the dot-net-transitions project on Google Code. It supports a variety of linear/non-linear transitions.

Invalidate on paint loops C# winforms

I have a panel I draw on, and I'm doing it in the paint event. I want to delete previous changes before drawing, but If I use Invalidate() or Refresh() it is redrawing it forever (it is flickering), and the strange thing is I call Invalidate() before any drawing, so if it's just forcing panel paint I shouldn't see the drawing
Edit: I figured out this:
void _paint(object sender, PaintEventArgs e)
{
Panel P = (Panel)sender;
if (painted = false) { painted = true; P.Invalidate(); }
Shows(30);
painted = false;
}
It stopped flickering. Anyway, turns out I've never needed that, it is repainting the panel even without the Invalidation. But strangely when I hide only part of the panel(either with form resizing or dragging window over the panel),when becoming visible again it is painted, not repainted(I can tell because the anti-aliasing becomes solid color, producing shitty result), that's why I thought I need to Invalidate the panel. Invalidating won't stop it from happening. I think probably another event is triggered, not paint.
I encountered a problem with my control flickering when I called Invalidate with a program I created not too long ago. I found overriding the OnPaintBackGround did the trick, it may work for you too;
protected override void OnPaintBackground(PaintEventArgs e)
{
/* Override to stop the background being repainted -> this stops flashing of the text */
}
First if all, the following condition is lacking an = sign:
if (painted = false) { painted = true; P.Invalidate(); }
It should read
if (painted == false) { painted = true; P.Invalidate(); }
or
if (!painted) { painted = true; P.Invalidate(); }
Secondly, double buffering is in many cases a good idea. To do so, paint all the content into an off-screen bitmap that has the same size as the client area of your control and then draw that bitmap to the target control if needed. Do not draw the off-screen bitmap in the OnPaint event, but whenever the content to be drawn changes!
Example:
private void PaintOffscreen()
{
// Do whatever necessary to draw the offscreen bitmap
...
// Cause the control to repaint itself. Change OnPaint to draw the bitmap only
Invalidate();
}
void _paint(object sender, PaintEventArgs e)
{
e.Graphics.DrawImage(offscreenBitmap, 0, 0);
}
Also, override the OnPaintBackground method as suggested by HorHAY to prevent the control from clearing the background before painting itself.

Best way to refresh changes in an image

I have a winform c# app.
I am using Emgu for comparing the motion differences between 2 images.
I impose the changes detected onto the 1st image so in affect the first image now looks identical to the second image.
I am overriding the onpaint event of a user control to draw the image. I have to Invalidate the usercontrol to force the onpaint event.
This works well but the memory still 'spikes' a bit. Is there a way to invalidate only the pixels that have changed - like regions for instance?
This is my current code:
protected override void OnPaint(PaintEventArgs pe)
{
Graphics g = pe.Graphics;
if (CurrentFrame != null)
{
pe.Graphics.DrawImageUnscaled(CurrentFrame, 0, 0);
}
}
The CurrentFrame is a static Bitmap
Thanks

C# Graphics Invalidate

I think I have miss understand the Invalidate method...I am trying to draw a square with the top left hand corner of the square at the location of the mouse at mousedown and then the bottom right hand corner is the current location of the mouse. Below is the method triggered on the MouseMove event. The parent is a panel with a pictureBox child. (I am trying to draw on top of these.)
The problem seems to be with pictureBoxMain.Invalidate(). When commented out the code behaves as expected and draws a gazillion squares.
[The Graphics g is created by the pictureBox, hence why I call the Invalidate method on the pictureBox.]
When I un-comment out the invalidate line then a box is draw as the mouse moves but as soon as it stops moving the box disappears. I can't work out for the life of me why. When I attempt to debug the code it appears that MouseMove method is being invoked in when the mouse isn't moving, which doesn't make any sense.
Any help is greatly appreciated!
private void pictureBoxMain_MouseMove(object sender, MouseEventArgs e)
{
if (MouseDrawLeft)
{
//Move
}
else if (MouseDrawRight)
{
MouseLast = e.Location;
if (MouseFirst != MouseLast)
{
pictureBoxMain.Invalidate();
Point bl = new Point(MouseFirst.X, MouseLast.Y);
Point tr = new Point(MouseLast.X, MouseFirst.Y);
g.DrawLine(pen, MouseFirst, tr);
g.DrawLine(pen, MouseFirst, bl);
g.DrawLine(pen, bl, MouseLast);
g.DrawLine(pen, tr, MouseLast);
}
}
}
Every component (button, textbox, window...) has its Paint method. This is invoked periodically by Windows (like 50x per second) to draw the object.
What you do is that you paint something on the object - but within a milisecond, it disappears, because the Paint method overpainted it. You need to override the Paint method of the frame and do you paintings there - this way, you drawings will be painted every time Windows ask.

Painted Border Runs In Certain Situations

In my tool I use a a panel to change pages. Each page has it's own panel and when I change a page I send the panel with the controls. On the panel I use as the canvas I have the following paint event:
private void panelContent_Paint(object sender, PaintEventArgs e)
{
e.Graphics.CompositingQuality = CompositingQuality.HighQuality;
e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
// Paints a border around the panel to match the treeview control
e.Graphics.DrawRectangle(Pens.CornflowerBlue,
e.ClipRectangle.Left,
e.ClipRectangle.Top,
e.ClipRectangle.Width - 1,
e.ClipRectangle.Height - 1);
e.Graphics.Flush();
base.OnPaint(e);
}
This method basically draws a nice border around the panel so it look better. For some reason when I move a another form above this panel the lines that make up the border start to run a little. Occasionally small lines will be drawn from the border too. The problem only happens for a few seconds before the entire panel redraws again. Is there anything I can do to prevent this from happening?
ClipRectangle tells you what part of the control needs to be repainted. If you're moving something over it, this is probably going to be the intersection of your object and the one being moved. You can use this information to more efficiently repaint your control.
You probably want to draw the rectangle from (0, 0) to (panelContent.Width-1, panelContent.Height-1).

Categories