using System.IO; using System.Drawing.Imaging; using IniParser; using IniParser.Model; using System.Text; /* WordCountSongs -> SongIDSearch WordCount -> SongID numberWordCount -> numberSongID NumberWordCount -> NumberSongID inputBoxWordCountFontName -> inputBoxSongIDFontName inputBoxWordCountFontSize -> inputBoxSongIDFontSize inputBoxWordCountFontStyle -> inputBoxSongIDFontStyle inputBoxWordCountForeColor -> inputBoxSongIDForeColor LoadConfigDataforWordCountSongs -> LoadConfigDataforSongIDSearch LoadButtonCoordinatesForWordCountSongs -> LoadButtonCoordinatesForSongIDSearch LoadButtonImagesForWordCountSongs -> LoadButtonImagesForSongIDSearch LoadSpecialButtonCoordinatesForWordCountSongs -> LoadSpecialButtonCoordinatesForSongIDSearch RemoveWhiteBorderForWordCountSongs -> RemoveWhiteBorderForSongIDSearch CreateSpecialButtonForWordCountSongs -> CreateSpecialButtonForSongIDSearch LoadInputBoxConfigForWordCountSongs -> LoadInputBoxConfigForSongIDSearch */ namespace DualScreenDemo { public partial class PrimaryForm { private PictureBox pictureBoxSongIDSearch; private Button[] numberSongIDButtonsForSongs; private Button modifyButtonSongIDSearch; private Button clearButtonSongIDSearch; private Button closeButtonSongIDSearch; private string[] numberSongIDSymbols; private (int X, int Y, int Width, int Height)[] numberSongIDButtonCoords; private Dictionary numberSongIDButtonImages; private (int X, int Y, int Width, int Height) modifyButtonSongIDCoords; private (int X, int Y, int Width, int Height) clearButtonSongIDCoords; private (int X, int Y, int Width, int Height) closeButtonSongIDCoords; private RichTextBox inputBoxSongIDSearch; private (int X, int Y, int Width, int Height) inputBoxSongIDCoords; private string inputBoxSongIDFontName; private float inputBoxSongIDFontSize; private FontStyle inputBoxSongIDFontStyle; private Color inputBoxSongIDForeColor; /// /// 點擊「注音歌手搜尋」按鈕時執行的事件處理函式。 /// 此函式負責更新按鈕的背景圖片、載入對應的歌手圖片,並切換相關 UI 控件的可見性。 /// /// 觸發事件的物件(通常是按鈕本身)。 /// 事件參數。 private void SongIDSearchSongsButton_Click(object sender, EventArgs e) { // 設定按鈕背景,將「注音搜尋」設為啟動狀態,其餘按鈕恢復為正常狀態 zhuyinSearchSongButton.BackgroundImage = zhuyinSearchSongNormalBackground; englishSearchSongButton.BackgroundImage = englishSearchSongNormalBackground; pinyinSearchSongButton.BackgroundImage = pinyinSearchSongNormalBackground; wordCountSearchSongButton.BackgroundImage = wordCountSearchSongNormalBackground; handWritingSearchSongButton.BackgroundImage = handWritingSearchSongNormalBackground; numberSearchSongButton.BackgroundImage = numberSearchSongActiveBackground; // 載入設定檔,取得圖片路徑資訊 var configData = LoadConfigDataforSongIDSearch(); // 取得「注音歌手圖片」的完整路徑 string imagePath = Path.Combine(Application.StartupPath, configData["ImagePaths"]["SongIDSearch"]); // 在 PictureBox 中顯示對應的「注音歌手」圖片 ShowImageOnPictureBoxSongIDSearch(Path.Combine(Application.StartupPath, imagePath)); // 鍵盤UI介面顯示設定 SetWordCountSongsAndButtonsVisibility(false); SetEnglishSongsAndButtonsVisibility(false); SetPinYinSongsAndButtonsVisibility(false); SetHandWritingForSongsAndButtonsVisibility(false); SetSongIDSearchAndButtonsVisibility(true); SetZhuYinSongsAndButtonsVisibility(false); ResetinputBox(); SetSongIDSearchAndButtonsVisibility(true); // 顯示字數搜尋相關控件 // 顯示「注音歌手搜尋」的圖片框 pictureBoxSongIDSearch.Visible = true; } /// /// 從 config.ini 設定檔中載入注音符號(NumberWordCount Symbols)。 /// 讀取 ini 檔的 [NumberWordCountSymbols] 區塊,並將「Symbols」欄位的值解析為陣列。 /// private void LoadNumberSongIDSymbolsFromConfig() { // 建立 INI 檔案解析器 var parser = new FileIniDataParser(); // 設定檔路徑 string iniFilePath = "config.ini"; IniData data; // 以 UTF-8 編碼開啟並讀取 INI 檔案 using (var reader = new StreamReader(iniFilePath, Encoding.UTF8)) { // 解析 INI 檔內容 data = parser.ReadData(reader); } // 取得 [NumberSongIDSymbols] 區塊中的 "Symbols" 欄位內容 string symbols = data["NumberSongIDSymbols"]["Symbols"]; // 將符號字串以逗號分隔,轉換為字串陣列 numberSongIDSymbols = symbols.Split(','); } /// /// 從設定檔 (config.ini) 載入 INI 設定數據。 /// /// 回傳解析後的 INI 設定數據 (IniData)。 private IniData LoadConfigDataforSongIDSearch() { var parser = new FileIniDataParser(); string iniFilePath = "config.ini"; // 使用 UTF-8 讀取 INI 檔案並解析內容 using (var reader = new StreamReader(iniFilePath, Encoding.UTF8)) { return parser.ReadData(reader); } } /// /// 從 INI 設定數據中讀取注音符號 (NumberSongID Symbols)。 /// /// 已解析的 INI 設定數據。 /// 回傳包含注音符號的字串陣列。 private string[] LoadNumberSongIDSymbols(IniData data) { // 從 INI 檔案的 [NumberSongIDSymbols] 區塊取得 Symbols 欄位值 string symbols = data["NumberSongIDSymbols"]["Symbols"]; // 以逗號分隔字串並轉換為字串陣列 return symbols.Split(','); } /// /// 從 INI 設定數據中載入按鈕座標資料。 /// /// 已解析的 INI 設定數據。 /// 設定檔中按鈕座標所屬的區塊名稱。 /// 按鈕數量。 /// 回傳包含按鈕座標的陣列,每個元素是由 (X, Y, Width, Height) 組成的元組。 private (int X, int Y, int Width, int Height)[] LoadButtonCoordinatesForSongIDSearch(IniData data, string section, int buttonCount) { var buttonList = new List<(int X, int Y, int Width, int Height)>(); // 迴圈讀取每個按鈕的座標設定 for (int i = 1; i <= buttonCount; i++) { // 取得按鈕座標的字串 (格式: X,Y,Width,Height) var coordString = data[section][$"button{i}"]; var coords = coordString.Split(','); // 將座標資料轉換為 (X, Y, Width, Height) 元組並加入清單 buttonList.Add(( int.Parse(coords[0]), // X 座標 int.Parse(coords[1]), // Y 座標 int.Parse(coords[2]), // 寬度 int.Parse(coords[3]) // 高度 )); } // 回傳所有按鈕座標的陣列 return buttonList.ToArray(); } /// /// 從 INI 設定數據中載入按鈕圖片檔案路徑資料 (包含正常、點擊、滑鼠移過圖片)。 /// /// 已解析的 INI 設定數據。 /// 設定檔中按鈕圖片設定所屬的區塊名稱。 /// 按鈕數量。 /// 回傳一個字典,鍵是按鈕名稱,值是包含正常、點擊和滑鼠移過狀態的元組。 private Dictionary LoadButtonImagesForSongIDSearch(IniData data, string section, int buttonCount) { var buttonImages = new Dictionary(); // 迴圈讀取每個按鈕的圖片設定 for (int i = 0; i < 10; i++) { // 讀取按鈕的三種圖片狀態:正常、點擊、滑鼠移過 buttonImages[$"button{i}"] = ( data[section][$"button{i}_normal"], // 正常狀態圖片路徑 data[section][$"button{i}_mouseDown"], // 點擊狀態圖片路徑 data[section][$"button{i}_mouseOver"] // 滑鼠移過狀態圖片路徑 ); } // 回傳包含所有按鈕圖片路徑資料的字典 return buttonImages; } /// /// 從 INI 設定數據中載入特定按鈕的座標資料。 /// /// 已解析的 INI 設定數據。 /// 設定檔中按鈕座標所屬的區塊名稱。 /// 指定按鈕的鍵名 (如 "button1")。 /// 回傳包含按鈕座標的元組 (X, Y, Width, Height)。 private (int X, int Y, int Width, int Height) LoadSpecialButtonCoordinatesForSongIDSearch(IniData data, string section, string buttonKey) { // 取得按鈕座標的字串 (格式: X,Y,Width,Height) var coords = data[section][buttonKey].Split(','); // 解析座標字串並回傳 (X, Y, Width, Height) 元組 return (int.Parse(coords[0]), int.Parse(coords[1]), int.Parse(coords[2]), int.Parse(coords[3])); } /// /// 從 INI 設定數據中載入按鈕的圖片資料 (包含正常、點擊、滑鼠移過圖片)。 /// /// 已解析的 INI 設定數據。 /// 設定檔中按鈕圖片設定所屬的區塊名稱。 /// 回傳包含按鈕三種狀態圖片路徑的元組 (normal, mouseDown, mouseOver)。 private (string normal, string mouseDown, string mouseOver) LoadButtonImagesForSongIDSearch(IniData data, string section) { // 讀取按鈕三種狀態的圖片路徑 return ( data[section]["normal"], // 正常狀態圖片路徑 data[section]["mouseDown"], // 點擊狀態圖片路徑 data[section]["mouseOver"] // 滑鼠移過狀態圖片路徑 ); } /// /// 初始化並設置語音按鈕的相關資料,包括符號、座標與圖片等。 /// private void InitializeNumberSongIDButtons() { // 載入配置資料 var data = LoadConfigDataforSongIDSearch(); // 載入語音符號(如拼音、注音符號等) numberSongIDSymbols = LoadNumberSongIDSymbols(data); // 載入按鈕座標資料 numberSongIDButtonCoords = LoadButtonCoordinatesForSongIDSearch(data, "NumberSongIDButtonCoordinates", 10); // 載入按鈕圖片資料 numberSongIDButtonImages = LoadButtonImagesForSongIDSearch(data, "NumberSongIDButtonImages", 10); // 初始化語音按鈕陣列,總共有 10 個按鈕 numberSongIDButtonsForSongs = new Button[10]; // 設置每個語音按鈕 for (int i = 0; i < 10; i++) { // 根據按鈕索引讀取其圖片資料 var buttonImages = numberSongIDButtonImages[$"button{i}"]; // 創建並初始化語音按鈕,設定其背景圖片 CreateNumberSongIDButton(i, buttonImages.normal, buttonImages.mouseDown, buttonImages.mouseOver); } } /// /// 創建一個語音按鈕,並為其設置圖片、座標、事件等屬性。 /// /// 按鈕的索引,用來獲取對應的語音符號、座標和圖片資料。 /// 正常狀態下的圖片路徑。 /// 點擊狀態下的圖片路徑。 /// 滑鼠移過狀態下的圖片路徑。 private void CreateNumberSongIDButton(int index, string normalImagePath, string mouseDownImagePath, string mouseOverImagePath) { try { // 創建語音按鈕並設置其屬性 numberSongIDButtonsForSongs[index] = new Button { Name = $"numberSongIDButton_{numberSongIDSymbols[index]}", // 按鈕名稱設為語音符號名稱 BackgroundImage = Image.FromFile(Path.Combine(Application.StartupPath, normalImagePath)), // 設定背景圖片 BackgroundImageLayout = ImageLayout.Stretch, // 設定圖片拉伸樣式 FlatStyle = FlatStyle.Flat, // 設定為平面風格 FlatAppearance = { BorderSize = 0 } // 設定無邊框 }; // 調整按鈕大小並設置位置 ResizeAndPositionButton(numberSongIDButtonsForSongs[index], numberSongIDButtonCoords[index].X, numberSongIDButtonCoords[index].Y, numberSongIDButtonCoords[index].Width, numberSongIDButtonCoords[index].Height); // 從檔案中讀取正常、點擊和滑鼠懸停狀態的圖片 Image normalImage = Image.FromFile(Path.Combine(Application.StartupPath, normalImagePath)); Image mouseDownImage = Image.FromFile(Path.Combine(Application.StartupPath, mouseDownImagePath)); Image mouseOverImage = Image.FromFile(Path.Combine(Application.StartupPath, mouseOverImagePath)); // 設置滑鼠事件:點擊、進入、離開等,改變按鈕的背景圖片 numberSongIDButtonsForSongs[index].MouseDown += (s, e) => numberSongIDButtonsForSongs[index].BackgroundImage = mouseDownImage; numberSongIDButtonsForSongs[index].MouseUp += (s, e) => numberSongIDButtonsForSongs[index].BackgroundImage = normalImage; numberSongIDButtonsForSongs[index].MouseEnter += (s, e) => numberSongIDButtonsForSongs[index].BackgroundImage = mouseOverImage; numberSongIDButtonsForSongs[index].MouseLeave += (s, e) => numberSongIDButtonsForSongs[index].BackgroundImage = normalImage; // 設置點擊事件處理方法 numberSongIDButtonsForSongs[index].Click += NumberSongIDButton_Click; // 設置按鈕的 Tag 屬性為對應的語音符號 numberSongIDButtonsForSongs[index].Tag = numberSongIDSymbols[index]; // 將按鈕添加到表單的控制項集合中 this.Controls.Add(numberSongIDButtonsForSongs[index]); } catch (Exception ex) { // 捕捉錯誤並輸出錯誤訊息 Console.WriteLine($"Error creating button at index {index}: {ex.Message}"); } } /// /// 初始化所有與注音歌手相關的按鈕,包括語音符號按鈕、特殊按鈕及輸入框。 /// private void InitializeButtonsForSongIDSearch() { // 從配置檔案加載注音符號並初始化按鈕 LoadNumberSongIDSymbolsFromConfig(); // 初始化所有語音按鈕 InitializeNumberSongIDButtons(); // 初始化注音歌手的特殊按鈕(例如音量、搜尋等) InitializeSpecialButtonsForSongIDSearch(); // 初始化注音歌手的輸入框 InitializeInputBoxSongIDSearch(); } /// /// 移除圖像周圍的白色邊框,將邊框的像素透明化。 /// /// 待處理的圖像文件路徑。 /// 處理後的圖像,其中白色邊框已被去除並替換為透明。 private Image RemoveWhiteBorderForSongIDSearch(string imagePath) { // 創建一個 Bitmap 物件來加載圖像 Bitmap bmp = new Bitmap(imagePath); // 定義圖像的矩形區域,這是我們將要操作的區域 Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height); // 鎖定圖像的位圖數據,以便進行直接修改 BitmapData bmpData = bmp.LockBits(rect, ImageLockMode.ReadWrite, bmp.PixelFormat); IntPtr ptr = bmpData.Scan0; // 獲取位圖數據的起始位置 int bytes = Math.Abs(bmpData.Stride) * bmp.Height; // 計算圖像的總字節數 byte[] rgbValues = new byte[bytes]; // 用來存儲圖像的像素數據 System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes); // 從圖像數據中複製像素數據到 rgbValues 陣列 // 遍歷每個像素點,檢查是否為白色邊框 for (int y = 0; y < bmp.Height; y++) { for (int x = 0; x < bmp.Width; x++) { int position = (y * bmpData.Stride) + (x * 4); // 計算當前像素的位址 byte b = rgbValues[position]; // 藍色分量 byte g = rgbValues[position + 1]; // 綠色分量 byte r = rgbValues[position + 2]; // 紅色分量 byte a = rgbValues[position + 3]; // alpha 分量(透明度) // 如果當前像素在圖像邊緣且為白色 (255, 255, 255),則將其設為透明 if ((x < 5 || x > bmp.Width - 5 || y < 5 || y > bmp.Height - 5) && r == 255 && g == 255 && b == 255) { // 將白色像素的 RGB 設置為 255, 255, 255 且 alpha 設為 0 (透明) rgbValues[position] = 255; rgbValues[position + 1] = 255; rgbValues[position + 2] = 255; rgbValues[position + 3] = 0; // 透明 } } } // 將修改後的像素數據重新複製回位圖數據 System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, bytes); // 解鎖圖像數據 bmp.UnlockBits(bmpData); // 返回處理後的圖像 return bmp; } /// /// 初始化與注音歌手相關的特殊按鈕,包括修改、清除和關閉按鈕。 /// private void InitializeSpecialButtonsForSongIDSearch() { // 初始化修改按鈕 InitializeModifyButtonSongIDSearch(); // 初始化清除按鈕 InitializeClearButtonSongIDSearch(); // 初始化關閉按鈕 InitializeCloseButtonSongIDSearch(); } /// /// 初始化「修改」按鈕,設定按鈕的坐標、圖片和點擊事件。 /// private void InitializeModifyButtonSongIDSearch() { // 加載配置數據 var data = LoadConfigDataforSongIDSearch(); // 讀取按鈕坐標 modifyButtonSongIDCoords = LoadSpecialButtonCoordinatesForSongIDSearch(data, "SpecialButtonCoordinates", "modifyButtonSongIDSearch"); // 加載按鈕圖片(正常、鼠標懸停、鼠標按下) var buttonImages = LoadButtonImagesForSongIDSearch(data, "ModifyButtonImagesSongID"); // 創建「修改」按鈕,並設置坐標、圖片及點擊事件 modifyButtonSongIDSearch = CreateSpecialButtonForSongIDSearch( "btnModifySongIDSearch", // 按鈕名稱 modifyButtonSongIDCoords, // 按鈕坐標 buttonImages.normal, // 正常狀態圖片 buttonImages.mouseOver, // 鼠標懸停圖片 buttonImages.mouseDown, // 鼠標按下圖片 ModifyButtonSongIDSearch_Click // 按鈕點擊事件 ); } /// /// 處理「修改」按鈕的點擊事件,該事件會刪除輸入框中的最後一個字符。 /// /// 觸發事件的對象 /// 事件參數 private void ModifyButtonSongIDSearch_Click(object sender, EventArgs e) { // 如果輸入框不為空,且包含輸入內容,則刪除最後一個字符 if (this.Controls.Contains(inputBoxSongIDSearch) && inputBoxSongIDSearch.Text.Length > 0) { inputBoxSongIDSearch.Text = inputBoxSongIDSearch.Text.Substring(0, inputBoxSongIDSearch.Text.Length - 1); } } /// /// 初始化「清除」按鈕,設定按鈕的坐標、圖片和點擊事件。 /// private void InitializeClearButtonSongIDSearch() { // 加載配置數據 var data = LoadConfigDataforSongIDSearch(); // 讀取按鈕坐標 clearButtonSongIDCoords = LoadSpecialButtonCoordinatesForSongIDSearch(data, "SpecialButtonCoordinates", "clearButtonSongIDSearch"); // 加載按鈕圖片(正常、鼠標懸停、鼠標按下) var buttonImages = LoadButtonImagesForSongIDSearch(data, "ClearButtonImagesSongID"); // 創建「清除」按鈕,並設置坐標、圖片及點擊事件 clearButtonSongIDSearch = CreateSpecialButtonForSongIDSearch( "btnClearSongIDSearch", // 按鈕名稱 clearButtonSongIDCoords, // 按鈕坐標 buttonImages.normal, // 正常狀態圖片 buttonImages.mouseOver, // 鼠標懸停圖片 buttonImages.mouseDown, // 鼠標按下圖片 ClearButtonSongIDSearch_Click // 按鈕點擊事件 ); } /// /// 處理「清除」按鈕的點擊事件,該事件會清空輸入框中的所有文本。 /// /// 觸發事件的對象 /// 事件參數 private void ClearButtonSongIDSearch_Click(object sender, EventArgs e) { // 如果輸入框不為空,則清空該框的文本內容 if (this.Controls.Contains(inputBoxSongIDSearch) && inputBoxSongIDSearch.Text.Length > 0) { inputBoxSongIDSearch.Text = ""; } } /// /// 初始化「關閉」按鈕,設定按鈕的坐標、圖片和點擊事件。 /// private void InitializeCloseButtonSongIDSearch() { // 加載配置數據 var data = LoadConfigDataforSongIDSearch(); // 讀取按鈕坐標 closeButtonSongIDCoords = LoadSpecialButtonCoordinatesForSongIDSearch(data, "SpecialButtonCoordinates", "closeButtonSongIDSearch"); // 加載按鈕圖片(正常、鼠標懸停、鼠標按下) var buttonImages = LoadButtonImagesForSongIDSearch(data, "CloseButtonImagesSongID"); // 創建「關閉」按鈕,並設置坐標、圖片及點擊事件 closeButtonSongIDSearch = CreateSpecialButtonForSongIDSearch( "btnCloseSongIDSearch", // 按鈕名稱 closeButtonSongIDCoords, // 按鈕坐標 buttonImages.normal, // 正常狀態圖片 buttonImages.mouseOver, // 鼠標懸停圖片 buttonImages.mouseDown, // 鼠標按下圖片 CloseButtonSongIDSearch_Click // 按鈕點擊事件 ); } /// /// 「關閉」按鈕的點擊事件處理方法。 /// 隱藏 SongID 歌手圖片框以及與其相關的按鈕。 /// /// 觸發事件的對象,這裡是關閉按鈕。 /// 事件參數。 private void CloseButtonSongIDSearch_Click(object sender, EventArgs e) { // 隱藏 SongID 歌手圖片框 pictureBoxSongIDSearch.Visible = false; numberSearchSongButton.BackgroundImage = numberSearchSongNormalBackground; // 隱藏與 SongID 歌手相關的所有按鈕 SetSongIDSearchAndButtonsVisibility(false); } /// /// 創建一個特殊的按鈕,並設定其顯示屬性、事件處理和位置。 /// /// 按鈕的名稱。 /// 按鈕的坐標和大小,包含 X, Y, 寬度和高度。 /// 按鈕正常狀態下的背景圖片路徑。 /// 鼠標懸停時按鈕的背景圖片路徑。 /// 鼠標點擊時按鈕的背景圖片路徑。 /// 按鈕的點擊事件處理程序。 /// 創建並返回的按鈕對象。 private Button CreateSpecialButtonForSongIDSearch(string name, (int X, int Y, int Width, int Height) coords, string normalImagePath, string mouseOverImagePath, string mouseDownImagePath, EventHandler clickEventHandler) { // 創建按鈕並設定基本屬性 var button = new Button { Name = name, FlatStyle = FlatStyle.Flat, FlatAppearance = { BorderSize = 0, MouseDownBackColor = Color.Transparent, MouseOverBackColor = Color.Transparent }, BackgroundImageLayout = ImageLayout.Stretch, BackgroundImage = Image.FromFile(Path.Combine(Application.StartupPath, normalImagePath)) }; // 設定按鈕的大小和位置 ResizeAndPositionButton(button, coords.X, coords.Y, coords.Width, coords.Height); // 設定鼠標事件:進入、離開、按下、放開 button.MouseEnter += (sender, e) => button.BackgroundImage = Image.FromFile(Path.Combine(Application.StartupPath, mouseOverImagePath)); button.MouseLeave += (sender, e) => button.BackgroundImage = Image.FromFile(Path.Combine(Application.StartupPath, normalImagePath)); button.MouseDown += (sender, e) => button.BackgroundImage = Image.FromFile(Path.Combine(Application.StartupPath, mouseDownImagePath)); button.MouseUp += (sender, e) => button.BackgroundImage = Image.FromFile(Path.Combine(Application.StartupPath, normalImagePath)); // 註冊點擊事件處理 button.Click += clickEventHandler; // 將按鈕添加到控件集合中 this.Controls.Add(button); return button; } /// /// 初始化 SongID 歌手的輸入框,並設定其屬性與事件處理程序。 /// private void InitializeInputBoxSongIDSearch() { try { // 加載輸入框配置 LoadInputBoxConfigForSongIDSearch(); // 創建一個 RichTextBox 控件來作為輸入框 inputBoxSongIDSearch = new RichTextBox { Name = "inputBoxSongIDSearch", ForeColor = inputBoxSongIDForeColor, // 設定文字顏色 Font = new Font(inputBoxSongIDFontName, inputBoxSongIDFontSize, inputBoxSongIDFontStyle), // 設定字體樣式 ScrollBars = RichTextBoxScrollBars.None // 不顯示滾動條 }; // 調整和定位輸入框的位置及大小 ResizeAndPositionControl(inputBoxSongIDSearch, inputBoxSongIDCoords.X, inputBoxSongIDCoords.Y, inputBoxSongIDCoords.Width, inputBoxSongIDCoords.Height); // 設定文本變更事件,當輸入框內容改變時觸發 inputBoxSongIDSearch.TextChanged += (sender, e) => { string searchText = inputBoxSongIDSearch.Text; // 取得輸入內容 // 根據輸入的注音篩選歌曲清單 var searchResults = allSongs.Where(song => song.SongNumber.StartsWith(searchText)).ToList(); // 重置分頁 currentPage = 0; currentSongList = searchResults; totalPages = (int)Math.Ceiling((double)searchResults.Count / itemsPerPage); // 更新多頁面面板的內容 multiPagePanel.currentPageIndex = 0; multiPagePanel.LoadSongs(currentSongList); }; // 將輸入框加入到窗體的控件集合中 this.Controls.Add(inputBoxSongIDSearch); } catch (Exception ex) { // 如果初始化過程中出現錯誤,則在控制台輸出錯誤信息 Console.WriteLine("Error initializing inputBoxSongIDSearch: " + ex.Message); } } /// /// 從配置文件 `config.ini` 中加載輸入框的設置,包括位置、大小、字體等屬性。 /// private void LoadInputBoxConfigForSongIDSearch() { try { // 創建 INI 解析器 var parser = new FileIniDataParser(); string iniFilePath = "config.ini"; // 配置文件的路徑 IniData data; // 打開並讀取配置文件 using (var reader = new StreamReader(iniFilePath, Encoding.UTF8)) { data = parser.ReadData(reader); } // 從配置中加載輸入框的坐標和大小 inputBoxSongIDCoords = ( int.Parse(data["InputBoxSongIDSearch"]["X"]), // 輸入框的 X 坐標 int.Parse(data["InputBoxSongIDSearch"]["Y"]), // 輸入框的 Y 坐標 int.Parse(data["InputBoxSongIDSearch"]["Width"]), // 輸入框的寬度 int.Parse(data["InputBoxSongIDSearch"]["Height"]) // 輸入框的高度 ); // 從配置中加載字體屬性 inputBoxSongIDFontName = data["InputBoxSongIDSearch"]["FontName"]; // 字體名稱 inputBoxSongIDFontSize = float.Parse(data["InputBoxSongIDSearch"]["FontSize"]); // 字體大小 inputBoxSongIDFontStyle = (FontStyle)Enum.Parse(typeof(FontStyle), data["InputBoxSongIDSearch"]["FontStyle"]); // 字體樣式 inputBoxSongIDForeColor = Color.FromName(data["InputBoxSongIDSearch"]["ForeColor"]); // 字體顏色 } catch (Exception ex) { // 若發生錯誤,顯示錯誤信息 Console.WriteLine("Error loading inputBox configuration: " + ex.Message); } } /// /// 存儲 `pictureBoxSongIDSearch` 控制項的坐標和大小設置。 /// /// /// 這個元組包含了 `X`、`Y` 坐標以及 `Width`、`Height` 大小,用於配置 `pictureBoxSongIDSearch` 的位置和大小。 /// private (int X, int Y, int Width, int Height) pictureBoxSongIDSongCoords; /// /// 從配置檔案中讀取 `PictureBoxSongIDSearch` 控制項的坐標和大小設置。 /// private void LoadPictureBoxSongIDSongCoordsFromConfig() { var parser = new FileIniDataParser(); IniData data = parser.ReadFile("config.ini"); var coords = data["PictureBoxSongIDSearch"]; pictureBoxSongIDSongCoords = ( int.Parse(coords["X"]), int.Parse(coords["Y"]), int.Parse(coords["Width"]), int.Parse(coords["Height"]) ); } /// /// 顯示圖片並根據配置文件設置顯示區域的大小和位置。 /// /// 圖片的路徑。 private void ShowImageOnPictureBoxSongIDSearch(string imagePath) { // 讀取配置文件中的顯示區域設置 LoadPictureBoxSongIDSongCoordsFromConfig(); // 加載原始圖片 Bitmap originalImage = new Bitmap(imagePath); // 創建顯示區域,根據配置文件中的坐標和大小設置 Rectangle displayArea = new Rectangle(pictureBoxSongIDSongCoords.X, pictureBoxSongIDSongCoords.Y, pictureBoxSongIDSongCoords.Width, pictureBoxSongIDSongCoords.Height); // 設置圖片到 PictureBox pictureBoxSongIDSearch.Image = originalImage; // 調整 PictureBox 大小和位置 ResizeAndPositionPictureBox(pictureBoxSongIDSearch, displayArea.X, displayArea.Y, displayArea.Width, displayArea.Height); // 顯示圖片 pictureBoxSongIDSearch.Visible = true; } /// /// 設置注音歌手相關控制項(包括圖片框、按鈕和輸入框)的顯示或隱藏狀態。 /// /// 指定控件是否可見。True 為顯示,False 為隱藏。 private void SetSongIDSearchAndButtonsVisibility(bool isVisible) { // 定義一個動作來處理控制項的顯示或隱藏 System.Action action = () => { try { // 暫停控制項佈局的重新排版,提高效率 SuspendLayout(); // 檢查並設置圖片框的可見性 if (pictureBoxSongIDSearch == null) { Console.WriteLine("pictureBoxSongIDSearch is null"); } else { pictureBoxSongIDSearch.Visible = isVisible; if (isVisible) pictureBoxSongIDSearch.BringToFront(); // 如果顯示,將其置於最前 } // 檢查並設置拼音按鈕的可見性 if (numberSongIDButtonsForSongs == null) { Console.WriteLine("numberSongIDButtonsForSongs is null"); } else { foreach (var button in numberSongIDButtonsForSongs) { if (button == null) { Console.WriteLine("One of the numberSongIDButtonsForSongs is null"); } else { button.Visible = isVisible; if (isVisible) button.BringToFront(); // 如果顯示,將其置於最前 } } } // 檢查並設置修改按鈕的可見性 if (modifyButtonSongIDSearch == null) { Console.WriteLine("modifyButtonSongIDSearch is null"); } else { modifyButtonSongIDSearch.Visible = isVisible; if (isVisible) modifyButtonSongIDSearch.BringToFront(); // 如果顯示,將其置於最前 } // 檢查並設置清除按鈕的可見性 if (clearButtonSongIDSearch == null) { Console.WriteLine("clearButtonSongIDSearch is null"); } else { clearButtonSongIDSearch.Visible = isVisible; if (isVisible) clearButtonSongIDSearch.BringToFront(); // 如果顯示,將其置於最前 } // 檢查並設置關閉按鈕的可見性 if (closeButtonSongIDSearch == null) { Console.WriteLine("closeButtonSongIDSearch is null"); } else { closeButtonSongIDSearch.Visible = isVisible; if (isVisible) closeButtonSongIDSearch.BringToFront(); // 如果顯示,將其置於最前 } // 檢查並設置輸入框的可見性 if (inputBoxSongIDSearch == null) { Console.WriteLine("inputBoxSongIDSearch is null"); } else { inputBoxSongIDSearch.Visible = isVisible; if (isVisible) inputBoxSongIDSearch.BringToFront(); // 如果顯示,將其置於最前 } // 恢復控制項的佈局重新排版 ResumeLayout(); PerformLayout(); // 刷新所有控制項的顯示 pictureBoxSongIDSearch?.Refresh(); if (numberSongIDButtonsForSongs != null) { foreach (var button in numberSongIDButtonsForSongs) { button?.Refresh(); // 刷新每個按鈕 } } modifyButtonSongIDSearch?.Refresh(); clearButtonSongIDSearch?.Refresh(); closeButtonSongIDSearch?.Refresh(); inputBoxSongIDSearch?.Refresh(); } catch (Exception ex) { Console.WriteLine("Error in SetSongIDSearchAndButtonsVisibility: " + ex.Message); } }; // 檢查是否需要在主執行緒外執行 if (this.InvokeRequired) { this.Invoke(action); // 如果需要,透過主執行緒執行 } else { action(); // 否則直接執行 } } private void NumberSongIDButton_Click(object sender, EventArgs e) { var button = sender as Button; if (button != null && button.Tag != null) { if (inputBoxSongIDSearch.Visible) { inputBoxSongIDSearch.Text += button.Tag.ToString(); } } } } }