前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >WindowsMobile/Win Form-界面自适应

WindowsMobile/Win Form-界面自适应

作者头像
用户1172223
发布2018-01-29 15:02:41
8480
发布2018-01-29 15:02:41
举报
文章被收录于专栏:哲学驱动设计哲学驱动设计

起因

    使用SmartPhone上的WinForm做了一个WM的小程序,结果放到手机上实际一运行。发现动态生成的控件在里面显示得都非常小,难以看清。

原因

    我的问题是需要在InitializeComponent方法结束后,动态生成一些控件,如下:

代码语言:js
复制
/// <summary>
/// 这个方法会根据传入的实体模型,生成一些选择框,设置它们的大小、位置;并会改变其它控件的大小、位置。
/// </summary>
/// <param name="categories"></param>
private void GenerateCheckBoxes(IList<Category> categories)
{
    ……
}

    原因就是因为手机分辨率较大,而这些动态生成的控件并没有进行随着分辨率不同而进行自动缩放。而由界面设计器设计出来的控件,都能很好的显示。

求索

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

代码语言:js
复制
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方法如下:

代码语言:javascript
复制
protected override void ScaleControl(SizeF factor, BoundsSpecified specified)
{
    var categories = Config.Instance.Categories;
    this.GenerateCheckBoxes(categories);

    base.ScaleControl(factor, specified);
}

    因为调用过程是这样的:

    Control.LayoutResume() –> ContainerControl.PerformAutoScale() –> Control.Scale() –> Control.ScaleControl() & Control.ScaleChildControls()。

    所以,只需要重写这个方法,就可以在真正执行自动缩放所有控件前,先把动态控件生成。

    不过,这样做同样有局限性:因为这里是在InitializeComponent方法中进行PerformAutoScale,所以这里的这些动态生成的控件,其实是在应用程序的开始阶段就已经被明确了。相反,如果在运行一段时间后,需要想再动态生成其它控件,就不能使用这个方法了。那时,就需要直接调用刚生成的需要缩放的控件的Scale方法。而且不能直接使用PerformAutoScale方法了,因为要保证一个控件只被调用Scale方法一次! 在这里,只需要这样简单实现就行了。:)

    另外,一开始以为PerformAutoScale并不会把缩放过的控件,再缩放一次,结果就写成了这样的错误方案:

代码语言:js
复制
public MainForm()
{
    InitializeComponent();
    //暂停布局
    this.SuspendLayout();
    //在InitComponents调用的PerformAutoScale方法里面,最后会把这个数给置为运行时的数据。所以这里需要重新设置。
    this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
    //生成控件
    this.GenerateCategories();
    //自动缩放
    this.PerformAutoScale();//其实这里会把InitializeComponent中缩放的控件都再缩放一遍。
    //继续布局
    this.ResumeLayout(false);
}

结束语

    其实,这里的自动缩放过程,在WinForm开发中,也是一样的。

    而且这次实践中,我还发现:我在Win7的系统上随手点了一下这个程序,居然所有功能都能够正常的运行……汗,当时做的时候,可是专门为WindowsMobile开发的窗体啊。这个“跨平台”功能,确实很强大,着实让我吃惊不小。

    另外,由于VS2008自带的模拟器的屏幕分辨率和设计时的分辨率是一样大的,而我手机的分辨率比这个要大得多。所以每次调试这个缩放过程时,都要生成好了,然后拷贝到手机上看效果,真是吐血……

引用

Windows 窗体中的自动缩放
自动缩放的执行过程

Windows 窗体现在使用下面的逻辑自动对窗体及其内容进行缩放:

  1. 设计时,每一个 ContainerControl 分别在 AutoScaleModeAutoScaleDimensions 中记录缩放模式和它的当前分辨率。
  2. 运行时,实际分辨率存储在 CurrentAutoScaleDimensions 属性中。AutoScaleFactor 属性会动态计算运行时分辨率与设计时分辨率的比值。
  3. 当加载窗体时,如果 CurrentAutoScaleDimensionsAutoScaleDimensions 的值不同,则会调用 PerformAutoScale 方法对该控件及其子控件进行缩放。此方法会挂起布局并调用 Scale 方法执行实际缩放。然后,会更新 AutoScaleDimensions 值以避免累进缩放。
  4. 在下面的情况下还会自动调用 PerformAutoScale
    • 在缩放模式为 Font 时响应 OnFontChanged 事件。
    • 当继续执行容器控件的布局时检测到 AutoScaleDimensionsAutoScaleMode 属性发生更改。
    • 与上面的情况类似,检测到父 ContainerControl 正在被缩放。每个容器控件只负责使用自己的比例因子缩放自己的子控件,并不负责缩放其父容器中的控件。
  5. 子控件可以通过下面的若干方式修改其缩放行为:
    • 可以重写 ScaleChildren 属性以确定是否应缩放其子控件。
    • 可以重写 GetScaledBounds 方法以调整要将控件缩放至的边界,但不调整缩放逻辑。
    • 可以重写 ScaleControl 方法以更改当前控件的缩放逻辑。
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2010-01-03 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Windows 窗体中的自动缩放
  • 自动缩放的执行过程
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档