0

I need to draw a lot of 2D graphics in the window. If I keep refreshing, it will lead to slow efficiency. I have learned about the drawing method with dirty rectangles. When using dirty rectangles for drawing, do I need to merge the old graphics with the refreshed graphics, and then move or zoom in and out together.

I tried multi buffering to draw these 2D graphics, but when the window zooms in and out, it still needs to be redrawn, which consumes a lot of time to run. I also tried using Bitmap to zoom in and out, but this will cause pixel distortion when zooming in. So I'd like to know if there is some solutions for this problem. It will be appreciated that if someone could give me some clue. Thanks for advance.

    private void PicDisplayCtr_Paint(object sender, PaintEventArgs e)
    {
        m_PicDisplayControl.m_GlobalGraphics = e.Graphics;
        m_PicDisplayControl.drwPaint();
        if (m_PicDisplayControl.bMBtnDown)
        {
            m_PicDisplayControl.drwPoint(true);
        }
        else
        {
            m_PicDisplayControl.drwPoint();
        }
        m_PicDisplayControl.drwScale();
    }
    public void drwPoint(bool bRet = false)
    {
        if (!bRet)
        {         
            double d1;
            d1 = myView.PPU * myView.ZoomLevel;
            BmpTabele = new Bitmap((int)(m_dInterRight * d1 + 1), (int)(m_dInterTop * d1) + 1);
            GraphicsTabele = Graphics.FromImage(BmpTabele);
            PointF pfFirstPos = new PointF(0, 0);
            PointF pfSecondPos = new PointF(0, 0);
            Rectangle rect = new Rectangle();
            rect.X = (int)(m_dInterLeft * d1);
            rect.Y = (int)(m_dInterBottom * d1);
            rect.Width = (int)((m_dInterRight * d1) - (m_dInterLeft * d1));
            rect.Height = (int)((m_dInterTop * d1) - (m_dInterBottom * d1));
            m_InterRect = rect;
            GraphicsTabele.DrawRectangle(Pens.White, rect);

            for (int i = 0; i < m_DrawPointF.m_DrawPos.Count; i++)
            {
                pfFirstPos = new PointF(m_DrawPointF.m_DrawPos[i].X - m_PosWidth / 2, m_DrawPointF.m_DrawPos[i].Y - m_PosLength / 2);
                pfSecondPos = new PointF(m_DrawPointF.m_DrawPos[i].X + m_PosWidth / 2, m_DrawPointF.m_DrawPos[i].Y + m_PosLength / 2);
                rect = new Rectangle();
                rect.X = (int)(pfFirstPos.X * d1);
                rect.Y = (int)((m_dInterTop - m_dInterBottom - m_DrawPointF.m_DrawPos[i].Y - m_PosLength / 2) * d1);
                rect.Width = (int)((pfSecondPos.X * d1) - (pfFirstPos.X * d1));
                rect.Height = (int)((pfSecondPos.Y * d1) - (pfFirstPos.Y * d1));

                GraphicsTabele.FillRectangle(m_DrawPointF.brushe, rect);
                GraphicsTabele.DrawRectangle(m_DrawPointF.pen, rect);
            }
            m_FirstDrwPos.X = (int)Func_U2PX(m_dInterLeft);
            m_FirstDrwPos.Y = (int)Func_U2PY(m_dInterTop);
            int nWidth = (int)(Func_U2PX(m_dInterRight) - Func_U2PX(m_dInterLeft));
            int nHeight = (int)(Func_U2PX(m_dInterTop) - Func_U2PX(m_dInterBottom));
            //m_GlobalGraphics.DrawImage(BmpTabele, m_FirstDrwPos.X, m_FirstDrwPos.Y, nWidth, nHeight);
            m_GlobalGraphics.DrawImage(BmpTabele, m_FirstDrwPos.X, m_FirstDrwPos.Y);
            m_dMBtnDownX = m_MDownFirstPos.X;
            m_dMBtnDownY = m_MDownFirstPos.Y;
        }
        else
        {
            m_GlobalGraphics.DrawImage(BmpTabele, (float)(m_MDownFirstPos.X - m_dMBtnDownX+ m_FirstDrwPos.X), (float)(m_MDownFirstPos.Y - m_dMBtnDownY+ m_FirstDrwPos.Y));
            
        }
    }
gzhhhhh
  • 1
  • 1
  • Use [SkiaSharp](https://www.nuget.org/packages/SkiaSharp) which uses fast hardware rendering and is much faster than GDI+ and works in Windows Forms as well as other UI technologies. – Olivier Jacot-Descombes Jul 09 '23 at 10:52
  • Thank you very much for your suggestion. I will try it out – gzhhhhh Jul 09 '23 at 11:11
  • On applications that need to draw lots of thing, best optimization to do is to keep the number of things to be drawed at as minimum as possible. For an example scenario, when you resize the window, calculate which objects are in the new added area and draw only those ones not all the objects. – jtxkopt Jul 09 '23 at 11:25
  • Hello, my current operation is to load the graphics that need to be drawn into a bitmap and paste it on the window. When adding new objects, may I create a new bitmap and merge the old and new areas together? – gzhhhhh Jul 09 '23 at 12:39
  • 1
    *drawing method with dirty rectangles*: this is already done, under the hood, with a BufferedGraphics object, i.e., when you draw on a double-buffered canvas. It keeps track of invalidated Regions, so when you invalidate a window (the canvas), only Regions that require repainting are affected -- *If I keep refreshing...*: code needed. You usually don't *Refresh*, you *Invalidate* one or more regions. When you draw your graphics on a canvas, you know what part is affected, because you specify the area were the new graphic is drawn – Jimi Jul 09 '23 at 13:26
  • If you use a Bitmap, then draw new parts inside the same Bitmap, then invalidate the Control that presents it -- Some note here: [Zoom and translate an Image from the mouse location](https://stackoverflow.com/a/61964222/7444103) . That abstracts from the *dirty rectangles* concept (it applies transformations to Rectangles), counting on the buffering operations that take place when using a buffered canvas – Jimi Jul 09 '23 at 13:34
  • @Jimi Hello, I have posted the code and I am still learning the Winform. May I ask how to use dirty rectangles in this situation, or what better way to improve efficiency? Currently, this method takes a long time to change the window size to redraw. – gzhhhhh Jul 09 '23 at 14:14
  • What kind of drawing application is it? What do you draw? Elaborate what you do. It is hard to determine what you are drawing or type of your app by just looking a snippet. – jtxkopt Jul 09 '23 at 15:34
  • And if were you, I would abstract the my app drawing logic from the underlying graphics library to make easy it to switch to another drawing library in the future (e.g. Direct2D, SkiaSharp as in above etc.). – jtxkopt Jul 09 '23 at 15:39
  • Hi @jtxkopt , the "PicDisplayCtr_Paint" function is the window refresh drawing operation, and the "drwPoint" function is the drawing function that I call when I refresh the window. Please ignore the coordinate conversion in it. In the "drwPoint" function, when bRet=true, I draw the content on the bitmap, and only change the position of the bitmap when the window moves. When the window zooms in and out, bRet=true, I will redraw all the contents of the graph onto a new bitmap. – gzhhhhh Jul 10 '23 at 12:52

0 Answers0