gpt4 book ai didi

c# - 临时变量对删除 GroupBox 背景的影响

转载 作者:行者123 更新时间:2023-11-30 17:28:53 24 4
gpt4 key购买 nike

上下文:

考虑绘制一个带有渐变的 GroupBox 作为其背景的一部分。

示例:

Ideal <code>GroupBox</code>


让我们执行以下操作:

  • 创建一个继承GroupBox
    • 将其 FlatStyle property 设置为 FlatStyle.System
    • override 它是 WndProc 方法。
    • 处理 WM_ERASEBKGND 消息,我们在其中绘制渐变
    • 处理 WM_PRINTCLIENT 消息,我们在其中调用 DefWndProcreturn
      (将需要稍后。)
  • 添加一个 Label 作为子 Control
    ( Label 的背景必须是透明的才能看到它后面的渐变 Text

    • 创建一个继承Label
    • 覆盖 WndProc 方法。
    • 模拟透明度”通过调用 DrawThemeParentBackground 函数在 Label 上绘制 GroupBox 的背景的图形

问题:

Depending on whether a temporary variable is used to hold the Graphics object, the end result varies, depicted with the code sample and image below:

using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace MCVE
{
class GroupBox : System.Windows.Forms.GroupBox
{
const int WM_ERASEBKGND = 0x14;
const int WM_PRINTCLIENT = 0x318;

protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case WM_ERASEBKGND:
base.WndProc(ref m);
using (var g = Graphics.FromHdc(m.WParam))//CASE 1
//using (var e = new PaintEventArgs(Graphics.FromHdc(m.WParam), ClientRectangle))//CASE 2
{
var e = new PaintEventArgs(g, ClientRectangle);//CASE 1
var r = new Rectangle(2, 12, Width - 4, Height - 2);
using (var b = new LinearGradientBrush(r, BackColor, SystemColors.Window, LinearGradientMode.Vertical))
{
e.Graphics.FillRectangle(b, r);//Draw the gradient.
}
}
m.Result = new IntPtr(1);//Signal that no further drawing of the background is necessary by WM_PAINT.
return;
case WM_PRINTCLIENT:
DefWndProc(ref m);//Bypass GroupBox's internal handling so that actual painting is handled by Windows.
return;
}
base.WndProc(ref m);//Default processing of the rest of the messages.
}
};

class Label : System.Windows.Forms.Label
{
const int WM_ERASEBKGND = 0x14;
const int WM_PAINT = 0xF;

[DllImport("user32.dll")] static extern IntPtr BeginPaint(IntPtr hWnd, out PAINTSTRUCT lpPaint);
[DllImport("user32.dll")] static extern IntPtr EndPaint(IntPtr hWnd, ref PAINTSTRUCT lpPaint);
//Ask Windows to send a message to the parent to draw it's background in the current device context.
[DllImport("uxtheme.dll")] extern static int DrawThemeParentBackground(IntPtr hWnd, IntPtr hdc, ref Rectangle pRect);

[StructLayout(LayoutKind.Sequential)]
struct PAINTSTRUCT
{
public IntPtr hdc;
public bool fErase;
public Rectangle rcPaint;
public bool fRestore;
public bool fIncUpdate;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] public byte[] rgcReserved;
};

protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case WM_ERASEBKGND:
var r = ClientRectangle;
DrawThemeParentBackground(Handle, m.WParam, ref r);
m.Result = new IntPtr(1);//Signal that no further drawing of the background is necessary by WM_PAINT.
return;
case WM_PAINT:
PAINTSTRUCT ps;
var hdc = BeginPaint(Handle, out ps);
EndPaint(Handle, ref ps);//Don't paint any text so that the gradient remains visible.
m.Result = IntPtr.Zero;
return;
}
base.WndProc(ref m);//Default processing of the rest of the messages.
}
};

static class Program
{
[STAThread] static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);

var form = new Form() { BackColor = SystemColors.Highlight };
var groupbox = new GroupBox() { Anchor = (AnchorStyles)15, FlatStyle = FlatStyle.System, Location = new Point(10, 10), Text = "groupBox1" };

form.Controls.Add(groupbox);
groupbox.Controls.Add(new Label() { FlatStyle = FlatStyle.System, Location = new Point(50, 50) });

Application.Run(form);
}
};
}

运行上面的 MCVE (案例 1) 会产生示例图像中所示的预期输出。

在注释掉标记为 CASE 1 的行并取消注释标记为 CASE 2 的行时,会产生以下不需要的输出:

Actual <code>GroupBox</code>

问题:

为什么删除临时变量会产生如此不同的输出?

最佳答案

为了完整起见,将此作为答案发布。

  • 正如 Ivan Stoev 指出的那样,非拥有 PaintEventArgs 调用 Graphics Dispose 对象
  • 这有可见的副作用,因为 DC 在 WM_PRINTCLIENT Message 中被 Windows 重用,即在 WndProc 旁边发送。

Graphics object 上手动调用 Dispose 可以确认这一点。

using (var g = Graphics.FromHdc(m.WParam))
{
using (var e = new PaintEventArgs(g, ClientRectangle))
{
var r = new Rectangle(2, 12, Width - 4, Height - 2);
using (var b = new LinearGradientBrush(r, BackColor, SystemColors.Window, LinearGradientMode.Vertical))
{
e.Graphics.FillRectangle(b, r);//Draw the gradient.
}
}
}

关于c# - 临时变量对删除 GroupBox 背景的影响,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51900815/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com