Winform下调整缩放与布局以及分辨率下界面混乱解决办法
文章目录
前言
当调整了分辨率或win10里的“更改文件、应用等项目的大小”选项时,winform界面会出现覆盖,混乱等情况,解决办法可参考方案一和方案二。
如果在程序运行时手动拖拽窗体改变大小触发了SizeChange事件,下次重新打开程序还是还来的样子,则使用方案四。
解决方案
方案一,设置this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi
第一种方式是设置this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi。 如果要相对于屏幕确定控件或窗体的大小,则按 Dpi 缩放十分有用。例如,对于显示图表或其他图形的控件,可能希望使用每英寸点数 (DPI) 缩放,以便该控件始终占据一定百分比的屏幕。
但这种方式能解决部分问题,算是第一种尝试方案
,对于无法解决的用下面方案。
方案二this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
第二种方式是设置this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font。然后在窗体里拖拽一个Panel控件,所有的后面添加的控件都放到Panel控件里。亲测,可行。
方案三:设置Form里字体大小(不推荐)
根据像素来设置界面每个控件大小,界面将整体缩放而不会凌乱,利用的就是DPI本身的特性。
缺点是字体大小都一样的,如果每个控件单独设置那太麻烦了。不推荐
public static void SetAutoScaleMode(Form form)
{
//设定按字体来缩放控件
form.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
loopControls(form);
}
private static void loopControls(Control control)
{
control.Font = new System.Drawing.Font("Microsoft Sans Serif", 16F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Pixel, ((byte)(134)));
if (control.Controls.Count > 0)
{
foreach (Control tmp in control.Controls)
{
loopControls(tmp);
}
}
}
方案四:根据缩放比例重新定义控件的位置和宽高(不推荐)
网上有种说法是计算新旧窗体的缩放比例,计算位置和宽高的,比如WinForm 根据屏幕分辨率自适应。这种解决办法只试用能触发SizeChange事件的情况,比如手动缩放窗体,或调整分辨率的时刻,并不适用重新打开程序的计算。
我优化了上述情况下计算
AutoSizeFormUtil.cs
public class AutoSizeFormUtil
{
//(1).声明结构,只记录窗体和其控件的初始位置和大小。
public struct controlRect
{
public int Left;
public int Top;
public int Width;
public int Height;
}
public Dictionary<string, controlRect> oldCtrlDir;
public void controllInitializeSize(Form mForm)
{
oldCtrlDir = new Dictionary<string, controlRect>();
controlRect cR;
cR.Left = mForm.Left; cR.Top = mForm.Top; cR.Width = mForm.Width; cR.Height = mForm.Height;
oldCtrlDir.Add(mForm.Name, cR);
LoopInitializeSize(mForm);
}
private void LoopInitializeSize(Control control)
{
if(control.Controls.Count > 0)
{
foreach (Control c in control.Controls)
{
controlRect cR;
cR.Left = c.Left; cR.Top = c.Top; cR.Width = c.Width; cR.Height = c.Height;
if (oldCtrlDir.ContainsKey(c.Name))
{
oldCtrlDir.Remove(c.Name);
}
oldCtrlDir.Add(c.Name, cR);
if(c.Controls.Count > 0)
{
LoopInitializeSize(c);
}
}
}
}
public void controlAutoSize(Form mForm)
{
float wScale = (float)mForm.Width / (float)oldCtrlDir[mForm.Name].Width;//新旧窗体之间的比例,与最早的旧窗体
float hScale = (float)mForm.Height / (float)oldCtrlDir[mForm.Name].Height;//.Height;
loopControls(mForm, wScale, hScale);
}
private void loopControls(Control c, float wScale, float hScale)
{
controlRect rect = oldCtrlDir[c.Name];
c.Left = (int)((rect.Left) * wScale);//新旧控件之间的线性比例。控件位置只相对于窗体,所以不能加 + wLeft1
c.Top = (int)((rect.Top) * hScale);//
c.Width = (int)(rect.Width * wScale);//只与最初的大小相关,所以不能与现在的宽度相乘 (int)(c.Width * w);
c.Height = (int)(rect.Height * hScale);//
if (c.Controls.Count > 0)
{
foreach (Control tmp in c.Controls)
{
loopControls(tmp, wScale, hScale);
}
}
}
在Load事件里调用AutoSizeFormUtil.controllInitializeSize(this),在SizeChange事件里调用AutoSizeFormUtil.controlAutoSize(this)
总结
目前没找到一劳永逸的方案。