[C#](純Winform) 無法在視窗最大化時調整視窗大小 解決方法

  • 3336
  • 0

摘要: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中),雙點擊黑色部分則會還原成原本大小。