摘要:C# 無法在視窗最大化時調整視窗大小 解決方法
這方法很簡單,
但是遇到時真的讓人很不知所措(因為沒有bug)。
原理很簡單,
因為你的視窗模式在最大化(Maximum),因此,你要改變視窗的大小就是先把它變回一般模式(FormWindowState.Normal),才能再調整大小
實例:
這個視窗按下縮小按鈕後會將視窗縮小,不是ForWindowState.Minimum喔!是單純調整成一個小視窗。
這個視窗已經用SizeChange調整各個元件在不同解析度或不同視窗大小時的比例設定。
使用isSmall當作目前是否為縮小化(迷你版視窗),並且用BFWidth與BFHeight記錄縮小前的視窗大小。
當使用者點雙點擊(DoubleClick)視窗的內容時,就會還原成原來大小。
因為視窗變成迷你版時,是不准使用者調整視窗大小的,因此MaximizeBox要等於false,
否則使用者點擊視窗兩下會變成最大化。
這個視窗其實是一個視訊畫面,一般狀態和最大狀態時,會顯示所有的元件(包括調整音量、撥打電話等等),但是迷你化後只會顯示視訊畫面(而且是迷你版的),雙點擊視訊畫面則恢復成原本的大小(使用者可能已將視窗調整成任意大小)。
視窗畫面叫做video,縮小的按鈕叫做btnSmall,用isSmall表示是否點擊縮小按鈕(否則隨時雙擊視窗畫面都會放大),isMax判斷是否有放到最大過,放到最大時,迷你視窗還原也要變回視窗最大化。接著若使用者不是最大化時,則用BFWidth與BFHeight還原使用者縮小前的視窗大小。
因此btnSmall的部分:
private void btnSmall_Click(object sender, EventArgs e)
{
if (!isSmall)
{
isSmall = true; //表示按下縮小按鈕
BFWidth = this.Width; //記錄縮小前的視窗寬度
BFHeight = this.Height; //記錄縮小前的視窗高度
plVideo.Width = 196; //plVideo是原本裝所有元件的panel
plVideo.Height = 155; //調整成符合迷你版視窗的大小
plVideo.Location = new Point(0, 0);
video.Dock = DockStyle.Fill; //video放在plVideo中,用Fill蓋住其他元件
WindowState = FormWindowState.Normal;//以防視窗是最大化時(本篇最重要的部分)
this.Width = 202; //迷你視窗寬度
this.Height = 180; //迷你視窗高度
this.FormBorderStyle = FormBorderStyle.FixedToolWindow; //不讓使用者調整視窗
this.MaximizeBox = false; //雙擊視窗周圍不會讓視窗最大化
}
}
video雙點擊後還原原本大小的部分:
private void video_DoubleClick(object sender, EventArgs e)
{
if (isSmall)
{
isSmall = false; //取消原本點擊縮小按鈕的狀態
if (isMax)
{
WindowState = FormWindowState.Maximized; //原本就是視窗最大化時
}
else
{
this.Width = BFWidth; //還原原本使用者調整的大小
this.Height = BFHeight;
}
video.Dock = DockStyle.None; //還原video的Dock
this.FormBorderStyle = FormBorderStyle.Sizable; //還原可調整大小的視窗模式
this.MaximizeBox = true; //雙擊視窗會變視窗最大化
//ScalePart(); //另外寫的元件調整部分
}
}
在視窗大小改變的事件則是:
private void MainWindow_SizeChanged(object sender, EventArgs e)
{
if(!isSmall) //非迷你版時隨視窗調整元件
ScalePart();
if (WindowState == FormWindowState.Maximized)
{
isMax = true; //記錄是否有最大化
}
else //其實是Normal部分
{ //最小化時也無法按縮小按鈕吧
if (!isSmall) isMax = false; //取消最大化的記錄
}
}
調整視窗大小的部分也不難,
大抵先做一些小function比較好處理:
double formwidth = 1222.0; //原本設計時視窗寬度
double formheight = 875.0; //原本設計時視窗高度
//因為要做double除法,因此要加小數點,否則結果都是1
//一般狀況下的調整大小、位置的function,若直接指定大小,則scaled=false
private void ChangeScale(Control obj, int width, int height, int x, int y, bool scaled)
{
if (scaled)
{
obj.Width = ChangeSizeX(width); //在下面的function
obj.Height = ChangeSizeY(height); //在下面的function
}
else
{
obj.Width = width; //直接給予指定的寬
obj.Height = height; //直接給予指定的高
}
obj.Location = new Point(x, y); //將位置移到指定的x,y
}
//將元件位置調整到target1(左)與target2(右)之間(在兩者的縱線中間)
private int BetweenX(Control obj, Control target1, Control target2)
{
return target1.Location.X + target1.Width + (target2.Location.X - target1.Location.X - target1.Width) / 2 - obj.Width / 2;
}
//將元件位置調整到target1(上)與target2(下)之間(在兩者的水平線之間)
private int BetweenY(Control obj, Control target1, Control target2)
{
return target1.Location.Y + target1.Height + (target2.Location.Y - target1.Location.Y - target1.Height) / 2 - obj.Height / 2;
}
//調整元件的位置(若無法使用ChangeScale時,要分開調整大小與位置)
private void ChangeLocat(Control obj, int x, int y)
{
obj.Location = new Point(x, y);
}
//調整元件的大小(若無法使用ChangeScale時,要分開調整大小與位置)
private void ChangeSize(Control obj, int width, int height, bool scaled)
{
if (scaled)
{
obj.Width = ChangeSizeX(width); //在下面的function
obj.Height = ChangeSizeY(height); //在下面的function
}
else
{
obj.Width = width;
obj.Height = height;
}
}
//調整元件的寬度,以目前視窗大小除以原本設計視窗大小(formwidth)為比例
private int ChangeSizeX(int orgin)
{
decimal scaleX = Convert.ToDecimal(this.Width / formwidth);
return Convert.ToInt16(scaleX * orgin);
}
//調整元件的高度,以目前視窗大小除以原本設計視窗大小(formheight)為比例
private int ChangeSizeY(int orgin)
{
decimal scaleY = Convert.ToDecimal(this.Height / formheight);
return Convert.ToInt16(scaleY * orgin);
}
//調整字型大小(記得改變字型,此例使用Meiryo)
private void FontSize(Control obj, int size)
{
decimal scaleX = this.Width > this.Height ? Convert.ToDecimal(this.Height / formheight) : Convert.ToDecimal(this.Width / formwidth);
obj.Font = new System.Drawing.Font("Meiryo", (float)(size * scaleX), System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
}
//置左對齊(當元件在父元件時,像是panel)
private void AlignLeft(Control child, Control parent)
{
child.Location = new Point(0, parent.Height / 2 - child.Height / 2);
}
//置中對齊(當元件在父元件時,像是panel)
private void AlignCenter(Control child, Control parent)
{
child.Location = new Point(parent.Width / 2 - child.Width / 2, parent.Height / 2 - child.Height / 2);
}
接著ChangeScale部分的舉例(部分):
private void ScalePart()
{
if (!isSmall)
{
//使用直接設定大小(scaled=false)
//pl6包含pl1,pl3,pl2,讓pl2填滿最後的位置
ChangeScale(panel2, panel6.Width - panel1.Width - panel3.Width, ChangeSizeY(59), panel3.Location.X + panel3.Width - 1, 1, false);
//pl2裡面有label->lbDate顯示日期,在pl2靠左對齊
AlignLeft(lbDate, panel2);
//plBG是lbName的背景圖,這個panel的BackgroundImage是Stretch
ChangeScale(plBG, 734, 61, ChangeSizeX(236), ChangeSizeY(187), true);
//若lbName原本是16號字,則依照視窗比例調整字型(例如視窗最大時為20號字)
FontSize(lbName, 16);
//將lbName在plBG置中
AlignCenter(lbName, plBG);
//上面是pl5,下面是pl6,plVideo放在兩者中間置中(Y的部分)
//而plVideo的X部分則是用pl5做對齊置中
//(plVideo的長度中央與pl5的長度中央一樣位置)
ChangeLocat(plVideo, panel5.Location.X + panel5.Width / 2 - plVideo.Width / 2, BetweenY(plVideo, panel5, panel6));
//調整音量部分,speaker是trackBar(音量拉霸)
//speaker在pB1(最低音量圖片)與pB2(最大音量圖片)中間(X部分)
//Y的部分則是以pB1對齊置中
//(speaker的寬度中央與pB1的寬度中央一樣位置)
ChangeLocat(speaker, BetweenX(speaker, pictureBox1, pictureBox2), pictureBox1.Location.Y + pictureBox1.Height / 2 - speaker.Height / 2);
}
}
圖片參考:
在視窗最大化時:
假如沒有在調整大小前改成Normal,按下縮小按鈕後:
元件的大小可以調整,但是視窗還是處於Maximum模式。
加了Normal後,無論何時都可以按下縮小變成迷你版視窗:
黑色的部分就是video(放在plVideo中),雙點擊黑色部分則會還原成原本大小。