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

打造 Dreamweaver 風格多視窗應用:隱藏主視窗、任務列獨立顯示、共享資料架構

     編輯:VC 教學

現象分析:Dreamweaver 的視窗管理奧秘

Dreamweaver (早期版本) 每開啟一個檔案,任務列就出現一個獨立按鈕,關閉任一視窗不影響其他視窗,彷彿每個視窗都是獨立進程。實則它們屬於同一進程,共享記憶體空間與資料 (如最近開啟路徑、設定檔)。

核心技術點:

  1. 建立多個頂層視窗 (WS_EX_APPWINDOW 或設定 ParentWindow = GetDesktopWindow()),使其各自在任務列顯示按鈕。
  2. 隱藏真正的主視窗 (Application->ShowMainForm = false + ShowWindow(SW_HIDE))。
  3. 由「最後一個視窗關閉」觸發整個應用程式結束。

C++ Builder 實作完整範例

以下以 C++ Builder (VCL) 為例,邏輯同樣適用於 MFC/Win32 API。

步驟 1:專案架構

  • 建立標準 VCL 應用程式,包含 Form1 (主視窗) 與 Form2 (文件視窗)。
  • Form2 設為不自動建立 (Project Options → Forms → 移出 Auto-create list)。

步驟 2:主視窗啟動時建立多個文件視窗


// Form1.h
public:
    int FormCount; // 追蹤存活的 Form2 實例數

// Form1.cpp - OnCreate
void __fastcall TForm1::FormCreate(TObject *Sender)
{
    // 取得標準視窗風格
    int style = GetWindowLong(Handle, GWL_STYLE);

    // 建立兩個 Form2 實例
    TForm2 *F = new TForm2(NULL); // Owner=NULL 表示由應用程式管理生命週期
    TForm2 *G = new TForm2(NULL);

    // 關鍵:設為桌面視窗的子視窗 -> 成為頂層視窗,獨立顯示於任務列
    F->ParentWindow = GetDesktopWindow();
    G->ParentWindow = GetDesktopWindow();

    F->Caption = "Document F";
    G->Caption = "Document G";

    // 套用相同視窗風格
    SetWindowLong(F->Handle, GWL_STYLE, style);
    SetWindowLong(G->Handle, GWL_STYLE, style);

    FormCount = 2;
    F->Show();
    G->Show();
}

步驟 3:修改 WinMain 隱藏主視窗與 Application


// Project1.cpp (WinMain)
WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
    try
    {
        Application->Initialize();
        Application->CreateForm(__classid(TForm1), &Form1);

        // 關鍵兩步:隱藏主視窗與 Application 視窗
        Application->ShowMainForm = false; // 不自動 Show Form1
        ShowWindow(Application->Handle, SW_HIDE); // 隱藏隱形 Application 視窗

        Application->Run();
    }
    catch (Exception &exception)
    {
        Application->ShowException(&exception);
    }
    return 0;
}

注意:單靠 ShowMainForm=false 不足,必須同時 ShowWindow(Application->Handle, SW_HIDE),否則 Alt+Tab 仍會出現空白應用程式圖示。

步驟 4:文件視窗關閉邏輯 - 最後一個關閉時結束程式


// Form2.cpp - OnClose
void __fastcall TForm2::FormClose(TObject *Sender, TCloseAction &Action)
{
    Action = caFree; // 釋放記憶體

    if (Form1->FormCount > 1)
    {
        Form1->FormCount--; // 還有其他視窗,僅遞減計數
    }
    else
    {
        Application->Terminate(); // 最後一個視窗,結束整個應用程式
    }
}

MFC/Win32 API 移植要點

C++ Builder / VCLMFC / Win32 API 對應
ParentWindow = GetDesktopWindow()CreateWindowEx(WS_EX_APPWINDOW, ..., NULL, ...) 或 SetParent(hwnd, NULL) + SetWindowLong(GWL_EXSTYLE, WS_EX_APPWINDOW)
Application->ShowMainForm=falsem_pMainWnd->ShowWindow(SW_HIDE) 在 InitInstance 中
ShowWindow(Application->Handle, SW_HIDE)MFC 無 Application 視窗概念,無需此步
Application->Terminate()PostQuitMessage(0) 或 AfxGetMainWnd()->PostMessage(WM_CLOSE)

MFC 版核心程式碼片段


// CMyApp::InitInstance
BOOL CMyApp::InitInstance()
{
    // ... 標準初始化 ...

    // 不建立主框架視窗,或建立後立即隱藏
    CMainFrame* pMainFrame = new CMainFrame;
    if (!pMainFrame->LoadFrame(IDR_MAINFRAME)) return FALSE;
    m_pMainWnd = pMainFrame;
    pMainFrame->ShowWindow(SW_HIDE); // 隱藏主視窗
    pMainFrame->UpdateWindow();

    // 建立第一個文件視窗
    CreateNewDocumentWindow();
    return TRUE;
}

// 建立新文件視窗 (對應 Form2)
void CMyApp::CreateNewDocumentWindow()
{
    CChildFrame* pFrame = new CChildFrame;
    if (pFrame->Create(NULL, _T("Document"), WS_OVERLAPPEDWINDOW | WS_EX_APPWINDOW, rectDefault, NULL, 0))
    {
        pFrame->ShowWindow(SW_SHOW);
        pFrame->UpdateWindow();
        m_nDocWindowCount++; // 成員變數追蹤數量
    }
}

// CChildFrame::OnClose
void CChildFrame::OnClose()
{
    CMDIChildWnd::OnClose(); // 執行 caFree 等效邏輯
    if (--((CMyApp*)AfxGetApp())->m_nDocWindowCount == 0)
    {
        AfxGetMainWnd()->PostMessage(WM_CLOSE); // 最後一個,關閉隱藏主視窗觸發結束
    }
}

資料共享機制

所有文件視窗屬於同一進程,共享機制天然存在:

  • 全域/靜態變數:最直接,但需注意執行緒安全。
  • Application 物件成員 (VCL) / CWinApp 派生類成員 (MFC):集中管理設定、最近檔案清單、快取資料。
  • 單例模式服務類別:封裝特定領域資料 (如專案設定、資料庫連線池)。

結語

Dreamweaver 風格的核心在於「多頂層視窗 + 隱藏主視窗 + 參考計數生命週期」。此架構適合文件導向應用 (IDE、圖片編輯器、文書處理),提供類似多進程的使用者體驗,同時享有單進程的低資源佔用與高效資料共享。移植到現代框架 (Qt, WPF, Electron) 時,同樣遵循此核心邏輯。

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