視窗程式設計 (Windows Programming) 鄭士康 國立台灣大學 電機工程學系/電信工程研究所/ 資訊網路與多媒體研究所
綱要 第一個視窗程式 工具箱與控制項 訊息盒 事件處理 標籤與按鈕 選單 對話表單 MVC:模型-呈現-控制器原理
綱要 改寫主控台程式為視窗程式 加入圖形影像 二十一點模擬程式0.1G版
綱要 第一個視窗程式 工具箱與控制項 訊息盒 事件處理 標籤與按鈕 選單 對話表單 MVC:模型-呈現-控制器原理
第一個C#視窗程式 新增專案/名稱 (WindowsForm應用程式) Form1.cs[設計]/屬性頁 建置方案/啟動但不偵錯 方案總管/Program.cs 方案總管/Form1.cs/Form1.Designer.cs 重新命名
Form
Form 屬性
WindowsFormsApplication1. Program.cs (1/2) using System; using System.Collections.Generic; using System.Linq; using System.Windows.Forms; namespace WindowsFormsApplication1 { static class Program /// <summary> /// 應用程式的主要進入點。 /// </summary> [STAThread]
WindowsFormsApplication1. Program.cs (2/2) static void Main() { Application.EnableVisualStyles(); Application. SetCompatibleTextRenderingDefault(false); Application.Run(new Form1()); }
WindowsFormsApplication1.Form1.Designer.cs (1/3) namespace WindowsFormsApplication1 { partial class Form1 /// <summary> /// 設計工具所需的變數。 /// </summary> private System.ComponentModel.IContainer components = null; /// 清除任何使用中的資源。 /// <param name="disposing">如果應該處置 Managed 資源則為 true,否則為 false。</param>
WindowsFormsApplication1.Form1.Designer.cs (2/3) protected override void Dispose(bool disposing) { if (disposing && (components != null)) components.Dispose(); } base.Dispose(disposing); #region Windows Form 設計工具產生的程式碼 /// <summary> /// 此為設計工具支援所需的方法 - 請勿使用程式碼編輯器修改這個方法的內容。 /// /// </summary>
WindowsFormsApplication1.Form1.Designer.cs (3/3) private void InitializeComponent() { this.components = new System.ComponentModel.Container(); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.Text = "Form1"; } #endregion
練習 產生一個視窗程式,表單類別名為MainForm,表單標題為Hello,嘗試改變其大小
綱要 第一個視窗程式 工具箱與控制項 訊息盒 事件處理 標籤與按鈕 選單 對話表單 MVC:模型-呈現-控制器原理
工具箱 檢視/工具箱 通用控制項 Button CheckBox Label ProgressBar etc.
練習 產生一個視窗程式,嘗試加入一些通用控制項
綱要 第一個視窗程式 工具箱與控制項 訊息盒 事件處理 標籤與按鈕 選單 對話表單 MVC:模型-呈現-控制器原理
程式UsingMessageBox畫面
UsingMessageBox.Program.cs using System; using System.Collections.Generic; using System.Windows.Forms; namespace UsingMessageBox { static class Program { static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new MainForm()); //******************************************* MessageBox.Show("Main form has been closed"); //******************************************* }
綱要 第一個視窗程式 工具箱與控制項 訊息盒 事件處理 標籤與按鈕 選單 對話表單 MVC:模型-呈現-控制器原理
視窗程式執行流程 程式進入 程式初始化 事件發生 等待狀態 事件處理 事件處理結束 程式關閉 資源釋放 程式離開
事件處理
程式HandlingEvents表單輸出
HandlingEvents.MainForm.cs (1/2) using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; namespace HandlingEvents { public partial class MainForm : Form public MainForm() InitializeComponent(); }
HandlingEvents.MainForm.cs (2/2) private void MainForm_Click(object sender, EventArgs e) { //******************************** MessageBox.Show( "滑鼠剛剛點擊" ); }
HandlingEvents.MainForm. Designer.cs片段 (1/2) #region Windows Form 設計工具產生的程式碼 /// <summary> /// 此為設計工具支援所需的方法 - 請勿使用程式碼編輯器修改 /// 這個方法的內容。 /// /// </summary> private void InitializeComponent() { this.SuspendLayout(); // // MainForm this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
HandlingEvents.MainForm. Designer.cs片段 (2/2) this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size( 292, 266); this.Name = "MainForm"; this.Text = "MainForm"; this.Click += new System.EventHandler(this.MainForm_Click); this.ResumeLayout(false); } #endregion
練習 產生一個視窗程式,每次滑鼠雙擊,即顯示訊息 修改程式,使能累計滑鼠雙擊次數,並顯示於訊息盒
綱要 第一個視窗程式 工具箱與控制項 訊息盒 事件處理 標籤與按鈕 選單 對話表單 MVC:模型-呈現-控制器原理
程式UsingLabels畫面
基本標籤
標籤點擊事件處理(1/2) using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; namespace UsingLabels { public partial class MainForm : Form public MainForm() InitializeComponent(); }
標籤點擊事件處理(2/2) private void label1_Click(object sender, EventArgs e) { //************************ label1.Text = "程式可關閉"; }
程式UsingButtons畫面
按鈕
按鈕點擊事件處理(1/3) using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; namespace UsingButtons { public partial class MainForm : Form public MainForm() InitializeComponent(); }
按鈕點擊事件處理(2/3) private void button1_Click( object sender, EventArgs e) { //********************************* if (button1.Text == "是(&Y)") label1.Text = "檔案已刪除"; button1.Text = "確定"; button2.Visible = false; } else Dispose(true);
按鈕點擊事件處理(3/3) private void button2_Click( object sender, EventArgs e) { //********************************* Dispose(true); }
練習 撰寫應用標籤與按鈕的視窗程式,內容自由發揮
綱要 第一個視窗程式 工具箱與控制項 訊息盒 事件處理 標籤與按鈕 選單 對話表單 MVC:模型-呈現-控制器原理
程式UsingMenuStrip畫面
主選單與選項
練習 設定主選單及選項,內容自定
綱要 第一個視窗程式 工具箱與控制項 訊息盒 事件處理 標籤與按鈕 選單 對話表單 MVC:模型-呈現-控制器原理
程式UsingDialogForm畫面
對話表單設計 專案/加入新項目/Windows Form Label/TextBox/Button TextBox屬性(Text, TextAlign)及Button行為調整設定
UsingDialog.MainForm.cs (1/2) using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; namespace UsingDialogForm { public partial class MainForm : Form public MainForm() InitializeComponent(); }
UsingDialog.MainForm.cs (2/2) private void 輸入表格ToolStripMenuItem_Click(object sender, EventArgs e) { //********************************* Dialog diag = new Dialog(); diag.ShowDialog(); }
UsingDialog.Dialog.cs (1/3) using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; namespace UsingDialogForm { public partial class Dialog : Form //*********************************** int[ , ] table = new int[2, 3]; public Dialog() InitializeComponent(); }
UsingDialog.Dialog.cs (2/3) private void button1_Click(object sender, EventArgs e) { //******************************************* table[0, 0] = Convert.ToInt32(textBox1.Text); table[0, 1] = Convert.ToInt32(textBox2.Text); table[0, 2] = Convert.ToInt32(textBox3.Text); table[1, 0] = Convert.ToInt32(textBox4.Text); table[1, 1] = Convert.ToInt32(textBox5.Text); table[1, 2] = Convert.ToInt32(textBox6.Text); MessageBox.Show(table[0, 0].ToString()+ "\t" + table[0, 1].ToString()+ "\t" + table[0, 2].ToString()+ "\n" + table[1, 0].ToString()+ "\t" + table[1, 1].ToString()+ "\t" + table[1, 2].ToString() + "\n"); //******************************************** }
UsingDialog.Dialog.cs (3/3) private void button2_Click(object sender, EventArgs e) { //********************************* Dispose(); }
練習 以對話表單輸入資料,內容自定
綱要 第一個視窗程式 工具箱與控制項 訊息盒 事件處理 標籤與按鈕 選單 對話表單 MVC:模型-呈現-控制器原理
Model-View-Controller *D. Collins, Designing Object-Oriented User Interfaces, Benjamin/Cummings, 1995.
形式與功能 Function determines forms 資料處理核心與使用介面儘量分離 (Document vs. View) 使用介面較常變動 資料處理核心較為穩定
綱要 改寫主控台程式為視窗程式 加入圖形影像 二十一點模擬程式0.1G版
程式UsingGUI畫面
UsingGUI.MainForm.cs (1/3) using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; namespace UsingGUI { public partial class MainForm : Form //********************************* Table t = new Table();
UsingGUI.MainForm.cs (2/3) public MainForm() { InitializeComponent(); } private void 輸入表格ToolStripMenuItem_Click( object sender, EventArgs e) //********************************* Dialog diag = new Dialog(); diag.ShowDialog(); t.Content = diag.Content; 計算ToolStripMenuItem.Enabled = true;
UsingGUI.MainForm.cs (3/3) private void 計算ToolStripMenuItem_Click( object sender, EventArgs e) { //********************************* Output output = new Output(); output.DoComputation(t); output.ShowDialog(); }
UsingGUI.Dialog.cs (1/4) using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; namespace UsingGUI { public partial class Dialog : Form //*********************************** int[ , ] table = new int[2, 3];
UsingGUI.Dialog.cs (2/4) public Dialog() { InitializeComponent(); } private void button1_Click( object sender, EventArgs e) //******************************************** table[0, 0] = Convert.ToInt32(textBox1.Text); table[0, 1] = Convert.ToInt32(textBox2.Text); table[0, 2] = Convert.ToInt32(textBox3.Text); table[1, 0] = Convert.ToInt32(textBox4.Text); table[1, 1] = Convert.ToInt32(textBox5.Text); table[1, 2] = Convert.ToInt32(textBox6.Text);
UsingGUI.Dialog.cs (3/4) MessageBox.Show(table[0, 0].ToString()+ "\t" + table[0, 1].ToString()+ "\t" + table[0, 2].ToString()+ "\n" + table[1, 0].ToString()+ "\t" + table[1, 1].ToString()+ "\t" + table[1, 2].ToString()+ "\n"); Dispose(); //******************************************** } private void button2_Click( object sender, EventArgs e) { //******************************************** Dispose();
UsingGUI.Dialog.cs (4/4) //********************************************** public int[,] Content { get { return table; } }
UsingGUI.Output.cs (1/3) using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; namespace UsingGUI { public partial class Output : Form public Output() InitializeComponent(); }
UsingGUI.Output.cs (2/3) private void Output_Load( object sender, EventArgs e) {} private void button1_Click( object sender, EventArgs e) { //******************************************** Dispose(); } //********************************************** public void DoComputation(Table t) int[,] table = t.Content; int[] rowSum = t.RowSum(); int[] colSum = t.ColSum(); int totalSum = t.TotalSum();
UsingGUI.Output.cs (3/3) label5.Text = table[0, 0].ToString(); label8.Text = rowSum[0].ToString(); label9.Text = table[1, 0].ToString(); label10.Text = table[1, 1].ToString(); label11.Text = table[1, 2].ToString(); label12.Text = rowSum[1].ToString(); label13.Text = colSum[0].ToString(); label14.Text = colSum[1].ToString(); label15.Text = colSum[2].ToString(); label16.Text = totalSum.ToString(); } //************************************************ }
UsingGUI.Table.cs片段 public int[,] Content { get { return data; } set { data = value; nRow = value.GetUpperBound(0) + 1; nCol = value.GetUpperBound(1) + 1; }
綱要 改寫主控台程式為視窗程式 加入圖形影像 二十一點模擬程式0.1G版
程式DisplayingCards畫面
程式DisplayingCards注意事項 檔案夾PlayingCards應放在bin資料夾內,與Debug(偵錯版)及Release(發行版)資料夾併行
DisplayingcCards.MainForm. Designer.cs (1/4) //***************************** using System.Drawing; namespace DisplayingCards { partial class MainForm /// <summary> /// 設計工具所需的變數。 /// </summary> private System.ComponentModel.IContainer components = null; //******************************************* private Image image; private Graphics graphics; private bool started = false; //*******************************************
DisplayingcCards.MainForm. Designer.cs (2/4) /// <summary> /// 清除任何使用中的資源。 /// </summary> /// <param name="disposing">如果應該處置 Managed 資源則為 true,否則為 false。</param> protected override void Dispose(bool disposing) { if (disposing && (components != null)) components.Dispose(); } base.Dispose(disposing);
DisplayingcCards.MainForm. Designer.cs (3/4) //****************************************** private void DisplayImage() { int si = listBox1.SelectedIndex; string[] suit = { "s", "h", "d", "c" }; int i = listBox2.SelectedIndex + 1; string rank = i.ToString(); string fileName = "..\\PlayingCards\\" + suit[si] + rank + ".jpg"; image = Image.FromFile(fileName); graphics = CreateGraphics(); graphics.DrawImage(image, 5, 5, 85, 150); }
DisplayingcCards.MainForm. Designer.cs (4/4) protected override void OnPaint(System.Windows.Forms.PaintEventArgs e) { base.OnPaint(e); if (started) DisplayImage(); } //****************************************** #region Windows Form 設計工具產生的程式碼 . . . . . . #endregion
MainForm.cs (1/2) using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; namespace DisplayingCards { public partial class MainForm : Form public MainForm() InitializeComponent(); }
MainForm.cs (2/2) private void MainForm_Load(object sender, EventArgs e) { } private void button1_Click(object sender, //***************** DisplayImage();
綱要 改寫主控台程式為視窗程式 加入圖形影像 二十一點模擬程式0.1G版
BlackJack_0_1G 類別圖
互動設計:Activity Diagram
Form Design 開始 要牌 莊家: 18 點 停 玩家: 21 點 清除
起始處理:Collaboration Diagram
起始處理:Sequence Diagram
玩家要牌:Sequence Diagram
玩家停牌:Sequence Diagram
系統表單
BlackJack_0_1G.MainForm.cs (1/11) using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; namespace BlackJack_0_1G { //*********************************** public struct PlayerInfo public string name; public Status status;
BlackJack_0_1G.MainForm.cs (2/11) public int totalPoints; public Card[] cards; public int nCards; } //*********************************** public partial class MainForm : Form { //******************************* private Game game; private PlayerInfo playerInfo; private PlayerInfo dealerInfo; private Image image; private Graphics graphics; private bool inGame = false;
BlackJack_0_1G.MainForm.cs (3/11) public MainForm() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) //************************************** game.ProcessPlayerRun(out playerInfo); ShowInfo(); CheckBlackJackOrBurst(playerInfo); CheckBlackJackOrBurst(dealerInfo);
BlackJack_0_1G.MainForm.cs (4/11) //****************************************** private void ShowInfo() { int i; string fileName; graphics = CreateGraphics(); for (i = 0; i < playerInfo.nCards; ++i) fileName = "..\\PlayingCards\\" + playerInfo.cards[i].Name() + ".jpg"; image = Image.FromFile(fileName); graphics.DrawImage(image, 5+100*i, 220, 85, 150); }
BlackJack_0_1G.MainForm.cs (5/11) for (i = 0; i < dealerInfo.nCards; ++i) { fileName = "..\\PlayingCards\\" + dealerInfo.cards[i].Name() + ".jpg"; image = Image.FromFile(fileName); graphics.DrawImage(image, 5+100*i, 5, 85, 150); } label1.Text = dealerInfo.totalPoints.ToString(); label2.Text = playerInfo.totalPoints.ToString(); label11.Text = dealerInfo.name; label12.Text = playerInfo.name; //******************************************
BlackJack_0_1G.MainForm.cs (6/11) private void button3_Click(object sender, EventArgs e) { //***************************************** // "開始"按鈕 inGame = true; game = new Game(); game.InitPlay(out playerInfo, out dealerInfo); ShowInfo(); CheckBlackJackOrBurst(playerInfo); CheckBlackJackOrBurst(dealerInfo); button3.Enabled = false; button4.Enabled = true; }
BlackJack_0_1G.MainForm.cs (7/11) private void button2_Click(object sender, EventArgs e) { //************************************** // "停"按鈕 game.ProcessDealerRun(out dealerInfo); ShowInfo(); CheckBlackJackOrBurst(playerInfo); CheckBlackJackOrBurst(dealerInfo); if (playerInfo.status == Status.PASS && dealerInfo.status == Status.PASS)
BlackJack_0_1G.MainForm.cs (8/11) if (dealerInfo.totalPoints >= playerInfo.totalPoints) { MessageBox.Show(dealerInfo.name + "勝" + playerInfo.name); } else MessageBox.Show(playerInfo.name + "勝" + dealerInfo.name); //**************************************
BlackJack_0_1G.MainForm.cs (9/11) private void CheckBlackJackOrBurst(PlayerInfo info) { if (info.status == Status.BLACK_JACK) MessageBox.Show(info.name+" 二十一點"); } if (info.status == Status.BURST) MessageBox.Show(info.name + " 爆!!!");
BlackJack_0_1G.MainForm.cs (10/11) private void button4_Click(object sender, EventArgs e) { //************************************** // "清除"按鈕 inGame = false; Invalidate(); label1.Text = "0"; label2.Text = "0"; button4.Enabled = false; button3.Enabled = true; }
BlackJack_0_1G.MainForm.cs (11/11) //****************************************** protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); if (inGame) ShowInfo(); }
BlackJack_0_1G.Game.cs (1/7) /* * 二十一點遊戲, for GUI version * 11/21/2008 */ using System; namespace BlackJack_0_1G { class Game const int N_PLAYERS = 2; Deck deck; Player[] players = new Player[N_PLAYERS]; public Game()
BlackJack_0_1G.Game.cs (2/7) players[0] = new Player("Jeng"); players[N_PLAYERS - 1] = new Dealer(); deck = new Deck(); } public void InitPlay(out PlayerInfo playerInfo, out PlayerInfo dealerInfo) { int i; // 第一輪發牌 for (i = 0; i < N_PLAYERS; ++i) players[i].SaveACard( deck.DealACard());
BlackJack_0_1G.Game.cs (3/7) // 第二輪發牌 for (i = 0; i < N_PLAYERS; ++i) { players[i].SaveACard( deck.DealACard()); } playerInfo.name = players[0].Name; playerInfo.status = players[0].GetStatus(); playerInfo.totalPoints = players[0].GetTotalPoints(); playerInfo.cards = players[0].DumpCards(); playerInfo.nCards = players[0].GetNCards();
BlackJack_0_1G.Game.cs (4/7) dealerInfo.name = players[N_PLAYERS - 1].Name; dealerInfo.status = players[N_PLAYERS - 1].GetStatus(); dealerInfo.totalPoints = players[N_PLAYERS - 1].GetTotalPoints(); dealerInfo.cards = players[N_PLAYERS - 1].DumpCards(); dealerInfo.nCards = players[N_PLAYERS - 1].GetNCards(); }
BlackJack_0_1G.Game.cs (5/7) public void ProcessPlayerRun(out PlayerInfo playerInfo) { players[0].SaveACard(deck.DealACard()); playerInfo.name = players[0].Name; playerInfo.status = players[0].GetStatus(); playerInfo.totalPoints = players[0].GetTotalPoints(); playerInfo.cards = players[0].DumpCards(); playerInfo.nCards = players[0].GetNCards(); }
BlackJack_0_1G.Game.cs (6/7) public void ProcessDealerRun(out PlayerInfo dealerInfo) { while ( players[N_PLAYERS - 1].WantOneMoreCard()) players[N_PLAYERS - 1].SaveACard( deck.DealACard()); } dealerInfo.name = players[N_PLAYERS - 1].Name; dealerInfo.status = players[N_PLAYERS - 1].GetStatus(); dealerInfo.totalPoints = players[N_PLAYERS - 1].GetTotalPoints();
BlackJack_0_1G.Game.cs (7/7) dealerInfo.cards = players[N_PLAYERS - 1].DumpCards(); dealerInfo.nCards = players[N_PLAYERS - 1].GetNCards(); }
BlackJack_0_1G.Player.cs (1/6) /* * 模擬玩家, for GUI version * 4/19/2009 */ using System; namespace BlackJack_0_1G { class Player // a player can have at most 11 cards // {A, A, A, A, 2, 2, 2, 2, 3, 3, 3} // for not burst or BlackJack private Card[] hand = new Card[11]; private int nCards;
BlackJack_0_1G.Player.cs (2/6) private Status status; private int totalPoints; private string name; public Player() { nCards = 0; name = "無名氏"; } public Player(string name) this.name = name;
BlackJack_0_1G.Player.cs (3/6) public string Name { get { return name; } } public void SaveACard(Card card) hand[nCards++] = card; StatusChecker.DetermineStatusAndTotalPoints(hand, nCards, out status, out totalPoints); public Status GetStatus() return status;
BlackJack_0_1G.Player.cs (4/6) public int GetTotalPoints() { return totalPoints; } virtual public bool WantOneMoreCard() Console.Write("要再一張牌嗎? (y/n) "); string answer = Console.ReadLine(); return (answer == "Y" || answer == "y"); public void Dump() int i; Console.Write(name + " 牌: ");
BlackJack_0_1G.Player.cs (5/6) for (i = 0; i < nCards; ++i) { hand[i].Dump(); Console.Write("\t"); if ((i + 1) % 5 == 0) Console.WriteLine(); } Console.WriteLine(name + " 總點數: " + totalPoints); public Card[] DumpCards() return hand;
BlackJack_0_1G.Player.cs (6/6) public int GetNCards() { return nCards; }