首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> 關於VC++

VC++ 實作自訂訊息與視窗客製化技巧完整指南

     編輯:關於VC++

前言:Windows 訊息機制與自訂需求

Windows 應用程式幾乎所有工作都建立在訊息處理機制之上,系統訊息分為標準視窗訊息、控制項通知訊息與命令訊息三大類。然而實際開發中,我們常需要定義專屬訊息來通知程式特定事件發生,這就是「使用者自訂訊息」。由於 ClassWizard 不支援直接新增自訂訊息,必須手動撰寫程式碼,完成後 ClassWizard 才能像處理標準訊息一樣管理自訂訊息。

一、自訂訊息的四步驟實作流程

第一步:定義訊息常數

Microsoft 建議自訂訊息編號至少從 WM_USER + 100 開始,避免與新版控制項使用的 WM_USER 範圍衝突。範例:

#define WM_MY_MESSAGE (WM_USER + 100)

第二步:實作訊息處理函式

處理函式必須採用標準簽名,回傳 LRESULT,接受 WPARAM 與 LPARAM 兩個參數:

LRESULT CMainFrame::OnMyMessage(WPARAM wParam, LPARAM lParam)
{
    // TODO: 處理自訂訊息邏輯
    AfxMessageBox(_T("收到自訂訊息"));
    return 0;
}

第三步:在類別標頭檔宣告處理函式

於 AFX_MSG 區塊中加入函式宣告:

class CMainFrame : public CMDIFrameWnd
{
    // ...
protected:
    //{{AFX_MSG(CMainFrame)
    afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
    afx_msg void OnTimer(UINT nIDEvent);
    afx_msg LRESULT OnMyMessage(WPARAM wParam, LPARAM lParam);
    //}}AFX_MSG
    DECLARE_MESSAGE_MAP()
};

第四步:訊息對應表註冊

使用 ON_MESSAGE 巨集將訊息 ID 對應至處理函式:

BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWnd)
    //{{AFX_MSG_MAP(CMainFrame)
    ON_WM_CREATE()
    ON_WM_TIMER()
    ON_MESSAGE(WM_MY_MESSAGE, OnMyMessage)
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()
進階技巧: 若需系統全域唯一訊息,可改用 RegisterWindowMessage SDK 函式搭配 ON_REGISTERED_MESSAGE 巨集,其他步驟相同。

二、MDI 視窗客製化實戰技巧

VC++ 雖提供強大的視窗生成工具,但預設樣式千篇一律。以下介紹多種客製化手法,打造專屬程式風格。

1. 取消 MDI 啟動時的預設子視窗

在 CMyMDIApp::InitInstance() 中,命令列解析程式碼之後加入:

cmdInfo.m_nShellCommand = CCommandLineInfo::FileNothing;

執行後程式僅顯示主框架視窗,不再自動開啟子視窗。

2. 修改視窗標題列文字

方法一: 呼叫 CWnd::SetWindowText() 設定固定標題。
方法二(保留文件名): 使用資源編輯器修改字串表 IDR_MAINFRAME 的 caption 欄位,第一個參數即為主視窗標題。
方法三(移除文件名後綴): 在 CMainFrame::PreCreateWindow 中移除 FWS_ADDTOTITLE 樣式旗標:

cs.style &= ~FWS_ADDTOTITLE;

3. 客製化主框架、子視窗與檢視區風格

透過覆寫 PreCreateWindow(CREATESTRUCT& cs) 修改建立參數:

主框架視窗範例:

BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
    if (!CFrameWnd::PreCreateWindow(cs))
        return FALSE;

    cs.cx = 450; cs.cy = 300;               // 設定初始尺寸
    cs.style = WS_POPUPWINDOW;              // 移除標題列與最大化按鈕
    return CFrameWnd::PreCreateWindow(cs);
}

子視窗範例:

BOOL CChildFrame::PreCreateWindow(CREATESTRUCT& cs)
{
    // 修改 cs 結構調整子視窗屬性
    return CMDIChildWnd::PreCreateWindow(cs);
}

檢視視窗範例(設定白底、無游標、重繪):

BOOL CMyView::PreCreateWindow(CREATESTRUCT& cs)
{
    cs.lpszClass = AfxRegisterWndClass(
        CS_HREDRAW | CS_VREDRAW,
        0,
        (HBRUSH)::GetStockObject(WHITE_BRUSH),
        0);
    return CScrollView::PreCreateWindow(cs);
}

AfxRegisterWndClass 參數依序為:類別風格、游標控制碼、背景筆刷、圖示控制碼。

4. 捲動視窗實作

使用 CScrollView 簡化捲動邏輯,於 OnInitialUpdate 設定捲動範圍:

void CMyScrollView::OnInitialUpdate()
{
    CScrollView::OnInitialUpdate();
    CSize sizePage(400, 400);  // 水平/垂直捲動閾值
    SetScrollSizes(MM_TEXT, sizePage);
}

視窗尺寸小於 400×400 像素時自動顯示捲動條;若修改為 sizePage(600, 800),則 600×800 以下才出現捲動條。

5. 視窗分割器應用

在 MainFrm.h 加入分割器成員與覆寫函式:

CSplitterWnd m_wndSplitter;
virtual BOOL OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext);

於 MainFrm.cpp 實作:

BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
{
    return m_wndSplitter.Create(this, 2, 2, CSize(20, 20), pContext);
}

參數說明:父視窗、列數(2)、行數(2)、最小格尺寸、建立內容。分割後需呼叫 pDoc->UpdateAllViews(NULL) 同步各格內容。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved