眾所周知,WinForm采用基于像素的布局模型。
因此,原生WinForm對(duì)于窗體自適應(yīng)支持不是很好。
但是我們也可以通過(guò)代碼來(lái)實(shí)現(xiàn)。
今天跟大家分享一下如何實(shí)現(xiàn)WinForm窗體自適應(yīng)。
當(dāng)我們想要實(shí)現(xiàn)窗體自適應(yīng)的時(shí)候,優(yōu)先要通過(guò)界面布局設(shè)置好窗體和控件的一些屬性:1、Anchor:用于固定控件的邊緣到窗體的邊緣,當(dāng)窗體大小改變時(shí),控件的位置也會(huì)相應(yīng)改變。2、Dock:用于將控件停靠到窗體的邊緣,控件的大小會(huì)隨著窗體邊緣的改變而改變。
3、布局控件:使用 TableLayoutPanel
或 FlowLayoutPanel
等布局控件可以更好地管理控件的布局,它們可以自動(dòng)調(diào)整大小和位置。
4、Padding:Padding屬性定義控件內(nèi)部的一段空間,用于將控件的內(nèi)容保持在距控件邊框一定的距離。5、Margin:Margin屬性定義控件周?chē)目臻g,該空間使其他控件與控件的邊框保持指定距離。
除了以上方法外,在實(shí)際應(yīng)用中,我們更多會(huì)使用通過(guò)代碼來(lái)手動(dòng)調(diào)整窗體和控件的大小和位置,這種方法第一次寫(xiě)的時(shí)候會(huì)麻煩一些,但是封裝好之后,后續(xù)應(yīng)用也比較簡(jiǎn)單。
一、我們創(chuàng)建一個(gè)類(lèi)FormAutoSize,然后創(chuàng)建三個(gè)字段,分別是窗體寬度、高度和窗體對(duì)象。
public class FormAutoSize
{
//窗體對(duì)象
private Form form;
//定義當(dāng)前窗體的寬度
private float width;
//定義當(dāng)前窗體的高度
private float height;
}
二、在FormAutoSize類(lèi)的構(gòu)造方法中,初始化寬度、高度和窗體對(duì)象,同時(shí)將各個(gè)控件的寬度、高度、左邊距、上邊距以及字體大小,按照指定的格式(這里使用分號(hào)拼接)存儲(chǔ)到AccessibleDescription屬性里,因?yàn)锳ccessibleDescription屬性很少使用,所以存儲(chǔ)到這個(gè)屬性里。
private void SetDescription(Control cons)
{
foreach (Control ctl in cons.Controls)
{
ctl.AccessibleDescription = ctl.Width + ";" + ctl.Height + ";" + ctl.Left +
";" + ctl.Top + ";" + ctl.Font.Size;
if (ctl.Controls.Count > 0)
{
SetDescription(ctl);
}
}
}
public FormAutoSize(Form form)
{
this.form = form;
width = this.form.Width;
height = this.form.Height;
SetDescription(this.form);
}
三、接下來(lái)就是如何重置窗體控件布局,這里將當(dāng)前的寬度高度與初始寬度高度進(jìn)行相除,會(huì)得到比例系數(shù)scaleX/scaleY,然后將這個(gè)系數(shù)疊加進(jìn)去,得到新的寬度高度等屬性值,然后重新設(shè)置控件屬性即可。
private void SetControls(float scaleX, float scaleY, Control cons)
{
//遍歷窗體中的控件,重新設(shè)置控件的值
foreach (Control con in cons.Controls)
{
//獲取控件的AccessibleDescription屬性值,并分割后存儲(chǔ)字符串?dāng)?shù)組
if (con.AccessibleDescription != null)
{
var tag = con.AccessibleDescription.ToString().Split(';');
//根據(jù)窗體縮放的比例確定控件的值
con.Width = Convert.ToInt32(Convert.ToSingle(tag[0]) * scaleX); //寬度
con.Height = Convert.ToInt32(Convert.ToSingle(tag[1]) * scaleY); //高度
con.Left = Convert.ToInt32(Convert.ToSingle(tag[2]) * scaleX); //左邊距
con.Top = Convert.ToInt32(Convert.ToSingle(tag[3]) * scaleY); //頂邊距
var currentSize = Convert.ToSingle(tag[4]) * scaleY; //字體大小
if (currentSize > 0)
{
con.Font = new Font(con.Font.Name, currentSize, con.Font.Style, con.Font.Unit);
}
con.Focus();
if (con.Controls.Count > 0)
{
SetControls(scaleX, scaleY, con);
}
}
}
}
/// <summary>
/// 重置窗體布局
/// </summary>
public void ResumeLayout()
{
var scaleX = form.Width / width;
var scaleY = form.Height / height;
SetControls(scaleX, scaleY, form);
}
四、最后一步就是如何進(jìn)行調(diào)用:首先在需要進(jìn)行縮放的窗體中定義一個(gè)FormAutoSize對(duì)象,然后在構(gòu)造方法中實(shí)例化該對(duì)象,將當(dāng)前窗體this作為參數(shù)傳遞進(jìn)去,最后在窗體的SizeChanged事件中調(diào)用該對(duì)象的ResumeLayout方法。
private FormAutoSize formAutoSize;
public FrmMain()
{
InitializeComponent();
formAutoSize = new FormAutoSize(this);
this.SizeChanged += (sender, e) =>
{
formAutoSize.ResumeLayout();
};
}
五、測(cè)試效果:
縮放前尺寸:1280*720
縮放后尺寸:1420*827
閱讀原文:原文鏈接
該文章在 2025/3/21 10:32:43 編輯過(guò)