This repository has been archived on 2025-06-24. You can view files and clone it, but cannot push or open issues or pull requests.
superstar/PrimaryFormParts/SongSearch/PrimaryForm.SongSearch.PinyinSearch.cs

432 lines
19 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.IO;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using IniParser;
using IniParser.Model;
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;
wordCountSearchSongButton.BackgroundImage = wordCountSearchSongNormalBackground;
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]}", // 按鈕名稱,例如 "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();
}
}
}
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 // 綁定按鈕的點擊事件處理函式
);
}
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 // 點擊事件處理函式
);
}
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, // 按鈕座標 (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; // 儲存解析後的 INI 數據
// 讀取 `config.ini` 文件,使用 UTF-8 編碼
using (var reader = new StreamReader("config.ini", System.Text.Encoding.UTF8))
{
data = parser.ReadData(reader);
}
// 從 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
)
};
// 設定輸入框的位置與大小
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); // 計算總頁數
// 更新 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"]), // 解析 X 座標
int.Parse(coords["Y"]), // 解析 Y 座標
int.Parse(coords["Width"]), // 解析 寬度
int.Parse(coords["Height"]) // 解析 高度
);
}
// 顯示拼音歌曲圖片
private void ShowImageOnPictureBoxPinYinSongs(string imagePath)
{
// 從設定檔載入 PictureBox 的座標與大小
LoadPictureBoxPinYinSongCoordsFromConfig();
// 使用指定的圖片路徑建立 Bitmap 影像
Bitmap originalImage = new Bitmap(imagePath);
// 建立一個矩形,表示 PictureBox 應該顯示的範圍
Rectangle displayArea = new Rectangle(
pictureBoxPinYinSongCoords.X, // 設定 X 座標
pictureBoxPinYinSongCoords.Y, // 設定 Y 座標
pictureBoxPinYinSongCoords.Width, // 設定 寬度
pictureBoxPinYinSongCoords.Height // 設定 高度
);
// 將載入的圖片設定為 `pictureBoxPinYinSongs` 的影像
pictureBoxPinYinSongs.Image = originalImage;
// 調整 `PictureBox` 的大小與位置,使其符合 `displayArea` 的設定
ResizeAndPositionPictureBox(
pictureBoxPinYinSongs,
displayArea.X,
displayArea.Y,
displayArea.Width,
displayArea.Height
);
// 顯示 `PictureBox`
pictureBoxPinYinSongs.Visible = true;
}
// 設定拼音模式的 UI 是否可見
private void SetPinYinSongsAndButtonsVisibility(bool isVisible)
{
// 定義一個委派 (Action),用於更新 UI 控件的可見性
System.Action action = () =>
{
// 暫停佈局更新,以防止 UI 閃爍或重繪時出現異常
SuspendLayout();
// 設定 `pictureBoxPinYinSongs` 的可見性
pictureBoxPinYinSongs.Visible = isVisible;
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);
}
else
{
action();
}
}
}
}