test #1

Merged
jasonchenwork merged 64 commits from test into master 2025-03-18 17:32:23 +08:00
8 changed files with 978 additions and 374 deletions
Showing only changes of commit f14e9b5ab3 - Show all commits

3
.gitignore vendored
View File

@ -3,4 +3,5 @@ Superstar.mdf
Superstar_log.ldf
.vs
build.bat
DualScreenKTVPlayStation.exe
DualScreenKTVPlayStation.exe
themes/superstar/_www/

View File

@ -8,21 +8,27 @@ using System.Collections.Generic;
using IniParser;
using IniParser.Model;
using System.Text;
/* 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;
@ -30,196 +36,318 @@ namespace DualScreenDemo
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));
SetZhuYinSingersAndButtonsVisibility(false);
//設定不同模式的UI顯示
//SetZhuYinSingersAndButtonsVisibility(false);
SetEnglishSingersAndButtonsVisibility(false);
SetPinYinSingersAndButtonsVisibility(false);
SetHandWritingForSingersAndButtonsVisibility(false);
SetZhuYinSongsAndButtonsVisibility(true);
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, buttonImages.normal, buttonImages.mouseDown, buttonImages.mouseOver);
// 建立單個注音按鈕,並設定其圖片與點擊事件
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 }
Name = $"phoneticButton_{phoneticSymbols[index]}", // 設定按鈕名稱,方便識別
BackgroundImage = Image.FromFile(Path.Combine(Application.StartupPath, normalImagePath)), // 設定預設背景圖
BackgroundImageLayout = ImageLayout.Stretch, // 背景圖自動填滿按鈕
FlatStyle = FlatStyle.Flat, // 設定按鈕為扁平樣式
FlatAppearance = { BorderSize = 0 } // 移除按鈕的邊框
};
ResizeAndPositionButton(phoneticButtonsForSongs[index], phoneticButtonCoords[index].X, phoneticButtonCoords[index].Y,
phoneticButtonCoords[index].Width, phoneticButtonCoords[index].Height);
// 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,
buttonImages.mouseOver,
buttonImages.mouseDown,
ModifyButtonZhuYinSongs_Click
"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
"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
"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;
// 隱藏注音輸入的所有按鈕與介面元素
SetZhuYinSongsAndButtonsVisibility(false);
}
/// <summary>
/// 初始化注音輸入框 (RichTextBox),設定外觀、事件處理及位置大小
/// </summary>
private void InitializeInputBoxZhuYinSongs()
{
try
{
// 讀取輸入框的配置,例如字體、顏色、大小等
LoadInputBoxConfig();
// 建立注音輸入框並套用讀取到的設定
inputBoxZhuYinSongs = new RichTextBox
{
Name = "inputBoxZhuYinSongs",
ForeColor = inputBoxForeColor,
Font = new Font(inputBoxFontName, inputBoxFontSize, inputBoxFontStyle),
ScrollBars = RichTextBoxScrollBars.None
ForeColor = inputBoxForeColor, // 設定文字顏色
Font = new Font(inputBoxFontName, inputBoxFontSize, inputBoxFontStyle), // 設定字體
ScrollBars = RichTextBoxScrollBars.None // 禁用滾動條
};
ResizeAndPositionControl(inputBoxZhuYinSongs, inputBoxZhuYinCoords.X, inputBoxZhuYinCoords.Y, inputBoxZhuYinCoords.Width, inputBoxZhuYinCoords.Height);
// 調整輸入框大小與位置
ResizeAndPositionControl(inputBoxZhuYinSongs, inputBoxZhuYinCoords.X, inputBoxZhuYinCoords.Y,
inputBoxZhuYinCoords.Width, inputBoxZhuYinCoords.Height);
// 設定文字變更事件,用來即時篩選歌曲
inputBoxZhuYinSongs.TextChanged += (sender, e) =>
{
string searchText = inputBoxZhuYinSongs.Text;
string searchText = inputBoxZhuYinSongs.Text; // 取得輸入內容
// 根據輸入的注音篩選歌曲清單
var searchResults = allSongs.Where(song => song.PhoneticNotation.StartsWith(searchText)).ToList();
// 重置分頁
currentPage = 0;
currentSongList = searchResults;
totalPages = (int)Math.Ceiling((double)searchResults.Count / itemsPerPage);
// 更新多頁面面板的內容
multiPagePanel.currentPageIndex = 0;
multiPagePanel.LoadSongs(currentSongList);
};
// 將輸入框加入到 UI 控制項
this.Controls.Add(inputBoxZhuYinSongs);
}
catch (Exception ex)
@ -227,51 +355,95 @@ namespace DualScreenDemo
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 設定檔的內容
IniData data = parser.ReadFile("config.ini");
// 取得 "PictureBoxZhuYinSongs" 段落的設定數據
var coords = data["PictureBoxZhuYinSongs"];
// 解析座標與尺寸,並存入 pictureBoxZhuYinSongCoords
pictureBoxZhuYinSongCoords = (
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"]) // 讀取高度
);
}
/// <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);
// 設定圖片顯示區域,使用從設定檔讀取的座標與尺寸
Rectangle displayArea = new Rectangle(
pictureBoxZhuYinSongCoords.X,
pictureBoxZhuYinSongCoords.Y,
pictureBoxZhuYinSongCoords.Width,
pictureBoxZhuYinSongCoords.Height
);
// 設定 PictureBox 的圖片
pictureBoxZhuYinSongs.Image = originalImage;
ResizeAndPositionPictureBox(pictureBoxZhuYinSongs, displayArea.X, displayArea.Y, displayArea.Width, displayArea.Height);
// 調整 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");
@ -282,6 +454,7 @@ namespace DualScreenDemo
if (isVisible) pictureBoxZhuYinSongs.BringToFront();
}
// 檢查並設定 phoneticButtonsForSongs 陣列中每個按鈕的可見性
if (phoneticButtonsForSongs == null)
{
Console.WriteLine("phoneticButtonsForSongs is null");
@ -302,6 +475,7 @@ namespace DualScreenDemo
}
}
// 檢查並設定 modifyButtonZhuYinSongs 的可見性
if (modifyButtonZhuYinSongs == null)
{
Console.WriteLine("modifyButtonZhuYinSongs is null");
@ -312,6 +486,7 @@ namespace DualScreenDemo
if (isVisible) modifyButtonZhuYinSongs.BringToFront();
}
// 檢查並設定 clearButtonZhuYinSongs 的可見性
if (clearButtonZhuYinSongs == null)
{
Console.WriteLine("clearButtonZhuYinSongs is null");
@ -322,6 +497,7 @@ namespace DualScreenDemo
if (isVisible) clearButtonZhuYinSongs.BringToFront();
}
// 檢查並設定 closeButtonZhuYinSongs 的可見性
if (closeButtonZhuYinSongs == null)
{
Console.WriteLine("closeButtonZhuYinSongs is null");
@ -332,6 +508,7 @@ namespace DualScreenDemo
if (isVisible) closeButtonZhuYinSongs.BringToFront();
}
// 檢查並設定 inputBoxZhuYinSongs 的可見性
if (inputBoxZhuYinSongs == null)
{
Console.WriteLine("inputBoxZhuYinSongs is null");
@ -342,10 +519,12 @@ namespace DualScreenDemo
if (isVisible) inputBoxZhuYinSongs.BringToFront();
}
// 恢復佈局邏輯,允許佈局計算
ResumeLayout();
PerformLayout();
// 強制控件立即執行佈局邏輯,確保佈局更新立即生效
PerformLayout();
// 刷新各控件,確保其狀態立即更新
pictureBoxZhuYinSongs?.Refresh();
if (phoneticButtonsForSongs != null)
{
@ -361,10 +540,12 @@ namespace DualScreenDemo
}
catch (Exception ex)
{
// 捕捉並輸出異常資訊,方便除錯
Console.WriteLine("Error in SetZhuYinSongsAndButtonsVisibility: " + ex.Message);
}
};
// 如果當前執行緒需要呼叫 Invoke 方法才能修改控件,則使用 Invoke
if (this.InvokeRequired)
{
this.Invoke(action);
@ -374,5 +555,6 @@ namespace DualScreenDemo
action();
}
}
}
}

View File

@ -7,11 +7,12 @@ using System.Drawing;
using IniParser;
using IniParser.Model;
using System.Text;
/* 歌曲查詢 英文輸入 */
namespace DualScreenDemo
{
public partial class PrimaryForm
{
/* 主頁面設計 */
private PictureBox pictureBoxEnglishSongs;
private Button[] numberButtonsForSongs;
@ -53,7 +54,7 @@ namespace DualScreenDemo
var data = LoadConfigData();
numberButtonCoords = LoadButtonCoordinates(data, "NumberButtonCoordinates", 10);
var buttonImages = LoadButtonImages(data, "NumberButtonImages", 10);
/* 按鈕圖片路徑設置 */
numberButtonsForSongs = new Button[10];
for (int i = 0; i < 10; i++)
{
@ -81,7 +82,7 @@ namespace DualScreenDemo
this.Controls.Add(numberButtonsForSongs[i]);
}
}
/* 按鈕按下事件 */
private void NumberButtonForSongs_Click(object sender, EventArgs e)
{
@ -95,6 +96,7 @@ namespace DualScreenDemo
}
}
/* 鍵盤對應按鈕位置 */
private void InitializeLetterButtonsForEnglishSongs()
{
var data = LoadConfigData();
@ -227,7 +229,7 @@ namespace DualScreenDemo
}
private void InitializeInputBoxEnglishSongs()
{
{ /* 英文輸入介面設定,參考 config.ini */
try
{
var parser = new FileIniDataParser();
@ -260,7 +262,7 @@ namespace DualScreenDemo
};
ResizeAndPositionControl(inputBoxEnglishSongs, x, y, width, height);
/*搜尋結果 傳回點歌介面*/
inputBoxEnglishSongs.TextChanged += (sender, e) =>
{
string searchText = inputBoxEnglishSongs.Text;
@ -280,7 +282,7 @@ namespace DualScreenDemo
Console.WriteLine($"An error occurred: {ex.Message}");
}
}
/* 圖片位置設置 */
private void ShowImageOnPictureBoxEnglishSongs(string imagePath)
{
try

View File

@ -8,95 +8,138 @@ namespace DualScreenDemo
{
public partial class PrimaryForm
{
/// <summary>
/// 「數字搜尋」按鈕點擊事件
/// 1. 更新所有搜尋按鈕的背景圖片,使「數字搜尋」顯示為啟動狀態
/// 2. 在 `pictureBoxSongIDSearch` 顯示對應的圖片
/// 3. 顯示「數字搜尋」相關 UI 元素
/// </summary>
private void NumberSearchButton2_Click(object sender, EventArgs e)
{
// 更新搜尋按鈕的背景圖片 (將所有按鈕設為未選中狀態,僅數字搜尋為選中狀態)
zhuyinSearchSongButton.BackgroundImage = zhuyinSearchSongNormalBackground;
englishSearchSongButton.BackgroundImage = englishSearchSongNormalBackground;
pinyinSearchSongButton.BackgroundImage = pinyinSearchSongNormalBackground;
wordCountSearchSongButton.BackgroundImage = wordCountSearchSongNormalBackground;
handWritingSearchSongButton.BackgroundImage = handWritingSearchNormalBackground;
numberSearchSongButton.BackgroundImage = numberSearchSongActiveBackground;
numberSearchSongButton.BackgroundImage = numberSearchSongActiveBackground; // 設定數字搜尋為選中狀態
// 在 `pictureBoxSongIDSearch` 顯示數字搜尋的 UI 圖片
ShowImageOnPictureBoxSongIDSearch(Path.Combine(Application.StartupPath, @"themes\superstar\6-1.png"));
// 顯示與數字搜尋相關的 UI 元素
SetPictureBoxSongIDSearchAndButtonsVisibility(true);
pictureBoxSongIDSearch.Visible = true;
}
/// <summary>
/// 在 pictureBoxSongIDSearch 中顯示指定路徑的圖片,並對其進行裁切與調整大小
/// <para> 1. 加載原始圖片 </para>
/// <para> 2. 裁切圖片以符合 UI 需求 </para>
/// <para> 3. 設定 pictureBoxSongIDSearch 的圖片 </para>
/// <para> 4. 調整 pictureBoxSongIDSearch 的位置與大小 </para>
/// <para> 5. 顯示 pictureBoxSongIDSearch </para>
/// </summary>
/// <param name="imagePath">要顯示的圖片路徑</param>
private void ShowImageOnPictureBoxSongIDSearch(string imagePath)
{
// 1. 加載原始圖片
Bitmap originalImage = new Bitmap(imagePath);
// 2. 定義裁切區域 (左上角 x=593, y=135, 寬=507, 高=508)
Rectangle cropArea = new Rectangle(593, 135, 507, 508);
// 3. 進行圖片裁切
Bitmap croppedImage = CropImage(originalImage, cropArea);
// 4. 設定 `pictureBoxSongIDSearch` 的圖片
pictureBoxSongIDSearch.Image = croppedImage;
// 5. 調整 `pictureBoxSongIDSearch` 的大小與位置 (基於 cropArea 並加上偏移量)
ResizeAndPositionPictureBox(pictureBoxSongIDSearch, cropArea.X + offsetXSongID, cropArea.Y + offsetYSongID, cropArea.Width, cropArea.Height);
// 6. 顯示 `pictureBoxSongIDSearch`
pictureBoxSongIDSearch.Visible = true;
}
/// <summary>
/// 當使用者點擊「修改按鈕」時,刪除 `inputBoxSongIDSearch` 輸入框內的最後一個字元。
/// </summary>
/// <param name="sender">觸發事件的對象(按鈕)</param>
/// <param name="e">事件參數</param>
private void ModifyButtonSongIDSearch_Click(object sender, EventArgs e)
{
// 確保 `inputBoxSongIDSearch` 內有文字,避免 `Substring` 發生錯誤
if (inputBoxSongIDSearch.Text.Length > 0)
{
// 刪除輸入框內的最後一個字元
inputBoxSongIDSearch.Text = inputBoxSongIDSearch.Text.Substring(0, inputBoxSongIDSearch.Text.Length - 1);
}
}
/// <summary>
/// 當使用者點擊「關閉按鈕」時,隱藏歌曲編號搜尋的相關 UI 元件。
/// </summary>
/// <param name="sender">觸發事件的對象(按鈕)</param>
/// <param name="e">事件參數</param>
private void CloseButtonSongIDSearch_Click(object sender, EventArgs e)
{
// 隱藏歌曲編號搜尋的相關 UI 元件(包含輸入框、按鈕、圖片等)
SetPictureBoxSongIDSearchAndButtonsVisibility(false);
}
/// <summary>
/// 控制歌曲編號搜尋的 UI 顯示與隱藏。
/// <para>當 <paramref name="isVisible"/> 為 <c>true</c> 時,顯示 UI 元件。</para>
/// <para>當 <paramref name="isVisible"/> 為 <c>false</c> 時,隱藏 UI 元件。</para>
/// </summary>
/// <param name="isVisible">是否顯示 UI</param>
private void SetPictureBoxSongIDSearchAndButtonsVisibility(bool isVisible)
{
// 定義 UI 更新的 Action
System.Action action = () =>
{
// 暫停佈局更新,提高效能
SuspendLayout();
// 控制歌曲編號搜尋圖片的顯示/隱藏
pictureBoxSongIDSearch.Visible = isVisible;
// 如果顯示圖片,則將其置頂
if (isVisible) pictureBoxSongIDSearch.BringToFront();
// 控制「修改」和「關閉」按鈕的可見性
modifyButtonSongIDSearch.Visible = isVisible;
closeButtonSongIDSearch.Visible = isVisible;
// 如果按鈕顯示,則置頂
if (isVisible)
{
modifyButtonSongIDSearch.BringToFront();
closeButtonSongIDSearch.BringToFront();
}
// 控制數字按鈕的可見性
foreach (Button button in numberButtonsSongIDSearch)
{
button.Visible = isVisible;
// 使按鈕顯示時位於最上層
if (isVisible)
button.BringToFront();
}
// 控制輸入框的可見性
inputBoxSongIDSearch.Visible = isVisible;
if (isVisible) inputBoxSongIDSearch.BringToFront();
// 恢復佈局更新
ResumeLayout();
};
// 如果當前執行緒不是 UI 執行緒,則使用 Invoke 呼叫
if (this.InvokeRequired)
{
this.Invoke(action);
@ -106,113 +149,140 @@ namespace DualScreenDemo
action();
}
}
/// <summary>
/// 初始化數字輸入 (Song ID Search) 相關按鈕與輸入框。
/// 這些按鈕用於數字輸入、刪除 (Modify) 及關閉 (Close) 功能。
/// </summary>
private void InitializeButtonsForPictureBoxSongIDSearch()
{
// 數字按鈕的座標陣列 (左上角 X, 左上角 Y, 右下角 X, 右下角 Y)
int[,] coords = new int[,]
{
{651, 292, 752, 400},
{760, 292, 861, 400},
{869, 292, 972, 399},
{652, 401, 752, 502},
{760, 401, 861, 504},
{869, 398, 972, 502},
{651, 502, 753, 607},
{759, 504, 863, 607},
{869, 503, 973, 608},
{981, 501, 1083, 609}
{651, 292, 752, 400}, // 1
{760, 292, 861, 400}, // 2
{869, 292, 972, 399}, // 3
{652, 401, 752, 502}, // 4
{760, 401, 861, 504}, // 5
{869, 398, 972, 502}, // 6
{651, 502, 753, 607}, // 7
{759, 504, 863, 607}, // 8
{869, 503, 973, 608}, // 9
{981, 501, 1083, 609} // 0
};
// 取得螢幕的解析度
int screenW = Screen.PrimaryScreen.Bounds.Width;
int screenH = Screen.PrimaryScreen.Bounds.Height;
// 計算畫面縮放比例
float widthRatio = screenW / (float)1920;
float heightRatio = screenH / (float)900;
// 初始化數字按鈕陣列
numberButtonsSongIDSearch = new Button[10];
// 建立數字按鈕
for (int i = 0; i < numberButtonsSongIDSearch.Length; i++)
{
numberButtonsSongIDSearch[i] = new Button();
// 設定按鈕大小與位置
ConfigureButton(
numberButtonsSongIDSearch[i],
coords[i, 0],
coords[i, 1],
coords[i, 2] - coords[i, 0],
coords[i, 3] - coords[i, 1],
resizedNormalStateImageFor6_1,
resizedMouseOverImageFor6_1,
resizedMouseDownImageFor6_1,
coords[i, 0], // X 座標
coords[i, 1], // Y 座標
coords[i, 2] - coords[i, 0], // 按鈕寬度
coords[i, 3] - coords[i, 1], // 按鈕高度
resizedNormalStateImageFor6_1, // 一般狀態圖片
resizedMouseOverImageFor6_1, // 滑鼠懸停圖片
resizedMouseDownImageFor6_1, // 按下時圖片
null
);
// 重新計算按鈕位置,確保適應不同解析度
int newXForSongID = (int)(((numberButtonsSongIDSearch[i].Location.X / widthRatio) + offsetXSongID) * widthRatio);
int newYForSongID = (int)(((numberButtonsSongIDSearch[i].Location.Y / heightRatio) + offsetYSongID) * heightRatio);
numberButtonsSongIDSearch[i].Location = new Point(newXForSongID, newYForSongID);
// 設定按鈕名稱與 Tag (數字值)
numberButtonsSongIDSearch[i].Name = "NumberButtonSongIDSearch" + i;
numberButtonsSongIDSearch[i].Tag = (i + 1).ToString();
if (i == 9)
if (i == 9) // 最後一個按鈕 (實際上應為數字 "0")
{
numberButtonsSongIDSearch[i].Name = "NumberButtonSongIDSearch0";
numberButtonsSongIDSearch[i].Tag = "0";
}
// 設定按鈕的點擊事件
numberButtonsSongIDSearch[i].Click += SongIDSearchButton_Click;
// 加入畫面
this.Controls.Add(numberButtonsSongIDSearch[i]);
}
modifyButtonSongIDSearch = new Button {
// 初始化「刪除」按鈕 (Modify)
modifyButtonSongIDSearch = new Button
{
Name = "ModifyButtonSongIDSearch",
Tag = "Modify",
Visible = false
};
ConfigureButton(modifyButtonSongIDSearch, 978, 292, 1081 - 978, 397 - 292, resizedNormalStateImageFor6_1, resizedMouseOverImageFor6_1, resizedMouseDownImageFor6_1, ModifyButtonSongIDSearch_Click);
ConfigureButton(modifyButtonSongIDSearch, 978, 292, 1081 - 978, 397 - 292,
resizedNormalStateImageFor6_1, resizedMouseOverImageFor6_1, resizedMouseDownImageFor6_1, ModifyButtonSongIDSearch_Click);
// 調整刪除按鈕位置以適應不同解析度
int newX = (int)(((modifyButtonSongIDSearch.Location.X / widthRatio) + offsetXSongID) * widthRatio);
int newY = (int)(((modifyButtonSongIDSearch.Location.Y / widthRatio) + offsetYSongID) * heightRatio);
int newY = (int)(((modifyButtonSongIDSearch.Location.Y / heightRatio) + offsetYSongID) * heightRatio);
modifyButtonSongIDSearch.Location = new Point(newX, newY);
this.Controls.Add(modifyButtonSongIDSearch);
closeButtonSongIDSearch = new Button {
// 初始化「關閉」按鈕 (Close)
closeButtonSongIDSearch = new Button
{
Name = "CloseButtonSongIDSearch",
Tag = "Close",
Visible = false
};
ConfigureButton(closeButtonSongIDSearch, 982, 147, 1082 - 982, 250 - 147, resizedNormalStateImageFor6_1, resizedMouseOverImageFor6_1, resizedMouseDownImageFor6_1, CloseButtonSongIDSearch_Click);
ConfigureButton(closeButtonSongIDSearch, 982, 147, 1082 - 982, 250 - 147,
resizedNormalStateImageFor6_1, resizedMouseOverImageFor6_1, resizedMouseDownImageFor6_1, CloseButtonSongIDSearch_Click);
// 調整關閉按鈕位置以適應不同解析度
newX = (int)(((closeButtonSongIDSearch.Location.X / widthRatio) + offsetXSongID) * widthRatio);
newY = (int)(((closeButtonSongIDSearch.Location.Y / widthRatio) + offsetYSongID) * heightRatio);
newY = (int)(((closeButtonSongIDSearch.Location.Y / heightRatio) + offsetYSongID) * heightRatio);
closeButtonSongIDSearch.Location = new Point(newX, newY);
this.Controls.Add(closeButtonSongIDSearch);
inputBoxSongIDSearch = new RichTextBox();
inputBoxSongIDSearch.Name = "inputBoxSongIDSearch";
ResizeAndPositionControl(inputBoxSongIDSearch, 645 + offsetXSongID, 197 + offsetXSongID, 986 - 645, 281 - 197);
inputBoxSongIDSearch.ForeColor = Color.Black;
inputBoxSongIDSearch.Font = new Font("細明體", (float)26 / 900 * Screen.PrimaryScreen.Bounds.Height, FontStyle.Regular);
// 初始化輸入框 (RichTextBox)
inputBoxSongIDSearch = new RichTextBox
{
Name = "inputBoxSongIDSearch",
ForeColor = Color.Black,
Font = new Font("細明體", (float)26 / 900 * Screen.PrimaryScreen.Bounds.Height, FontStyle.Regular)
};
// 調整輸入框大小與位置
ResizeAndPositionControl(inputBoxSongIDSearch, 645 + offsetXSongID, 197 + offsetXSongID, 986 - 645, 281 - 197);
// 當輸入框內容改變時,自動搜尋歌曲
inputBoxSongIDSearch.TextChanged += (sender, e) =>
{
string searchText = inputBoxSongIDSearch.Text;
// 使用 LINQ 搜尋符合條件的歌曲 (以輸入的數字開頭)
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);
};
@ -220,16 +290,25 @@ namespace DualScreenDemo
this.Controls.Add(inputBoxSongIDSearch);
}
/// <summary>
/// 數字按鈕點擊事件,將按鈕上的數字 (Tag 值) 加入到 inputBoxSongIDSearch 中。
/// </summary>
/// <param name="sender">觸發事件的按鈕</param>
/// <param name="e">事件參數</param>
private void SongIDSearchButton_Click(object sender, EventArgs e)
{
// 嘗試將 sender 轉型為 Button
var button = sender as Button;
// 確保按鈕不為 null 且具有 Tag 屬性 (Tag 屬性存放數字)
if (button != null && button.Tag != null)
{
// 將按鈕的 Tag 值 (數字) 加入到輸入框
inputBoxSongIDSearch.Text += button.Tag.ToString();
}
}
}
}

View File

@ -10,15 +10,22 @@ 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;
/// <summary>
/// 拼音歌曲搜尋按鈕點擊事件
/// </summary>
private void PinyinSearchSongsButton_Click(object sender, EventArgs e)
{
// 更新搜尋模式按鈕的背景圖
zhuyinSearchSongButton.BackgroundImage = zhuyinSearchSongNormalBackground;
englishSearchSongButton.BackgroundImage = englishSearchSongNormalBackground;
pinyinSearchSongButton.BackgroundImage = pinyinSearchSongActiveBackground;
@ -26,288 +33,445 @@ 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;
}
/// <summary>
/// 初始化拼音按鈕
/// </summary>
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]);
}
}
/// <summary>
/// 處理拼音按鈕點擊事件
/// </summary>
/// <param name="sender">觸發事件按鈕</param>
/// <param name="e">事件參數</param>
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();
}
}
}
/// <summary>
/// 初始化拼音輸入相關的 UI 控件,包括字母按鈕、特殊功能按鈕(修改、清除、關閉),以及拼音輸入框。
/// </summary>
private void InitializeButtonsForPinYinSongs()
{
// 初始化拼音字母按鈕,根據 QWERTY 鍵盤佈局建立對應的按鈕
InitializeLetterButtonsForPinYinSongs();
// 初始化特殊功能按鈕(修改、清除、關閉)
InitializeSpecialButtonsForPinYinSongs();
// 初始化拼音輸入框,使用者可透過輸入拼音來搜尋歌曲
InitializeInputBoxPinYinSongs();
}
/// <summary>
/// 初始化拼音輸入的特殊功能按鈕,包括:
/// <para>1. 修改按鈕 - 刪除輸入框中的最後一個字母</para>
/// <para>2. 清除按鈕 - 清空輸入框的內容</para>
/// <para>3. 關閉按鈕 - 隱藏拼音輸入的 UI 元件</para>
/// </summary>
private void InitializeSpecialButtonsForPinYinSongs()
{
// 初始化「修改」按鈕(刪除輸入框最後一個字母)
InitializeModifyButtonPinYinSongs();
// 初始化「清除」按鈕(清空輸入框內容)
InitializeClearButtonPinYinSongs();
// 初始化「關閉」按鈕(關閉拼音輸入 UI
InitializeCloseButtonPinYinSongs();
}
/// <summary>
/// 初始化「修改」按鈕,提供刪除拼音輸入框最後一個字母的功能。
/// </summary>
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 // 綁定按鈕的點擊事件處理函式
);
}
/// <summary>
/// 「修改」按鈕點擊事件:刪除拼音輸入框 (inputBoxPinYinSongs) 中的最後一個字母。
/// </summary>
private void ModifyButtonPinYinSongs_Click(object sender, EventArgs e)
{
// 確保 inputBoxPinYinSongs 存在於視窗控制項集合內,且輸入框內有文字
if (this.Controls.Contains(inputBoxPinYinSongs) && inputBoxPinYinSongs.Text.Length > 0)
{
// 刪除輸入框內的最後一個字母
inputBoxPinYinSongs.Text = inputBoxPinYinSongs.Text.Substring(0, inputBoxPinYinSongs.Text.Length - 1);
}
}
/// <summary>
/// 初始化「清除」按鈕 (clearButtonPinYinSongs),用於清空拼音輸入框 (inputBoxPinYinSongs)。
/// </summary>
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 // 綁定按鈕的點擊事件處理函式
);
}
/// <summary>
/// 清空拼音輸入框的內容。
/// 當使用者點擊清除按鈕時,若輸入框存在且有內容,則將其清空。
/// </summary>
private void ClearButtonPinYinSongs_Click(object sender, EventArgs e)
{
// 檢查視窗內是否包含 inputBoxPinYinSongs 控制項,且輸入框內是否有文字
if (this.Controls.Contains(inputBoxPinYinSongs) && inputBoxPinYinSongs.Text.Length > 0)
{
// 清空拼音輸入框的內容
inputBoxPinYinSongs.Text = "";
}
}
/// <summary>
/// 初始化「關閉」按鈕 (closeButtonPinYinSongs),用於隱藏拼音輸入介面。
/// </summary>
private void InitializeCloseButtonPinYinSongs()
{
// 讀取設定檔中的按鈕配置數據
var data = LoadConfigData();
// 從設定檔中取得「關閉」按鈕的座標 (X, Y, Width, Height)
closeButtonPinYinCoords = LoadSpecialButtonCoordinates(data, "SpecialButtonCoordinates", "closeButtonPinYinSongs");
// 從設定檔中讀取「關閉」按鈕的圖片 (一般狀態、滑鼠懸停、按下時的圖片)
var buttonImages = LoadButtonImages(data, "CloseButtonImagesPinYin");
// 建立「關閉」按鈕,設定名稱、座標、圖片及點擊事件
closeButtonPinYinSongs = CreateSpecialButton(
"btnClosePinYinSongs",
closeButtonPinYinCoords,
buttonImages.normal,
buttonImages.mouseOver,
buttonImages.mouseDown,
CloseButtonPinYinSongs_Click
"btnClosePinYinSongs", // 按鈕名稱
closeButtonPinYinCoords, // 設定按鈕的座標與大小
buttonImages.normal, // 設定按鈕的正常狀態圖片
buttonImages.mouseOver, // 設定按鈕的滑鼠懸停圖片
buttonImages.mouseDown, // 設定按鈕的按下狀態圖片
CloseButtonPinYinSongs_Click // 綁定按鈕的點擊事件處理函式
);
}
/// <summary>
/// 關閉拼音輸入模式,隱藏相關 UI 元件。
/// </summary>
/// <param name="sender">觸發事件的按鈕。</param>
/// <param name="e">事件參數。</param>
private void CloseButtonPinYinSongs_Click(object sender, EventArgs e)
{
// 隱藏拼音輸入的背景圖片 (可能是 UI 中的輸入框背景)
pictureBoxPinYinSongs.Visible = false;
// 設定拼音輸入框與所有相關按鈕的可見性為 false
SetPinYinSongsAndButtonsVisibility(false);
}
}
/// <summary>
/// 初始化拼音輸入框 (RichTextBox),並從 config.ini 讀取相關設定。
/// </summary>
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}");
}
}
/// <summary>
/// 存儲 PictureBoxPinYinSongs 的座標與尺寸信息。
/// </summary>
/// <remarks>
/// 此元組包含以下四個值:
/// XX 座標
/// , YY 座標
/// , Width寬度
/// , Height高度
/// </remarks>
private (int X, int Y, int Width, int Height) pictureBoxPinYinSongCoords;
/// <summary>
/// 從 config.ini 配置檔案中載入 PictureBoxPinYinSongs 的座標與尺寸設定。
/// </summary>
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"]) // 解析 高度
);
}
/// <summary>
/// 顯示拼音歌曲圖片
/// </summary>
/// <param name="imagePath">圖片路徑</param>
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;
}
/// <summary>
/// 設定拼音模式的 UI 是否可見
/// </summary>
/// <param name="isVisible">是否可見</param>
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 +480,7 @@ namespace DualScreenDemo
{
action();
}
}
}
}

View File

@ -8,182 +8,237 @@ namespace DualScreenDemo
{
public partial class PrimaryForm
{
/// <summary>
/// 當使用者點擊「詞數查歌」按鈕時,切換到詞數查歌模式,更新 UI 並顯示對應的查歌界面。
/// </summary>
/// <param name="sender">觸發事件的按鈕。</param>
/// <param name="e">事件參數。</param>
private void WordCountSearchSong_Click(object sender, EventArgs e)
{
zhuyinSearchSongButton.BackgroundImage = zhuyinSearchSongNormalBackground;
englishSearchSongButton.BackgroundImage = englishSearchSongNormalBackground;
pinyinSearchSongButton.BackgroundImage = pinyinSearchSongNormalBackground;
wordCountSearchSongButton.BackgroundImage = wordCountSearchSongActiveBackground;
handWritingSearchSongButton.BackgroundImage = handWritingSearchNormalBackground;
numberSearchSongButton.BackgroundImage = numberSearchSongNormalBackground;
{
// 設定查歌模式按鈕的背景圖片
zhuyinSearchSongButton.BackgroundImage = zhuyinSearchSongNormalBackground; // 注音查歌(普通狀態)
englishSearchSongButton.BackgroundImage = englishSearchSongNormalBackground; // 英文查歌(普通狀態)
pinyinSearchSongButton.BackgroundImage = pinyinSearchSongNormalBackground; // 拼音查歌(普通狀態)
wordCountSearchSongButton.BackgroundImage = wordCountSearchSongActiveBackground; // 詞數查歌(選中狀態)
handWritingSearchSongButton.BackgroundImage = handWritingSearchNormalBackground; // 手寫查歌(普通狀態)
numberSearchSongButton.BackgroundImage = numberSearchSongNormalBackground; // 數字查歌(普通狀態)
// 顯示詞數查歌對應的圖片
ShowImageOnPictureBoxWordCount(Path.Combine(Application.StartupPath, @"themes\superstar\6-1.png"));
// 設定詞數查歌的 PictureBox 和按鈕的可見性
SetPictureBoxWordCountAndButtonsVisibility(true);
pictureBoxWordCount.Visible = true;
}
pictureBoxWordCount.Visible = true; // 顯示 PictureBoxWordCount
}
/// <summary>
/// 顯示詞數查歌對應的圖片
/// </summary>
/// <param name="imagePath">圖片路徑</param>
private void ShowImageOnPictureBoxWordCount(string imagePath)
{
// 載入原始圖片
Bitmap originalImage = new Bitmap(imagePath);
// 定義裁切區域 (起始座標: 593, 135寬度: 507高度: 508)
Rectangle cropArea = new Rectangle(593, 135, 507, 508);
// 裁切圖片,獲得指定範圍的影像
Bitmap croppedImage = CropImage(originalImage, cropArea);
// 將裁切後的圖片顯示在 pictureBoxWordCount 上
pictureBoxWordCount.Image = croppedImage;
ResizeAndPositionPictureBox(pictureBoxWordCount, cropArea.X + offsetXWordCount, cropArea.Y + offsetXWordCount, cropArea.Width, cropArea.Height);
// 調整 pictureBoxWordCount 的大小與位置
ResizeAndPositionPictureBox(pictureBoxWordCount,
cropArea.X + offsetXWordCount, // X 座標 (包含位移量)
cropArea.Y + offsetYWordCount, // Y 座標 (包含位移量)
cropArea.Width, // 寬度
cropArea.Height // 高度
);
// 顯示 pictureBoxWordCount
pictureBoxWordCount.Visible = true;
}
private void InitializeButtonsForPictureBoxWordCount()
{
int[,] coords = new int[,]
/// <summary>
/// 初始化「詞數查歌」模式的按鈕與輸入框,並根據螢幕解析度進行調整。
/// </summary>
private void InitializeButtonsForPictureBoxWordCount()
{
{651, 292, 752, 400},
{760, 292, 861, 400},
{869, 292, 972, 399},
{652, 401, 752, 502},
{760, 401, 861, 504},
{869, 398, 972, 502},
{651, 502, 753, 607},
{759, 504, 863, 607},
{869, 503, 973, 608},
{981, 501, 1083, 609}
};
int screenW = Screen.PrimaryScreen.Bounds.Width;
int screenH = Screen.PrimaryScreen.Bounds.Height;
float widthRatio = screenW / (float)1440;
float heightRatio = screenH / (float)900;
numberButtonsWordCount = new Button[10];
for (int i = 0; i < numberButtonsWordCount.Length; i++)
{
numberButtonsWordCount[i] = new Button();
ConfigureButton(
numberButtonsWordCount[i],
coords[i, 0],
coords[i, 1],
coords[i, 2] - coords[i, 0],
coords[i, 3] - coords[i, 1],
resizedNormalStateImageFor6_1,
resizedMouseOverImageFor6_1,
resizedMouseDownImageFor6_1,
null
);
int newXForWordCount = (int)(((numberButtonsWordCount[i].Location.X / widthRatio) + offsetXWordCount) * widthRatio);
int newYForWordCount = (int)(((numberButtonsWordCount[i].Location.Y / heightRatio) + offsetYWordCount) * heightRatio);
numberButtonsWordCount[i].Location = new Point(newXForWordCount, newYForWordCount);
numberButtonsWordCount[i].Name = "NumberButtonWordCount" + i;
numberButtonsWordCount[i].Tag = (i + 1).ToString();
if (i == 9)
// 定義數字按鈕的座標範圍 (左上角 X, Y 以及右下角 X, Y)
int[,] coords = new int[,]
{
numberButtonsWordCount[i].Name = "NumberButtonWordCount0";
numberButtonsWordCount[i].Tag = "0";
{651, 292, 752, 400}, // 1
{760, 292, 861, 400}, // 2
{869, 292, 972, 399}, // 3
{652, 401, 752, 502}, // 4
{760, 401, 861, 504}, // 5
{869, 398, 972, 502}, // 6
{651, 502, 753, 607}, // 7
{759, 504, 863, 607}, // 8
{869, 503, 973, 608}, // 9
{981, 501, 1083, 609} // 0
};
// 取得螢幕解析度
int screenW = Screen.PrimaryScreen.Bounds.Width;
int screenH = Screen.PrimaryScreen.Bounds.Height;
// 計算寬高比例,供座標縮放使用
float widthRatio = screenW / (float)1440;
float heightRatio = screenH / (float)900;
// 建立數字按鈕陣列
numberButtonsWordCount = new Button[10];
// 依序建立 0-9 按鈕
for (int i = 0; i < numberButtonsWordCount.Length; i++)
{
numberButtonsWordCount[i] = new Button();
// 設定按鈕屬性 (位置、大小、圖片)
ConfigureButton(
numberButtonsWordCount[i],
coords[i, 0],
coords[i, 1],
coords[i, 2] - coords[i, 0], // 計算按鈕寬度
coords[i, 3] - coords[i, 1], // 計算按鈕高度
resizedNormalStateImageFor6_1,
resizedMouseOverImageFor6_1,
resizedMouseDownImageFor6_1,
null
);
// 調整按鈕位置,使其適應不同解析度
int newXForWordCount = (int)(((numberButtonsWordCount[i].Location.X / widthRatio) + offsetXWordCount) * widthRatio);
int newYForWordCount = (int)(((numberButtonsWordCount[i].Location.Y / heightRatio) + offsetYWordCount) * heightRatio);
numberButtonsWordCount[i].Location = new Point(newXForWordCount, newYForWordCount);
// 設定按鈕名稱
numberButtonsWordCount[i].Name = "NumberButtonWordCount" + i;
numberButtonsWordCount[i].Tag = (i + 1).ToString();
// 處理按鈕 0 的特殊名稱與標籤
if (i == 9)
{
numberButtonsWordCount[i].Name = "NumberButtonWordCount0";
numberButtonsWordCount[i].Tag = "0";
}
// 設定點擊事件
numberButtonsWordCount[i].Click += WordCountButton_Click;
// 將按鈕加入視窗控制項
this.Controls.Add(numberButtonsWordCount[i]);
}
numberButtonsWordCount[i].Click += WordCountButton_Click;
// 建立「修改」按鈕 (Modify)
modifyButtonWordCount = new Button {
Name = "ModifyButtonWordCount",
Tag = "Modify",
Visible = false
};
ConfigureButton(modifyButtonWordCount, 978, 292, 1081 - 978, 397 - 292,
resizedNormalStateImageFor6_1, resizedMouseOverImageFor6_1, resizedMouseDownImageFor6_1,
ModifyButtonWordCount_Click);
this.Controls.Add(numberButtonsWordCount[i]);
// 調整「修改」按鈕的位置
int newX = (int)(((modifyButtonWordCount.Location.X / widthRatio) + offsetXWordCount) * widthRatio);
int newY = (int)(((modifyButtonWordCount.Location.Y / heightRatio) + offsetYWordCount) * heightRatio);
modifyButtonWordCount.Location = new Point(newX, newY);
// 加入「修改」按鈕至視窗
this.Controls.Add(modifyButtonWordCount);
// 建立「關閉」按鈕 (Close)
closeButtonWordCount = new Button {
Name = "CloseButtonWordCount",
Tag = "Close",
Visible = false
};
ConfigureButton(closeButtonWordCount, 982, 147, 1082 - 982, 250 - 147,
resizedNormalStateImageFor6_1, resizedMouseOverImageFor6_1, resizedMouseDownImageFor6_1,
CloseButtonWordCount_Click);
// 調整「關閉」按鈕的位置
newX = (int)(((closeButtonWordCount.Location.X / widthRatio) + offsetXWordCount) * widthRatio);
newY = (int)(((closeButtonWordCount.Location.Y / heightRatio) + offsetYWordCount) * heightRatio);
closeButtonWordCount.Location = new Point(newX, newY);
// 加入「關閉」按鈕至視窗
this.Controls.Add(closeButtonWordCount);
// 建立輸入框 (RichTextBox) 供使用者輸入詞數
inputBoxWordCount = new RichTextBox();
inputBoxWordCount.Name = "inputBoxWordCount";
// 設定輸入框位置與大小
ResizeAndPositionControl(inputBoxWordCount, 645 + offsetXWordCount, 197 + offsetYWordCount, 986 - 645, 281 - 197);
inputBoxWordCount.ForeColor = Color.Black;
inputBoxWordCount.Font = new Font("細明體", (float)26 / 900 * Screen.PrimaryScreen.Bounds.Height, FontStyle.Regular);
// 設定輸入框內容變更時的處理邏輯
inputBoxWordCount.TextChanged += (sender, e) =>
{
string searchText = inputBoxWordCount.Text;
int targetLength = 0;
// 檢查輸入的是否為數字
if (int.TryParse(searchText, out targetLength))
{
// 根據詞數長度篩選歌曲
var searchResults = allSongs.Where(song => song.Song.Replace(" ", "").Length == targetLength).ToList();
currentPage = 0;
currentSongList = searchResults;
totalPages = (int)Math.Ceiling((double)searchResults.Count / itemsPerPage);
// 更新多頁面面板
multiPagePanel.currentPageIndex = 0;
multiPagePanel.LoadSongs(currentSongList);
}
else
{
// 若輸入非數字,則清空當前歌曲列表
currentSongList.Clear();
}
};
// 加入輸入框至視窗
this.Controls.Add(inputBoxWordCount);
}
modifyButtonWordCount = new Button {
Name = "ModifyButtonWordCount",
Tag = "Modify",
Visible = false
};
ConfigureButton(modifyButtonWordCount, 978, 292, 1081 - 978, 397 - 292, resizedNormalStateImageFor6_1, resizedMouseOverImageFor6_1, resizedMouseDownImageFor6_1, ModifyButtonWordCount_Click);
int newX = (int)(((modifyButtonWordCount.Location.X / widthRatio) + offsetXWordCount) * widthRatio);
int newY = (int)(((modifyButtonWordCount.Location.Y / widthRatio) + offsetYWordCount) * heightRatio);
modifyButtonWordCount.Location = new Point(newX, newY);
this.Controls.Add(modifyButtonWordCount);
closeButtonWordCount = new Button {
Name = "CloseButtonWordCount",
Tag = "Close",
Visible = false
};
ConfigureButton(closeButtonWordCount, 982, 147, 1082 - 982, 250 - 147, resizedNormalStateImageFor6_1, resizedMouseOverImageFor6_1, resizedMouseDownImageFor6_1, CloseButtonWordCount_Click);
newX = (int)(((closeButtonWordCount.Location.X / widthRatio) + offsetXWordCount) * widthRatio);
newY = (int)(((closeButtonWordCount.Location.Y / widthRatio) + offsetYWordCount) * heightRatio);
closeButtonWordCount.Location = new Point(newX, newY);
this.Controls.Add(closeButtonWordCount);
inputBoxWordCount = new RichTextBox();
inputBoxWordCount.Name = "inputBoxWordCount";
ResizeAndPositionControl(inputBoxWordCount, 645 + offsetXWordCount, 197 + offsetYWordCount, 986 - 645, 281 - 197);
inputBoxWordCount.ForeColor = Color.Black;
inputBoxWordCount.Font = new Font("細明體", (float)26 / 900 * Screen.PrimaryScreen.Bounds.Height, FontStyle.Regular);
inputBoxWordCount.TextChanged += (sender, e) =>
{
string searchText = inputBoxWordCount.Text;
int targetLength = 0;
if (int.TryParse(searchText, out targetLength))
{
var searchResults = allSongs.Where(song => song.Song.Replace(" ", "").Length == targetLength).ToList();
currentPage = 0;
currentSongList = searchResults;
totalPages = (int)Math.Ceiling((double)searchResults.Count / itemsPerPage);
multiPagePanel.currentPageIndex = 0;
multiPagePanel.LoadSongs(currentSongList);
}
else
{
currentSongList.Clear();
}
};
this.Controls.Add(inputBoxWordCount);
}
private void WordCountButton_Click(object sender, EventArgs e)
{
var button = sender as Button;
if (button != null && button.Tag != null)
/// <summary>
/// 處理數字按鈕的點擊事件,將按鈕對應的數字 (Tag) 加入輸入框 inputBoxWordCount 中。
/// </summary>
/// <param name="sender">觸發事件的按鈕</param>
/// <param name="e">事件參數</param>
private void WordCountButton_Click(object sender, EventArgs e)
{
inputBoxWordCount.Text += button.Tag.ToString();
}
}
// 嘗試將 sender 轉換為 Button 類型
var button = sender as Button;
private void CloseButtonWordCount_Click(object sender, EventArgs e)
{
SetPictureBoxWordCountAndButtonsVisibility(false);
}
// 確保按鈕不為空,且擁有有效的 Tag 值
if (button != null && button.Tag != null)
{
// 將按鈕的 Tag 值 (數字) 追加到輸入框中
inputBoxWordCount.Text += button.Tag.ToString();
}
}
/// <summary>
/// 關閉詞數輸入界面,隱藏相關的 PictureBox 和按鈕。
/// </summary>
/// <param name="sender">觸發事件的按鈕。</param>
/// <param name="e">事件參數。</param>
private void CloseButtonWordCount_Click(object sender, EventArgs e)
{
// 設定詞數輸入界面及其按鈕的可見性為 false使其隱藏
SetPictureBoxWordCountAndButtonsVisibility(false);
}
}
}

View File

@ -4,8 +4,13 @@ using System.Windows.Forms;
namespace DualScreenDemo
{
/*
* (PrimaryForm)
* UI
*/
public partial class PrimaryForm
{
// 各種歌曲搜尋按鈕及其對應的背景圖片 (一般狀態 / 啟動狀態)
private Button zhuyinSearchSongButton;
private Bitmap zhuyinSearchSongNormalBackground;
private Bitmap zhuyinSearchSongActiveBackground;
@ -25,8 +30,15 @@ namespace DualScreenDemo
private Bitmap numberSearchSongNormalBackground;
private Bitmap numberSearchSongActiveBackground;
/// <summary>
/// 點擊「歌曲搜尋」按鈕時的事件處理函式
/// 1. 更新導航按鈕的背景圖片,使「歌曲搜尋」按鈕顯示為啟動狀態
/// 2. 隱藏其他搜尋/分類 UI僅顯示歌曲搜尋選單
/// 3. 若有 QR Code 顯示,則將其隱藏
/// </summary>
private void SongSearchButton_Click(object sender, EventArgs e)
{
// 更新導航按鈕的背景圖片
newSongAlertButton.BackgroundImage = newSongAlertNormalBackground;
hotPlayButton.BackgroundImage = hotPlayNormalBackground;
singerSearchButton.BackgroundImage = singerSearchNormalBackground;
@ -40,7 +52,7 @@ namespace DualScreenDemo
deliciousFoodButton.BackgroundImage = deliciousFoodNormalBackground;
isOnOrderedSongsPage = false;
// 隱藏其他 UI
SetHotSongButtonsVisibility(false);
SetNewSongButtonsVisibility(false);
SetSingerSearchButtonsVisibility(false);
@ -50,14 +62,15 @@ namespace DualScreenDemo
SetZhuYinSingersAndButtonsVisibility(false);
SetZhuYinSongsAndButtonsVisibility(false);
SetEnglishSingersAndButtonsVisibility(false);
SetPinYinSingersAndButtonsVisibility(false);
SetPinYinSongsAndButtonsVisibility(false);
SetPictureBoxToggleLightAndButtonsVisibility(false);
SetPictureBoxSceneSoundEffectsAndButtonsVisibility(false);
// 顯示歌曲搜尋選單按鈕
SetSongSearchButtonsVisibility(true);
// 隱藏 QR Code (若有)
if (pictureBoxQRCode != null)
{
pictureBoxQRCode.Visible = false;
@ -65,12 +78,25 @@ namespace DualScreenDemo
}
}
/// <summary>
/// 設定「歌曲搜尋」相關按鈕的可見性
/// </summary>
/// <param name="isVisible">是否顯示</param>
private void SetSongSearchButtonsVisibility(bool isVisible)
{
pictureBox4.Visible = isVisible;
pictureBox4.Visible = isVisible; // 控制搜尋 UI 背景的可見性
Button[] songSearchButtons = { zhuyinSearchSongButton, englishSearchSongButton, wordCountSearchSongButton, pinyinSearchSongButton, handWritingSearchSongButton, numberSearchSongButton };
// 歌曲搜尋的按鈕陣列
Button[] songSearchButtons = {
zhuyinSearchSongButton,
englishSearchSongButton,
wordCountSearchSongButton,
pinyinSearchSongButton,
handWritingSearchSongButton,
numberSearchSongButton
};
// 設定按鈕可見性,若顯示則移至最前
foreach (var button in songSearchButtons)
{
button.Visible = isVisible;
@ -81,25 +107,41 @@ namespace DualScreenDemo
}
}
/// <summary>
/// 初始化所有「歌曲搜尋」按鈕
/// 依據不同的搜尋方式 (注音、英文、拼音、筆劃、手寫、數字) 建立對應按鈕
/// </summary>
private void InitializeButtonsForSongSearch()
{
InitializeSearchButton(ref zhuyinSearchSongButton, "zhuyinSearchSongButton", 1214, 230, 209, 59, ref zhuyinSearchSongNormalBackground, ref zhuyinSearchSongActiveBackground, normalStateImageSongQuery, mouseDownImageSongQuery, ZhuyinSearchSongsButton_Click);
// 初始化「注音搜尋」按鈕
InitializeSearchButton(ref zhuyinSearchSongButton, "zhuyinSearchSongButton",
1214, 230, 209, 59, ref zhuyinSearchSongNormalBackground, ref zhuyinSearchSongActiveBackground,
normalStateImageSongQuery, mouseDownImageSongQuery, ZhuyinSearchSongsButton_Click);
InitializeSearchButton(ref englishSearchSongButton, "englishSearchSongButton", 1214, 293, 209, 58, ref englishSearchSongNormalBackground, ref englishSearchSongActiveBackground, normalStateImageSongQuery, mouseDownImageSongQuery, EnglishSearchSongsButton_Click);
// 初始化「英文搜尋」按鈕
InitializeSearchButton(ref englishSearchSongButton, "englishSearchSongButton",
1214, 293, 209, 58, ref englishSearchSongNormalBackground, ref englishSearchSongActiveBackground,
normalStateImageSongQuery, mouseDownImageSongQuery, EnglishSearchSongsButton_Click);
InitializeSearchButton(ref pinyinSearchSongButton, "pinyinSearchSongButton", 1214, 356, 209, 58, ref pinyinSearchSongNormalBackground, ref pinyinSearchSongActiveBackground, normalStateImageSongQuery, mouseDownImageSongQuery, PinyinSearchSongsButton_Click);
// 初始化「拼音搜尋」按鈕
InitializeSearchButton(ref pinyinSearchSongButton, "pinyinSearchSongButton",
1214, 356, 209, 58, ref pinyinSearchSongNormalBackground, ref pinyinSearchSongActiveBackground,
normalStateImageSongQuery, mouseDownImageSongQuery, PinyinSearchSongsButton_Click);
InitializeSearchButton(ref wordCountSearchSongButton, "wordCountSearchSongButton", 1214, 418, 209, 59, ref wordCountSearchSongNormalBackground, ref wordCountSearchSongActiveBackground, normalStateImageSongQuery, mouseDownImageSongQuery, WordCountSearchSong_Click);
// 初始化「筆劃搜尋」按鈕
InitializeSearchButton(ref wordCountSearchSongButton, "wordCountSearchSongButton",
1214, 418, 209, 59, ref wordCountSearchSongNormalBackground, ref wordCountSearchSongActiveBackground,
normalStateImageSongQuery, mouseDownImageSongQuery, WordCountSearchSong_Click);
InitializeSearchButton(ref handWritingSearchSongButton, "handWritingSearchSongButton", 1214, 481, 209, 59, ref handWritingSearchSongNormalBackground, ref handWritingSearchSongActiveBackground, normalStateImageSongQuery, mouseDownImageSongQuery, HandWritingSearchButtonForSongs_Click);
// 初始化「手寫搜尋」按鈕
InitializeSearchButton(ref handWritingSearchSongButton, "handWritingSearchSongButton",
1214, 481, 209, 59, ref handWritingSearchSongNormalBackground, ref handWritingSearchSongActiveBackground,
normalStateImageSongQuery, mouseDownImageSongQuery, HandWritingSearchButtonForSongs_Click);
InitializeSearchButton(ref numberSearchSongButton, "numberSearchSongButton", 1214, 544, 209, 58, ref numberSearchSongNormalBackground, ref numberSearchSongActiveBackground, normalStateImageSongQuery, mouseDownImageSongQuery, NumberSearchButton2_Click);
// 初始化「數字搜尋」按鈕
InitializeSearchButton(ref numberSearchSongButton, "numberSearchSongButton",
1214, 544, 209, 58, ref numberSearchSongNormalBackground, ref numberSearchSongActiveBackground,
normalStateImageSongQuery, mouseDownImageSongQuery, NumberSearchButton2_Click);
}
}
}
}

View File

@ -7,6 +7,7 @@ ZhuYinSongs = themes\superstar\歌名\注音\VOD_歌名查詢_注音查詢(按
EnglishSongs = themes\superstar\歌名\英文\VOD_歌名查詢_英文查詢(按鍵)_歌星查詢-注音查詢_未按.png
PinYinSongs = themes\superstar\歌星\拼音\VOD_歌星查詢_拼音查詢(按鍵)_歌星查詢-注音查詢_未按.png
HandWritingSongs = themes\superstar\歌星\手寫\3.歌星查詢(手寫按鍵)_未按.png
WordCountSongs = themes\superstar\歌名\編號\VOD_歌名查詢_編號查詢(按鍵)_未按.png
[PictureBoxZhuYinSingers]
X = 130
@ -44,6 +45,12 @@ Y = 350
Width = 1079
Height = 394
[PictureBoxWordCountSongs]
X = 130
Y = 350
Width = 1079
Height = 394
[PhoneticSymbols]
Symbols=ㄅ,ㄉ,ㄍ,ㄐ,ㄓ,ㄗ,ㄛ,ㄡ,ㄤ,ㄧ,ㄆ,ㄊ,ㄎ,ㄑ,ㄔ,ㄘ,ㄜ,ㄢ,ㄦ,ㄨ,ㄇ,ㄋ,ㄏ,ㄒ,ㄕ,ㄙ,ㄞ,ㄣ,ㄩ,ㄈ,ㄌ, ,ㄖ,ㄚ,ㄠ
@ -595,4 +602,75 @@ Height = 63
FontName = Times New Roman
FontSize = 26
FontStyle = Regular
ForeColor = Black
ForeColor = Black
[InputBoxWordCountSongs]
X=150
Y=264
Width=596
Height=63
FontName=微軟正黑體
FontSize=26
FontStyle=Bold
ForeColor=Black
[NumberButtonCoordinatesWithWordCount]
button1 = 157,201,27,32
button2 = 187,201,27,32
button3 = 217,201,27,32
button4 = 247,201,27,32
button5 = 277,200,27,32
button6 = 307,201,27,32
button7 = 337,201,27,32
button8 = 367,201,27,32
button9 = 397,201,27,32
button10 = 427,201,27,32
[NumberButtonImagesWithWordCount]
button0_normal = themes\superstar\歌名\編號\VOD_歌名查詢_編號查詢(按鍵)-02.png
button0_mouseDown = themes\superstar\歌名\編號\VOD_歌名查詢_編號查詢(按鍵)-17.png
button0_mouseOver = themes\superstar\歌名\編號\VOD_歌名查詢_編號查詢(按鍵)-02.png
button1_normal = themes\superstar\歌名\編號\VOD_歌名查詢_編號查詢(按鍵)-03.png
button1_mouseDown = themes\superstar\歌名\編號\VOD_歌名查詢_編號查詢(按鍵)-18.png
button1_mouseOver = themes\superstar\歌名\編號\VOD_歌名查詢_編號查詢(按鍵)-03.png
button2_normal = themes\superstar\歌名\編號\VOD_歌名查詢_編號查詢(按鍵)-04.png
button2_mouseDown = themes\superstar\歌名\編號\VOD_歌名查詢_編號查詢(按鍵)-19.png
button2_mouseOver = themes\superstar\歌名\編號\VOD_歌名查詢_編號查詢(按鍵)-04.png
button3_normal = themes\superstar\歌名\編號\VOD_歌名查詢_編號查詢(按鍵)-05.png
button3_mouseDown = themes\superstar\歌名\編號\VOD_歌名查詢_編號查詢(按鍵)-20.png
button3_mouseOver = themes\superstar\歌名\編號\VOD_歌名查詢_編號查詢(按鍵)-05.png
button4_normal = themes\superstar\歌名\編號\VOD_歌名查詢_編號查詢(按鍵)-06.png
button4_mouseDown = themes\superstar\歌名\編號\VOD_歌名查詢_編號查詢(按鍵)-21.png
button4_mouseOver = themes\superstar\歌名\編號\VOD_歌名查詢_編號查詢(按鍵)-06.png
button5_normal = themes\superstar\歌名\編號\VOD_歌名查詢_編號查詢(按鍵)-07.png
button5_mouseDown = themes\superstar\歌名\編號\VOD_歌名查詢_編號查詢(按鍵)-22.png
button5_mouseOver = themes\superstar\歌名\編號\VOD_歌名查詢_編號查詢(按鍵)-07.png
button6_normal = themes\superstar\歌名\編號\VOD_歌名查詢_編號查詢(按鍵)-08.png
button6_mouseDown = themes\superstar\歌名\編號\VOD_歌名查詢_編號查詢(按鍵)-23.png
button6_mouseOver = themes\superstar\歌名\編號\VOD_歌名查詢_編號查詢(按鍵)-08.png
button7_normal = themes\superstar\歌名\編號\VOD_歌名查詢_編號查詢(按鍵)-09.png
button7_mouseDown = themes\superstar\歌名\編號\VOD_歌名查詢_編號查詢(按鍵)-24.png
button7_mouseOver = themes\superstar\歌名\編號\VOD_歌名查詢_編號查詢(按鍵)-09.png
button8_normal = themes\superstar\歌名\編號\VOD_歌名查詢_編號查詢(按鍵)-10.png
button8_mouseDown = themes\superstar\歌名\編號\VOD_歌名查詢_編號查詢(按鍵)-25.png
button8_mouseOver = themes\superstar\歌名\編號\VOD_歌名查詢_編號查詢(按鍵)-10.png
button9_normal = themes\superstar\歌名\編號\VOD_歌名查詢_編號查詢(按鍵)-11.png
button9_mouseDown = themes\superstar\歌名\編號\VOD_歌名查詢_編號查詢(按鍵)-26.png
button9_mouseOver = themes\superstar\歌名\編號\VOD_歌名查詢_編號查詢(按鍵)-11.png
[ModifyButtonImagesWordCount]
normal = themes\superstar\歌星\拼音\VOD_歌名查詢_編號查詢(按鍵)-13.png
mouseOver = themes\superstar\歌星\拼音\VOD_歌名查詢_編號查詢(按鍵)-13.png
mouseDown = themes\superstar\歌星\拼音\VOD_歌名查詢_編號查詢(按鍵)-28.png
[ClearButtonImagesWordCount]
normal = themes\superstar\歌名\拼音\VOD_歌名查詢_編號查詢(按鍵)-14.png
mouseOver = themes\superstar\歌名\拼音\VOD_歌名查詢_編號查詢(按鍵)-14.png
mouseDown = themes\superstar\歌名\拼音\VOD_歌名查詢_編號查詢(按鍵)-29.png
[CloseButtonImagesWordCount]
normal = themes\superstar\歌名\拼音\VOD_歌名查詢_編號查詢(按鍵)-15.png
mouseOver = themes\superstar\歌名\拼音\VOD_歌名查詢_編號查詢(按鍵)-15.png
mouseDown = themes\superstar\歌名\拼音\VOD_歌名查詢_編號查詢(按鍵)-30.png