界面自适应,WinForm响应式布局设计实践

作者: 策略游戏排行  发布:2019-08-30

引言

开创响应式WinForm应用程序并不那么粗略。 响应式布局,在此作者指的是应用程序在差别显示屏分辨率下的可用性。 对于WinForm应用程序,大家需求驾驭地根据分辨率来调动控件的深浅和重复定位。 就算在选择WPF时有相关的推行应用,通过行使控件的docking和anchoring,或使用panels等格局,但本文提供了一种将响应式应用于WinForm应用程序的两样形式。

起因

背景

本人在三个自个儿安顿的轻易游戏中相遇了难题:作者设计了一台分辨率为1916x1080的机器, 然则当自家计划在台式机计算机上播报时,开掘应用程序边界跑到荧屏之外。由此很有必不可缺让程序来适应不相同分辨率的配备,实际不是让顾客来适应程序。 由此,作者对代码进行了改良。

界面自适应,WinForm响应式布局设计实践。界面自适应,WinForm响应式布局设计实践。    使用SmartPhone上的WinForm做了七个WM的小程序,结果放到手提式有线电话机上其实七日转。开采动态变化的控件在在那之中展现得都比较小,难以决断。

技术

其实没什么手艺可言,只是用了一个小手艺。大家用多个常量来保存设计时的显示屏分辨率,我们誉为设计时分辨率。那样,无论哪一天运营应用程序,它都会获取贰个乘法因子,这实际上是八个比重因子,通过将近期分辨率除以设计时分辨率来猎取该因子。 窗体的具有控件都被传送给那几个类对象开展缩放和调治大小。


代码

界面自适应,WinForm响应式布局设计实践。界面自适应,WinForm响应式布局设计实践。原因

The Responsive Class - Responsive.cs

界面自适应,WinForm响应式布局设计实践。成立叁个类Responsive.cs,增添5个变量。

float WIDTH_AT_DESIGN_TIME = (float)Convert.ToDouble
                             (ConfigurationManager.AppSettings["DESIGN_TIME_SCREEN_WIDTH"]);
float HEIGHT_AT_DESIGN_TIME = (float)Convert.ToDouble
                              (ConfigurationManager.AppSettings["DESIGN_TIME_SCREEN_HEIGHT"]);
Rectangle Resolution;
float WidthMultiplicationFactor;
float HeightMultiplicationFactor;

界面自适应,WinForm响应式布局设计实践。设计时荧屏分辨率保存在App.config文件中。

<add key ="DESIGN_TIME_SCREEN_WIDTH" value="1920"/>
<add key ="DESIGN_TIME_SCREEN_HEIGHT" value="1080"/>

界面自适应,WinForm响应式布局设计实践。当类的八个实例被创立时,当前的深入分析被提必要构造函数。 之后调用该类的SetMultiplicationFactor()方法。 这种办法通过将这段日子分辨率除以设计时间分辨率来获取缩放因子。

public Responsive(Rectangle ResolutionParam)
{
    Resolution = ResolutionParam;
}

public void SetMultiplicationFactor()
{
    WidthMultiplicationFactor = Resolution.Width / WIDTH_AT_DESIGN_TIME;
    HeightMultiplicationFactor = Resolution.Height / HEIGHT_AT_DESIGN_TIME;
}

界面自适应,WinForm响应式布局设计实践。比方,该应用程序设计在1919x1080分辨率。 固然此应用程序在分辨率为1024x768的Computer上运转,则WidthMultiplicationFactor和HeightMultiplicationFactor退换如下:

WidthMultiplicationFactor = 1024/1920 = 0.533
HeightMultiplicationFactor = 768/1080 = 0.711

聊到底有二种重载方法,它们为应用程序控件提供响应式实施方案(最棒大小,地点和字体大小)的最后方法。

public int GetMetrics(int ComponentValue)
{
    return (int)(Math.Floor(ComponentValue * WidthMultiplicationFactor));
}

public int GetMetrics(int ComponentValue, string Direction)
{
    if (Direction.Equals("Width") || Direction.Equals("Left"))
        return (int)(Math.Floor(ComponentValue * WidthMultiplicationFactor));
    else if (Direction.Equals("Height") || Direction.Equals("Top"))
        return (int)(Math.Floor(ComponentValue * HeightMultiplicationFactor));
    return 1;
}

举例,要是存在宽度=465,中度=72,左=366,最上端=41和字体大小=40的控件,则该办法再次回到建议的轻重缓急,地方和字体大小为:

Width = 465 * 0.533 = 248
Height = 72 * 0.711= 51
Left = 366 * 0.533= 195
Top = 41 * 0.711= 29
Font-size = 40 * 0.533 = 21

实际上,这个措施重临缩放的控件与大小、地方和字体大小,而那个值是显得的最好值。

    我的难题是急需在InitializeComponent方法截至后,动态变化一些控件,如下:

使用 Responsive Class

笔者们供给的是以任何索要响应的花样轻易地开创那些类的目的。 当前的分辨率是在构造函数中提供的, 之后的办事正是确立所需的乘法因子。

Responsive ResponsiveObj;
ResponsiveObj = new Responsive(Screen.PrimaryScreen.Bounds);
ResponsiveObj.SetMultiplicationFactor();

在那件事后,表单的具备控件都将各个传递,以在表单的加载事件中调治大小和重新定位。 那么些调用在上边包车型地铁代码中实现。 它所做的是第一将窗体定位到显示屏的宗旨。 小编在此处安装了一个校准常数(30),为超级的垂直地方加多控件,那可能因开拓职员而异。 之后,表单的每叁个控件都会重新定位,调节大小,并再一次校准字体大小。

private void ResponsiveForm_Load(object sender, EventArgs e)
{
    Width = ResponsiveObj.GetMetrics(Width, "Width");           // Form width and height set up.
    Height = ResponsiveObj.GetMetrics(Height, "Height");
    Left = Screen.GetBounds(this).Width / 2 - Width / 2;        // Form centering.
    Top = Screen.GetBounds(this).Height / 2 - Height / 2 - 30;  // 30 is a calibration factor.

    foreach (Control Ctl in this.Controls)
    {
        Ctl.Font = new Font(FontFamily.GenericSansSerif, 
                   ResponsiveObj.GetMetrics((int)Ctl.Font.Size), FontStyle.Regular);
        Ctl.Width = ResponsiveObj.GetMetrics(Ctl.Width, "Width");
        Ctl.Height = ResponsiveObj.GetMetrics(Ctl.Height, "Height");
        Ctl.Top = ResponsiveObj.GetMetrics(Ctl.Top, "Top");
        Ctl.Left = ResponsiveObj.GetMetrics(Ctl.Left, "Left");
    }
}
/// <summary>
/// 这个方法会根据传入的实体模型,生成一些选择框,设置它们的大小、位置;并会改变其它控件的大小、位置。
/// </summary>
/// <param name="categories"></param>
private void GenerateCheckBoxes(IList<Category> categories)
{

    ……
}

示例

以下是贰个特别轻巧的表单,当中带有几个data gird,一个label,一个textbox和一个button。 下边包车型客车图样以二种分裂的分辨率截取。 上边包车型大巴截图是在一九一八x1080分辨率下截取的:
图片 1

上边包车型地铁截图是在1360x768分辨率下截取的:
图片 2

下边包车型地铁截图是在1024x768分辨率下截取的:
图片 3

实际上,通过收缩/扩张和重新定位调整到最棒水平,Form在区别的分辨率下看起来是一律的。

    原因就是因为手提式有线电话机分辨率非常大,而这一个动态变化的控件并不曾进展随着分辨率差别而开展活动缩放。而由界面设计器设计出来的控件,都能很好的彰显。

代码调解

就如我们对垂直中央定位所做的那样,我们可能需求设置有个别参数来调动总体布局。

其它,建议开垦者尝试以不一样的分辨率查看表单的外观,以确认全部的控件都以可知的,并根据预期在显示屏上正分明位。

而外,对于贰个简约的表单,那是三个通用的办法,它纵然表单的具备控件都富有这个属性---宽度,中度,侧边,最上部和字体大小。可是,真实情况并不是那样。有局地表单控件不拥有全体这个属性。比方,图片框没有font-size属性。由此,就算如此的状态下未有鲜明管理,运营代码将会促成运转时足够。本文目的在于介绍这种办法,开辟职员必要依据实情进行校准。建议的办法如下:

private void ResponsiveForm_Load(object sender, EventArgs e)
{
    Width = ResponsiveObj.GetMetrics(Width, "Width");           // Form width and height set up.
    Height = ResponsiveObj.GetMetrics(Height, "Height");
    Left = Screen.GetBounds(this).Width / 2 - Width / 2;        // Form centering.
    Top = Screen.GetBounds(this).Height / 2 - Height / 2 - 30;  // 30 is a calibration factor.

    foreach (Control Ctl in this.Controls)
    {
        if (Ctl is PictureBox)
        {
            Ctl.Width = ResponsiveObj.GetMetrics(Ctl.Width, "Width");
            Ctl.Height = ResponsiveObj.GetMetrics(Ctl.Height, "Height");
            Ctl.Top = ResponsiveObj.GetMetrics(Ctl.Top, "Top");
            Ctl.Left = ResponsiveObj.GetMetrics(Ctl.Left, "Left");
        }
        else
        {
            Ctl.Font = new Font(FontFamily.GenericSansSerif, 
                                ResponsiveObj.GetMetrics((int)Ctl.Font.Size), FontStyle.Regular);
            Ctl.Width = ResponsiveObj.GetMetrics(Ctl.Width, "Width");
            Ctl.Height = ResponsiveObj.GetMetrics(Ctl.Height, "Height");
            Ctl.Top = ResponsiveObj.GetMetrics(Ctl.Top, "Top");
            Ctl.Left = ResponsiveObj.GetMetrics(Ctl.Left, "Left");
        }
    }
}

或许会基于业务员要求和控件的质量来调动代码。 其余,或者须要为分化的控件类型引进更加多的重载方法。


其他

如前所述,还也许有其余部分办法,比如利用WPF,使用anchoring/docking等,那是四个更掌握的抉择。 要是表单上有数千个控件,则也许会遇到加载延迟。 不过,那一点延迟对前周运维高效的微管理器来说小意思。 这种艺术只是在表单的加载时才施行三次调用操作,由此不会推动致命的习性裁减的难点。

求索

结尾

始建响应式WinForm应用程序,依照机器的运作时刻分辨率自动调节大小,重新定位字体大小并再一次校准字体大小,那是一种面向开发职员的章程。 只需将该类增加到项目中,在App.config文件中装置规划时分辨率,然后在窗体的加载事件中丰裕响应代码。 So easy!

    由于界面生成的控件能够很好的自适应分辨率的区别,所以先看一下Designer生成的代码:

private void InitializeComponent()
{
    this.BAdd = new System.Windows.Forms.Button();
    this.PCategories = new System.Windows.Forms.Panel();
    this.SuspendLayout();

    // BAdd
    this.BAdd.Location = new System.Drawing.Point(165, 164);
    this.BAdd.Name = "BAdd";
    this.BAdd.Size = new System.Drawing.Size(72, 20);
    this.BAdd.TabIndex = 11;
    this.BAdd.Text = "Add";
    this.BAdd.Click  = new System.EventHandler(this.BAdd_Click);
    // PCategories
    this.PCategories.Location = new System.Drawing.Point(73, 83);
    this.PCategories.Name = "PCategories";
    this.PCategories.Size = new System.Drawing.Size(164, 75);
    // MainForm
    this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
    this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
    this.AutoScroll = true;
    this.ClientSize = new System.Drawing.Size(243, 258);
    this.Controls.Add(this.PCategories);
    this.Controls.Add(this.BAdd);
    this.Name = "MainForm";
    this.Text = "MoneyManagerForm";
    this.ResumeLayout(false);
}

    这里的主借使使用了AutoScaleDimensions和AutoScaleMode属性来安装分界面为电动缩放。(Dpi代表Dot per inch,WPF就是直接行使这种艺术来调控分界面包车型客车。)然后最终一步调用ResumeLayout方法,那个方式中,会调用到ContainerControl.PerformAutoScale方法进行活动缩放。

    最可恶的有些:从控件的结构,到界面包车型地铁自行缩放,全体在一个艺术中贯彻!何况以此方式中,未有啥样好的不二等秘书技来调用笔者生成控件的格局……


杀鸡取蛋进度

    在Form中,重写ScaleControl方法如下:

protected override void ScaleControl(SizeF factor, BoundsSpecified specified)
{
    var categories = Config.Instance.Categories;
    this.GenerateCheckBoxes(categories);

    base.ScaleControl(factor, specified);
}

本文由bg游戏资讯发布于策略游戏排行,转载请注明出处:界面自适应,WinForm响应式布局设计实践

关键词: .NET技术 WinForm 响应式设计 响应式布局 具体

上一篇:类定义关键字详解,背后的故事之
下一篇:没有了