圖形介面程式設計(五) 佈局容器類(3)
5 表格佈局
無論使用錨定佈局還是流式佈局,都無法達到複雜佈局的效果,很多時候我們不得不使用絕對佈局,忍受絕對佈局帶來的麻煩(要麼容器尺寸一變化,介面就變得一團糟;要麼在容器的Resize事件中寫複雜的佈局程式碼)。其實.net Framework中還具備一種很高階的佈局方式——表格佈局。
表格佈局顧名思義,就是將容器分為n行m列的二維表,這樣一個二維元組就可以表示表格的一個單元格,例如(0,0)就表示表格的第一行第一列。通過這個表格,我們可以將控制元件妥善的安放在容器合適的位置。
通過控制元件的Margin屬性,我們還可以控制控制元件距離表格單元格邊框的空白;通過控制元件的Dock屬性,我們可以進一步控制控制元件錨定在單元格的哪個方位。
在我們熟悉的網頁中,DIV和Table(層和表)就可以佈局出來豐富多彩的頁面,那麼.net Framework的表格佈局,就具備層和表的特點,同樣也可以佈局出來五花八門的介面。
TableLayoutPanel是.net Framework中的表格佈局容器,這個容器可以分為n行m列,如下圖:
圖1 表格佈局示意圖
從上圖可以形象的看到,TableLayoutPanel被分成了若干行和列,即容器被分為了若干格子,每個格子內規定只能放置一個控制元件,格子也可以跨行或跨列(也可以同時既跨行又跨列),從而把一個控制元件方式放置在相鄰的多行、多列中。
如果要給格子裡放置多個控制元件呢?首先就得給格子裡放置一個容器類
下面我們看一下表格佈局的步驟:
- 初始化TableLayoutPanel物件,然後要指定容器究竟分為多少行和列,設定容器物件的RowCount(行)和ColumnCount(列)屬性;
- 為所有的行和列設定樣式,樣式具體指:行的高度(自動調整、絕對、百分比),列的寬度(自動調整、絕對、百分比);
- 將控制元件增加到TableLayoutPanel容器物件內,呼叫容器的Controls屬性的Add方法,這個和前面講的容器相同;
- 定位控制元件:呼叫TableLayoutPanel容器物件的SetRow方法(指定行)和SetColumn方法(指定列);除此之外,TableLayoutPanel物件的Controls屬性具有一個過載的Add方法,可以在加入控制元件的同時指定其行列數;
- 設定跨行、跨列(可選):呼叫TableLayoutPanel容器物件的SetRowSpan方法(設定控制元件跨行)和SetColumnSpan方法(設定控制元件跨列)
好了,通過一個例子,我們仔細體會這種容器佈局的特點:
圖2 程式執行效果圖
可以看到,本次程式執行結果是一個簡易的計算器,是使用表格佈局的絕好素材。
詳細看一下介面佈局方式:
圖3 介面佈局分佈圖
可以看到,整個介面分為兩大部分,上面的顯示區和下面的按鈕區,這是由一個2行1列的TableLayoutPanel容器構成的;在顯示區裡(綠框),使用一個Panel容器承載了一個TextBox,用於顯示計算結果;在按鈕區域(黃框),使用一個6行5列的TableLayoutPanel容器(紅框),存放所有按鈕。
對於最外面的TableLayoutPanel容器,其顯示區(綠框)具有一個固定尺寸的行樣式;按鈕區(黃框)是自動尺寸的行樣式,其列樣式為自動尺寸,這樣,當介面尺寸改變後,顯示區的尺寸不會發生變化,按鈕區則隨著容器的尺寸變化而變化;
對於按鈕區內的TableLayoutPanel容器(紅框),則按容器尺寸百分比平均分為6行5列,這樣,無論容器尺寸如何變化,其行列百分比是不會變化的,單元格尺寸會隨著容器尺寸自動調整。
看程式碼:
Program.cs
- using System;
- using System.Drawing;
- using System.Runtime.InteropServices;
- using System.Windows.Forms;
- namespace Edu.Study.Graphics.TableLayout {
- /// <summary>
- /// 計算器主窗體
- /// </summary>
- class MyForm : Form {
- /// <summary>
- /// 計算器運算操作標誌列舉
- /// </summary>
- privateenum Operators {
- // 無操作
- None,
- // 加法操作
- Add,
- // 減法操作
- Sub,
- // 除法操作
- Div,
- // 乘法操作
- Mult
- }
- // 主容器面板, 充滿整個窗體
- private TableLayoutPanel mainPane;
- // 顯示結果的容器面板
- private Panel displayPane;
- // 顯示操作盤的容器面板
- private TableLayoutPanel optPane;
- // 顯示結果的文字框
- private TextBox resultTextbox;
- // 儲存第一個數字
- privatedecimal firstNumber = 0;
- // 儲存運算操作
- private Operators operators = Operators.None;
- // 是否需要清屏
- privatebool needClear = true;
- // M功能鍵儲存的值
- privatedecimal mValue = 0;
- // MR功能鍵按鈕
- private Button MRButton;
- /// <summary>
- /// 構造器, 初始化所有控制元件
- /// </summary>
- public MyForm() {
- // 設定窗體標題
- this.Text = "簡易計算器";
- /************ 初始化mainPane容器 ***********/
- this.mainPane = new TableLayoutPanel();
- // 容器分為2行1列
- this.mainPane.RowCount = 2;
- this.mainPane.ColumnCount = 1;
- // 為一列設定列樣式, 根據父容器(Form窗體)自動調整尺寸
- this.mainPane.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));
- // 為第一行設定行樣式, 固定高度, 50單位
- this.mainPane.RowStyles.Add(new RowStyle(SizeType.Absolute, 50));
- // 為第二行設定行樣式, 自動調整尺寸
- this.mainPane.RowStyles.Add(new RowStyle(SizeType.AutoSize));
- // mainPane在父容器上的錨定方式為中央充滿
- this.mainPane.Dock = DockStyle.Fill;
- /************ 初始化displayPane容器 ***********/
- this.displayPane = new Panel();
- // 設定displayPane容器在父容器上的錨定方式為中央充滿
- this.displayPane.Dock = DockStyle.Fill;
- // 設定displayPane容器的Padding屬性為5
- this.displayPane.Padding = new Padding(5);
- // 將displayPane容器加入到mainPane容器內
- this.mainPane.Controls.Add(this.displayPane);
- // 設定displayPane容器位於mainPane容器的第1行
- this.mainPane.SetRow(this.displayPane, 0);
- /************ 初始化resultTextbox容器 ***********/
- this.resultTextbox = new TextBox();
- // 設定resultTextbox控制元件顯示文字
- this.resultTextbox.Text = "0";
- // 設定resultTextbox文字對齊方式為居右對齊
- this.resultTextbox.TextAlign = HorizontalAlignment.Right;
- // 設定resultTextbox只讀
- this.resultTextbox.ReadOnly = true;
- // 設定resultTextbox控制元件背景色為淡藍色
- this.resultTextbox.BackColor = Color.LightBlue;
- // 設定resultTextbox控制元件字型
- this.resultTextbox.Font = new Font(new FontFamily("Times New Roman"), this.displayPane.Height / 2);
- // 設定resultTextbox控制元件在父容器上居中錨定
- this.resultTextbox.Dock = DockStyle.Fill;
- this.displayPane.Controls.Add(this.resultTextbox);
- /************ 初始化resultTextbox容器 ***********/
- this.optPane = new TableLayoutPanel();
- // 設定optPane具有6行
- this.optPane.RowCount = 6;
- // 設定optPane具有5列
- this.optPane.ColumnCount = 5;
- //