C# 在窗口内绘图不需要';重画和涂片
我试图在窗口周围绘制一个矩形(窗口的内部,而不是外部),但该图形会被涂污,在某些情况下不会重新绘制 我将HWND WndProc子类化(当然,代码在HWND进程中运行): 正如您在代码中看到的,我正在WM_PAINT和WM_CPAINT上重新绘制“矩形”,但这还不够:C# 在窗口内绘图不需要';重画和涂片,c#,windows,winapi,gdi+,C#,Windows,Winapi,Gdi+,我试图在窗口周围绘制一个矩形(窗口的内部,而不是外部),但该图形会被涂污,在某些情况下不会重新绘制 我将HWND WndProc子类化(当然,代码在HWND进程中运行): 正如您在代码中看到的,我正在WM_PAINT和WM_CPAINT上重新绘制“矩形”,但这还不够: 当我使窗口变大(调整大小)时,矩形不会变大 当我缩小窗口(再次调整大小)时,矩形会变小,但当我放大窗口时,矩形会一直涂抹到其原始大小(而不是更大) 当我将窗口置于可见屏幕之外时,部分矩形(仅底部)不会被重新绘制 我应该指出,我
- 当我使窗口变大(调整大小)时,矩形不会变大
- 当我缩小窗口(再次调整大小)时,矩形会变小,但当我放大窗口时,矩形会一直涂抹到其原始大小(而不是更大)
- 当我将窗口置于可见屏幕之外时,部分矩形(仅底部)不会被重新绘制
base.WndProc(ref m);
只有在WndProc结束时,才得到相同的结果。我不确定,因为我无法测试它,也不知道成员变量
g
的背景,但我认为剪切矩形有问题。因此,您可以在WndProc
函数中尝试类似的操作,以确保整个窗口都被重新绘制:
case 0x05: // WM_SIZE
InvalidateRect(this.Handle, GetWndRect(this.Handle), TRUE);
break;
我不确定,因为我无法测试它,也不知道成员变量
g
的背景,但我认为剪切矩形有问题。因此,您可以在WndProc
函数中尝试类似的操作,以确保重新绘制整个窗口:
case 0x05: // WM_SIZE
InvalidateRect(this.Handle, GetWndRect(this.Handle), TRUE);
break;
首先,不能对消息多次调用
base.WndProc(refm);
其次,g
应该在每次更改窗口大小时重新创建,这样它就可以在更大的曲面上绘制
第三,在窗口上调用Invalidate
,以便在窗口大小更改时强制重画。我使用SizeChanged
事件和ClientSize
,因为我可以轻松编译代码(需要阅读文档来编写GDI+/WINAPI内容)
首先,不能对消息多次调用
base.WndProc(refm);
其次,g
应该在每次更改窗口大小时重新创建,这样它就可以在更大的曲面上绘制
第三,在窗口上调用Invalidate
,以便在窗口大小更改时强制重画。我使用SizeChanged
事件和ClientSize
,因为我可以轻松编译代码(需要阅读文档来编写GDI+/WINAPI内容)
如果只需要绘制一个边界,那么我们可以有一个更简单的机制,如下所示
OnPaint
表单
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
SetStyle(ControlStyles.ResizeRedraw, true); // this is important
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
Rectangle rcBorder = e.ClipRectangle;
rcBorder.Inflate(-10, -10); // just to accentuate with red colored border
e.Graphics.DrawRectangle(Pens.Red, rcBorder);
}
}
如果只需要绘制一个边界,那么我们可以有一个更简单的机制,如下所示
OnPaint
表单
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
SetStyle(ControlStyles.ResizeRedraw, true); // this is important
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
Rectangle rcBorder = e.ClipRectangle;
rcBorder.Inflate(-10, -10); // just to accentuate with red colored border
e.Graphics.DrawRectangle(Pens.Red, rcBorder);
}
}
感谢kennyzx和Fratyx的回答,我找到了一个有效的解决方案
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
switch(m.Msg)
{
case 0x85: // WM_CPAINT
case 0xf: // WM_PAINT
{
g = Graphics.FromHwnd(this.Handle);
Rectangle r = GetWndRect(this.Handle);
g.DrawRectangle(p, r);
Trace.WriteLine("WM_PAINT: "+r.ToString());
}
break;
case 0x05: // WM_SIZE
{
InvalidateRect(this.Handle, IntPtr.Zero, true);
Trace.WriteLine("WM_SIZE");
}
break;
default:
Trace.WriteLine("0x" + m.Msg.ToString("X"));
break;
}
}
请注意base.WndProc处于开始阶段,因为我必须先让应用程序绘制,然后我需要绘制,这样我就可以处于顶部。感谢kennyzx和Fratyx的回答,我得到了一个有效的解决方案
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
switch(m.Msg)
{
case 0x85: // WM_CPAINT
case 0xf: // WM_PAINT
{
g = Graphics.FromHwnd(this.Handle);
Rectangle r = GetWndRect(this.Handle);
g.DrawRectangle(p, r);
Trace.WriteLine("WM_PAINT: "+r.ToString());
}
break;
case 0x05: // WM_SIZE
{
InvalidateRect(this.Handle, IntPtr.Zero, true);
Trace.WriteLine("WM_SIZE");
}
break;
default:
Trace.WriteLine("0x" + m.Msg.ToString("X"));
break;
}
}
请注意base.WndProc在开头,因为我必须先让应用程序绘图,然后我需要绘图,这样我才能在顶部。在
GetWndRect
中到底发生了什么?@Fratyx-将其添加到:-)谢谢!你的任务听起来更像。阅读您正在“跳过”许多GDI详细信息,例如BeginPaint()
/EndPaint()
。在GetWndRect
中到底发生了什么?@Fratyx-将其添加到:-)谢谢!你的任务听起来更像。阅读您正在“跳过”许多GDI详细信息,例如BeginPaint()
/EndPaint()
。感谢您的想法,但我正在对本机窗口(任何给定窗口)进行子类化抱歉,我完全错过了它!谢谢你的想法,但是我正在对本机窗口(任何给定的窗口)进行子类化抱歉,我完全错过了它!不要忘记使用using
语句进行后续操作。不要忘记使用using
语句进行后续操作。