gpt4 book ai didi

c# - 玻璃 : Solution found, 上的渲染控件需要双缓冲/完善

转载 作者:IT王子 更新时间:2023-10-29 03:52:44 27 4
gpt4 key购买 nike

我(终于!)找到了一种在玻璃上呈现 Windows.Forms 控件的方法,它似乎没有任何重大缺点,也没有任何大的实现时间。它的灵感来自 this article来自 Coded,它基本上解释了如何 native 覆盖控件的绘制以在其上绘制。

我使用这种方法将控件呈现为位图,然后使用 GDI+ 和 NativeWindow 的绘画区域上的适当 alpha channel 将其绘制回来。实现很简单,但可以针对可用性进行完善,但这不是这个问题的重点。然而,结果非常令人满意:

Real textbox on glass

但是,要使其真正可用,需要修复 2 个区域。

  1. 双缓冲,因为这个叠加图像和实际控件之间的闪烁频繁且可怕(用代码测试自己)。使用 SetStyles(this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true) 将基本控件设置为双缓冲不起作用,但我怀疑我们可以通过一些试验和错误使其工作。<
  2. 某些控件不起作用。我已经能够完成以下工作:

    • 文本框
    • 蒙面组合框
    • 组合框(DropDownStyle == DropDownList)
    • 列表框
    • 勾选列表框
    • ListView
    • TreeView
    • 日期时间选择器
    • 月历

    但我无法让这些工作,虽然我不明白为什么不。我有根据的猜测是,我引用整个控件的实际 NativeWindow 句柄,而我需要引用它的“输入”(文本)部分,可能是一个 child 。欢迎 WinAPI 专家就如何获取该输入窗口句柄提供任何帮助。

    • 组合框(DropDownStyle != DropDownList)
    • 数字向上向下
    • 富文本框

但修复双缓冲将是可用性的主要焦点

这是一个示例用法:

new GlassControlRenderer(textBox1);

代码如下:

public class GlassControlRenderer : NativeWindow
{
private Control Control;
private Bitmap Bitmap;
private Graphics ControlGraphics;

protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case 0xF: // WM_PAINT
case 0x85: // WM_NCPAINT
case 0x100: // WM_KEYDOWN
case 0x200: // WM_MOUSEMOVE
case 0x201: // WM_LBUTTONDOWN
this.Control.Invalidate();
base.WndProc(ref m);
this.CustomPaint();
break;

default:
base.WndProc(ref m);
break;
}
}

public GlassControlRenderer(Control control)
{
this.Control = control;
this.Bitmap = new Bitmap(this.Control.Width, this.Control.Height);
this.ControlGraphics = Graphics.FromHwnd(this.Control.Handle);
this.AssignHandle(this.Control.Handle);
}

public void CustomPaint()
{
this.Control.DrawToBitmap(this.Bitmap, new Rectangle(0, 0, this.Control.Width, this.Control.Height));
this.ControlGraphics.DrawImageUnscaled(this.Bitmap, -1, -1); // -1, -1 for content controls (e.g. TextBox, ListBox)
}
}

我真的很乐意解决这个问题,并且一劳永逸有一种真正的在玻璃上呈现的方式,适用于所有 .NET 控件,无需 WPF。

编辑:双缓冲/防闪烁的可能路径:

  • 删除行 this.Control.Invalidate() 会消除闪烁,但会中断文本框中的输入。
  • 我已经尝试了 WM_SETREDRAW 方法和 SuspendLayout 方法,但没有成功:

    [DllImport("user32.dll")]
    public static extern int SendMessage(IntPtr hWnd, Int32 wMsg, bool wParam, Int32 lParam);

    private const int WM_SETREDRAW = 11;

    public static void SuspendDrawing(Control parent)
    {
    SendMessage(parent.Handle, WM_SETREDRAW, false, 0);
    }

    public static void ResumeDrawing(Control parent)
    {
    SendMessage(parent.Handle, WM_SETREDRAW, true, 0);
    parent.Refresh();
    }

    protected override void WndProc(ref Message m)
    {
    switch (m.Msg)
    {
    case 0xF: // WM_PAINT
    case 0x85: // WM_NCPAINT
    case 0x100: // WM_KEYDOWN
    case 0x200: // WM_MOUSEMOVE
    case 0x201: // WM_LBUTTONDOWN
    //this.Control.Parent.SuspendLayout();
    //GlassControlRenderer.SuspendDrawing(this.Control);
    //this.Control.Invalidate();
    base.WndProc(ref m);
    this.CustomPaint();
    //GlassControlRenderer.ResumeDrawing(this.Control);
    //this.Control.Parent.ResumeLayout();
    break;

    default:
    base.WndProc(ref m);
    break;
    }
    }

最佳答案

这是一个闪烁更少的版本,但仍然不完美。

public class GlassControlRenderer : NativeWindow
{
private Control Control;
private Bitmap Bitmap;
private Graphics ControlGraphics;

private object Lock = new object();

protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case 0x14: // WM_ERASEBKGND
this.CustomPaint();
break;

case 0x0F: // WM_PAINT
case 0x85: // WM_NCPAINT

case 0x100: // WM_KEYDOWN
case 0x101: // WM_KEYUP
case 0x102: // WM_CHAR

case 0x200: // WM_MOUSEMOVE
case 0x2A1: // WM_MOUSEHOVER
case 0x201: // WM_LBUTTONDOWN
case 0x202: // WM_LBUTTONUP
case 0x285: // WM_IME_SELECT

case 0x300: // WM_CUT
case 0x301: // WM_COPY
case 0x302: // WM_PASTE
case 0x303: // WM_CLEAR
case 0x304: // WM_UNDO
base.WndProc(ref m);
this.CustomPaint();
break;

default:
base.WndProc(ref m);
break;
}
}

private Point Offset { get; set; }

public GlassControlRenderer(Control control, int xOffset, int yOffset)
{
this.Offset = new Point(xOffset, yOffset);
this.Control = control;
this.Bitmap = new Bitmap(this.Control.Width, this.Control.Height);
this.ControlGraphics = Graphics.FromHwnd(this.Control.Handle);
this.AssignHandle(this.Control.Handle);
}

public void CustomPaint()
{
this.Control.DrawToBitmap(this.Bitmap, new Rectangle(0, 0, this.Control.Width, this.Control.Height));
this.ControlGraphics.DrawImageUnscaled(this.Bitmap, this.Offset); // -1, -1 for content controls (e.g. TextBox, ListBox)
}
}

关于c# - 玻璃 : Solution found, 上的渲染控件需要双缓冲/完善,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7061531/

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