C#語言 第四部分 圖形界面編程(五) 佈局容器類(3)

原文:http://blog.csdn.net/mousebaby808/article/details/5532190

5 表格佈局

無論使用錨定佈局還是流式佈局,都無法達到複雜佈局的效果,很多時候我們不得不使用絕對佈局,忍受絕對佈局帶來的麻煩(要麼容器尺寸一變化,界面就變得一團糟;要麼在容器的Resize事件中寫複雜的佈局代碼)。其實.net Framework中還具備一種很高級的佈局方式——表格佈局。

表格佈局顧名思義,就是將容器分爲n行m列的二維表,這樣一個二維元組就可以表示表格的一個單元格,例如(0,0)就表示表格的第一行第一列。通過這個表格,我們可以將控件妥善的安放在容器合適的位置。

通過控件的Margin屬性,我們還可以控制控件距離表格單元格邊框的空白;通過控件的Dock屬性,我們可以進一步控制控件錨定在單元格的哪個方位。

在我們熟悉的網頁中,DIV和Table(層和表)就可以佈局出來豐富多彩的頁面,那麼.net Framework的表格佈局,就具備層和表的特點,同樣也可以佈局出來五花八門的界面。

TableLayoutPanel是.net Framework中的表格佈局容器,這個容器可以分爲n行m列,如下圖:

表格佈局示意圖
圖1 表格佈局示意圖

從上圖可以形象的看到,TableLayoutPanel被分成了若干行和列,即容器被分爲了若干格子,每個格子內規定只能放置一個控件,格子也可以跨行或跨列(也可以同時既跨行又跨列),從而把一個控件方式放置在相鄰的多行、多列中。

如果要給格子裏放置多個控件呢?首先就得給格子裏放置一個容器類控件,例如放一個Panel或FlowlayoutPanel,然後再把多個控件放置在這些容器內,就可以解決問題了。

下面我們看一下表格佈局的步驟:

  1. 初始化TableLayoutPanel對象,然後要指定容器究竟分爲多少行和列,設置容器對象的RowCount(行)和ColumnCount(列)屬性;
  2. 爲所有的行和列設置樣式,樣式具體指:行的高度(自動調整、絕對、百分比),列的寬度(自動調整、絕對、百分比);
  3. 將控件增加到TableLayoutPanel容器對象內,調用容器的Controls屬性的Add方法,這個和前面講的容器相同;
  4. 定位控件:調用TableLayoutPanel容器對象的SetRow方法(指定行)和SetColumn方法(指定列);除此之外,TableLayoutPanel對象的Controls屬性具有一個重載的Add方法,可以在加入控件的同時指定其行列數;
  5. 設置跨行、跨列(可選):調用TableLayoutPanel容器對象的SetRowSpan方法(設置控件跨行)和SetColumnSpan方法(設置控件跨列)

好了,通過一個例子,我們仔細體會這種容器佈局的特點:

程序執行效果圖
圖2 程序執行效果圖

可以看到,本次程序執行結果是一個簡易的計算器,是使用表格佈局的絕好素材。

詳細看一下界面佈局方式:

界面佈局分佈圖
圖3 界面佈局分佈圖

可以看到,整個界面分爲兩大部分,上面的顯示區和下面的按鈕區,這是由一個2行1列的TableLayoutPanel容器構成的;在顯示區裏(綠框),使用一個Panel容器承載了一個TextBox,用於顯示計算結果;在按鈕區域(黃框),使用一個6行5列的TableLayoutPanel容器(紅框),存放所有按鈕。

對於最外面的TableLayoutPanel容器,其顯示區(綠框)具有一個固定尺寸的行樣式;按鈕區(黃框)是自動尺寸的行樣式,其列樣式爲自動尺寸,這樣,當界面尺寸改變後,顯示區的尺寸不會發生變化,按鈕區則隨着容器的尺寸變化而變化;

對於按鈕區內的TableLayoutPanel容器(紅框),則按容器尺寸百分比平均分爲6行5列,這樣,無論容器尺寸如何變化,其行列百分比是不會變化的,單元格尺寸會隨着容器尺寸自動調整。

看代碼:

Program.cs

  1. using System;  
  2. using System.Drawing;  
  3. using System.Runtime.InteropServices;  
  4. using System.Windows.Forms;  
  5.    
  6. namespace Edu.Study.Graphics.TableLayout {  
  7.    
  8.     /// <summary>   
  9.     /// 計算器主窗體   
  10.     /// </summary>   
  11.     class MyForm : Form {  
  12.    
  13.         /// <summary>   
  14.         /// 計算器運算操作標誌枚舉   
  15.         /// </summary>   
  16.         private enum Operators {  
  17.             // 無操作   
  18.             None,  
  19.             // 加法操作   
  20.             Add,  
  21.             // 減法操作   
  22.             Sub,  
  23.             // 除法操作   
  24.             Div,  
  25.             // 乘法操作   
  26.             Mult  
  27.         }  
  28.    
  29.         // 主容器面板, 充滿整個窗體   
  30.         private TableLayoutPanel mainPane;  
  31.    
  32.         // 顯示結果的容器面板   
  33.         private Panel displayPane;  
  34.    
  35.         // 顯示操作盤的容器面板   
  36.         private TableLayoutPanel optPane;  
  37.    
  38.         // 顯示結果的文本框   
  39.         private TextBox resultTextbox;  
  40.    
  41.         // 保存第一個數字   
  42.         private decimal firstNumber = 0;  
  43.    
  44.         // 保存運算操作   
  45.         private Operators operators = Operators.None;  
  46.    
  47.         // 是否需要清屏   
  48.         private bool needClear = true;  
  49.    
  50.         // M功能鍵保存的值   
  51.         private decimal mValue = 0;  
  52.    
  53.         // MR功能鍵按鈕   
  54.         private Button MRButton;  
  55.    
  56.         /// <summary>   
  57.         /// 構造器, 初始化所有控件   
  58.         /// </summary>   
  59.         public MyForm() {  
  60.    
  61.             // 設置窗體標題   
  62.             this.Text = "簡易計算器";  
  63.    
  64.             /************ 初始化mainPane容器 ***********/  
  65.             this.mainPane = new TableLayoutPanel();  
  66.             // 容器分爲2行1列   
  67.             this.mainPane.RowCount = 2;  
  68.             this.mainPane.ColumnCount = 1;  
  69.             // 爲一列設置列樣式, 根據父容器(Form窗體)自動調整尺寸  
  70.             this.mainPane.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));  
  71.             // 爲第一行設置行樣式, 固定高度, 50單位  
  72.             this.mainPane.RowStyles.Add(new RowStyle(SizeType.Absolute, 50));  
  73.             // 爲第二行設置行樣式, 自動調整尺寸  
  74.             this.mainPane.RowStyles.Add(new RowStyle(SizeType.AutoSize));  
  75.             // mainPane在父容器上的錨定方式爲中央充滿  
  76.             this.mainPane.Dock = DockStyle.Fill;  
  77.    
  78.             /************ 初始化displayPane容器 ***********/  
  79.             this.displayPane = new Panel();  
  80.             // 設置displayPane容器在父容器上的錨定方式爲中央充滿  
  81.             this.displayPane.Dock = DockStyle.Fill;  
  82.             // 設置displayPane容器的Padding屬性爲5  
  83.             this.displayPane.Padding = new Padding(5);  
  84.             // 將displayPane容器加入到mainPane容器內  
  85.             this.mainPane.Controls.Add(this.displayPane);  
  86.             // 設置displayPane容器位於mainPane容器的第1行  
  87.             this.mainPane.SetRow(this.displayPane, 0);  
  88.    
  89.             /************ 初始化resultTextbox容器 ***********/  
  90.             this.resultTextbox = new TextBox();  
  91.             // 設置resultTextbox控件顯示文本  
  92.             this.resultTextbox.Text = "0";  
  93.             // 設置resultTextbox文本對齊方式爲居右對齊  
  94.             this.resultTextbox.TextAlign = HorizontalAlignment.Right;  
  95.             // 設置resultTextbox只讀  
  96.             this.resultTextbox.ReadOnly = true;  
  97.             // 設置resultTextbox控件背景色爲淡藍色  
  98.             this.resultTextbox.BackColor = Color.LightBlue;  
  99.             // 設置resultTextbox控件字體  
  100.             this.resultTextbox.Font = new Font(new FontFamily("Times New Roman"), this.displayPane.Height / 2);  
  101.             // 設置resultTextbox控件在父容器上居中錨定  
  102.             this.resultTextbox.Dock = DockStyle.Fill;  
  103.             this.displayPane.Controls.Add(this.resultTextbox);  
  104.    
  105.             /************ 初始化resultTextbox容器 ***********/  
  106.             this.optPane = new TableLayoutPanel();  
  107.             // 設置optPane具有6行   
  108.             this.optPane.RowCount = 6;  
  109.             // 設置optPane具有5列   
  110.             this.optPane.ColumnCount = 5;  
  111.             // 設置optPane在父容器內居中錨定  
  112.             this.optPane.Dock = DockStyle.Fill;  
  113.             // 爲optPane中的每一行設置樣式, 百分比高度, 每行高度爲總體的16.67%  
  114.             for (int i = 0; i < optPane.RowCount; i++) {  
  115.                 this.optPane.RowStyles.Add(  
  116.                     new RowStyle(SizeType.Percent, 100.0F / (float)optPane.RowCount));  
  117.             }  
  118.             // 爲optPane中的每一列設置樣式, 百分比寬度, 每列寬度爲總體的20%  
  119.             for (int i = 0; i < optPane.ColumnCount; i++) {  
  120.                 this.optPane.ColumnStyles.Add(  
  121.                     new ColumnStyle(SizeType.Percent, 100.0F / (float)optPane.ColumnCount));  
  122.             }  
  123.             // 設置optPane容器Padding屬性爲5  
  124.             this.optPane.Padding = new Padding(5);  
  125.             // 將optPane容器增加在mainPane容器中  
  126.             this.mainPane.Controls.Add(this.optPane);  
  127.             // 設置optPane容器位於mainPane容器的第2行  
  128.             this.optPane.SetRow(this.optPane, 1);  
  129.    
  130.             // 保存計算器按鈕的字符串數組   
  131.             // 數組中null值項表示這裏沒有對應的按鈕  
  132.             string[] BUTTON_TEXT = {  
  133.                 "MC""MR""MS""M+""M-",  
  134.                 "BACK""CE""C""+-""SQRT",  
  135.                 "7""8""9""/""%",  
  136.                 "4""5""6""*""1/x",  
  137.                 "1""2""3""-""=",  
  138.                 "0"null".""+"null  
  139.             };  
  140.    
  141.             /************ 初始化Button控件 ***********/  
  142.             for (int i = 0; i < BUTTON_TEXT.Length; i++) {  
  143.                 //  如果BUTTON_TEXT數組第i項不爲null,   
  144.                 // 表示要爲該項生成一個對應按鈕   
  145.                 if (BUTTON_TEXT[i] != null) {  
  146.                     // 計算按鈕所處的行和列   
  147.                     int row = i / this.optPane.ColumnCount;  
  148.                     int col = i - row * 5;  
  149.    
  150.                     // 初始化按鈕   
  151.                     Button btn = new Button();  
  152.                     // 設置按鈕上呈現的文字(Text屬性)和按鈕的名字  
  153.                     btn.Text = btn.Name = BUTTON_TEXT[i];  
  154.                     // 設置按鈕錨定在父容器中央並充滿   
  155.                     btn.Dock = DockStyle.Fill;  
  156.                     // 設置按鈕四周空白爲2個單位   
  157.                     btn.Margin = new Padding(2);  
  158.                     // 設置按鈕點擊事件處理委託   
  159.                     btn.Click += new EventHandler(ButtonClicked);  
  160.    
  161.                     // 將按鈕加入到optPane容器內  
  162.                     this.optPane.Controls.Add(btn, col, row);  
  163.                       
  164.                     // 將MR按鈕的引用存儲在字段中, 程序中要使用  
  165.                     if (string.CompareOrdinal(btn.Text, "MR") == 0) {  
  166.                         this.MRButton = btn;  
  167.                     }  
  168.                 }  
  169.             }  
  170.    
  171.             // 找到名稱爲"="的按鈕   
  172.             Control[] ctrl = this.optPane.Controls.Find("="false);  
  173.             // 設置控件向右跨兩行   
  174.             this.optPane.SetRowSpan(ctrl[0], 2);  
  175.    
  176.             // 找到名爲"0"的按鈕   
  177.             ctrl = this.optPane.Controls.Find("0"false);  
  178.             // 設置控件向下跨兩列   
  179.             this.optPane.SetColumnSpan(ctrl[0], 2);  
  180.    
  181.             // 將mainPane容器添加到窗體上  
  182.             this.Controls.Add(this.mainPane);  
  183.         }  
  184.    
  185.         /// <summary>   
  186.         /// 處理按鈕點擊事件的方法   
  187.         /// </summary>   
  188.         private void ButtonClicked(object sender, EventArgs e) {  
  189.             // 得到本次點擊的按鈕實例引用(通過sender參數)  
  190.             Button btn = (Button)sender;  
  191.    
  192.             // 根據按鈕上的文本, 進行分支處理   
  193.             switch (btn.Text) {  
  194.             case "1":  
  195.             case "2":  
  196.             case "3":  
  197.             case "4":  
  198.             case "5":  
  199.             case "6":  
  200.             case "7":  
  201.             case "8":  
  202.             case "9":  
  203.             case "0":  
  204.                 /*** 對於數字按鈕的處理 ***/  
  205.    
  206.                 if (this.needClear) {  
  207.                     //  如果needClear字段爲true, 則將按鈕  
  208.                     // 的Text屬性賦予文本框Text屬性, 相當於  
  209.                     // 清除掉文本框原有內容  
  210.                     this.resultTextbox.Text = btn.Text;  
  211.                     // 確保以後輸入不再清屏  
  212.                     this.needClear = false;  
  213.                 } else {  
  214.                     //  對於needClear字段false的情況, 將  
  215.                     // 按鈕對應的數字字符加到文本框字符串  
  216.                     // 末尾即可   
  217.                     this.resultTextbox.Text += btn.Text;  
  218.                 }  
  219.                 break;  
  220.             case ".":  
  221.                 /*** 對於小數點按鈕的處理 ***/  
  222.                   
  223.                 if (this.resultTextbox.Text.IndexOf('.') >= 0) {  
  224.                     // 如果文本框內已經有一個小數點, 則發出警報聲  
  225.                     MessageBeep(0xFFFFFFFF);  
  226.                 } else {  
  227.                     // 在文本框字符串末尾增加小數點字符  
  228.                     this.resultTextbox.Text += btn.Text;  
  229.                 }  
  230.                 break;  
  231.             case "BACK":  
  232.                 /*** 對於刪除按鈕的處理 ***/  
  233.                   
  234.                 if (this.resultTextbox.Text.Length > 1) {  
  235.                     // 如果文本框字符串長度大於1個字符, 則刪除最後一個字符  
  236.                     this.resultTextbox.Text =   
  237.                         this.resultTextbox.Text.Remove(this.resultTextbox.Text.Length - 1);  
  238.                 } else {  
  239.                     // 如果文本框字符串只剩1個字符, 則將文本框設置爲字符"0"  
  240.                     this.resultTextbox.Text = "0";  
  241.                     // 文本框需要清屏一次  
  242.                     this.needClear = true;  
  243.                 }  
  244.                 break;  
  245.             case "+":  
  246.                 /*** 對於加號按鈕的處理 ***/  
  247.    
  248.                 // 將文本框字符串轉爲數字類型保存在firstNumber字段中  
  249.                 this.firstNumber = decimal.Parse(this.resultTextbox.Text);  
  250.                 // 設置操作標誌爲Add   
  251.                 this.operators = Operators.Add;  
  252.                 // 文本框需要清屏一次   
  253.                 this.needClear = true;  
  254.                 break;  
  255.             case "-":  
  256.                 /*** 對於減號按鈕的處理, 操作同上 ***/  
  257.    
  258.                 this.firstNumber = decimal.Parse(this.resultTextbox.Text);  
  259.                 this.operators = Operators.Sub;  
  260.                 this.needClear = true;  
  261.                 break;  
  262.             case "*":  
  263.                 /*** 對於乘號按鈕的處理, 操作同上 ***/  
  264.    
  265.                 this.firstNumber = decimal.Parse(this.resultTextbox.Text);  
  266.                 this.operators = Operators.Mult;  
  267.                 this.needClear = true;  
  268.                 break;  
  269.             case "/":  
  270.                 /*** 對於除號按鈕的處理, 操作同上 ***/  
  271.    
  272.                 this.firstNumber = decimal.Parse(this.resultTextbox.Text);  
  273.                 this.operators = Operators.Div;  
  274.                 this.needClear = true;  
  275.                 break;  
  276.             case "=": {  
  277.                     /*** 對於等號按鈕的處理 ***/  
  278.    
  279.                     // 將文本框字符串轉爲數字類型保存在secondNumber變量中  
  280.                     decimal secondNumber = decimal.Parse(this.resultTextbox.Text);  
  281.    
  282.                     // 根據保存的運算操作類型進行分支, 進行加減乘除運算  
  283.                     // 計算結果保存在firstNumber字段中  
  284.                     switch (this.operators) {  
  285.                     case Operators.Add:  
  286.                         this.firstNumber += secondNumber;  
  287.                         break;  
  288.                     case Operators.Sub:  
  289.                         this.firstNumber -= secondNumber;  
  290.                         break;  
  291.                     case Operators.Div:  
  292.                         this.firstNumber /= secondNumber;  
  293.                         break;  
  294.                     case Operators.Mult:  
  295.                         this.firstNumber *= secondNumber;  
  296.                         break;  
  297.                     }  
  298.                     // 在文本框中顯示firstNumber字段的內容  
  299.                     this.resultTextbox.Text = this.firstNumber.ToString();  
  300.                     // 文本框需要清屏一次   
  301.                     this.needClear = true;  
  302.                 }  
  303.                 break;  
  304.             case "CE":  
  305.                 /*** 對於CE按鈕的處理 ***/  
  306.                   
  307.                 // CE按鈕清除以前所有的操作和屏幕顯示  
  308.                 this.firstNumber = 0;  
  309.                 this.needClear = true;  
  310.                 this.resultTextbox.Text = "0";  
  311.                 this.operators = Operators.None;  
  312.                 break;  
  313.             case "C":  
  314.                 /*** 對於C按鈕的處理 ***/  
  315.    
  316.                 // C按鈕只清除屏幕顯示, 運算類型和上一次輸入數字不清除  
  317.                 this.resultTextbox.Text = "0";  
  318.                 this.needClear = true;  
  319.                 break;  
  320.             case "+-":  
  321.                 /*** 對於正負號按鈕的處理 ***/  
  322.    
  323.                 // 根據文本框字符串第一個字符是否爲-號字符, 對文本框字符串進行處理  
  324.                 if (this.resultTextbox.Text[0] == '-') {  
  325.                     // 刪除第一個字符  
  326.                     this.resultTextbox.Text = this.resultTextbox.Text.Remove(0, 1);  
  327.                 } else {  
  328.                     // 在第一個字符處插入-號字符   
  329.                     this.resultTextbox.Text = this.resultTextbox.Text.Insert(0, "-");  
  330.                 }  
  331.                 break;  
  332.             case "SQRT":  
  333.                 /*** 對於開方號按鈕的處理 ***/  
  334.    
  335.                 // 得到文本框內字符串表示的數字, 保存在firstNumber字段中  
  336.                 this.firstNumber = decimal.Parse(this.resultTextbox.Text);  
  337.                 // 對firstNumber中保存的數字進行開方  
  338.                 this.firstNumber = (decimal)Math.Sqrt((double)this.firstNumber);  
  339.                 // 將結果存入文本框字符串中  
  340.                 this.resultTextbox.Text = this.firstNumber.ToString();  
  341.                 // 設置運算操作類型爲"無", 防止按等號後改變計算結果  
  342.                 this.operators = Operators.None;  
  343.                 // 文本框清屏一次   
  344.                 this.needClear = true;  
  345.                 break;  
  346.             case "1/x":  
  347.                 /*** 對於倒數按鈕的處理 ***/  
  348.    
  349.                 // 得到文本框內字符串表示的數字, 保存在firstNumber字段中  
  350.                 this.firstNumber = decimal.Parse(this.resultTextbox.Text);  
  351.                 // 防止除數爲0的判斷   
  352.                 if (this.firstNumber > 0) {  
  353.                     // 對firstNumber中保存的數字求倒數  
  354.                     this.firstNumber = 1 / this.firstNumber;  
  355.                     // 將結果存入文本框字符串中  
  356.                     this.resultTextbox.Text = this.firstNumber.ToString();  
  357.                 }  
  358.                 // 設置運算操作類型爲"無", 防止按等號後改變計算結果  
  359.                 this.operators = Operators.None;  
  360.                 // 文本框清屏一次   
  361.                 this.needClear = true;  
  362.                 break;  
  363.             case "M+":  
  364.                 /*** 對於M+按鈕的處理 ***/  
  365.    
  366.                 // 得到文本框內字符串表示的數字, 保存在firstNumber字段中  
  367.                 this.firstNumber = decimal.Parse(this.resultTextbox.Text);  
  368.                 // 將firstNumber字段值和mValue字段值相加,  
  369.                 // 結果保存在mValue字段中  
  370.                 this.mValue += this.firstNumber;  
  371.                 // 設置文本框清除一次   
  372.                 this.needClear = true;  
  373.                 // 如果mValue的值不爲0, 則MR按鈕顯示爲粉紅色, 表示有值已被存儲  
  374.                 // 如果mValue的值爲0, 表示沒有存儲有效值, 按鈕恢復原本顏色  
  375.                 this.MRButton.BackColor = this.mValue == 0 ? SystemColors.ButtonFace : Color.Pink;  
  376.                 break;  
  377.             case "M-":  
  378.                 /*** 對於M-按鈕的處理, 處理同上, 這一次是減法 ***/  
  379.    
  380.                 this.firstNumber = decimal.Parse(this.resultTextbox.Text);  
  381.                 this.mValue -= this.firstNumber;  
  382.                 this.needClear = true;  
  383.                 this.MRButton.BackColor = this.mValue == 0 ? SystemColors.ButtonFace : Color.Pink;  
  384.                 break;  
  385.             case "MS":  
  386.                 /*** 對於MS按鈕的處理, 處理類似M+, 將文本框內表示的數字存儲起來 ***/  
  387.    
  388.                 this.firstNumber = decimal.Parse(this.resultTextbox.Text);  
  389.                 this.mValue = this.firstNumber;  
  390.                 this.needClear = true;  
  391.                 this.MRButton.BackColor = this.mValue == 0 ? SystemColors.ButtonFace : Color.Pink;  
  392.                 break;  
  393.             case "MR":  
  394.                 /*** 對於MR按鈕的處理 ***/  
  395.                 // 將存儲的mValue的值恢復到文本框和firstNumber字段中, 以備運算使用  
  396.    
  397.                 this.firstNumber = this.mValue;  
  398.                 this.resultTextbox.Text = this.firstNumber.ToString();  
  399.                 this.needClear = true;  
  400.                 break;  
  401.             case "MC":  
  402.                 /*** 對於MC按鈕的處理 ***/  
  403.                 // 將存儲的mValue的值清除  
  404.    
  405.                 this.mValue = 0;  
  406.                 this.MRButton.BackColor = SystemColors.ButtonFace;  
  407.                 break;  
  408.             }  
  409.         }  
  410.    
  411.         /// <summary>   
  412.         /// 從Win32 SDK中引入播放報警聲音的系統函數   
  413.         /// </summary>   
  414.         [DllImport("user32.dll")]  
  415.         public static extern int MessageBeep(uint n);  
  416.     }  
  417.    
  418.     /// <summary>   
  419.     /// 包含主方法的類   
  420.     /// </summary>   
  421.     static class Program {  
  422.         /// <summary>   
  423.         /// 應用程序的主入口點。   
  424.         /// </summary>   
  425.         static void Main() {  
  426.             Application.EnableVisualStyles();  
  427.             Application.SetCompatibleTextRenderingDefault(false);  
  428.             Application.Run(new MyForm());  
  429.         }  
  430.     }  
  431. }  

本節代碼下載

注意事項:

  • 代碼中設置容器行列數(67-68行,108-110行);針對行列樣式的設置(70-74行,114-122行);控件加入單元格的各種方法(85-87行,162行,前者加入控件後設置控件的佈局位置,後者再加入的同時指定佈局位置);設置控件跨行跨列(174行、179行);
  • 本次代碼爲一系列控件指定了同一個事件處理委託方法,注意這種事件處理的方式(159行指定委託;190行,根據sender參數獲取發送事件控件對象的引用);
  • 本地代碼使用了控件的Name屬性(153行,設置Name屬性),其作用是,可以根據Name屬性在容器中查找控件的對象引用(172行,177行);
  • 本次代碼使用了一些技巧一次性實例化和佈局多個按鈕(132-179行),這種批量處理的技巧在製作一些控件重複性很高的界面中,非常有用;
  • 本代碼主要是介紹表格佈局管理,附帶了一個簡易計算器的算法流程(188-409行),算法的原理和代碼都很簡單,但這些代碼並沒有經過嚴格的測試,需要同學在看懂的基礎上自行摸索。

運行程序,拖動鼠標改變窗體尺寸,看看控件的大小和位置,是否也隨着容器的尺寸變化而變化?這就是相對佈局的特色。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章