2

Today I am trying to solve problem with a blinking panel, when I draw onto it.

Lots of threads I read, like these:

So I tried to draw onto PictureBox, MyPanel with doubleBuffered, but the best solution I found, when I read, that I can't use g.Clear() every time, after that, even on non-doubleBuffered panel, blinking disappeared.

I even read, that I should free Graphics after draw is done. So I use everywhere using(Graphics g = panel.CreateGraphics()).

So my question, is it a great idea to create graphics for bitmap only when I draw something to it? Because before I created Bitmap, and Graphics (only for this bitmap, not for all components), so I had Graphics available for this bitmap every time

Here is my code:

public void newSizeDrawing()
    {
        Size size = collector.getLetterSize(selectedName);
        Size drawingSize = new Size(size.Width * (pixelSizeArray[pixelSize] + 1),size.Height * (pixelSizeArray[pixelSize] + 1));
        bitmapDraw = new Bitmap(drawingSize.Width, drawingSize.Height);
        int width = (this.MinimumSize.Width - panelDraw.MinimumSize.Width) + drawingSize.Width + 10;
        int height = (this.MinimumSize.Height - panelDraw.MinimumSize.Height) + drawingSize.Height + 10;
        this.Size = new Size(
            (width > this.MinimumSize.Width) ? width : this.MinimumSize.Width,
            (height > this.MinimumSize.Height) ? height : this.MinimumSize.Height);
        zeroDrawPosition = new Point((panelDraw.Size.Width - bitmapDraw.Width) / 2 - 1, (panelDraw.Size.Height - bitmapDraw.Height) / 2 - 1);
        using (Graphics g = panelDraw.CreateGraphics())
        {
            g.Clear(panelDraw.BackColor);
        }
        redrawDrawingLetter();
    }
public void redrawDrawingLetter()
    {
        bool[][] grid = collector.getArray(selectedName);
        using (Graphics graphicDraw = Graphics.FromImage(bitmapDraw))
        {
            graphicDraw.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighSpeed;
            graphicDraw.Clear(panelDraw.BackColor);
            int pxSize = pixelSizeArray[pixelSize];
            for (int y = 0; y < grid.Length; y++)
            {
                for (int x = 0; x < grid[y].Length; x++)
                {
                    graphicDraw.FillRectangle((grid[y][x] ? Brushes.Black : Brushes.White), x * (pxSize + 1), y * (pxSize + 1), pxSize, pxSize);
                }
            }
        }
        redrawDrawingPanel();
    }
private void redrawDrawingPanel()
    {
        using (Graphics g = panelDraw.CreateGraphics())
        {
            if (bitmapDraw != null)
                g.DrawImage(bitmapDraw, zeroDrawPosition);
        }
    }
private void panelDraw_Paint(object sender, PaintEventArgs e)
    {
        redrawDrawingPanel();
    }

Nobody can explain to me how to draw in C# the best way. So maybe my code isn't good, but that is reason why I asking how to do it correctly.

newSizeDrawing is called by myself only, when user click on + or - button. I have bool double-dimension array if pixel is on or off. This is program for drawing letters for microchips and LED display (often 8px height of letter).

I wrote a method that checks if the mouse moved from one "pixel" to another, so I don't redraw it after every call mouseMove event, because "pixel" can be from 10x10 px to 30x30 px.

Community
  • 1
  • 1
Arxeiss
  • 976
  • 16
  • 34
  • 5
    Hi Arxeiss, do you have any code for what you are doing? With some code examples, people can look at what you are doing and either suggest improvements or agreee with what you've implemented - it's also much easier to share ideas! – dash Jul 09 '12 at 21:09
  • 4
    Do *not* use CreateGraphics(), double-buffering can only work when you use the Paint event. And do *not* dispose the e.Graphics object in your event handler, you didn't create it. – Hans Passant Jul 09 '12 at 21:46
  • I added code to fist post. Because I don't have double buffered panel, I can still use CreateGraphics, can't I? But thanks for explaining. – Arxeiss Jul 09 '12 at 22:33

1 Answers1

1
private void panelDraw_Paint(object sender, PaintEventArgs e)
{
    redrawDrawingPanel();
}

This is fundamentally wrong. The Paint event passes e.Graphics to let you draw whatever you want to paint. When you turn on double-buffering, e.Graphics refers to a bitmap, it is initialized with the BackColor. You then proceed to drawing using another Graphics object you got from CreateGraphics(). That one draws directly to the screen.

The flicker effect you see if very pronounced. For a split second you see what the other Graphics context draws. Then your panelDraw_Paint() method returns and Winforms draws the double-buffered bitmap. There's nothing on it so it immediately erases what you drew.

Modify the redrawDrawingPanel() method and give it an argument of type Graphics. Pass e.Graphics in the call. And only use that Graphics object, remove all calls to CreateGraphics().

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • I'm little confused now. If I can't use CreateGraphics(), where I should use g.Clear() when Panel is resized? (Panel has Anchor Top,Left,Bottom,Right, and only by program I can resize form, as you can see in `public void newSizeDrawing()`? And what about function to immidiately redraw, because I know that somethink was changed? How I should do this, if I can't use CreateGraphics()? Thanks – Arxeiss Jul 10 '12 at 08:20
  • Set ResizeRedraw = true in the constructor so a paint is triggered when the panel resizes. Use Invalidate() when you know something changed. – Hans Passant Jul 10 '12 at 11:43
  • In which construktor? I don't use my own panel. But Ivalidate is great, I can call it everytime when it is resized, because, such I wrote, you can resize only by buttons. So it's enough for me. Thanks much – Arxeiss Jul 10 '12 at 11:54
  • I tried now delete all CreateGraphics and all Clear(), draw only in Paint event and it works totaly great :) Thanks much But last thing, I have to use Graphics.FromImage() to draw into Bitmap, which later I draw in Paint event to Panel. Or I can do this other way? I use Bitmap, because after Panel need redraw, I don't have to draw whole image, because it is in Bitmap. Is this correct? Thanks much – Arxeiss Jul 10 '12 at 19:03