zoukankan      html  css  js  c++  java
  • vs 在高分屏下开发 winform 配置

    一、窗体控件大小

    第一种方法:使用网格避免整除误差

    在选项中将Windows窗体设计器的LayoutMode(布局模式)改成SnapToGrid(对齐到网格),并将Default Grid Cell Size(默认网格大小)设为最小可缩放单元(或它的倍数),以避免移植时产生整除误差。同时由于这些单元是可见的,也使得将控件拖到合适的尺寸非常简单。

    同时,应该将窗体的AutoScaleMode改为Dpi。默认的Font缩放使用系统默认字体的大小进行缩放,但是系统默认字体并不和DPI完全等比例,这样也会造成整除误差。

    如果文字不能对齐的话,可以考虑调整TextAlign属性,比如单行Label推荐使用MiddleLeft、MiddleCenter或MiddleRight对齐方式,而不是默认的TopLeft对齐方式,以和其它控件的对齐方式统一。

    最小可缩放单元如下表所示(最小可缩放单元=缩放/25%=DPI/24):

    缩放    DPI值   最小可缩放单元
    100%    96      4
    125%    120     5
    150%    144     6
    175%    168     7
    200%    192     8
    225%    216     9
    250%    240     10


    Windows窗体设计器选项(150%):
    pic


    效果:
    pic


    第二种方法:使用布局容器进行布局

    如果认真学习过WPF,就会知道WPF可通过Grid、StackPanel、WrapPanel等布局容器进行布局。实际上,Windows Forms也有两个这样的容器,叫做TableLayoutPanel和FlowLayoutPanel,其中前者和Grid一样是表格布局容器,而后者和WrapPanel一样是流式布局容器。

    在新建了窗体之后,按照以下流程使用TableLayoutPanel(表格布局面板)布局控件:

    1.拖拉父窗口到合适大小,属性设置如下:
    Padding:设置合适的内边距【最小可缩放单元(如150%缩放下是6)或它的倍数】

    2.拖一个TableLayoutPanel控件,属性设置如下:
    Dock:设置为Fill(停靠方式=填充)

    3.根据需要分割出Columns(列)和Rows(行)
    要求:一个单元格最多只能放置一个控件(或容器),但是一个控件可跨多行或多列

    4.拖其它控件(或容器)到对应单元格,设置
    Dock:设置为Fill(停靠方式=填充)
    Margin:设置合适的外边距【最小可缩放单元(如150%缩放下是6)或它的倍数】
    ColumnSpan:需要跨的列数
    RowSpan:需要跨的行数

    注意:Windows Forms中某些控件的Height属性有时不起作用(比如单行TextBox等),设置Dock属性并不能保证单元格被完全填充,但是只要文字仍然能够对齐就可以了。

    FlowLayoutPanel(流式布局面板)和TableLayoutPanel有所不同,子控件要设置Width、Height、Margin属性,不能设置Dock属性,并且Width、Height和Margin一样也必须是最小可缩放单元的倍数。也就是说,仍然需要使用“对齐到网格”功能来完成设计。

    运行阶段

    默认情况下,Windows Forms程序由于高DPI支持不完整,在Windows Vista以后的系统中是由系统的DWM来缩放的(称为DPI虚拟化),这样的话会导致界面模糊。可以修改Program.cs并调用SetProcessDPIAware函数关闭DPI虚拟化,由程序自己来管理界面:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Runtime.InteropServices; // 导入System.Runtime.InteropServices命名空间
    using System.Threading.Tasks;
    using System.Windows.Forms;
    
    namespace WindowsFormsApplication1
    {
        static class Program
        {
            // 外部函数声明
            [DllImport("kernel32.dll")]
            private static extern IntPtr GetModuleHandle(string name);
            // 这个函数只能接受ASCII,所以一定要设置CharSet = CharSet.Ansi,不然会失败
            [DllImport("kernel32.dll", CharSet = CharSet.Ansi)]
            private static extern IntPtr GetProcAddress(IntPtr hmod, string name);
            private delegate void FarProc();
            /// <summary>
            /// The main entry point for the application.
            /// </summary>
            [STAThread]
            static void Main()
            {
                // SetProcessDPIAware是Vista以上才有的函数,需兼容XP的话不能直接调用,需按如下所示间接调用
                IntPtr hUser32 = GetModuleHandle("user32.dll");
                IntPtr addrSetProcessDPIAware = GetProcAddress(hUser32, "SetProcessDPIAware");
                if (addrSetProcessDPIAware != IntPtr.Zero)
                {
                    FarProc SetProcessDPIAware = (FarProc)Marshal.GetDelegateForFunctionPointer(addrSetProcessDPIAware, typeof(FarProc));
                    SetProcessDPIAware();
                }
                // C#的原有代码
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                Application.Run(new Form1());
            }
        }
    }


    如果不需要兼容Windows XP的话,可以更简单地直接调用SetProcessDPIAware:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Runtime.InteropServices; // 导入System.Runtime.InteropServices命名空间
    using System.Threading.Tasks;
    using System.Windows.Forms;
    
    namespace WindowsFormsApplication1
    {
        static class Program
        {
            // 外部函数声明
            [DllImport("user32.dll")]
            private static extern void SetProcessDPIAware();
            /// <summary>
            /// The main entry point for the application.
            /// </summary>
            [STAThread]
            static void Main()
            {
                // SetProcessDPIAware是Vista以上才有的函数,这样直接调用会使得程序不兼容XP
                SetProcessDPIAware();
                // C#的原有代码
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                Application.Run(new Form1());
            }
        }
    }


    .NET Framework 4.5.1提供了优化的高DPI支持,但需要手动开启,在工程中添加app.config(发布时需要将.exe文件和.exe.config文件一起发布),内容如下:

    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
        <appSettings>
            <add key="EnableWindowsFormsHighDpiAutoResizing" value="true" />
        </appSettings>
    </configuration>

    二 、FormSize和设计不符

    Windows的高DPI支持是通过DWM(Desktop Window Manager)缩放实现的,但是有时候我们不希望这种效果(例如缩放会使一些内容变得模糊),因此需要禁用Windows高DPI对程序的缩放。有两种方式可以实现这种效果:一个是使用应用程序清单文件,一个是使用系统API实现。

    1、使用清单文件

    这里以Winform为例,右键项目->添加->新建项->应用程序清单文件,将含有dpiAware标签的属性取消注释,代码如下:

    <application xmlns="urn:schemas-microsoft-com:asm.v3">
    <windowsSettings>
    <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
    </windowsSettings>
    </application>
    2、使用系统API

    下面的代码对Win7及以上的系统禁用高DPI。

    if (Environment.OSVersion.Version.Major >= 6)
    {
    SetProcessDPIAware();
    }

    [DllImport("user32.dll")]

  • 相关阅读:
    NYOJ 10 skiing DFS+DP
    51nod 1270 数组的最大代价
    HDU 4635 Strongly connected
    HDU 4612 Warm up
    POJ 3177 Redundant Paths
    HDU 1629 迷宫城堡
    uva 796
    uva 315
    POJ 3180 The Cow Prom
    POJ 1236 Network of Schools
  • 原文地址:https://www.cnblogs.com/z45281625/p/11090140.html
Copyright © 2011-2022 走看看