2016-11-21 44 views
0

我一直在創建一個自定義的RichTextBox控件來向文本區域添加一些額外的圖形。從我一直在閱讀的內容來看,這個控件默認不會公開它的Paint事件。通過PInvoke調用BeginPaint返回PAINTSTRUCT中的空更新區域

我遵循MSDN上的建議(Painting on a RichTextBox Control)重新公開Paint事件並創建OnPaint事件處理程序,該程序由WM_PAINT消息觸發。

OnPaint方法中,我試圖從Win32 API中調用BeginPaint()來繪製一些圖形,但沒有繪製任何圖形。當我檢查PAINTSTRUCT結構中的rcPaint字段時,它始終爲空(所有值均爲0)。所以我的問題是,爲什麼更新區域總是空的?我肯定錯過了什麼。

相關代碼:

public partial class RichTextBoxEnhanced : RichTextBox 
{ 

    private PAINTSTRUCT ps; 


    new public void OnPaint(PaintEventArgs e) 
    { 
     var hdc = BeginPaint(this.Handle, out ps); 

     FillRect(hdc, ref ps.rcPaint, CreateSolidBrush(100)); 

     Rectangle(hdc, 1000, 2000, 1000, 2000); 

     EndPaint(this.Handle, ref ps); 

     Paint?.Invoke(this, e); 
    } 

    [DllImport("user32.dll")] 
    static extern IntPtr BeginPaint(IntPtr hwnd, out PAINTSTRUCT lpPaint); 

    [DllImport("user32.dll")] 
    static extern bool EndPaint(IntPtr hWnd, [In] ref PAINTSTRUCT lpPaint); 

    [DllImport("gdi32.dll")] 
    static extern IntPtr CreateSolidBrush(uint crColor); 
} 
+2

我猜測的時候'的OnPaint()'被調用時,.NET已經被稱爲'調用BeginPaint()'你來填充'PaintEventArgs',所以返回的DC可能是'NULL'(表示失敗)... – andlabs

+0

@andlabs,這確實是問題。顯然base.WndPrc在到達我的OnPaint方法之前調用BeginPaint。 –

回答

0

我發現了這個問題。 @andlabs的評論讓我看看我重寫的WndProc方法。我的繪畫方法在base.WndProc(ref msg)之後被調用,顯然執行BeginPaint。移動我的OnPaint()方法糾正了這個問題。

錯誤代碼:

protected override void WndProc(ref Message m) 
     { 
      switch (m.Msg) 
      { 
       case WM_PAINT: 
        mBaseControl.Invalidate(); 
        base.WndProc(ref m); 
        OnPaint(); 
        break; 
       default: 
        base.WndProc(ref m); 
        break; 
      } 

     } 

正確的代碼:

protected override void WndProc(ref Message m) 
     { 
      switch (m.Msg) 
      { 
       case WM_PAINT: 
        mBaseControl.Invalidate(); 
        OnPaint(); 
        base.WndProc(ref m); 
        break; 
       default: 
        base.WndProc(ref m); 
        break; 
      } 

     } 
+0

我的建議是隻使用'PaintEventArgs'中的'Graphics'對象。這不行嗎? – andlabs

+0

是的,那是有效的。我只是試驗BeginPaint。 –

+0

好的。關於'BeginPaint()'的一個重要事項是它驗證更新rect,所以如果你在同一個'WM_PAINT'調用中調用它兩次,你會得到不同的更新rect值。確實,更新矩形的存在決定了是否生成WM_PAINT,所以BeginPaint()告訴Windows「好吧,我們現在正在繪畫;不需要擔心更多的WM_PAINT,直到下一次更新rect改變「。 – andlabs

1

你必須要經過WndProc和允許控制做其默認畫。您可以使用Graphics對象作爲繪畫。例如:

public partial class MyRichEdit : RichTextBox 
{ 
    public MyRichEdit() 
    { 
     InitializeComponent(); 
    } 

    protected override void WndProc(ref Message msg) 
    { 
     switch (msg.Msg) 
     { 
      case 15://WM_PAINT 
       base.WndProc(ref msg); 
       Graphics g = Graphics.FromHwnd(Handle); 
       Pen pen = new Pen(Color.Red); 
       g.DrawRectangle(pen, 0, 0, 10, 10); 
       return; 
     } 
     base.WndProc(ref msg); 
    } 
} 
+0

謝謝,巴馬克。我使用Graphics類進行了測試,這個工作正常,但是當我想用BeginPaint方法測試時,我遇到了一個問題。我不知道base.WndProc已經調用了BeginPaint,所以我不得不改變我的邏輯來調用我的OnPaint方法。 –