CButtonST 功能極強,但缺少「滑鼠經過播放聲音」這一增強交互體驗的小功能。本文展示如何通過修改源碼 (BtnST.h/.cpp) 為其添加聲音支援:**簡單 Beep 音或播放自訂 WAVE 資源**,並透過 SetPlaySound(BOOL, LPCTSTR) 統一介面控制。
BtnST.h 引入多媒體庫與宣告新介面#include#pragma comment(lib, "Winmm.lib") class CButtonST : public CButton { private: CString m_strSoundID; // WAVE 資源 ID BOOL m_bPlaySound = FALSE; // 是否啟用聲音 public: void PlaySound(); // 內部播放邏輯 void SetPlaySound(BOOL bPlaySound, LPCTSTR pszSoundID = NULL); // 公開設定介面 // ... 原有成員 ... };
CButtonST::CButtonST()
{
m_bPlaySound = FALSE;
m_strSoundID = _T("");
// ... 原有初始化 ...
}
PlaySound 與 SetPlaySoundvoid CButtonST::PlaySound()
{
if (!m_bPlaySound) return;
if (m_strSoundID.IsEmpty())
{
::MessageBeep(-1); // 系統預設 Beep
return;
}
// 播放專案內嵌 WAVE 資源
HINSTANCE hInst = AfxGetInstanceHandle();
HRSRC hRes = FindResource(hInst, m_strSoundID, _T("WAVE"));
if (!hRes) return;
HGLOBAL hGlob = LoadResource(hInst, hRes);
if (!hGlob) return;
LPSTR lpData = (LPSTR)LockResource(hGlob);
if (!lpData) return;
// SND_ASYNC 非同步播放,不阻塞 UI 執行緒
::sndPlaySound(lpData, SND_MEMORY | SND_ASYNC);
FreeResource(hGlob);
}
void CButtonST::SetPlaySound(BOOL bPlaySound, LPCTSTR pszSoundID)
{
m_bPlaySound = bPlaySound;
m_strSoundID = pszSoundID ? pszSoundID : _T("");
}
OnMouseMove 滑鼠進入判斷中觸發播放// CButtonST::OnMouseMove 內部,滑鼠確認進入按鈕區域後
if (!m_bMouseOnButton)
{
m_bMouseOnButton = TRUE;
Invalidate(); // 觸發重繪 (熱態)
// 註冊離開追蹤
m_csTME.cbSize = sizeof(m_csTME);
m_csTME.dwFlags = TME_LEAVE;
m_csTME.hwndTrack = m_hWnd;
::_TrackMouseEvent(&m_csTME);
// ==== 新增:播放聲音 ====
PlaySound();
}
// ... 原有邏輯 ...
OnInitDialog)| 模式 | 代碼 | 效果 |
|---|---|---|
| 系統 Beep 音 | m_btn.SetPlaySound(TRUE); | 滑鼠經過發出系統預設 "Ding" 音 |
| 自訂 WAVE 資源 | m_btn.SetPlaySound(TRUE, _T("IDR_WAVE1")); | 播放專案資源 ID 為 IDR_WAVE1 的 .wav 檔 |
.wav 檔。IDR_WAVE1 (類型自動識別為 WAVE)。resource.h 定義 #define IDR_WAVE1 1000 (或類似)。SetFlat(TRUE) (扁平模式) 下生效**,因聲音觸發邏輯綁定在扁平模式的滑鼠進入偵測中。SND_ASYNC) 避免 UI 卡頓,但快速移動滑鼠可能疊加多聲音,實際專案可加入防抖邏輯 (如 m_bSoundPlaying 標記)。CButtonSTEx : public CButtonST 而非直接修改原檔 (本文為演示原理直接修改)。