1. 程式人生 > >圖形介面程式設計(五) 佈局容器類(3)

圖形介面程式設計(五) 佈局容器類(3)

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. namespace Edu.Study.Graphics.TableLayout {  
  6.     /// <summary>
  7.     /// 計算器主窗體
  8.     /// </summary>
  9.     class MyForm : Form {  
  10.         /// <summary>
  11.         /// 計算器運算操作標誌列舉
  12.         /// </summary>
  13.         privateenum Operators {  
  14.             // 無操作
  15.             None,  
  16.             // 加法操作
  17.             Add,  
  18.             // 減法操作
  19.             Sub,  
  20.             // 除法操作
  21.             Div,  
  22.             // 乘法操作
  23.             Mult  
  24.         }  
  25.         // 主容器面板, 充滿整個窗體
  26.         private TableLayoutPanel mainPane;  
  27.         // 顯示結果的容器面板
  28.         private Panel displayPane;  
  29.         // 顯示操作盤的容器面板
  30.         private TableLayoutPanel optPane;  
  31.         // 顯示結果的文字框
  32.         private TextBox resultTextbox;  
  33.         // 儲存第一個數字
  34.         privatedecimal firstNumber = 0;  
  35.         // 儲存運算操作
  36.         private Operators operators = Operators.None;  
  37.         // 是否需要清屏
  38.         privatebool needClear = true;  
  39.         // M功能鍵儲存的值
  40.         privatedecimal mValue = 0;  
  41.         // MR功能鍵按鈕
  42.         private Button MRButton;  
  43.         /// <summary>
  44.         /// 構造器, 初始化所有控制元件
  45.         /// </summary>
  46.         public MyForm() {  
  47.             // 設定窗體標題
  48.             this.Text = "簡易計算器";  
  49.             /************ 初始化mainPane容器 ***********/
  50.             this.mainPane = new TableLayoutPanel();  
  51.             // 容器分為2行1列
  52.             this.mainPane.RowCount = 2;  
  53.             this.mainPane.ColumnCount = 1;  
  54.             // 為一列設定列樣式, 根據父容器(Form窗體)自動調整尺寸
  55.             this.mainPane.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));  
  56.             // 為第一行設定行樣式, 固定高度, 50單位
  57.             this.mainPane.RowStyles.Add(new RowStyle(SizeType.Absolute, 50));  
  58.             // 為第二行設定行樣式, 自動調整尺寸
  59.             this.mainPane.RowStyles.Add(new RowStyle(SizeType.AutoSize));  
  60.             // mainPane在父容器上的錨定方式為中央充滿
  61.             this.mainPane.Dock = DockStyle.Fill;  
  62.             /************ 初始化displayPane容器 ***********/
  63.             this.displayPane = new Panel();  
  64.             // 設定displayPane容器在父容器上的錨定方式為中央充滿
  65.             this.displayPane.Dock = DockStyle.Fill;  
  66.             // 設定displayPane容器的Padding屬性為5
  67.             this.displayPane.Padding = new Padding(5);  
  68.             // 將displayPane容器加入到mainPane容器內
  69.             this.mainPane.Controls.Add(this.displayPane);  
  70.             // 設定displayPane容器位於mainPane容器的第1行
  71.             this.mainPane.SetRow(this.displayPane, 0);  
  72.             /************ 初始化resultTextbox容器 ***********/
  73.             this.resultTextbox = new TextBox();  
  74.             // 設定resultTextbox控制元件顯示文字
  75.             this.resultTextbox.Text = "0";  
  76.             // 設定resultTextbox文字對齊方式為居右對齊
  77.             this.resultTextbox.TextAlign = HorizontalAlignment.Right;  
  78.             // 設定resultTextbox只讀
  79.             this.resultTextbox.ReadOnly = true;  
  80.             // 設定resultTextbox控制元件背景色為淡藍色
  81.             this.resultTextbox.BackColor = Color.LightBlue;  
  82.             // 設定resultTextbox控制元件字型
  83.             this.resultTextbox.Font = new Font(new FontFamily("Times New Roman"), this.displayPane.Height / 2);  
  84.             // 設定resultTextbox控制元件在父容器上居中錨定
  85.             this.resultTextbox.Dock = DockStyle.Fill;  
  86.             this.displayPane.Controls.Add(this.resultTextbox);  
  87.             /************ 初始化resultTextbox容器 ***********/
  88.             this.optPane = new TableLayoutPanel();  
  89.             // 設定optPane具有6行
  90.             this.optPane.RowCount = 6;  
  91.             // 設定optPane具有5列
  92.             this.optPane.ColumnCount = 5;  
  93.             //