---
tags: 視窗程式設計
---
# 實作:記事本(字型、字體大小、樣式)
之前我們完成的記事本,已經具有基本純文字編輯的功能,不過我們如果希望文字的樣式要修改,就沒有辦法了,現在我們要介紹如何實現基本的文字樣式編輯功能。
# 第一部分:介面設定
大多數可以編輯文字樣式的文字編輯器,都會有一個類似下拉選單的按鍵可以按,按下去之後就會有選項選擇。
這樣的控制項叫做「**下拉選單(ComboBox)**」,這個控制項和清單方塊有點類似,一樣可以顯示一連串的資料,但差異點就是要按下去才會顯示清單,這樣可以讓視窗介面更加簡潔。
我們要設計的樣子就像這樣,你可以看到下圖有三個下拉選單,分別可以設定字型、字體大小、樣式。

同樣的和大多數控制項類似,在工具箱裡面你可以找到下拉選單,也是一樣可以直接置放到視窗畫面之上,你可以再調整成你要的大小。

因此你可以增加三個下拉選單,並且你可以參考以下名稱作為下拉選單的名稱。
:::info
1. 字型選單:comboBoxFont
2. 字體大小選單:comboBoxSize
3. 字體樣式選單:comboBoxStyle
:::
## 清單項目如何製作?
下拉選單設定好之後,就要將清單項目塞進選單之中,這時你可能會好奇,要怎麼把清單弄進去呢?
你可能第一個想到的會是:自己輸入進去。字體大小和樣式設定可以這樣做,但字型選單就沒辦法,因為每一個人電腦安裝的字型可能都不一樣,你不可能手動輸入。
所以我們需要能夠取得電腦內部的字型項目,再轉成清單放到下拉選單裡面。
:::success
字型與字體樣式其實都是程式物件,你可以直接放到程式裡面來取用。
:::
# 第二部分:程式碼撰寫
## 選單初始化
接下來將以下程式碼放到專案之中,請特別注意,方法 Form1() 你只需要加入第 7、8、9 三行即可。剩下的程式則是要複製再貼上。
再測試程式,你應該可以點選下拉選單,就可以看到選項。
```csharp=
public Form1()
{
InitializeComponent();
// 加入以下三行
InitializeFontComboBox();
InitializeFontSizeComboBox();
InitializeFontStyleComboBox();
}
// 初始化字體下拉選單
private void InitializeFontComboBox()
{
// 將所有系統字體名稱添加到字體選擇框中
foreach (FontFamily font in FontFamily.Families)
{
comboBoxFont.Items.Add(font.Name);
}
// 設置預設選中的項目為第一個字體
comboBoxFont.SelectedIndex = 0;
}
// 初始化字體大小下拉選單
private void InitializeFontSizeComboBox()
{
// 從8開始,每次增加2,直到72,將這些數值添加到字體大小選擇框中
for (int i = 8; i <= 72; i += 2)
{
comboBoxSize.Items.Add(i);
}
// 設置預設選中的項目為第三個大小,即12字體大小
comboBoxSize.SelectedIndex = 2;
}
// 初始化字體樣式下拉選單
private void InitializeFontStyleComboBox()
{
// 將不同的字體樣式添加到字體樣式選擇框中
comboBoxStyle.Items.Add(FontStyle.Regular.ToString()); // 正常
comboBoxStyle.Items.Add(FontStyle.Bold.ToString()); // 粗體
comboBoxStyle.Items.Add(FontStyle.Italic.ToString()); // 斜體
comboBoxStyle.Items.Add(FontStyle.Underline.ToString()); // 底線
comboBoxStyle.Items.Add(FontStyle.Strikeout.ToString()); // 刪除線
// 設置預設選中的項目為第一個樣式,即正常字體
comboBoxStyle.SelectedIndex = 0;
}
```
1. 字型選單

字型選單的項目,其實是擷取電腦內部的字型項目,然後使用迴圈將字型項目一個一個加入(Items.Add())到下拉選單之中。
SelectedIndex = 0 則是指,預設項目為第一個項目,如果沒有這行程式碼,項目會看起來沒有東西。
2. 字體大小選單

字體大小選單的設計反而很簡單,實際上就是把從數字 8 到 72 之間的偶數加入到下拉選單之中,你可以研究一下迴圈是怎麼寫的?
3. 字體樣式選單

字體樣式的加入則是手動一一將各種樣式的程式物件加入,以下是這些程式物件的說明。
1. FontStyle.Regular:標準字體
2. FontStyle.Bold: 粗體
3. FontStyle.Italic:斜體
4. FontStyle.Underline:底線
5. FontStyle.Strikeout:刪除線
## 文字樣式套用
選單做好之後,我們要能夠在文字反白後,再選擇下拉選單的項目,接著改變文字的樣式。
接下來請加入以下的程式碼片段。
```csharp=
// 這個方法在 comboBox 的選項變更時觸發
private void comboBox_SelectedIndexChanged(object sender, EventArgs e)
{
// 檢查當前選擇的文字是否有字型,如果有,則進行後續處理
if (rtbText.SelectionFont != null)
{
// 從下拉選單中獲取選擇的字型、大小和樣式
string selectedFont = comboBoxFont.SelectedItem?.ToString();
string selectedSizeStr = comboBoxSize.SelectedItem?.ToString();
string selectedStyleStr = comboBoxStyle.SelectedItem?.ToString();
// 確保字型、大小和樣式都已選擇
if (selectedFont != null && selectedSizeStr != null && selectedStyleStr != null)
{
// 將選擇的大小字串轉換為浮點數
float selectedSize = float.Parse(selectedSizeStr);
// 將選擇的樣式字串轉換為 FontStyle 枚舉值
FontStyle selectedStyle = (FontStyle)Enum.Parse(typeof(FontStyle), selectedStyleStr);
// 獲取當前選擇的文字的字型
Font currentFont = rtbText.SelectionFont;
FontStyle newStyle = currentFont.Style;
// 檢查是否需要應用新的樣式,並更新樣式
if (comboBoxStyle.SelectedItem.ToString() == FontStyle.Bold.ToString())
newStyle = FontStyle.Bold;
else if (comboBoxStyle.SelectedItem.ToString() == FontStyle.Italic.ToString())
newStyle = FontStyle.Italic;
else if (comboBoxStyle.SelectedItem.ToString() == FontStyle.Underline.ToString())
newStyle = FontStyle.Underline;
else if (comboBoxStyle.SelectedItem.ToString() == FontStyle.Strikeout.ToString())
newStyle = FontStyle.Strikeout;
else
newStyle = FontStyle.Regular;
// 創建新的字型並應用到選擇的文字
Font newFont = new Font(selectedFont, selectedSize, newStyle);
rtbText.SelectionFont = newFont;
}
}
}
```
你可能會好奇,那麼三個下拉選單的事件綁定呢?請在這三個下拉選單的事件清單裡,找到「**當選擇項目不同時(SelectedIndexChanged)**」,這時請不要立刻點兩下做事件綁定,我們先點選旁邊的箭頭,把這個清單打開,你應該可以找到「comboBox_SelectedIndexChanged」這個項目,就像下圖的樣子。

三個下拉選單都要做一樣的事情,這時你或許就可以理解,這樣的做法等於是當三個選單選擇項目時,都要執行上方程式碼的意思。如果你選擇特定字型、字體大小與樣式,就會將它們套用在文字裡。
## 小修正
這時你可能會發現,當你選擇一段文字反白,然後選擇想要修改的字型、字體大小與樣式,但是文字反白卻消失了,現在我們要把這個小問題給修正一下。
```csharp=
private int selectionStart = 0; // 記錄文字反白的起點
private int selectionLength = 0; // 記錄文字反白的長度
private void comboBox_SelectedIndexChanged(object sender, EventArgs e)
{
// 保存當前選擇的文字起始位置和長度
selectionStart = rtbText.SelectionStart;
selectionLength = rtbText.SelectionLength;
// 確保當前選擇的文字具有字型
if (rtbText.SelectionFont != null)
{
// 從下拉選單中獲取選擇的字型、大小和樣式
string selectedFont = comboBoxFont.SelectedItem?.ToString();
string selectedSizeStr = comboBoxSize.SelectedItem?.ToString();
string selectedStyleStr = comboBoxStyle.SelectedItem?.ToString();
// 確保字型、大小和樣式都已選擇
if (selectedFont != null && selectedSizeStr != null && selectedStyleStr != null)
{
// 將選擇的大小字串轉換為浮點數
float selectedSize = float.Parse(selectedSizeStr);
// 將選擇的樣式字串轉換為 FontStyle 枚舉值
FontStyle selectedStyle = (FontStyle)Enum.Parse(typeof(FontStyle), selectedStyleStr);
// 獲取當前選擇的文字的字型
Font currentFont = rtbText.SelectionFont;
FontStyle newStyle = currentFont.Style;
// 檢查是否需要應用新的樣式,並更新樣式
if (comboBoxStyle.SelectedItem.ToString() == FontStyle.Bold.ToString())
newStyle = FontStyle.Bold;
else if (comboBoxStyle.SelectedItem.ToString() == FontStyle.Italic.ToString())
newStyle = FontStyle.Italic;
else if (comboBoxStyle.SelectedItem.ToString() == FontStyle.Underline.ToString())
newStyle = FontStyle.Underline;
else if (comboBoxStyle.SelectedItem.ToString() == FontStyle.Strikeout.ToString())
newStyle = FontStyle.Strikeout;
else
newStyle = FontStyle.Regular;
// 創建新的字型並應用到選擇的文字
Font newFont = new Font(selectedFont, selectedSize, newStyle);
rtbText.SelectionFont = newFont;
}
}
// 恢復選擇狀態
rtbText.Focus();
rtbText.Select(selectionStart, selectionLength);
}
```
修正後的程式碼的主要是保存和恢復在「rtbText」中選擇的文字反白範圍,這在需要對文字進行某些操作後(如修改文本格式、顏色等)仍能保持使用者所選擇反白文字範圍時非常有用。
以上程式碼的說明,首先你要將第 1 與 2 行的全域變數宣告出來。分別是用來保存文字反白選擇的文字起始位置(SelectionStart)和長度(SelectionLength)。
接著我們在修改文字樣式前,會在第 7 與 8 行記錄目前選擇的文字反白範圍。
文字樣式修改後,在第 49 與 50 行,將要控制的「rtbText」豐富文字框取得控制,再將原本紀錄的文字起始位置和長度重新反白起來。
這樣就能夠讓文字反白範圍一直顯示在「rtbText」之中。
# 完整程式碼
:::spoiler
```csharp=
// 初始化字體下拉選單
private void InitializeFontComboBox()
{
// 將所有系統字體名稱添加到字體選擇框中
foreach (FontFamily font in FontFamily.Families)
{
comboBoxFont.Items.Add(font.Name);
}
// 設置預設選中的項目為第一個字體
comboBoxFont.SelectedIndex = 0;
}
// 初始化字體大小下拉選單
private void InitializeFontSizeComboBox()
{
// 從8開始,每次增加2,直到72,將這些數值添加到字體大小選擇框中
for (int i = 8; i <= 72; i += 2)
{
comboBoxSize.Items.Add(i);
}
// 設置預設選中的項目為第三個大小,即12字體大小
comboBoxSize.SelectedIndex = 2;
}
// 初始化字體樣式下拉選單
private void InitializeFontStyleComboBox()
{
// 將不同的字體樣式添加到字體樣式選擇框中
comboBoxStyle.Items.Add(FontStyle.Regular.ToString()); // 正常
comboBoxStyle.Items.Add(FontStyle.Bold.ToString()); // 粗體
comboBoxStyle.Items.Add(FontStyle.Italic.ToString()); // 斜體
comboBoxStyle.Items.Add(FontStyle.Underline.ToString()); // 底線
comboBoxStyle.Items.Add(FontStyle.Strikeout.ToString()); // 刪除線
// 設置預設選中的項目為第一個樣式,即正常字體
comboBoxStyle.SelectedIndex = 0;
}
private int selectionStart = 0; // 記錄文字反白的起點
private int selectionLength = 0; // 記錄文字反白的長度
// 這個方法在 comboBox 的選項變更時觸發
private void comboBox_SelectedIndexChanged(object sender, EventArgs e)
{
// 檢查當前選擇的文字是否有字型,如果有,則進行後續處理
if (rtbText.SelectionFont != null)
{
// 從下拉選單中獲取選擇的字型、大小和樣式
string selectedFont = comboBoxFont.SelectedItem?.ToString();
string selectedSizeStr = comboBoxSize.SelectedItem?.ToString();
string selectedStyleStr = comboBoxStyle.SelectedItem?.ToString();
// 確保字型、大小和樣式都已選擇
if (selectedFont != null && selectedSizeStr != null && selectedStyleStr != null)
{
// 將選擇的大小字串轉換為浮點數
float selectedSize = float.Parse(selectedSizeStr);
// 將選擇的樣式字串轉換為 FontStyle 枚舉值
FontStyle selectedStyle = (FontStyle)Enum.Parse(typeof(FontStyle), selectedStyleStr);
// 獲取當前選擇的文字的字型
Font currentFont = rtbText.SelectionFont;
FontStyle newStyle = currentFont.Style;
// 檢查是否需要應用新的樣式,並更新樣式
if (comboBoxStyle.SelectedItem.ToString() == FontStyle.Bold.ToString())
newStyle = FontStyle.Bold;
else if (comboBoxStyle.SelectedItem.ToString() == FontStyle.Italic.ToString())
newStyle = FontStyle.Italic;
else if (comboBoxStyle.SelectedItem.ToString() == FontStyle.Underline.ToString())
newStyle = FontStyle.Underline;
else if (comboBoxStyle.SelectedItem.ToString() == FontStyle.Strikeout.ToString())
newStyle = FontStyle.Strikeout;
else
newStyle = FontStyle.Regular;
// 創建新的字型並應用到選擇的文字
Font newFont = new Font(selectedFont, selectedSize, newStyle);
rtbText.SelectionFont = newFont;
}
}
}
```
:::