通过 PInvoke 调用 BeginPaint,返回 PAINTSTRUCT 中的空更新区域
Call to BeginPaint via PInvoke returning empty update region in PAINTSTRUCT
我一直致力于创建一个自定义 RichTextBox
控件来向文本区域添加一些额外的图形。根据我一直在阅读的内容,此控件默认情况下不会公开其 Paint 事件。
我按照 MSDN (Painting on a RichTextBox Control ) 上的建议重新公开 Paint 事件并创建一个由 WM_PAINT
消息触发的 OnPaint
事件处理程序。
在 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);
}
您必须完成 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);
}
}
我发现了问题。 @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;
}
}
我一直致力于创建一个自定义 RichTextBox
控件来向文本区域添加一些额外的图形。根据我一直在阅读的内容,此控件默认情况下不会公开其 Paint 事件。
我按照 MSDN (Painting on a RichTextBox Control ) 上的建议重新公开 Paint 事件并创建一个由 WM_PAINT
消息触发的 OnPaint
事件处理程序。
在 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);
}
您必须完成 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);
}
}
我发现了问题。 @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;
}
}