拼音歌曲查詢完整註解

This commit is contained in:
jasonchenwork 2025-03-18 17:21:15 +08:00
parent fbd988de09
commit 1253c605db

View File

@ -10,15 +10,20 @@ namespace DualScreenDemo
{
public partial class PrimaryForm
{
// 拼音歌曲的 PictureBox
private PictureBox pictureBoxPinYinSongs;
// 存放拼音按鈕的陣列
private Button[] letterButtonsForPinYinSongs;
// 特殊功能按鈕(修改、清除、關閉)
private Button modifyButtonPinYinSongs;
private Button clearButtonPinYinSongs;
private Button closeButtonPinYinSongs;
// 用於顯示輸入文字的輸入框
private RichTextBox inputBoxPinYinSongs;
// 拼音歌曲搜尋按鈕點擊事件
private void PinyinSearchSongsButton_Click(object sender, EventArgs e)
{
// 更新搜尋模式按鈕的背景圖
zhuyinSearchSongButton.BackgroundImage = zhuyinSearchSongNormalBackground;
englishSearchSongButton.BackgroundImage = englishSearchSongNormalBackground;
pinyinSearchSongButton.BackgroundImage = pinyinSearchSongActiveBackground;
@ -26,52 +31,71 @@ namespace DualScreenDemo
handWritingSearchSongButton.BackgroundImage = handWritingSearchSongNormalBackground;
numberSearchSongButton.BackgroundImage = numberSearchSongNormalBackground;
// 讀取 config.ini 並獲取拼音圖片的路徑
var configData = LoadConfigData();
string pinyinImagePath = Path.Combine(Application.StartupPath, configData["ImagePaths"]["PinYinSongs"]);
// 顯示拼音歌曲圖片
ShowImageOnPictureBoxPinYinSongs(Path.Combine(Application.StartupPath, pinyinImagePath));
// 設定不同模式的 UI 顯示
SetZhuYinSingersAndButtonsVisibility(false);
SetEnglishSingersAndButtonsVisibility(false);
SetPinYinSingersAndButtonsVisibility(false);
SetPinYinSongsAndButtonsVisibility(true);
pictureBoxPinYinSongs.Visible = true;
}
// 初始化拼音按鈕
private void InitializeLetterButtonsForPinYinSongs()
{
// 從設定檔 (config.ini) 讀取配置數據
var data = LoadConfigData();
// 從配置數據中載入拼音字母按鈕的影像 (包含正常、點擊、滑鼠懸停三種狀態)
var buttonImages = LoadButtonImages(data, "PinYinLetterButtonImages", 26);
// 定義 QWERTY 鍵盤排列的字母順序
string qwertyLayout = "QWERTYUIOPASDFGHJKLZXCVBNM";
// 初始化拼音按鈕陣列,長度為 26對應英文字母
letterButtonsForPinYinSongs = new Button[26];
// 迴圈遍歷 26 個字母,依序建立按鈕
for (int i = 0; i < 26; i++)
{
// 從配置檔案讀取當前按鈕的座標資訊 (X, Y, Width, Height)
var coords = data["PinYinLetterButtonCoordinates"][$"button{i}"].Split(',');
// 建立拼音按鈕,並設定名稱、座標、影像與事件處理函式
letterButtonsForPinYinSongs[i] = CreateButton(
$"letterButton_{qwertyLayout[i]}",
(int.Parse(coords[0]), int.Parse(coords[1]), int.Parse(coords[2]), int.Parse(coords[3])),
buttonImages[$"button{i}"].normal,
buttonImages[$"button{i}"].mouseDown,
buttonImages[$"button{i}"].mouseOver,
LetterButtonPinYinSongs_Click
$"letterButton_{qwertyLayout[i]}", // 按鈕名稱,例如 "letterButton_Q"
(int.Parse(coords[0]), int.Parse(coords[1]), int.Parse(coords[2]), int.Parse(coords[3])), // 解析座標數據
buttonImages[$"button{i}"].normal, // 正常狀態影像
buttonImages[$"button{i}"].mouseDown, // 按下狀態影像
buttonImages[$"button{i}"].mouseOver, // 滑鼠懸停狀態影像
LetterButtonPinYinSongs_Click // 點擊事件處理函式
);
// 設定按鈕的標籤 (Tag) 為對應的字母,例如 Q、W、E...
letterButtonsForPinYinSongs[i].Tag = qwertyLayout[i];
// 將按鈕新增到表單的控制項集合中,讓其顯示在介面上
this.Controls.Add(letterButtonsForPinYinSongs[i]);
}
}
// 處理拼音按鈕點擊事件
private void LetterButtonPinYinSongs_Click(object sender, EventArgs e)
{
// 嘗試將觸發事件的物件轉換為 Button 類型
var button = sender as Button;
// 檢查按鈕是否為 null並確保該按鈕的 Tag 屬性不為 null
if (button != null && button.Tag != null)
{
// 確保輸入框 (inputBoxPinYinSongs) 是可見狀態
if (inputBoxPinYinSongs.Visible)
{
// 將按鈕的標籤 (Tag) 轉換為字串,並附加到輸入框的文字內容中
inputBoxPinYinSongs.Text += button.Tag.ToString();
}
}
@ -79,235 +103,321 @@ namespace DualScreenDemo
private void InitializeButtonsForPinYinSongs()
{
// 初始化拼音字母按鈕,根據 QWERTY 鍵盤佈局建立對應的按鈕
InitializeLetterButtonsForPinYinSongs();
// 初始化特殊功能按鈕,包括修改、清除和關閉按鈕
InitializeSpecialButtonsForPinYinSongs();
// 初始化拼音輸入框,讓使用者可以輸入拼音來搜尋歌曲
InitializeInputBoxPinYinSongs();
}
private void InitializeSpecialButtonsForPinYinSongs()
{
// 初始化「修改」按鈕,讓使用者可以刪除輸入框中的最後一個字母
InitializeModifyButtonPinYinSongs();
// 初始化「清除」按鈕,讓使用者可以清空輸入框的內容
InitializeClearButtonPinYinSongs();
// 初始化「關閉」按鈕,讓使用者可以關閉拼音輸入的 UI 元件
InitializeCloseButtonPinYinSongs();
}
private void InitializeModifyButtonPinYinSongs()
{
// 載入設定檔資料,取得特殊按鈕的相關配置
var data = LoadConfigData();
// 從設定檔讀取「修改按鈕」的座標位置與大小
modifyButtonPinYinCoords = LoadSpecialButtonCoordinates(data, "SpecialButtonCoordinates", "modifyButtonPinYinSongs");
// 從設定檔讀取「修改按鈕」的不同狀態圖片 (一般、滑鼠懸停、按下)
var buttonImages = LoadButtonImages(data, "ModifyButtonImagesPinYin");
// 創建「修改按鈕」,並綁定點擊事件
modifyButtonPinYinSongs = CreateSpecialButton(
"btnModifyPinYinSongs",
modifyButtonPinYinCoords,
buttonImages.normal,
buttonImages.mouseOver,
buttonImages.mouseDown,
ModifyButtonPinYinSongs_Click
"btnModifyPinYinSongs", // 按鈕名稱
modifyButtonPinYinCoords, // 設定按鈕的座標與大小
buttonImages.normal, // 設定按鈕的正常狀態圖片
buttonImages.mouseOver, // 設定按鈕的滑鼠懸停圖片
buttonImages.mouseDown, // 設定按鈕的按下狀態圖片
ModifyButtonPinYinSongs_Click // 綁定按鈕的點擊事件處理函式
);
}
private void ModifyButtonPinYinSongs_Click(object sender, EventArgs e)
{
// 檢查 `inputBoxPinYinSongs` 是否已被加入到 `Controls` 集合中 (確保輸入框存在)
if (this.Controls.Contains(inputBoxPinYinSongs) && inputBoxPinYinSongs.Text.Length > 0)
{
// 若 `inputBoxPinYinSongs` 有內容,刪除最後一個字母
inputBoxPinYinSongs.Text = inputBoxPinYinSongs.Text.Substring(0, inputBoxPinYinSongs.Text.Length - 1);
}
}
private void InitializeClearButtonPinYinSongs()
{
// 從設定檔載入資料
var data = LoadConfigData();
// 讀取清除按鈕的座標配置 (X, Y, Width, Height)
clearButtonPinYinCoords = LoadSpecialButtonCoordinates(data, "SpecialButtonCoordinates", "clearButtonPinYinSongs");
// 載入清除按鈕的圖片 (一般狀態、滑鼠懸停、按下時的圖片)
var buttonImages = LoadButtonImages(data, "ClearButtonImagesPinYin");
// 建立「清除按鈕」並指定對應的座標與圖片
clearButtonPinYinSongs = CreateSpecialButton(
"btnClearPinYinSongs",
clearButtonPinYinCoords,
buttonImages.normal,
buttonImages.mouseOver,
buttonImages.mouseDown,
ClearButtonPinYinSongs_Click
"btnClearPinYinSongs", // 按鈕名稱
clearButtonPinYinCoords, // 按鈕的座標與大小
buttonImages.normal, // 按鈕的普通狀態圖片
buttonImages.mouseOver, // 滑鼠懸停時的圖片
buttonImages.mouseDown, // 滑鼠按下時的圖片
ClearButtonPinYinSongs_Click // 點擊事件處理函式
);
}
private void ClearButtonPinYinSongs_Click(object sender, EventArgs e)
{
// 檢查視窗內是否包含 inputBoxPinYinSongs 控制項,且輸入框內是否有文字
if (this.Controls.Contains(inputBoxPinYinSongs) && inputBoxPinYinSongs.Text.Length > 0)
{
// 清空拼音輸入框的內容
inputBoxPinYinSongs.Text = "";
}
}
private void InitializeCloseButtonPinYinSongs()
{
// 讀取設定檔中的按鈕配置數據
var data = LoadConfigData();
// 從設定檔中取得「關閉」按鈕的座標
closeButtonPinYinCoords = LoadSpecialButtonCoordinates(data, "SpecialButtonCoordinates", "closeButtonPinYinSongs");
// 從設定檔中讀取「關閉」按鈕的圖片
var buttonImages = LoadButtonImages(data, "CloseButtonImagesPinYin");
// 建立「關閉」按鈕,並設定名稱、座標、按鈕圖片及點擊事件
closeButtonPinYinSongs = CreateSpecialButton(
"btnClosePinYinSongs",
closeButtonPinYinCoords,
buttonImages.normal,
buttonImages.mouseOver,
buttonImages.mouseDown,
CloseButtonPinYinSongs_Click
"btnClosePinYinSongs", // 按鈕名稱
closeButtonPinYinCoords, // 按鈕座標 (X, Y, Width, Height)
buttonImages.normal, // 按鈕的普通狀態圖片
buttonImages.mouseOver, // 滑鼠懸停時的圖片
buttonImages.mouseDown, // 按下時的圖片
CloseButtonPinYinSongs_Click // 點擊事件處理函式
);
}
private void CloseButtonPinYinSongs_Click(object sender, EventArgs e)
{
// 隱藏拼音輸入的背景圖片 (可能是 UI 中的輸入框背景)
pictureBoxPinYinSongs.Visible = false;
// 設定拼音輸入框與所有相關按鈕的可見性為 false
SetPinYinSongsAndButtonsVisibility(false);
}
private void InitializeInputBoxPinYinSongs()
{
try
{
// 創建一個 INI 檔案解析器
var parser = new FileIniDataParser();
parser.Parser.Configuration.AssigmentSpacer = "";
parser.Parser.Configuration.CommentString = "#";
parser.Parser.Configuration.CaseInsensitive = true;
IniData data;
// 配置解析器的參數
parser.Parser.Configuration.AssigmentSpacer = ""; // 設定 `=` 兩側沒有空格
parser.Parser.Configuration.CommentString = "#"; // 使用 `#` 作為註解符號
parser.Parser.Configuration.CaseInsensitive = true; // 參數名稱不區分大小寫
IniData data; // 儲存解析後的 INI 數據
// 讀取 `config.ini` 文件,使用 UTF-8 編碼
using (var reader = new StreamReader("config.ini", System.Text.Encoding.UTF8))
{
data = parser.ReadData(reader);
}
int x = int.Parse(data["InputBoxPinYinSongs"]["X"]);
int y = int.Parse(data["InputBoxPinYinSongs"]["Y"]);
int width = int.Parse(data["InputBoxPinYinSongs"]["Width"]);
int height = int.Parse(data["InputBoxPinYinSongs"]["Height"]);
string fontName = data["InputBoxPinYinSongs"]["FontName"];
float fontSize = float.Parse(data["InputBoxPinYinSongs"]["FontSize"]);
FontStyle fontStyle = (FontStyle)Enum.Parse(typeof(FontStyle), data["InputBoxPinYinSongs"]["FontStyle"]);
Color foreColor = Color.FromName(data["InputBoxPinYinSongs"]["ForeColor"]);
// 從 INI 檔案讀取拼音輸入框的位置與大小
int x = int.Parse(data["InputBoxPinYinSongs"]["X"]); // X 座標
int y = int.Parse(data["InputBoxPinYinSongs"]["Y"]); // Y 座標
int width = int.Parse(data["InputBoxPinYinSongs"]["Width"]); // 寬度
int height = int.Parse(data["InputBoxPinYinSongs"]["Height"]); // 高度
// 讀取字型設定
string fontName = data["InputBoxPinYinSongs"]["FontName"]; // 字型名稱
float fontSize = float.Parse(data["InputBoxPinYinSongs"]["FontSize"]); // 字體大小
FontStyle fontStyle = (FontStyle)Enum.Parse(typeof(FontStyle), data["InputBoxPinYinSongs"]["FontStyle"]); // 字體樣式
Color foreColor = Color.FromName(data["InputBoxPinYinSongs"]["ForeColor"]); // 文字顏色
// 創建拼音輸入框 (`RichTextBox`)
inputBoxPinYinSongs = new RichTextBox
{
Visible = false,
Name = "inputBoxPinYinSongs",
ForeColor = foreColor,
Font = new Font(fontName, fontSize / 900 * Screen.PrimaryScreen.Bounds.Height, fontStyle)
Visible = false, // 預設為隱藏
Name = "inputBoxPinYinSongs", // 設定控制項名稱
ForeColor = foreColor, // 設定文字顏色
Font = new Font(
fontName,
fontSize / 900 * Screen.PrimaryScreen.Bounds.Height, // 根據螢幕大小調整字體
fontStyle
)
};
// 設定輸入框的位置與大小
ResizeAndPositionControl(inputBoxPinYinSongs, x, y, width, height);
// 綁定 `TextChanged` 事件 (當輸入內容改變時觸發搜尋)
inputBoxPinYinSongs.TextChanged += (sender, e) =>
{
string searchText = inputBoxPinYinSongs.Text;
var searchResults = allSongs.Where(song => song.PinyinNotation.StartsWith(searchText)).ToList();
currentPage = 0;
currentSongList = searchResults;
totalPages = (int)Math.Ceiling((double)searchResults.Count / itemsPerPage);
// 根據拼音前綴篩選歌曲
var searchResults = allSongs.Where(song => song.PinyinNotation.StartsWith(searchText)).ToList();
currentPage = 0; // 重置當前頁面索引
currentSongList = searchResults; // 更新搜尋結果
totalPages = (int)Math.Ceiling((double)searchResults.Count / itemsPerPage); // 計算總頁數
// 更新 UI顯示搜尋結果
multiPagePanel.currentPageIndex = 0;
multiPagePanel.LoadSongs(currentSongList);
};
// 將拼音輸入框加入視窗中
this.Controls.Add(inputBoxPinYinSongs);
}
catch (Exception ex)
{
// 發生錯誤時輸出錯誤訊息 (避免程式崩潰)
Console.WriteLine($"An error occurred: {ex.Message}");
}
}
}
// 讀取 PictureBoxPinYinSongs 的座標設定
private (int X, int Y, int Width, int Height) pictureBoxPinYinSongCoords;
private void LoadPictureBoxPinYinSongCoordsFromConfig()
{
// 創建一個 INI 檔案解析器
var parser = new FileIniDataParser();
// 讀取 `config.ini` 文件並解析成 `IniData` 對象
IniData data = parser.ReadFile("config.ini");
// 取得 `PictureBoxPinYinSongs` 區段的設定值
var coords = data["PictureBoxPinYinSongs"];
// 解析 `X`, `Y`, `Width`, `Height`,並存入 `pictureBoxPinYinSongCoords`
pictureBoxPinYinSongCoords = (
int.Parse(coords["X"]),
int.Parse(coords["Y"]),
int.Parse(coords["Width"]),
int.Parse(coords["Height"])
int.Parse(coords["X"]), // 解析 X 座標
int.Parse(coords["Y"]), // 解析 Y 座標
int.Parse(coords["Width"]), // 解析 寬度
int.Parse(coords["Height"]) // 解析 高度
);
}
// 顯示拼音歌曲圖片
private void ShowImageOnPictureBoxPinYinSongs(string imagePath)
{
LoadPictureBoxPinYinSongCoordsFromConfig();
// 從設定檔載入 PictureBox 的座標與大小
LoadPictureBoxPinYinSongCoordsFromConfig();
Bitmap originalImage = new Bitmap(imagePath);
// 使用指定的圖片路徑建立 Bitmap 影像
Bitmap originalImage = new Bitmap(imagePath);
Rectangle displayArea = new Rectangle(pictureBoxPinYinSongCoords.X, pictureBoxPinYinSongCoords.Y, pictureBoxPinYinSongCoords.Width, pictureBoxPinYinSongCoords.Height);
// 建立一個矩形,表示 PictureBox 應該顯示的範圍
Rectangle displayArea = new Rectangle(
pictureBoxPinYinSongCoords.X, // 設定 X 座標
pictureBoxPinYinSongCoords.Y, // 設定 Y 座標
pictureBoxPinYinSongCoords.Width, // 設定 寬度
pictureBoxPinYinSongCoords.Height // 設定 高度
);
pictureBoxPinYinSongs.Image = originalImage;
// 將載入的圖片設定為 `pictureBoxPinYinSongs` 的影像
pictureBoxPinYinSongs.Image = originalImage;
// 調整 `PictureBox` 的大小與位置,使其符合 `displayArea` 的設定
ResizeAndPositionPictureBox(
pictureBoxPinYinSongs,
displayArea.X,
displayArea.Y,
displayArea.Width,
displayArea.Height
);
// 顯示 `PictureBox`
pictureBoxPinYinSongs.Visible = true;
ResizeAndPositionPictureBox(pictureBoxPinYinSongs, displayArea.X, displayArea.Y, displayArea.Width, displayArea.Height);
pictureBoxPinYinSongs.Visible = true;
}
// 設定拼音模式的 UI 是否可見
private void SetPinYinSongsAndButtonsVisibility(bool isVisible)
{
// 定義一個委派 (Action),用於更新 UI 控件的可見性
System.Action action = () =>
{
// 暫停佈局更新,以防止 UI 閃爍或重繪時出現異常
SuspendLayout();
// 設定 `pictureBoxPinYinSongs` 的可見性
pictureBoxPinYinSongs.Visible = isVisible;
if (isVisible) pictureBoxPinYinSongs.BringToFront();
if (isVisible) pictureBoxPinYinSongs.BringToFront(); // 確保顯示時位於最前方
// 設定所有拼音字母按鈕的可見性
foreach (var button in letterButtonsForPinYinSongs)
{
button.Visible = isVisible;
if (isVisible) button.BringToFront();
}
// 設定 `modifyButtonPinYinSongs` (修改按鈕) 的可見性
if (modifyButtonPinYinSongs != null)
{
modifyButtonPinYinSongs.Visible = isVisible;
if (isVisible) modifyButtonPinYinSongs.BringToFront();
}
// 設定 `clearButtonPinYinSongs` (清除按鈕) 的可見性
if (clearButtonPinYinSongs != null)
{
clearButtonPinYinSongs.Visible = isVisible;
if (isVisible) clearButtonPinYinSongs.BringToFront();
}
// 設定 `closeButtonPinYinSongs` (關閉按鈕) 的可見性
closeButtonPinYinSongs.Visible = isVisible;
if (isVisible) closeButtonPinYinSongs.BringToFront();
// 設定 `inputBoxPinYinSongs` (輸入框) 的可見性
inputBoxPinYinSongs.Visible = isVisible;
if (isVisible) inputBoxPinYinSongs.BringToFront();
// 恢復佈局,允許 UI 更新
ResumeLayout();
PerformLayout();
// 刷新 `pictureBoxPinYinSongs`,確保畫面更新
pictureBoxPinYinSongs.Refresh();
// 刷新拼音字母按鈕
foreach (var button in letterButtonsForPinYinSongs)
{
button.Refresh();
}
// 刷新其他按鈕與輸入框
modifyButtonPinYinSongs.Refresh();
clearButtonPinYinSongs.Refresh();
closeButtonPinYinSongs.Refresh();
inputBoxPinYinSongs.Refresh();
};
// 如果當前執行緒不是 UI 執行緒,則使用 Invoke 確保執行於 UI 執行緒
if (this.InvokeRequired)
{
this.Invoke(action);
@ -316,6 +426,7 @@ namespace DualScreenDemo
{
action();
}
}
}
}