【轉】Windows 中不規則表單的編程實現

來源:互聯網
上載者:User

標籤:

 

一、序言

在絕大多數的Windows應用程式中,其表單都是使用的正規正矩的矩形表單,例如我們常用的,“記事本”,“掃雷”,等等。矩形表單,具有編程實現簡單,風格簡潔的優點,所以在普通文檔應用程式和簡單小遊戲中使用足矣。但在某些娛樂遊戲程式中使用就略顯呆板些了,這時若用不規則表單替代原先的矩形表單,將會使這類程式更添情趣。典型的例子有windows 自代的Media Player,新版本的Media Player有個控制台的選項,選中這些面板,播放器就以選中的面板形狀出現,這時的播放器比以前版本的Media Player的古老矩形介面要生動有趣的多了。 要實現不規則表單不是太難,知道了基本原理後,你也可以建立各種有趣的不規則表單。

二、實現原理

所有的 Windows 表單都位於一個稱為“region”中,表單的大小如果超出“region”的範圍,windows 會自動裁剪超出"region"範圍那部分的表單,使其不可見。所以,要建立不規則表單有兩個步驟:第一步就是建立不規則"region".第二步就是將表單放到建立的“region”中。

其中第二步很簡單就調用一條語句即可。在SDK中調用API函數SetWindowRgn,該函數原型如下:

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

其中hWnd為待設定的表單控制代碼,hRgn為已經建立的"region"控制代碼,bRedraw代表是否要重繪表單。在MFC 中使用視窗類別CWnd的成員函數int CWnd::SetWindowRgn(HRGN hRgn, BOOL bRedraw );該函數的參數意義與API中同名函數相同。

相對與第二步,建立不規則表單的第一步要複雜許多,並且不規則表單越複雜,建立其"region"的過程也越複雜。接下去我們將由淺入深地介紹各種建立”region”的方法。

在MFC中"region"對象,由CRgn類實現。CRgn的幾乎每個成員函數都有同名的SDK API函數對應。

三、簡單“region”的建立

類CRgn建立一個新的"region"的簡單方法有以下幾個成員函數:

1.BOOL CRgn::CreateRectRgn( int x1, int y1, int x2, int y2 ); 建立矩形的“region”。

2.BOOL CRgn::CreateEllipticRgn( int x1, int y1, int x2, int y2 ); 建立圓形或橢圓形“region”。

3.BOOL CRgn::CreateRoundRectRgn( int x1, int y1, int x2, int y2, int x3, int y3 ); 建立圓角矩形“region”。

4.BOOL CRgn::CreatePolygonRgn( LPPOINT lpPoints, int nCount, int nMode ); 建立多邊形“region”。

這裡以建立橢圓表單為例,介紹橢圓表單建立的方法。在建立橢圓“region”的CreateEllipticRgn函數中,x1,y1指橢圓所在矩形的左上方座標,x2,y2指該矩形的右下角座標。

下面的代碼加入到MFC對話方塊程式的OnInitDialog函數中,可將該對話方塊變成橢圓表單:

BOOL CTestDlg::OnInitDialog(){    CDialog::OnInitDialog();    ...    CRgn rgn;    rgn. CreateEllipticRgn(0,0,200,100);    SetWindowRgn(rgn,TRUE);}

 

圖一 橢圓表單

四、作圖路徑法建立”region”

使用該方法建立”region”的過程如下:

第一步繪製所要建立的表單形狀。

該步驟中使用到CDC類中的一些成員函數如下:

BOOL CDC::BeginPath( );

 

調用該函數後當前裝置環境(DC)開始追蹤繪圖的過程。

int CDC::SetBkMode( int nBkMode );

設定繪圖時的背景模式,此應用中nBkMode必須取值為TRANSPARENT 。即設定繪圖時背景不發生變化。

BOOL CDC::EndPath( );

調用該函數後當前裝置環境(DC)結束追蹤繪圖的過程。

開始繪圖前,先調用BeginPath,然後調用SetBkMode。接下去就可調用CDC的其他繪圖函數作圖,例如Arc,AngleArc,LineTo,MoveTo,RoundRect,,Textout等等。繪圖完畢調用EndPath().

第二步將繪製的結果轉成”region”.

此步驟中使用SDK API函數

HRGN PathToRegion( HDC hdc );

Hdc為作圖DC的控制代碼, CDC類中的m_hDC成員變數可做此參數傳入。樣本,將下面代碼加入某個按鈕單擊事件中,可以將當前表單變為字串”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;        pOldFont = dc.SelectObject( &mFont );        dc.TextOut(0, 0, "Hello");             //結束記錄表單輪廓路徑        dc.SelectObject( pOldFont );        dc.EndPath();                 //把所記錄的路徑轉化為表單輪廓控制代碼        wndRgn = ::PathToRegion(dc.m_hDC);         //賦予表單指定的輪廓形狀        this->SetWindowRgn(wndRgn, TRUE);           }}

 

CClientDC是CDC的衍生類別,故此該類具有所有CDC類的成員變數和成員函數。

圖二 hello形狀的表單

五、根據映像建立”region”

此法建立不規則表單比較複雜。首先準備一張含有目標表單形狀的圖片,設定透明色即將圖片中部不屬於表單形狀的部分,標記成同一種顏色,例如藍色RGB(0,0,255).程式運行後先裝入圖片。然後逐個掃描圖片的每個像素,如這個像素不屬於透明色,則在相應位置建立一個只含一個像素的“region”然後將這些小”region ”合并起來組成一個任意形狀的”region”.這裡將使用到CRgn的一個成員函數 :

  1. int CRgn::CombineRgn( CRgn* pRgn1, CRgn* pRgn2, int nCombineMode );

其中pRgn1,pRgn2為要合并的兩個“region”,nCombineMode為合并的方式,此應用中取RGN_OR,即兩”region”全部合并去處重複部分。代碼實現如下:

void SetupRegion(CDC *pDC, //表單的DC指標CBitmap &cBitmap, //含有表單形狀的位元影像對象COLORREF TransColor //透明色){    CDC memDC;    //建立與傳入DC相容的臨時DC    memDC.CreateCompatibleDC(pDC);     CBitmap *pOldMemBmp=NULL;    //將位元影像選入臨時DC    pOldMemBmp=memDC.SelectObject(&cBitmap);        CRgn wndRgn;    //建立總的表單地區,初始region為0    wndRgn.CreateRectRgn(0,0,0,0);      BITMAP bit;      cBitmap.GetBitmap (&bit);//取得位元影像參數,這裡要用到位元影像的長和寬            int y;        for(y=0;y<=bit.bmHeight  ;y++)        {        CRgn rgnTemp; //儲存臨時region                         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;                 //建立一個包含起點與重點間高為1像素的臨時“region”                rgnTemp.CreateRectRgn(iLeftX, y, iX, y+1);                 //合并到主"region".                wndRgn.CombineRgn(&wndRgn, &rgnTemp, RGN_OR);                         //刪除臨時"region",否則下次建立時和出錯                rgnTemp.DeleteObject();            }while(iX GetWindow();    pWnd->SetWindowRgn(wndRgn,TRUE);       pWnd->SetForegroundWindow();   }

 

上述代碼建立的不規則表單中,在OnEraseBkgnd事件中繪製該位元影像,就可得到與該位元影像形狀一模一樣的表單。

圖三 根據位元影像和位元影像中的透明色建立的表單

六、小結

三種建立“region”的方法,第一種最簡單,如果所需的表單形狀是簡單的幾何圖形,這種方法最合適;第二種稍微複雜些,但是建立的表單形狀更多些;第三種方法可以建立任何在圖片中畫出的表單形狀,但是實現的複雜度也最高。

註:本文的寫作曾參考了“形態各異的不規則表單”一文。 

【轉】Windows 中不規則表單的編程實現

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.