C#利用GDI+實現橡皮筋效果


C#利用GDI+實現橡皮筋效果

因為C#課一次作業需要在winform上實現一個簡單的繪圖程序,要求添加橡皮筋效果。圖像是在picturebox控件上繪制的,我一開始始終解決不了的問題是要實現橡皮筋效果,鼠標移動過程中繪制顯示的圖形就要隨時擦除,但是通過GDI+在控件的Graphic對象上繪制圖形就不能再擦掉了。在網上搜索了一下,不管是刷新重繪控件,還是通過在內存中開辟位圖的辦法都失敗,后面那種辦法是最多的,但我怎么都弄不好,可能是我真地太菜了吧!

最終找到了辦法是通過GDI+自帶的雙緩沖技術實現的。我們要實現橡皮筋的效果就要先擦除掉原來的圖案,然后再繪制新的圖案,我們可以先通過GDI+的填充背景色,覆蓋原來的圖形,再將所有圖形繪制到屏幕上,讓窗體刷新。但是窗體刷新時會頻繁地重繪窗體表面,這樣就會導致閃爍,而雙緩沖能有效避免這個問題。自己也是在搜素的過程中大致理解了下這個技術。大概是先在內存中創建一個新的與窗體大小一樣的緩沖區,我們的繪圖操作先在這塊緩沖區上完成,然后再將緩沖區上的圖形渲染到屏幕上。由於渲染時只是進行位圖的拷貝,所以速度是非常快的,能有效避免窗體反復刷新重繪時帶來的閃爍。

大概思路是這樣的:用GeometryBase基類及其派生類儲存圖形對象,類中包括相應圖形對象相應的繪制函數draw(Graphic g),用一個list集合GeometrySet存放所有已經繪制完成的圖形,定義一個接口Tool,里面包括響應鼠標事件的函數onmousedown,onmousemove等,再定義一個工具類及其派生類,繼承自接口Tool,實現接口,構造圖形對象並添加到GeometrySet集合中。

具體代碼如下:

  • 定義工具和控件的Graphic對象初始化

    // 繪制工具
          private Tool _actionTool = null;
          private Tool actionTool
          {
              get => _actionTool ?? new NoneTool(op);
              set => _actionTool = value;
          }
          private readonly Graphics pb;
          public Form1()
          {
    
              InitializeComponent();
              pb = pictureBox1.CreateGraphics();// 獲取pictureBox1空間的繪制畫布
    
          }
    
  • 選擇繪制的工具

          /// <summary>
          /// 選擇繪圖方式
          /// </summary>
          /// <param name="sender"></param>
          /// <param name="e"></param>
          private void comboBox2_SelectedIndexChanged(object sender, EventArgs e)
          {
              // 獲取繪圖方式
              Drawstyle = this.comboBox2.SelectedIndex;
              // 創建相應的圖形繪制工具
              actionTool = CreateToolFactory.getDrawTool(Drawstyle, op);
    
          }
    
  • 鼠標移動事件響應函數

    private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
            {
                // 利用雙緩沖實現橡皮筋效果和繪制圖層容器圖形
                BufferedGraphicsContext Mybuffer = BufferedGraphicsManager.Current;   // 創建緩沖圖形上下文
                BufferedGraphics buffered = Mybuffer.Allocate(pb, pictureBox1.ClientRectangle); // 創建指定大小的緩沖區
                // 設置背景色為白色
                buffered.Graphics.FillRectangle(Brushes.White, pictureBox1.ClientRectangle); // 填充背景色,不填充的話屏幕最終顯示的背景色是黑色
                // 繪制當前的圖形
                actionTool.onmousemove(e, buffered.Graphics); // 繪制當前正在繪制中的圖形
                // 繪制圖層容器中的圖形
                LayerService.DrawLayer(buffered.Graphics); // 繪制GeometrySet集合中已經存在的圖形
                // 將圖形渲染到屏幕上
                buffered.Render(pb); // 將所有圖形渲染到屏幕上
                
                // 釋放資源
                buffered.Dispose();
                Mybuffer.Dispose();
    
            }
    
  • 鼠標點擊事件響應函數

    private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
            {
                // 使用繪制工具構造並添加圖形對像
                actionTool.onmousedown(e);
            }
    
  • 繪制工具類[^以繪制直線為例]

    class DrawLine : AbstractTool
        {
            private Point _startPoint;
            private Point _endPoint;
            private Polyline2D _line;
            public bool _dragging = false;
            public DrawLine(Options p) : base(p) {}
            public override void onmousedown(MouseEventArgs e)
            {
                // 構造圖形對象
                base.onmousedown(e);
                if(e.Button == MouseButtons.Left)
                {
                    if (_dragging)
                    {
                        _endPoint = mouseDown;
                        _line.Add_Point(_endPoint);
                        LayerService.Add_Geometry(_line);
                        _dragging = false;
                        
                    }
                    else
                    {
                        _startPoint = mouseDown;
                        _line = new Polyline2D(ops);
                        _line.Add_Point(_startPoint);
                        _dragging = true;
                    }
                }
                
            }
            // 橡皮筋效果實現
            public override void onmousemove(MouseEventArgs e,Graphics g)
            {
                base.onmousemove(e, g);
                if (_dragging)
                {
                    if (_line.getPtCount() < 2)
                        _line.Add_Point(mouseMove);
                    else
                        _line[1] = mouseMove;
                    _line.draw(g);
                }
            }
        }
    


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM