WinForm响应式布局设计实践
引言
创建响应式WinForm应用程序并不那么简单。 响应式布局,在此我指的是应用程序在不同屏幕分辨率下的可用性。 对于WinForm应用程序,我们需要明确地根据分辨率来调整控件的大小和重新定位。 虽然在使用WPF时有相关的实践应用,通过使用控件的docking和anchoring,或使用panels等方法,但本文提供了一种将响应式应用于WinForm应用程序的不同方法。
背景
我在一个自己设计的简单游戏中遇到了问题:我设计了一台分辨率为1920x1080的机器, 但是当我试图在笔记本电脑上播放时,发现应用程序边界跑到屏幕之外。由此很有必要让程序来适应不同分辨率的设备,而不是让用户来适应程序。 因此,我对代码进行了改进。
技术
其实没什么技术可言,只是用了一个小技巧。我们用两个常量来保存设计时的屏幕分辨率,我们称之为设计时分辨率。这样,无论何时运行应用程序,它都会获得一个乘法因子,这实际上是一个比例因子,通过将当前分辨率除以设计时分辨率来获得该因子。 窗体的所有控件都被传递给这个类对象进行缩放和调整大小。
代码
The Responsive Class - Responsive.cs###
创建一个类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;
设计时屏幕分辨率保存在App.config文件中。
<add key ="DESIGN_TIME_SCREEN_WIDTH" value="1920"/>
<add key ="DESIGN_TIME_SCREEN_HEIGHT" value="1080"/>
当类的一个实例被创建时,当前的解析被提供给构造函数。 之后调用该类的SetMultiplicationFactor()方法。 这种方法通过将当前分辨率除以设计时间分辨率来获得缩放因子。
public Responsive(Rectangle ResolutionParam)
{
Resolution = ResolutionParam;
}
public void SetMultiplicationFactor()
{
WidthMultiplicationFactor = Resolution.Width / WIDTH_AT_DESIGN_TIME;
HeightMultiplicationFactor = Resolution.Height / HEIGHT_AT_DESIGN_TIME;
}
例如,该应用程序设计在1920x1080分辨率。 如果此应用程序在分辨率为1024x768的计算机上运行,则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
事实上,这些方法返回缩放的控件与大小、位置和字体大小,而这些值是展示的最佳值。
使用 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");
}
}
示例###
以下是一个非常简单的表单,其中包含一个data gird,一个label,一个textbox和一个button。 下面的图片以三种不同的分辨率截取。 下面的截图是在1920x1080分辨率下截取的:
下面的截图是在1360x768分辨率下截取的:
下面的截图是在1024x768分辨率下截取的:
实际上,通过缩小/扩大和重新定位控制到最佳水平,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!
WinForm响应式布局设计实践的更多相关文章
- 《响应式Web设计实践》学习笔记
原书: 响应式Web设计实践 目录: 第2章 流动布局 1. 布局选项 2. 字体大小 3. 网格布局 4. 混合固定宽度和流动宽度 第3章 媒介查询 1. 视口 2. 媒介查询结构 3. 内嵌样式与 ...
- html5 + css3 + jQuery + 响应式布局设计
1. [代码][HTML]代码 <!DOCTYPE html><html dir="ltr" lang="zh-CN">< ...
- css3响应式布局设计——回顾
响应式设计是在不同设备下分辨率不同显示的样式就不同. media 属性用于为不同的媒体类型规定不同的样式.根绝浏览器的宽度和高度重新渲染页面. 语法: @media mediatype and | n ...
- [已读]响应式web设计实践
薄的一本,彩印,书质量和内容都不错. 响应设计三要素:媒体查询.流动布局.自适应图片.
- 【响应式Web设计实践 #BOOK#】
<!doctype html> <html> <head> <meta charset="utf-8"> <title> ...
- web页面之响应式布局
一.什么是响应式布局? 响应式布局是Ethan Marcotte在2010年5月份提出的一个概念,简而言之,就是一个网站能够兼容多个终端——而不是为每个终端做一个特定的版本.这个概念是为解决移动互联网 ...
- css3媒体查询实现网站响应式布局
最常见的办法就是基类(最常用的网站布局)+扩展类(几种不同的网站布局类)来实现不同的布局. <!–使用说明:网站基本布局,使用class="layout";使用ipad访问时 ...
- media screen 响应式布局(知识点)
一.什么是响应式布局? 响应式布局是Ethan Marcotte在2010年5月份提出的一个概念,简而言之,就是一个网站能够兼容多个终端--而不是为每个终端做一个特定的版本.这个概念是为解决移动互联网 ...
- 初探响应式Web设计
公司书柜有本<响应式Web设计:HTML5和CSS3实战>,大概就认真看了前面几章,后面大部分介绍css3(随便找本手册都可以了要你可用!) <响应式Web设计:HTML5和CSS3 ...
随机推荐
- 进程与进程描写叙述符(task_struct)
一. 进程 进程(Process) 计算机中的程序关于某数据集合上的一次执行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础.在早期面向进程设计的计算机结构中,进程是程序的基本执行实体: ...
- PHP 数据库连接池实现
摘要 xml 读取配置文件 简易方式 常规方式 PHP解析XML 配置文件 解析 数据库连接池 測试 申请过多时拒绝请求 已满后拒绝放入 总结 摘要 之前总是以脚本面向过程的方式写PHP代码,所以非常 ...
- Java基础(十一) Stream I/O and Files
Java基础(十一) Stream I/O and Files 1. 流的概念 程序的主要任务是操纵数据.在Java中,把一组有序的数据序列称为流. 依据操作的方向,能够把流分为输入流和输出流两种.程 ...
- Java中用Apache POI生成excel和word文档
概述: 近期在做项目的过程中遇到了excel的数据导出和word的图文表报告的导出功能.最后决定用Apache POI来完毕该项功能.本文就项目实现过程中的一些思路与代码与大家共享.同一时候.也作为自 ...
- 工作中git 操作汇总
1. git branch -l 查看本地branch 2. git reset --hard 回滚全部修改 3. git status 查看本地修改 4. git pull 更新代码 5. gi ...
- C(8)
C语言位运算与文件 本章引言: 在不知不觉中我们的C高速入门系列已经慢慢地接近尾声了,而在这一节中,我们会对 C语言中的位运算和文件进行解析,相信这两章对于一些人来说是陌生的,由于非常多 老师都会跳过 ...
- 零基础学python-2.8 字典
字典类型,事实上就是相当于java的map,通过key-value来记录数据,工作原理类似于哈希表 差点儿全部的python对象都能够作为key,可是一般最经常使用的还是数字和字符串 字典元素使用{} ...
- JAVA入门[9]-mybatis多表关联查询
概要 本节要实现的是多表关联查询的简单demo.场景是根据id查询某商品分类信息,并展示该分类下的商品列表. 一.Mysql测试数据 新建表Category(商品分类)和Product(商品),并插入 ...
- 腾讯云实力通过工信部测评,获全国范围CDN经营许可
欢迎大家前往腾讯云社区,获取更多腾讯海量技术实践干货哦~ 近日,腾讯云提前完成了全国范围的CDN资质测评,顺利获得工信部颁发的CDN业务全国范围的经营许可证. 2017年1月份,工信部发布<关于 ...
- 数据库——MongoDB——>Java篇
MongoDB是一个基于分布式文件存储的数据库.由C++语言编写.旨在为WEB应用提供可扩展的高性能数据存储解决方案. MongoDB 是一个介于关系数据库和非关系数据库之间的产 ...