2016-11-21 49 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方法。 –