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

MFC 浮動工具列移除關閉按鈕:自訂 CToolBarEx 處理 WM_WINDOWPOSCHANGED 實作

     編輯:關於VC++

前言:需求背景

MFC 預設浮動工具列 (拖離主框架) 右上角會有「關閉」按鈕 (系統選單)。某些應用需移除此按鈕防止使用者誤關。本文透過繼承 `CToolBar` 實作 `CToolBarEx`,攔截視窗位置變更訊息,動態修改父視窗樣式移除 `WS_SYSMENU`。

核心原理

  1. 浮動工具列由 `CMiniFrameWnd` 包裹 (MFC 內部實作)
  2. `CControlBar::m_pDockBar` 指向停駐列物件,其 `GetParent()` 即為 `CMiniFrameWnd`
  3. 移除 `CMiniFrameWnd` 的 `WS_SYSMENU` 樣式即可隱藏關閉按鈕
  4. 需在浮動狀態下執行一次,停駐時恢復

實作步驟

1. 建立 CToolBarEx 類別 (ClassWizard → Add Class → MFC Class → Base: CToolBar)

2. ToolBarEx.h


#pragma once
class CToolBarEx : public CToolBar {
    DECLARE_DYNAMIC(CToolBarEx)
public:
    CToolBarEx();
    virtual ~CToolBarEx();
protected:
    BOOL m_bMenuRemoved; // 狀態旗標
    afx_msg void OnWindowPosChanged(WINDOWPOS FAR* lpwndpos);
    DECLARE_MESSAGE_MAP()
};

3. ToolBarEx.cpp


#include "StdAfx.h"
#include "ToolBarEx.h"
#include  // CMiniFrameWnd 定義

IMPLEMENT_DYNAMIC(CToolBarEx, CToolBar)

BEGIN_MESSAGE_MAP(CToolBarEx, CToolBar)
    ON_WM_WINDOWPOSCHANGED()
END_MESSAGE_MAP()

CToolBarEx::CToolBarEx() : m_bMenuRemoved(FALSE) {}
CToolBarEx::~CToolBarEx() {}

void CToolBarEx::OnWindowPosChanged(WINDOWPOS FAR* lpwndpos) {
    CToolBar::OnWindowPosChanged(lpwndpos);

    // 僅在浮動狀態處理
    if (IsFloating()) {
        if (m_pDockBar && !m_bMenuRemoved) {
            CWnd* pParent = m_pDockBar->GetParent(); // 取得 CMiniFrameWnd
            if (pParent->IsKindOf(RUNTIME_CLASS(CMiniFrameWnd))) {
                pParent->ModifyStyle(WS_SYSMENU, 0, 0); // 移除系統選單
                m_bMenuRemoved = TRUE;
            }
        }
    }
    else if (m_bMenuRemoved) { // 重新停駐,重置旗標
        m_bMenuRemoved = FALSE;
    }
}

4. 套用至主框架

在 `MainFrm.h` 修改工具列成員型別:


#include "ToolBarEx.h"
// ...
protected:
    CToolBarEx m_wndToolBar; // 原為 CToolBar

關鍵技術點解析

點說明
為何用 WM_WINDOWPOSCHANGED涵蓋大小、位置、Z 序變更;WM_SIZE 僅大小變更時觸發,浮動拖曳不一定觸發
IsFloating()CControlBar 成員函式,判斷是否為浮動狀態
m_pDockBarCControlBar 成員,指向 CDockBar,浮動時其父視窗為 CMiniFrameWnd
ModifyStyle(WS_SYSMENU, 0)移除 WS_SYSMENU 樣式,即隱藏標題列與關閉按鈕
m_bMenuRemoved 旗標確保僅執行一次,避免重複修改;停駐時重置

擴充應用

  • 移除標題列但保留拖曳:同樣移除 `WS_CAPTION`,但需自行實作拖曳邏輯
  • 動態切換:提供 `SetCloseButtonVisible(BOOL)` 介面,內部呼叫 `ModifyStyle` 並 `SetWindowPos(..., SWP_FRAMECHANGED)`
  • 其他控制列:同樣適用於 `CStatusBar`、`CDialogBar` 等 `CControlBar` 派生類

測試驗證

  1. 編譯執行,拖曳工具列使其浮動
  2. 觀察浮動視窗右上角:無關閉按鈕、無系統選單圖示
  3. 將工具列拖回停駐位置,再次拖出:關閉按鈕仍不出現 (旗標機制正確)
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved