天天看點

C#建立不規則窗體(視窗)的幾種方式處理WM_NCPAINT時排除客戶區

C#建立不規則窗體(視窗)的幾種方式

一、自定義窗體,一般為規則的圖形,如圓、橢圓等。

做法:重寫Form1_Paint事件(Form1是窗體的名字),最簡單的一種情況如下:

System.Drawing.Drawing2D.GraphicsPath shape = new System.Drawing.Drawing2D.GraphicsPath();

shape.AddEllipse(0,0,this.Height, this.Width);

this.Region = newRegion(shape);

即重繪窗體的規則。

二、利用背景圖檔實作

1.       設定窗體的背景圖檔,其中背景圖檔是24位(不包括24)以下的位圖(BMP圖檔),并且要設定TansparencyKey的值,一般為你背景圖檔的背景色,即建立不規則圖檔時的底色,一般設為你圖檔中沒有的顔色。

這種做法的不好的地方就是背景圖檔一定要16位或者更低的,而且還要確定用戶端的顯示。如果螢幕的顔色深度設定大于 24 位,則不管TransparencyKey 屬性是如何設定的,窗體的非透明部分都會産生顯示問題。若要避免出現這種問題,請確定“顯示”控制台中的螢幕顔色深度的設定小于 24 位。當開發具有這種透明功能的應用程式時,請牢記應使您的使用者意識到此問題。

實作步驟如下:

1. 建立windowsapplication

2. 選擇窗體,找到BackgroundImage屬性,點選打開新的視窗,選擇下面的導入資源檔案,選擇你的不規則的BMP圖檔

3. 找到窗體的TansparencyKey,将它設定為你背景圖檔的背景色(如黃色)

4. 找到窗體的FormBorderStyle,将其設定為none,即不顯示标題欄

5. 運作

<!--[endif]-->

2.       跟背景圖檔一樣的圖形,不過是動态加載,周遊位圖以實作不規則窗體。它的原理是這樣的,在Form的load事件中寫方法使得窗體的描繪區域發生改變。

實作步驟如下:

1. 建立winform應用程式

2. 找到窗體的Load事件,輕按兩下進行編輯

3. 編寫方法,主要的代碼如下:

代碼

    class BitmapRegion

    {

        public BitmapRegion()

        { }

        /// <summary> 

        /// Create and apply the region on the supplied control

        /// 建立支援位圖區域的控件(目前有button和form)

        /// </summary> 

        /// <param name="control">The Control object to apply the region to控件</param> 

        /// <param name="bitmap">The Bitmap object to create the region from位圖</param> 

        public static void CreateControlRegion(Control control, Bitmap bitmap)

        {

            // Return if control and bitmap are null

            //判斷是否存在控件和位圖

            if (control == null || bitmap == null)

                return;

            // Set our control''s size to be the same as the bitmap

            //設定控件大小為位圖大小

            control.Width = bitmap.Width;

            control.Height = bitmap.Height;

            // Check if we are dealing with Form here 

            //當控件是form時

            if (control is System.Windows.Forms.Form)

            {

                // Cast to a Form object

                //強制轉換為FORM

                Form form = (Form)control;

                // Set our form''s size to be a little larger that the  bitmap just 

                // in case the form''s border style is not set to none in the first place 

                //當FORM的邊界FormBorderStyle不為NONE時,應将FORM的大小設定成比位圖大小稍大一點

                form.Width = control.Width;

                form.Height = control.Height;

                // No border 

                //沒有邊界

                form.FormBorderStyle = FormBorderStyle.None;

                // Set bitmap as the background image 

                //将位圖設定成窗體背景圖檔

                form.BackgroundImage = bitmap;

                // Calculate the graphics path based on the bitmap supplied 

                //計算位圖中不透明部分的邊界

                GraphicsPath graphicsPath = CalculateControlGraphicsPath(bitmap);

                // Apply new region 

                //應用新的區域

                form.Region = new Region(graphicsPath);

            }

            // Check if we are dealing with Button here 

            //當控件是button時

            else if (control is System.Windows.Forms.Button)

            {

                // Cast to a button object 

                //強制轉換為 button

                Button button = (Button)control;

                // Do not show button text 

                //不顯示button text

                button.Text = "";

                // Change cursor to hand when over button 

                //改變 cursor的style

                button.Cursor = Cursors.Hand;

                // Set background image of button 

                //設定button的背景圖檔

                button.BackgroundImage = bitmap;

                // Calculate the graphics path based on the bitmap supplied 

                //計算位圖中不透明部分的邊界

                GraphicsPath graphicsPath = CalculateControlGraphicsPath(bitmap);

                // Apply new region 

                //應用新的區域

                button.Region = new Region(graphicsPath);

            }

        }

        /// <summary> 

        /// Calculate the graphics path that representing the figure in the bitmap 

        /// excluding the transparent color which is the top left pixel. 

        /// //計算位圖中不透明部分的邊界

        /// </summary> 

        /// <param name="bitmap">The Bitmap object to calculate our graphics path from</param> 

        /// <returns>Calculated graphics path</returns> 

        private static GraphicsPath CalculateControlGraphicsPath(Bitmap bitmap)

        {

            // Create GraphicsPath for our bitmap calculation 

            //建立 GraphicsPath

            GraphicsPath graphicsPath = new GraphicsPath();

            // Use the top left pixel as our transparent color 

            //使用左上角的一點的顔色作為我們透明色

            Color colorTransparent = bitmap.GetPixel(0, 0);

            // This is to store the column value where an opaque pixel is first found. 

            // This value will determine where we start scanning for trailing opaque pixels.

            //第一個找到點的X

            int colOpaquePixel = 0;

            // Go through all rows (Y axis) 

            // 偏曆所有行(Y方向)

            for (int row = 0; row < bitmap.Height; row++)

            {

                // Reset value 

                //重設

                colOpaquePixel = 0;

                // Go through all columns (X axis) 

                //偏曆所有列(X方向)

                for (int col = 0; col < bitmap.Width; col++)

                {

                    // If this is an opaque pixel, mark it and search for anymore trailing behind 

                    //如果是不需要透明處理的點則标記,然後繼續偏曆

                    if (bitmap.GetPixel(col, row) != colorTransparent)

                    {

                        // Opaque pixel found, mark current position

                        //記錄目前

                        colOpaquePixel = col;

                        // Create another variable to set the current pixel position 

                        //建立新變量來記錄目前點

                        int colNext = col;

                        // Starting from current found opaque pixel, search for anymore opaque pixels 

                        // trailing behind, until a transparent   pixel is found or minimum width is reached 

                        ///從找到的不透明點開始,繼續尋找不透明點,一直到找到或則達到圖檔寬度 

                        for (colNext = colOpaquePixel; colNext < bitmap.Width; colNext++)

                            if (bitmap.GetPixel(colNext, row) == colorTransparent)

                                break;

                        // Form a rectangle for line of opaque   pixels found and add it to our graphics path 

                        //将不透明點加到graphics path

                        graphicsPath.AddRectangle(new Rectangle(colOpaquePixel, row, colNext - colOpaquePixel, 1));

                        // No need to scan the line of opaque pixels just found 

                        col = colNext;

                    }

                }

            }

            // Return calculated graphics path 

            return graphicsPath;

        }

    }

4. 運作

  <!--[endif]-->

三、調用類庫實作

主要就是根據一些坐标,然後根據這些坐标繪制窗體

代碼如下:

代碼

public Form3()

        {

            InitializeComponent();

            //建立不規則窗體

            POINTAPI[] poin;

            poin = new POINTAPI[5];

            poin[0].x = 90;

            poin[0].y = 90;

            poin[1].x = this.Width;

            poin[1].y = 0;

            poin[2].x = Width;

            poin[2].y = this.Height / 2;

            poin[3].x = Width / 2;

            poin[3].y = Height / 2;

            poin[4].x = 0;

            poin[4].y = Width;

            Boolean flag = true;

            IntPtr hRgn = CreatePolygonRgn(ref poin[0], 8, 1);

            SetWindowRgn(this.Handle, hRgn, ref flag);

            this.BackColor = Color.BurlyWood;

        }

        [StructLayout(LayoutKind.Sequential)]

        private struct POINTAPI

        {

            internal int x;

            internal int y;

        }

        [DllImport("gdi32.dll")]

        private static extern IntPtr CreatePolygonRgn(ref POINTAPI lpPoint,int nCount,int nPolyFillMode);

        [DllImport("user32.dll")]

        private static extern IntPtr SetWindowRgn(IntPtr hWnd,IntPtr hRgn, ref Boolean bRedraw);

        //設定窗體顯示狀态

        [DllImport("user32.dll")]

        private static extern int SetWindowPos(IntPtr hwnd,int hWndInsertAfter,int x,int y,int cx,int cy,int wFlags);

        private void Start_Btn_Click(object sender, EventArgs e)

        {//始終顯示在前面

            SetWindowPos(this.Handle, -1, 0, 0, 0, 0, 1);

        }

        private void button1_Click(object sender, EventArgs e)

        {

            //最小化始終顯示在前面

            SetWindowPos(this.Handle, -1, 0, 0, 0, 0, 0);

        }

當然,我們也可以自定義窗體的動作,如按着某個軌迹一定,下面的代碼中的BackgroundForm程式中就小試了一下,效果還不錯,下面是這些程式的效果圖(有點亂)和代碼:

 代碼是.Net 2.0的,也可以轉換為其他版本的,隻要運作主程式即可。(PS:圖檔做的不是很好看,就随便亂P了一通)

 以上的四種方法有利也有弊,希望大家提意見或者更好的解決方案。

windows下不規則窗體建立的幾種方法

http://www.cnblogs.com/tyjsjl/archive/2006/10/27/2156115.html

一、序言

  在絕大多數的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"的簡單方法有以下幾個成員函數: BOOL CRgn::CreateRectRgn( int x1, int y1, int x2, int y2 ); 建立矩形的“region”。

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

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

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);

}

C#建立不規則窗體(視窗)的幾種方式處理WM_NCPAINT時排除客戶區
圖一 橢圓窗體效果圖

  四、作圖路徑法建立”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類的成員變量和成員函數。

C#建立不規則窗體(視窗)的幾種方式處理WM_NCPAINT時排除客戶區
圖二 hello形狀的窗體效果圖

  五、根據圖像建立”region”

  此法建立不規則窗體比較複雜。首先準備一張含有目标窗體形狀的圖檔,設定透明色即将圖檔中部不屬于窗體形狀的部分,标記成同一種顔色,例如藍色RGB(0,0,255).程式運作後先裝入圖檔。然後逐個掃描圖檔的每個像素,如這個像素不屬于透明色,則在相應位置建立一個隻含一個像素的“region”然後将這些小”region ”合并起來組成一個任意形狀的”region”.這裡将使用到CRgn的一個成員函數 :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事件中繪制該位圖,就可得到與該位圖形狀一模一樣的窗體。

C#建立不規則窗體(視窗)的幾種方式處理WM_NCPAINT時排除客戶區
圖三 根據位圖和位圖中的透明色建立的窗體效果圖

  六、小結

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

CRgn幾種建立方法,不規則窗體

http://blog.csdn.net/tajon1226/article/details/6589180

一、序言

  在絕大多數的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();   ...

[cpp] view plain copy print ?

  1. CRgn rgn; 
  2. rgn. CreateEllipticRgn(0,0,200,100); 
  3. SetWindowRgn(rgn,TRUE); 
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() {

[cpp] view plain copy print ?

  1. HRGN wndRgn; 
  2. CClientDC dc(this); 
  3. CFont mFont; 
  4. if (dc.m_hDC!=NULL) 
  5.     VERIFY(mFont.CreateFont( 
  6.         200, 50, 0, 0, FW_HEAVY, TRUE, FALSE, 
  7.         0, ANSI_CHARSET, OUT_DEFAULT_PRECIS, 
  8.         CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, 
  9.         DEFAULT_PITCH|FF_SWISS, "宋體")); 
  10.     //開始記錄窗體輪廓路徑 
  11.     dc.BeginPath(); 
  12.     //設定背景為透明模式,這句話是必須有的。 
  13.     dc.SetBkMode(TRANSPARENT); 
  14.     CFont * pOldFont; 
  15.     pOldFont = dc.SelectObject( &mFont ); 
  16.     dc.TextOut(0, 0, "Hello"); 
  17.     //結束記錄窗體輪廓路徑 
  18.     dc.SelectObject( pOldFont ); 
  19.     dc.EndPath(); 
  20.     //把所記錄的路徑轉化為窗體輪廓句柄 
  21.     wndRgn = ::PathToRegion(dc.m_hDC); 
  22.     //賦予窗體指定的輪廓形狀 
  23.     this->SetWindowRgn(wndRgn, TRUE); 
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的一個成員函數 :

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

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

[cpp] view plain copy print ?

  1. void CIrregularDlg::SetupRegion(CDC *pDC, CBitmap &cBitmap, COLORREF TransColor) 
  2.     CDC memDC; 
  3.     memDC.CreateCompatibleDC(pDC); 
  4.     CBitmap *pOldMemBmp=NULL; 
  5.     pOldMemBmp=memDC.SelectObject(&cBitmap); 
  6.     CRgn wndRgn; 
  7.     //建立總的窗體區域,初始region為0 
  8.     wndRgn.CreateRectRgn(0,0,0,0); 
  9.     BITMAP bit; 
  10.     cBitmap.GetBitmap (&bit);//取得位圖參數,這裡要用到位圖的長和寬 
  11.     int y; 
  12.     for(y=0; y<bit.bmHeight; y++) 
  13.     { 
  14.         CRgn rgnTemp; //儲存臨時region 
  15.         int iX = 0; 
  16.         do 
  17.         { 
  18.             //跳過透明色找到下一個非透明色的點. 
  19.             while (iX < bit.bmWidth && memDC.GetPixel(iX, y) == TransColor) 
  20.                 iX++; 
  21.             int iLeftX = iX; //記住這個起始點 
  22.             //尋找下個透明色的點 
  23.             while (iX < bit.bmWidth && memDC.GetPixel(iX, y) != TransColor) 
  24.                 ++iX; 
  25.             //建立一個包含起點與重點間高為1像素的臨時“region” 
  26.             rgnTemp.CreateRectRgn(iLeftX, y, iX, y+1); 
  27.             wndRgn.CombineRgn(&wndRgn, &rgnTemp, RGN_OR); 
  28.             //删除臨時"region",否則下次建立時和出錯 
  29.             rgnTemp.DeleteObject(); 
  30.         }while(iX < bit.bmWidth); 
  31.     } 
  32.     SetWindowRgn(wndRgn,TRUE); 
  33.     SetForegroundWindow(); 
void CIrregularDlg::SetupRegion(CDC *pDC, CBitmap &cBitmap, COLORREF TransColor)
{
	CDC memDC;
	
	memDC.CreateCompatibleDC(pDC);
	CBitmap *pOldMemBmp=NULL;
	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);
			wndRgn.CombineRgn(&wndRgn, &rgnTemp, RGN_OR);
			
			//删除臨時"region",否則下次建立時和出錯
			rgnTemp.DeleteObject();
		}while(iX < bit.bmWidth);
	}

	SetWindowRgn(wndRgn,TRUE);
	SetForegroundWindow();
}
           

筆者:memDC.CreateCompatibleDC(NULL);也是可行的,不知道會不會有什麼不良情況,但可以省個參數

處理WM_NCPAINT時排除客戶區

http://bcpl.cnblogs.com/archive/2005/03/22/123629.aspx

CWindowDC dc(this);

CRgn rgn;

CRect rcWindow, rcClient;

GetWindowRect(rcWindow);

GetClientRect(rcClient);

ClientToScreen(rcClient);

rcClient.OffsetRect(-rcWindow.TopLeft());

rgn.CreateRectRgn(rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);

dc.SelectClipRgn(&rgn, RGN_DIFF);