Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/windows/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在窗口内绘图不需要';重画和涂片_C#_Windows_Winapi_Gdi+ - Fatal编程技术网

C# 在窗口内绘图不需要';重画和涂片

C# 在窗口内绘图不需要';重画和涂片,c#,windows,winapi,gdi+,C#,Windows,Winapi,Gdi+,我试图在窗口周围绘制一个矩形(窗口的内部,而不是外部),但该图形会被涂污,在某些情况下不会重新绘制 我将HWND WndProc子类化(当然,代码在HWND进程中运行): 正如您在代码中看到的,我正在WM_PAINT和WM_CPAINT上重新绘制“矩形”,但这还不够: 当我使窗口变大(调整大小)时,矩形不会变大 当我缩小窗口(再次调整大小)时,矩形会变小,但当我放大窗口时,矩形会一直涂抹到其原始大小(而不是更大) 当我将窗口置于可见屏幕之外时,部分矩形(仅底部)不会被重新绘制 我应该指出,我

我试图在窗口周围绘制一个矩形(窗口的内部,而不是外部),但该图形会被涂污,在某些情况下不会重新绘制

我将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内容)


如果只需要绘制一个边界,那么我们可以有一个更简单的机制,如下所示

  • 将“调整大小时重绘”设置为true
  • 覆盖
    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); 
            }
        }
    

    如果只需要绘制一个边界,那么我们可以有一个更简单的机制,如下所示

  • 将“调整大小时重绘”设置为true
  • 覆盖
    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
    语句进行后续操作。