我试图在窗口周围绘制一个矩形(窗口内部,而不是外部),但绘图涂抹,在某些情况下不会重绘。
我将HWND WndProc子类化(当然,代码在HWND进程中运行):
class SubClasser : NativeWindow
{
...
protected override void WndProc(ref Message m)
{
switch(m.Msg)
{
case 0x85: // WM_CPAINT
case 0xf: // WM_PAINT
{
base.WndProc(ref m);
Rectangle r = GetWndRect(this.Handle);
g.DrawRectangle(p, r);
Trace.WriteLine("WM_PAINT: "+r.ToString());
}
break;
default:
Trace.WriteLine("0x" + m.Msg.ToString("X"));
base.WndProc(ref m);
break;
}
}
...
}
private Rectangle RECTtoRectangle(RECT r)
{
return new Rectangle(r.Left, r.Top, r.Right, r.Bottom);
}
private Rectangle GetWndRect(IntPtr hwnd)
{
RECT r = new RECT();
GetClientRect(hwnd, out r);
return RECTtoRectangle(r);
}
正如您在代码中看到的那样,我正在重新绘制"矩形"在WM_PAINT和WM_CPAINT上,但还不够:
我应该指出,我确实得到了绘制消息,似乎子类化工作正常。
我真的被困: - (
编辑:
OH,我也试过放置:
base.WndProc(ref m);
仅在WndProc的末尾,得到了相同的结果。
答案 0 :(得分:1)
我不确定因为我无法测试它并且不知道成员变量g
的背景但是我认为这是剪切矩形的问题。因此,您可以在WndProc
函数中尝试这样的操作,以确保重绘整个窗口:
case 0x05: // WM_SIZE
InvalidateRect(this.Handle, GetWndRect(this.Handle), TRUE);
break;
答案 1 :(得分:1)
首先,您无法在消息上多次致电base.WndProc(ref m);
;
其次,每次更改窗口大小时都应重新创建g
,因此它可以在更大的表面上绘制。
第三,在窗口上调用Invalidate
以在窗口大小改变时强制重绘。我使用SizeChanged
事件和ClientSize
,因为我可以轻松编译代码(需要阅读文档来编写GDI + / WINAPI)。
public partial class RedrawInWndProcForm : Form
{
public RedrawInWndProcForm()
{
InitializeComponent();
p = new Pen(Color.Red, 2.0f);
this.SizeChanged += (s, e) => { this.Invalidate(); };
}
Graphics g;
Pen p;
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
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;
}
Trace.WriteLine("handled");
base.WndProc(ref m);
}
private Rectangle GetWndRect(IntPtr hwnd)
{
return new Rectangle(0, 0, (int)this.ClientSize.Width, (int)this.ClientSize.Height);
}
}
答案 2 :(得分:1)
如果只需要绘制边框,那么我们可以使用更简单的机制吗?
OnPaint
实施例:
假设您正在进行子类化的窗口是Form
,
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);
}
}
答案 3 :(得分:1)
感谢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在开头,因为我必须首先让应用程序绘制,然后我需要绘制,所以我将在顶部。