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

Windows 非矩形視窗程式設計完整教學:從幾何圖形到任意形狀

     編輯:關於VC++

絕大多數 Windows 應用程式皆採用標準矩形視窗,雖然實作簡單、風格簡潔,適合文件處理類與簡單遊戲應用,但在娛樂性程式中顯得缺乏生氣。若能以非矩形視窗取代傳統矩形框架,將大幅提升程式趣味性。典型例子如 Windows Media Player 新版控制面板,依選取面板形狀呈現播放器外型,遠比舊版矩形介面生動。實作非矩形視窗並不困難,掌握核心原理後即可創建各式有趣視窗。

核心原理:Region 機制

所有 Windows 視窗皆位於一個稱為「Region」的區域中。若視窗大小超出 Region 範圍,Windows 會自動裁切超出部分使其不可見。建立非矩形視窗僅需兩步驟:

  1. 建立非矩形 Region
  2. 將視窗套用至該 Region

第二步極為簡單,僅需呼叫 API 函式 SetWindowRgn:

int SetWindowRgn(HWND hWnd, HRGN hRgn, BOOL bRedraw);

MFC 中對應 CWnd::SetWindowRgn(HRGN hRgn, BOOL bRedraw)。參數含義相同:hWnd 為目標視窗控制代碼,hRgn 為已建立的 Region 控制代碼,bRedraw 決定是否重繪。

第一步視非矩形複雜度而異。MFC 中 Region 物件由 CRgn 類別實現,其成員函式幾乎皆有對應的 SDK API 函式。

簡單 Region 建立方法

CRgn 提供四種基本建立函式:

  • CreateRectRgn:矩形 Region
  • CreateEllipticRgn:圓形/橢圓 Region
  • CreateRoundRectRgn:圓角矩形 Region
  • CreatePolygonRgn:多邊形 Region

範例:建立橢圓視窗

將下列程式碼加入 MFC 對話方塊專案的 OnInitDialog 中:

BOOL CTestDlg::OnInitDialog() {
    CDialog::OnInitDialog();
    CRgn rgn;
    rgn.CreateEllipticRgn(0, 0, 200, 100);  // 左上(0,0) 右下(200,100)
    SetWindowRgn(rgn, TRUE);
    return TRUE;
}

繪圖路徑法建立 Region

此法可建立更豐富形狀,流程如下:

  1. 繪製目標形狀:使用 CDC::BeginPath() 開始追蹤繪圖過程,SetBkMode(TRANSPARENT) 設定透明背景,繼而呼叫 Arc、LineTo、TextOut 等繪圖函式,最後以 EndPath() 結束追蹤。
  2. 轉換為 Region:呼叫 SDK API PathToRegion(HDC hdc),將裝置環境中的路徑轉為 Region 控制代碼。

範例:文字形狀視窗

按鈕點擊事件中實作「Hello」文字形狀視窗:

void CTestDlg::OnTest() {
    HRGN wndRgn;
    CClientDC dc(this);
    CFont mFont;

    if (dc.m_hDC != NULL) {
        VERIFY(mFont.CreateFont(200, 50, 0, 0, FW_HEAVY, TRUE, FALSE, 0,
            ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
            DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, "宋體"));

        dc.BeginPath();
        dc.SetBkMode(TRANSPARENT);  // 必須設定透明模式

        CFont* pOldFont = dc.SelectObject(&mFont);
        dc.TextOut(0, 0, "Hello");
        dc.SelectObject(pOldFont);
        dc.EndPath();

        wndRgn = ::PathToRegion(dc.m_hDC);
        this->SetWindowRgn(wndRgn, TRUE);
    }
}

根據點陣圖建立 Region

此法可實現任意圖片形狀視窗,步驟較複雜:

  1. 準備含目標視窗形狀的圖片,指定透明色(如藍色 RGB(0,0,255))標記非視窗區域。
  2. 程式載入圖片後逐行掃描每個像素,非透明色處建立單像素高的矩形 Region。
  3. 使用 CRgn::CombineRgn 以 RGN_OR 模式合併所有小 Region 形成完整形狀。

核心實作碼

void SetupRegion(CDC* pDC, CBitmap& cBitmap, COLORREF TransColor) {
    CDC memDC;
    memDC.CreateCompatibleDC(pDC);
    CBitmap* pOldMemBmp = memDC.SelectObject(&cBitmap);

    CRgn wndRgn;
    wndRgn.CreateRectRgn(0, 0, 0, 0);  // 初始空 Region

    BITMAP bit;
    cBitmap.GetBitmap(&bit);

    for (int y = 0; y <= bit.bmHeight; y++) {
        CRgn rgnTemp;
        int iX = 0;
        do {
            // 跳過透明色尋找非透明色起始點
            while (iX <= bit.bmWidth && memDC.GetPixel(iX, y) == TransColor) iX++;
            int iLeftX = iX;
            // 尋找下一個透明色作為結束點
            while (iX <= bit.bmWidth && memDC.GetPixel(iX, y) != TransColor) ++iX;
            // 建立單列高度的矩形 Region
            rgnTemp.CreateRectRgn(iLeftX, y, iX, y + 1);
            // 合併至主 Region
            wndRgn.CombineRgn(&wndRgn, &rgnTemp, RGN_OR);
            rgnTemp.DeleteObject();  // 必須刪除暫存 Region
        } while (iX <= bit.bmWidth);
    }

    memDC.SelectObject(pOldMemBmp);
    CWnd* pWnd = pDC->GetWindow();
    pWnd->SetWindowRgn(wndRgn, TRUE);
    pWnd->SetForegroundWindow();
}

搭配 OnEraseBkgnd 繪製該點陣圖,即可獲得與圖片形狀完全一致的視窗。

三種方法比較總結

方法複雜度適用場景
基本幾何函式最低簡單幾何形狀(圓、矩形、圓角矩形、多邊形)
繪圖路徑法中等文字、曲線、複合幾何圖形
點陣圖掃描法最高任意複雜圖片形狀

依需求選擇適當方法:簡單幾何形狀用第一法;需文字或曲線組合用第二法;任意圖片外型用第三法。

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