摘要:[C#](純Winform)讓UI適應不同解析度
這是一項非常大的困擾,所以我把我找來的知識全部做個整理。
特別是針對Winform的部分,若是WPF建議使用ViewBox並且設定適合的模式。
大致的概念是這樣:
Step 1: 將你的UI先固定大小,但實際操作還是依個人以及美工的複雜度(圖片越複雜就要小心所謂的作用範圍問題,以免圖片重疊等等),像有的時候Label需要用AutoSize=true,有的則是false。
Step2:用程式碼取得現在的解析度(顯示器)
Step3:依照公式:你的UI大小除以現在的解析度,來做UI的調整。
調整時要記得不只是大小改變,位置也要改變!
若是在容器裡就用for抓每個元件,若容器裡還有容器,則用遞迴的方式做處理。
範例以容器為Panel為例:
string sHeight = SystemInformation.PrimaryMonitorSize.Height.ToString();
string sWidth = SystemInformation.PrimaryMonitorSize.Width.ToString();
double sw = Convert.ToDouble(sWidth);
double sh = Convert.ToDouble(sHeight);
double sizeX = sw / 1024;
double sizeY = sh / 768;
foreach (Control p in panel1.Controls)
{
p.Top = Convert.ToInt32(Convert.ToDouble(p.Top) * sizeX);
p.Left = Convert.ToInt32(Convert.ToDouble(p.Left) * sizeY);
if (p is Label || p is TextBox || p is ComboBox)
{
p.Font = new Font(p.Font.FontFamily, p.Font.SizeInPoints * Convert.ToSingle(sizeX) * Convert.ToSingle(sizeY));
if (!(p is Label))
p.Width = Convert.ToInt32(Convert.ToDouble(p.Width) * sizeX);
}
else
{
p.Width = Convert.ToInt32(Convert.ToDouble(p.Width) * sizeX);
p.Height = Convert.ToInt32(Convert.ToDouble(p.Height) * sizeY);
}
}
panel1即是容器,而p則是裡面的元件,假設原本設計的解析度是1024x768。
但如果容器裡還有容器,比方另一個panel,
原本的寫法是這樣:
string sHeight = SystemInformation.PrimaryMonitorSize.Height.ToString();
string sWidth = SystemInformation.PrimaryMonitorSize.Width.ToString();
double sw = Convert.ToDouble(sWidth);
double sh = Convert.ToDouble(sHeight);
double sizeX = sw / 1024;
double sizeY = sh / 768;
foreach (Control p in panel1.Controls)
{
p.Top = Convert.ToInt32(Convert.ToDouble(p.Top) * sizeX);
p.Left = Convert.ToInt32(Convert.ToDouble(p.Left) * sizeY);
if (p is Label || p is TextBox || p is ComboBox)
{
p.Font = new Font(p.Font.FontFamily, p.Font.SizeInPoints * Convert.ToSingle(sizeX) * Convert.ToSingle(sizeY));
if (!(p is Label))
p.Width = Convert.ToInt32(Convert.ToDouble(p.Width) * sizeX);
}
else
{
if (p is Panel)
{
foreach (Control c in p.Controls)
{
c.Top = Convert.ToInt32(Convert.ToDouble(c.Top) * sizeX);
c.Left = Convert.ToInt32(Convert.ToDouble(c.Left) * sizeY);
if (c is Label || c is TextBox || c is ComboBox)
{
c.Font = new Font(c.Font.FontFamily, c.Font.SizeInPoints * Convert.ToSingle(sizeX) * Convert.ToSingle(sizeY));
if (!(c is Label))
c.Width = Convert.ToInt32(Convert.ToDouble(c.Width) * sizeX);
}
else
{
c.Width = Convert.ToInt32(Convert.ToDouble(c.Width) * sizeX);
c.Height = Convert.ToInt32(Convert.ToDouble(c.Height) * sizeY);
}
}
}
p.Width = Convert.ToInt32(Convert.ToDouble(p.Width) * sizeX);
p.Height = Convert.ToInt32(Convert.ToDouble(p.Height) * sizeY);
}
}
所以概念就是若碰到容器則要以容器本身再做一次同樣的事,所以就是:
double sw = Convert.ToDouble(SystemInformation.PrimaryMonitorSize.Width);
double sh = Convert.ToDouble(SystemInformation.PrimaryMonitorSize.Height);
double sizeX = sw / 1024;
double sizeY = sh / 768;
private void chResolution(Panel p,sizeX,sizeY)
{
if (p.Name == "panel1" || p.Name == "panel2" || p.Name == "panel3")
{
p.Top = Convert.ToInt32(Convert.ToDouble(p.Top) * sizeX);
p.Left = Convert.ToInt32(Convert.ToDouble(p.Left) * sizeY);
p.Width = Convert.ToInt32(Convert.ToDouble(p.Width) * sizeX);
p.Height = Convert.ToInt32(Convert.ToDouble(p.Height) * sizeY);
}
foreach (Control c in p.Controls)
{
c.Top = Convert.ToInt32(Convert.ToDouble(c.Top) * sizeX);
c.Left = Convert.ToInt32(Convert.ToDouble(c.Left) * sizeY);
if (c is Label || c is TextBox || c is ComboBox)
{
c.Font = new Font(c.Font.FontFamily, c.Font.SizeInPoints * Convert.ToSingle(sizeX) * Convert.ToSingle(sizeY));
if (!(c is Label))
c.Width = Convert.ToInt32(Convert.ToDouble(c.Width) * sizeX);
}
else
{
if (c is Panel) chResolution(c as Panel);
c.Width = Convert.ToInt32(Convert.ToDouble(c.Width) * sizeX);
c.Height = Convert.ToInt32(Convert.ToDouble(c.Height) * sizeY);
}
}
}
中間遇到control是Panel時呼叫自己。
中間的is Label那些是為了調整Label等元件的字型,
因為這些元件,如果你改變大小(Width, Height),只是改變作用範圍,字的大小不變。
目前這樣的作法差不多能解決我的困擾了,
若是再遇到比較困難的處理會繼續研究,也一併更新文章。
Edit:
實際操作後,修改了遞迴的版本程式碼。
panel1~panel3是最大的panel(就是一開始在winform裡的),若是從winform的角度抓取panel,則不用if (p.Name == "panel1" || p.Name == "panel2" || p.Name == "panel3")的部分。因為先在winform的角度將所有的control修改大小了(即是使用基本公式)
若是取從form取得Control則是用:
http://stackoverflow.com/questions/653284/get-available-controls-from-a-form-using-c-sharp