winforms 如何正确对齐标签到文本框,如果DPI是变化的?

krugob8w  于 2023-03-31  发布在  其他
关注(0)|答案(1)|浏览(119)

我已经在配置文件中启用了这些建议的设置:

<add key="DpiAware" value="true" />
<add key="DpiAwareness" value="PerMonitorV2" />
<add key="EnableWindowsFormsHighDpiAutoResizing" value="true" />

在main函数中:

Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);

所有内容都在顶部和左侧锚定,这是它在100%缩放显示屏上的外观:

当我将窗口移动到150或175%缩放显示时:

如您所见,标签向下偏移了几个像素。
容器的AutoScaleMode设置为DPI
如何保持对齐?

plupiseo

plupiseo1#

我遇到了同样的问题,经过一些挖掘,我带着这个控件来了,它可以代替标签使用。已知问题:单击时,获得焦点的控件将失去焦点。这既可以在TableLayoutPanel中使用,也可以单独使用。

public class LabelTextBox : System.Windows.Forms.TextBox
{
    private const int WM_NCPAINT = 0x85;
    private const int WM_SETFOCUS = 0x07;
    private const int WM_ENABLE = 0x0A;
    private const int WM_SETCURSOR = 0x20;

    [StructLayout(LayoutKind.Sequential)]
    private struct RECT
    {
        // https://www.pinvoke.net/default.aspx/Structures/RECT.html
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct POINT
    {
        // https://www.pinvoke.net/default.aspx/Structures/POINT.html
    }

    public LabelTextBox()
    {
        // Disable some TextBox interactions, so it is intact as the Label
        this.ReadOnly = true;
        this.TabStop = false;
    }

    [DllImport("user32")]
    private static extern IntPtr GetWindowDC(IntPtr hwnd);
    
    [DllImport("user32")]
    private static extern bool GetClientRect(IntPtr hwnd, out RECT rectangle);
    
    [DllImport("user32")]
    private static extern bool GetWindowRect(IntPtr hwnd, out RECT rectangle);

    [DllImport("user32.dll")]
    static extern bool ClientToScreen(IntPtr hWnd, ref POINT lpPoint);

    protected override void WndProc(ref Message m)
    {
        // Disable some TextBox interactions, so it is intact as the Label
        if (m.Msg == WM_SETFOCUS || m.Msg == WM_ENABLE || m.Msg == WM_SETCURSOR)
            return;

        // When the boreder should be painted
        if (m.Msg == WM_NCPAINT)
        {
            // Get the rect of the client area in the sceen coordinates.
            var clientOrigin = new POINT(0, 0);
            ClientToScreen(Handle, ref clientOrigin);
            GetClientRect(Handle, out var clientRect);
            clientRect.X = clientOrigin.X;
            clientRect.Y = clientOrigin.Y;

            // Get the rect of the window area in the sceen coordinates.
            GetWindowRect(Handle, out var windowRect);

            // Calculate the rect of the client area in the window coordinates.
            // This will be our clipping area, because we want to paint only the border.
            var clip = new Rectangle(
                clientRect.Left - windowRect.Left,
                clientRect.Top - windowRect.Top,
                clientRect.Width,
                clientRect.Height
                );

            // Get the Graphics, set the clip and fill with the BackColor.
            var dc = GetWindowDC(Handle);
            using (Graphics g = Graphics.FromHdc(dc))
            {
                g.SetClip(clip, CombineMode.Exclude);
                g.FillRectangle(new SolidBrush(BackColor), 0, 0, windowRect.Width, windowRect.Height);
            }
            
            return;
        }

        base.WndProc(ref m);
    }
}

结果是:
百分百

百分之二百

我是通过TableLayoutPanel中的那些糟糕的解决方案得出这个结论的:
1.垂直居中-非常稳定的对齐,但无法与基线对齐。
1.通过填充进行微调-在更高的DPI上仍然不够稳定。
1.使用无边框的文本框代替标签-无边框的文本框与标签的对齐方式相同。
该溶液通过以下方式制备:

  1. https://stackoverflow.com/a/27027829/2408668
  2. https://stackoverflow.com/a/74106039/2408668

相关问题