superstar_v2/PrimaryFormParts/SongSearch/PrimaryForm.SongSearch.BopomofoSearch.cs
2025-06-17 09:31:00 +08:00

563 lines
25 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.IO;
using IniParser;
using IniParser.Model;
/* Song Search with ZhuYin */
namespace DualScreenDemo
{
public partial class PrimaryForm
{
// 注音歌曲的 PictureBox
private PictureBox pictureBoxZhuYinSongs;
//存放注音按鈕的陣列
private Button[] phoneticButtonsForSongs;
//特殊功能按鈕(修改、清除、關閉)
private Button modifyButtonZhuYinSongs;
private Button clearButtonZhuYinSongs;
private Button closeButtonZhuYinSongs;
//用於顯示輸入文字的輸入框
private RichTextBox inputBoxZhuYinSongs;
/// <summary>
/// 注音歌曲搜尋按鈕點擊事件
/// </summary>
private void ZhuyinSearchSongsButton_Click(object sender, EventArgs e)
{
//更新搜尋模式按鈕的背景圖
zhuyinSearchSongButton.BackgroundImage = zhuyinSearchSongActiveBackground;
englishSearchSongButton.BackgroundImage = englishSearchSongNormalBackground;
pinyinSearchSongButton.BackgroundImage = pinyinSearchSongNormalBackground;
wordCountSearchSongButton.BackgroundImage = wordCountSearchSongNormalBackground;
handWritingSearchSongButton.BackgroundImage = handWritingSearchSongNormalBackground;
numberSearchSongButton.BackgroundImage = numberSearchSongNormalBackground;
// 讀取 config.ini 並獲取注音圖片的路徑
var configData = LoadConfigData();
string imagePath = Path.Combine(Application.StartupPath, configData["ImagePaths"]["ZhuYinSongs"]);
//顯示注音歌曲圖片
ShowImageOnPictureBoxZhuYinSongs(Path.Combine(Application.StartupPath, imagePath));
//設定不同模式的UI顯示
SetWordCountSongsAndButtonsVisibility(false); // 隱藏字數搜尋相關控件
SetEnglishSongsAndButtonsVisibility(false);
SetPinYinSongsAndButtonsVisibility(false);
SetHandWritingForSongsAndButtonsVisibility(false);
SetSongIDSearchAndButtonsVisibility(false);
SetZhuYinSongsAndButtonsVisibility(true);
ResetinputBox();
pictureBoxZhuYinSongs.Visible = true;
}
/// <summary>
/// 初始化注音按鈕 (Phonetic Buttons) 並載入其對應的圖片與座標
/// <para>1. 讀取 config.ini 設定檔,獲取按鈕的相關數據 (符號、座標、圖片)</para>
/// <para>2. 解析注音符號並儲存至 phoneticSymbols 陣列</para>
/// <para>3. 解析按鈕的座標資訊,存入 phoneticButtonCoords</para>
/// <para>4. 解析按鈕的圖片 (正常狀態、按下狀態、懸停狀態),存入 phoneticButtonImages。</para>
/// <para>5. 依序建立 35 個注音按鈕,並套用對應的圖片與事件處理函數。</para>
/// </summary>
private void InitializePhoneticButtonsForSongs()
{
// 1. 從設定檔 (config.ini) 讀取配置數據,包含按鈕座標、圖片等
var data = LoadConfigData();
// 2. 讀取注音符號列表,這些符號將用於顯示在按鈕上
phoneticSymbols = LoadPhoneticSymbols(data);
// 3. 從設定檔載入 **注音按鈕的座標**,每個按鈕都有對應的 (X, Y, Width, Height)
phoneticButtonCoords = LoadButtonCoordinates(data, "PhoneticButtonCoordinates", 35);
// 4. 從設定檔載入 **注音按鈕的圖片**,每個按鈕都有正常、按下、懸停三種狀態
phoneticButtonImages = LoadButtonImages(data, "PhoneticButtonImages", 35);
// 5. 建立 35 個注音按鈕的陣列 (每個按鈕對應一個注音符號)
phoneticButtonsForSongs = new Button[35];
// 6. 迴圈建立所有的注音按鈕
for (int i = 0; i < 35; i++)
{
// 取得當前按鈕的圖片 (從已載入的 phoneticButtonImages 字典中獲取)
var buttonImages = phoneticButtonImages[$"button{i}"];
// 建立單個注音按鈕,並設定其圖片與點擊事件
CreatePhoneticButtonForSongs(
i, // 按鈕索引 (對應於 phoneticSymbols)
buttonImages.normal, // 按鈕的普通狀態圖片
buttonImages.mouseDown, // 按下時的圖片
buttonImages.mouseOver // 滑鼠懸停時的圖片
);
}
}
/// <summary>
/// 建立單個注音按鈕,並設定其圖片、大小、位置,以及滑鼠事件。
/// </summary>
/// <param name="index">按鈕索引 (對應於 phoneticSymbols)</param>
/// <param name="normalImagePath">按鈕的普通狀態圖片路徑</param>
/// <param name="mouseDownImagePath">按鈕被按下時的圖片路徑</param>
/// <param name="mouseOverImagePath">滑鼠懸停時的圖片路徑</param>
private void CreatePhoneticButtonForSongs(int index, string normalImagePath, string mouseDownImagePath, string mouseOverImagePath)
{
try
{
// 1. 創建按鈕並初始化屬性
phoneticButtonsForSongs[index] = new Button
{
Name = $"phoneticButton_{phoneticSymbols[index]}", // 設定按鈕名稱,方便識別
BackgroundImage = Image.FromFile(Path.Combine(Application.StartupPath, normalImagePath)), // 設定預設背景圖
BackgroundImageLayout = ImageLayout.Stretch, // 背景圖自動填滿按鈕
FlatStyle = FlatStyle.Flat, // 設定按鈕為扁平樣式
FlatAppearance = { BorderSize = 0 } // 移除按鈕的邊框
};
// 2. 設定按鈕的大小與位置
ResizeAndPositionButton(
phoneticButtonsForSongs[index],
phoneticButtonCoords[index].X,
phoneticButtonCoords[index].Y,
phoneticButtonCoords[index].Width,
phoneticButtonCoords[index].Height
);
// 3. 載入三種狀態的圖片
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));
// 4. 設定滑鼠事件,改變背景圖
phoneticButtonsForSongs[index].MouseDown += (s, e) => phoneticButtonsForSongs[index].BackgroundImage = mouseDownImage;
phoneticButtonsForSongs[index].MouseUp += (s, e) => phoneticButtonsForSongs[index].BackgroundImage = normalImage;
phoneticButtonsForSongs[index].MouseEnter += (s, e) => phoneticButtonsForSongs[index].BackgroundImage = mouseOverImage;
phoneticButtonsForSongs[index].MouseLeave += (s, e) => phoneticButtonsForSongs[index].BackgroundImage = normalImage;
// 5. 設定按鈕的點擊事件 (當按下按鈕時,觸發 PhoneticButton_Click)
phoneticButtonsForSongs[index].Click += PhoneticButton_Click;
// 6. 存入對應的注音符號,方便之後的處理
phoneticButtonsForSongs[index].Tag = phoneticSymbols[index];
// 7. 將按鈕加入視窗
this.Controls.Add(phoneticButtonsForSongs[index]);
}
catch (Exception ex)
{
// 例外處理,確保按鈕建立失敗時不影響其他部分
Console.WriteLine($"Error creating button at index {index}: {ex.Message}");
}
}
/// <summary>
/// 初始化注音輸入界面的所有按鈕和輸入框。
/// </summary>
private void InitializeButtonsForZhuYinSongs()
{
// 1. 從設定檔 (config.ini) 載入注音符號
LoadPhoneticSymbolsFromConfig();
// 2. 初始化 35 個注音按鈕
InitializePhoneticButtonsForSongs();
// 3. 初始化特殊按鈕 (例如:刪除、確定、返回按鈕)
InitializeSpecialButtonsForZhuYinSongs();
// 4. 初始化輸入框 (用於顯示使用者輸入的注音符號)
InitializeInputBoxZhuYinSongs();
}
/// <summary>
/// 初始化注音輸入界面的特殊按鈕,包括「修改」、「清除」和「關閉」。
/// </summary>
private void InitializeSpecialButtonsForZhuYinSongs()
{
// 1. 初始化「修改」按鈕 (刪除上一個輸入的注音符號)
InitializeModifyButtonZhuYinSongs();
// 2. 初始化「清除」按鈕 (清空所有輸入內容)
InitializeClearButtonZhuYinSongs();
// 3. 初始化「關閉」按鈕 (關閉注音輸入介面)
InitializeCloseButtonZhuYinSongs();
}
/// <summary>
/// 初始化「修改」按鈕,讓使用者可以刪除上一個輸入的注音符號。
/// </summary>
private void InitializeModifyButtonZhuYinSongs()
{
// 1. 讀取設定檔 (config.ini) 來獲取特殊按鈕的座標與圖像資訊
var data = LoadConfigData();
// 2. 從設定檔讀取「修改」按鈕的座標數據
modifyButtonZhuYinCoords = LoadSpecialButtonCoordinates(data, "SpecialButtonCoordinates", "modifyButtonZhuYinSongs");
// 3. 從設定檔讀取「修改」按鈕的圖像 (Normal、MouseOver、MouseDown)
var buttonImages = LoadButtonImages(data, "ModifyButtonImagesZhuYin");
// 4. 使用座標與圖像來建立「修改」按鈕,並綁定點擊事件
modifyButtonZhuYinSongs = CreateSpecialButton(
"btnModifyZhuYinSongs", // 按鈕名稱
modifyButtonZhuYinCoords, // 按鈕座標
buttonImages.normal, // 預設 (normal) 圖像
buttonImages.mouseOver, // 滑鼠移過 (hover) 圖像
buttonImages.mouseDown, // 按下 (pressed) 圖像
ModifyButtonZhuYinSongs_Click // 綁定按鈕點擊事件
);
}
/// <summary>
/// 「修改」按鈕的點擊事件,刪除輸入框內的最後一個注音符號。
/// </summary>
private void ModifyButtonZhuYinSongs_Click(object sender, EventArgs e)
{
// 1. 確保輸入框 (inputBoxZhuYinSongs) 存在於目前的視窗控制項中
if (this.Controls.Contains(inputBoxZhuYinSongs) && inputBoxZhuYinSongs.Text.Length > 0)
{
// 2. 刪除輸入框中的最後一個字元 (即移除最後一個注音符號)
inputBoxZhuYinSongs.Text = inputBoxZhuYinSongs.Text.Substring(0, inputBoxZhuYinSongs.Text.Length - 1);
}
}
/// <summary>
/// 初始化「清除」按鈕,並從設定檔載入其位置與圖片資源。
/// </summary>
private void InitializeClearButtonZhuYinSongs()
{
// 1. 從設定檔 (config.ini) 讀取配置數據
var data = LoadConfigData();
// 2. 讀取「清除」按鈕的座標設定 (從 "SpecialButtonCoordinates" 內的 "clearButtonZhuYinSongs" 取得)
clearButtonZhuYinCoords = LoadSpecialButtonCoordinates(data, "SpecialButtonCoordinates", "clearButtonZhuYinSongs");
// 3. 讀取「清除」按鈕的圖片 (正常、滑鼠懸停、按下狀態)
var buttonImages = LoadButtonImages(data, "ClearButtonImagesZhuYin");
// 4. 建立「清除」按鈕,並設定對應的事件處理函式 (ClearButtonZhuYinSongs_Click)
clearButtonZhuYinSongs = CreateSpecialButton(
"btnClearZhuYinSongs", // 按鈕名稱
clearButtonZhuYinCoords, // 按鈕座標與大小
buttonImages.normal, // 正常狀態圖片
buttonImages.mouseOver, // 滑鼠懸停圖片
buttonImages.mouseDown, // 按下時圖片
ClearButtonZhuYinSongs_Click // 點擊事件處理函式
);
}
/// <summary>
/// 當使用者點擊「清除」按鈕時,將輸入框 (inputBoxZhuYinSongs) 的內容清空。
/// </summary>
/// <param name="sender">觸發事件的按鈕。</param>
/// <param name="e">事件參數。</param>
private void ClearButtonZhuYinSongs_Click(object sender, EventArgs e)
{
// 1. 確保視窗內包含「注音輸入框」(inputBoxZhuYinSongs),且輸入框內有文字
if (this.Controls.Contains(inputBoxZhuYinSongs) && inputBoxZhuYinSongs.Text.Length > 0)
{
// 2. 清空輸入框內容
inputBoxZhuYinSongs.Text = "";
}
}
/// <summary>
/// 初始化注音輸入的關閉按鈕,從設定檔讀取按鈕座標與圖片,並設置點擊事件
/// </summary>
private void InitializeCloseButtonZhuYinSongs()
{
// 讀取設定檔數據
var data = LoadConfigData();
// 從設定檔讀取關閉按鈕的座標
closeButtonZhuYinCoords = LoadSpecialButtonCoordinates(data, "SpecialButtonCoordinates", "closeButtonZhuYinSongs");
// 從設定檔讀取關閉按鈕的圖片
var buttonImages = LoadButtonImages(data, "CloseButtonImagesZhuYin");
// 創建關閉按鈕並綁定點擊事件
closeButtonZhuYinSongs = CreateSpecialButton(
"btnCloseZhuYinSongs", // 按鈕名稱
closeButtonZhuYinCoords, // 按鈕座標
buttonImages.normal, // 正常狀態圖片
buttonImages.mouseOver, // 滑鼠懸停圖片
buttonImages.mouseDown, // 按下圖片
CloseButtonZhuYinSongs_Click // 綁定點擊事件
);
}
/// <summary>
/// 關閉注音輸入介面,隱藏相關 UI 元件
/// </summary>
/// <param name="sender">觸發事件的按鈕 (關閉按鈕)</param>
/// <param name="e">事件參數</param>
private void CloseButtonZhuYinSongs_Click(object sender, EventArgs e)
{
// 隱藏注音輸入的圖片
pictureBoxZhuYinSongs.Visible = false;
zhuyinSearchSongButton.BackgroundImage = zhuyinSearchSongNormalBackground;
// 隱藏注音輸入的所有按鈕與介面元素
SetZhuYinSongsAndButtonsVisibility(false);
FindZhuYiSongs(); // 查詢歌曲
}
/// <summary>
/// 查詢歌曲(字數查詢),連接資料庫並執行 SQL 查詢。
/// </summary>
private void FindZhuYiSongs(){
string searchText = inputBoxZhuYinSongs.Text;
// 在這裡添加搜尋歌曲的邏輯
// 例如:根據輸入框的內容搜尋歌曲
string query = string.IsNullOrWhiteSpace(searchText)
? "SELECT * FROM song_library_cache ORDER BY `song_id` DESC LIMIT 200;"
: $"SELECT * FROM song_library_cache WHERE `phonetic_abbr` LIKE '{searchText}%' ORDER BY `song_id`;";
var searchResults = SearchSongs_Mysql(query);
// 重置分頁
currentPage = 0;
currentSongList = searchResults;
totalPages = (int)Math.Ceiling((double)searchResults.Count / itemsPerPage);
// 更新多頁面面板的內容
multiPagePanel.currentPageIndex = 0;
multiPagePanel.LoadSongs(currentSongList);
}
/// <summary>
/// 初始化注音輸入框 (RichTextBox),設定外觀、事件處理及位置大小
/// </summary>
private void InitializeInputBoxZhuYinSongs()
{
try
{
// 讀取輸入框的配置,例如字體、顏色、大小等
LoadInputBoxConfig();
// 建立注音輸入框並套用讀取到的設定
inputBoxZhuYinSongs = new RichTextBox
{
Name = "inputBoxZhuYinSongs",
ForeColor = inputBoxForeColor, // 設定文字顏色
Font = new Font(inputBoxFontName, inputBoxFontSize, inputBoxFontStyle), // 設定字體
ScrollBars = RichTextBoxScrollBars.None // 禁用滾動條
};
// 調整輸入框大小與位置
ResizeAndPositionControl(inputBoxZhuYinSongs, inputBoxZhuYinCoords.X, inputBoxZhuYinCoords.Y,
inputBoxZhuYinCoords.Width, inputBoxZhuYinCoords.Height);
// 將輸入框加入到 UI 控制項
this.Controls.Add(inputBoxZhuYinSongs);
}
catch (Exception ex)
{
Console.WriteLine("Error initializing inputBoxZhuYinSongs: " + ex.Message);
}
}
/// <summary>
/// 存儲 PictureBoxZhuYinSongs 的座標與尺寸信息。
/// </summary>
/// <remarks>
/// 此元組包含以下四個值:
/// XX 座標
/// , YY 座標
/// , Width寬度
/// , Height高度
/// </remarks>
private (int X, int Y, int Width, int Height) pictureBoxZhuYinSongCoords;
/// <summary>
/// 從設定檔 (config.ini) 讀取 PictureBoxZhuYinSongs 的座標與尺寸
/// </summary>
private void LoadPictureBoxZhuYinSongCoordsFromConfig()
{
// 建立 INI 檔案解析器
var parser = new FileIniDataParser();
// 讀取 config.ini 設定檔的內容
string iniPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "config.ini");
IniData data = parser.ReadFile(iniPath);
// 取得 "PictureBoxZhuYinSongs" 段落的設定數據
var coords = data["PictureBoxZhuYinSongs"];
// 解析座標與尺寸,並存入 pictureBoxZhuYinSongCoords
pictureBoxZhuYinSongCoords = (
int.Parse(coords["X"]), // 讀取 X 座標
int.Parse(coords["Y"]), // 讀取 Y 座標
int.Parse(coords["Width"]), // 讀取寬度
int.Parse(coords["Height"]) // 讀取高度
);
}
/// <summary>
/// 在 pictureBoxZhuYinSongs 上顯示指定路徑的圖片,並根據設定調整其大小與位置。
/// </summary>
/// <param name="imagePath">要顯示的圖片檔案路徑</param>
private void ShowImageOnPictureBoxZhuYinSongs(string imagePath)
{
// 從 config.ini 讀取 PictureBox 的座標與尺寸
LoadPictureBoxZhuYinSongCoordsFromConfig();
// 讀取圖片檔案並載入 Bitmap 物件
Bitmap originalImage = new Bitmap(imagePath);
// 設定圖片顯示區域,使用從設定檔讀取的座標與尺寸
Rectangle displayArea = new Rectangle(
pictureBoxZhuYinSongCoords.X,
pictureBoxZhuYinSongCoords.Y,
pictureBoxZhuYinSongCoords.Width,
pictureBoxZhuYinSongCoords.Height
);
// 設定 PictureBox 的圖片
pictureBoxZhuYinSongs.Image = originalImage;
// 調整 PictureBox 的大小與位置,使其符合設定
ResizeAndPositionPictureBox(
pictureBoxZhuYinSongs,
displayArea.X,
displayArea.Y,
displayArea.Width,
displayArea.Height
);
// 顯示 PictureBox
pictureBoxZhuYinSongs.Visible = true;
}
/// <summary>
/// 設定注音歌曲相關的 PictureBox、按鈕和輸入框的可見性。
/// </summary>
/// <param name="isVisible">若為 true則顯示這些控件否則隱藏。</param>
private void SetZhuYinSongsAndButtonsVisibility(bool isVisible)
{
// 定義要執行的操作,設定各控件的可見性
System.Action action = () =>
{
try
{
// 暫停佈局邏輯,防止在調整控件可見性時觸發不必要的佈局計算,提升性能
SuspendLayout();
// 檢查並設定 pictureBoxZhuYinSongs 的可見性
if (pictureBoxZhuYinSongs == null)
{
Console.WriteLine("pictureBoxZhuYinSongs is null");
}
else
{
pictureBoxZhuYinSongs.Visible = isVisible;
if (isVisible) pictureBoxZhuYinSongs.BringToFront();
}
// 檢查並設定 phoneticButtonsForSongs 陣列中每個按鈕的可見性
if (phoneticButtonsForSongs == null)
{
Console.WriteLine("phoneticButtonsForSongs is null");
}
else
{
foreach (var button in phoneticButtonsForSongs)
{
if (button == null)
{
Console.WriteLine("One of the phoneticButtonsForSongs is null");
}
else
{
button.Visible = isVisible;
if (isVisible) button.BringToFront();
}
}
}
// 檢查並設定 modifyButtonZhuYinSongs 的可見性
if (modifyButtonZhuYinSongs == null)
{
Console.WriteLine("modifyButtonZhuYinSongs is null");
}
else
{
modifyButtonZhuYinSongs.Visible = isVisible;
if (isVisible) modifyButtonZhuYinSongs.BringToFront();
}
// 檢查並設定 clearButtonZhuYinSongs 的可見性
if (clearButtonZhuYinSongs == null)
{
Console.WriteLine("clearButtonZhuYinSongs is null");
}
else
{
clearButtonZhuYinSongs.Visible = isVisible;
if (isVisible) clearButtonZhuYinSongs.BringToFront();
}
// 檢查並設定 closeButtonZhuYinSongs 的可見性
if (closeButtonZhuYinSongs == null)
{
Console.WriteLine("closeButtonZhuYinSongs is null");
}
else
{
closeButtonZhuYinSongs.Visible = isVisible;
if (isVisible) closeButtonZhuYinSongs.BringToFront();
}
// 檢查並設定 inputBoxZhuYinSongs 的可見性
if (inputBoxZhuYinSongs == null)
{
Console.WriteLine("inputBoxZhuYinSongs is null");
}
else
{
inputBoxZhuYinSongs.Visible = isVisible;
if (isVisible) inputBoxZhuYinSongs.BringToFront();
}
// 恢復佈局邏輯,允許佈局計算
ResumeLayout();
// 強制控件立即執行佈局邏輯,確保佈局更新立即生效
PerformLayout();
// 刷新各控件,確保其狀態立即更新
pictureBoxZhuYinSongs?.Refresh();
if (phoneticButtonsForSongs != null)
{
foreach (var button in phoneticButtonsForSongs)
{
button?.Refresh();
}
}
modifyButtonZhuYinSongs?.Refresh();
clearButtonZhuYinSongs?.Refresh();
closeButtonZhuYinSongs?.Refresh();
inputBoxZhuYinSongs?.Refresh();
}
catch (Exception ex)
{
// 捕捉並輸出異常資訊,方便除錯
Console.WriteLine("Error in SetZhuYinSongsAndButtonsVisibility: " + ex.Message);
}
};
// 如果當前執行緒需要呼叫 Invoke 方法才能修改控件,則使用 Invoke
if (this.InvokeRequired)
{
this.Invoke(action);
}
else
{
action();
}
}
}
}