用Visual C++.NET進行GDI+編程

發表于:2007-05-25來源:作者:點擊數: 標簽:編程GDI+C++.NETvisual進行
GDI+接口是Microsoft Whistler操作系統中的一部分,它是GDI的一個新版本,不僅在GDI基礎上添加許多新特性而且對原有的GDI功能進行優化。在為 開發 人員提供的二維矢量圖形、文本、圖像處理、區域、路徑以及圖形數據矩陣等方面構造了一系列相關的類,如Bitmap


  GDI+接口是Microsoft Whistler操作系統中的一部分,它是GDI的一個新版本,不僅在GDI基礎上添加許多新特性而且對原有的GDI功能進行優化。在為開發人員提供的二維矢量圖形、文本、圖像處理、區域、路徑以及圖形數據矩陣等方面構造了一系列相關的類,如Bitmap(位圖類)、Brush(畫刷類)、Color(顏色類)、Font(字體類)、Graphics(圖形類)、Image(圖像類)、Pen(畫筆類)和Region(區域類)等。其中,圖形類Graphics是GDI+接口中的一個核心類,許多繪圖操作都可用它來完成。
  我們首先介紹一下GDI+的新特性以及其編程方式的改變,然后介紹用Visual C++.NET在基于對話框和單文檔/多文檔等應用程序中使用GDI+的一般方法。

  GDI+新特性

  GDI+與GDI相比,增加了下列新的特性:

  1、漸變畫刷

  以往GDI實現顏色漸變區域的方法是通過使用不同顏色的線條來填充一個裁剪區域而達到的?,F在GDI+拓展了GDI功能,提供線型漸變和路徑漸變畫刷來填充一個圖形、路徑和區域,甚至也可用來繪制直線、曲線等。這里的路徑可以視為由各種繪圖函數產生的軌跡。

  2、樣條曲線

  對于曲線而言,最具實際意義的莫過于樣條曲線。樣條曲線是在生產實踐的基礎上產生和發展起來的。模線間的設計人員在繪制模線時,先按給定的數據將型值點準確地"點"到圖板上。然后,采用一種稱為"樣條"的工具(一根富有彈性的有機玻璃條或木條),用壓鐵強迫它通過這些型值點,再適當調整這些壓鐵,讓樣條的形態發生變化,直至取得合適的形狀,才沿著樣條畫出所需的曲線。如果我們把樣條看成彈性細梁,那么壓鐵就可看成作用在這梁上的某些點上的集中力。GDI+的Graphics:: DrawCurve函數中就有一個這樣的參數用來調整集中力的大小。除了樣條曲線外,GDI+還支持原來GDI中的Bezier曲線。

  3、持久的路徑對象

  我們知道,在GDI中,路徑是隸屬于一個設備環境(上下文),也就是說一旦設備環境指針超過它的有效期,路徑也會被刪除。而GDI+是使用Graphics對象來進行繪圖操作,并將路徑操作從Graphics對象分離出來,提供一個GraphicsPath類供用戶使用。這就是說,我們不必擔心路徑對象會受到Graphics對象操作的影響,從而可以使用同一個路徑對象進行多次的路徑繪制操作。

  4、矩陣和矩陣變換

  在圖形處理過程中常需要對其幾何信息進行變換以便產生復雜的新圖形,矩陣是這種圖形幾何變換最常用的方法。為了滿足人們對圖形變換的需求,GDI+提供了功能強大的Matrix類來實現矩陣的旋轉、錯切、平移、比例等變換操作,并且GDI+還支持Graphics圖形和區域(Region)的矩陣變換。

  5、Alpha混色

  在圖像處理中,Alpha用來衡量一個像素或圖像的透明度。在非壓縮的32位RGB圖像中,每個像素是由四個部分組成:一個Alpha通道和三個顏色分量(R、G和B)。當Alpha值為0時,該像素是完全透明的,而當Alpha值為255時,則該像素是完全不透明。

  Alpha混色是將源像素和背景像素的顏色進行混合,最終顯示的顏色取決于其RGB顏色分量和Alpha值。它們之間的關系可用下列公式來表示:
顯示顏色 = 源像素顏色 X alpha / 255 + 背景顏色 X (255 - alpha) / 255

  GDI+的Color類定義了ARGB顏色數據類型,從而可以通過調整Alpha值來改變線條、圖像等與背景色混合后的實際效果。

  除了上述新特性外,GDI+還將支持重新著色、色彩修正、消除走樣、元數據以及Graphics容器等特性。



  GDI+編程模塊的變化

  為了簡化GDI+的編程開發過程,Microsoft對GDI+的編程模塊作了一些調整,這主要體現在以下幾個方面:

  1、不再使用設備環境或句柄

  我們知道,在使用GDI繪圖時,必須要指定一個設備環境(DC)。MFC為設備環境提供了許多由基類CDC派生的設備環境類,如CPaintDC、CClientDC和CWindowDC等,用來將某個窗口或設備與設備環境類的句柄指針關聯起來,所有的繪圖操作都與該句柄有關。而GDI+不再使用這個設備環境或句柄,取而代之是使用Graphics對象。

  與設備環境相類似,Graphics對象也是將屏幕的某一個窗口與之相關聯,并包含繪圖操作所需要的相關屬性。但是,只有這個Graphics對象與設備環境句柄還存在著聯系,其余的如Pen、Brush、Image和Font等對象均不再使用設備環境。

  2、繪圖方式的變化

  先來看看同樣繪制一條從點(20, 10)到點(200, 100)直線的GDI和GDI+代碼,假設這些代碼都是添加在OnDraw函數中。

  GDI繪制該直線的代碼如下:

void CMyView::OnDraw(CDC* pDC)
{
 CMyDoc* pDoc = GetDocument();
 ASSERT_VALID(pDoc);
 CPen newPen( PS_SOLID, 3, RGB(255, 0, 0) );
 CPen* pOldPen = pDC->SelectObject( &newPen );
 pDC->MoveTo( 20, 10 );
 pDC->LineTo( 200, 100);
 pDC->SelectObject( pOldPen );
}

  GDI+繪制該直線的代碼如下:

void CMyView::OnDraw(CDC* pDC)
{
 CMyDoc* pDoc = GetDocument();
 ASSERT_VALID(pDoc);
 using namespace Gdiplus; // 使用名稱空間
 Graphics graphics( pDC->m_hDC );
 Pen newPen( Color( 255, 0, 0 ), 3 );
 graphics.DrawLine(&newPen, 20, 10, 200, 100);
}

  從上面代碼可以看出,GDI先創建一個CPen(畫筆)對象,然后通過SelectObject將該畫筆選入到設備環境(pDC)中。接下來調用相應的畫線函數,最后恢復設備環境中原來的GDI對象。而GDI+是先使用Graphics類創建一個與pDC設備環境相關聯的Graphics對象,然后使用Pen類進行畫筆的創建,最后調用相應的畫線方法。由于Pen和設備環境是相互獨立的,因而不需要像GDI那樣恢復設備環境中原來的設置,而且Pen和Graphics對象的創建不存在先后次序。

  2、Graphics繪圖方法直接將Pen、Brush等對象作為自己的參數

  從上面的代碼可以看出,Graphics繪圖方法直接將Pen對象作為自己的參數,從而避免了在GDI使用SelectObject進行繁瑣的切換,類似的還有Brush、Path、Image和Font等。

  3、不再使用"當前位置"

  我們知道,GDI繪圖操作(如畫線)中總存在一個被稱為"當前位置"的特殊位置。每次畫線都是以此當前位置為起始點,畫線操作結束之后,直線的結束點位置又成為了當前位置。設置當前位置的理由是為了提高畫線操作的效率,因為在一些場合下,總是一條直線連著另一條直線,首尾相接。有了當前位置的自動更新,就可避免每次畫線時都要給出兩點的坐標。盡管有其必要性,但是單獨繪制一條直線的場合總是比較多的,因此GDI+取消這個"當前位置"以避免當無法確定"當前位置"時所造成的繪圖的差錯,取而代之的是直接在DrawLine中指定直線起止點的坐標。

  4、形狀輪廓繪制和填充采用不同的方法

  GDI總是讓形狀輪廓繪制和填充使用同一個繪圖函數,例如Rectangle。我們知道,輪廓繪制需要一個畫筆,而填充一個區域需要一個畫刷。也就是說,不管我們是否需要填充所繪制的形狀,我們都需要指定一個畫刷,否則GDI采用默認的畫刷進行填充。這種方式確實給我們帶來了許多不便,現在GDI+將形狀輪廓繪制和填充操作分開而采用不同的方法,例如DrawRectangle和FillRectangle分別用來繪制和填充一個矩形。

  5、簡化區域的創建

  我們知道,GDI提供了許多區域創建函數,如CreateRectRgn、CreateEllpticRgn、CreateRoundRectRgn、CreatePolygonRgn和CreatePolyPolygonRgn等。誠然,這些函數給我們帶來了許多方便。但在GDI+中,由于為了便于將區域引入矩陣變換操作,GDI+簡化一般區域創建的方法,而將更復雜的區域創建交由Path接管。由于Path對象是與設備環境分離開來的,因而可以直接在Region構造函數中加以指定。


  6、用Visual C++.NET使用GDI+的一般方法

  在Visual C++.NET使用GDI+一般遵循下列步驟:

  (1) 在應用程序中添加GDI+的包含文件gdiplus.h以及附加的類庫gdiplus.lib。通常gdiplus.h包含文件添加在應用程序的stdafx.h文件中,而gdiplus.lib可用兩種進行添加:第一種是直接在stdafx.h文件中添加下列語句:

#pragma comment( lib, "gdiplus.lib" )

  另一種方法是:選擇"項目"ò"屬性"菜單命令,在彈出的對話框中選中左側的"鏈接器"ò"輸入"選項,在右側的"附加依賴項"框中鍵入gdiplus.lib,結果如圖1所示。


圖1

  (2) 在應用程序項目的應用類中,添加一個成員變量,如下列代碼:

ULONG_PTR m_gdiplusToken;

  其中,ULONG_PTR是一個DWORD數據類型,該成員變量用來保存GDI+被初始化后在應用程序中的GDI+標識,以便能在應用程序退出后,引用該標識來調用Gdiplus:: GdiplusShutdown來關閉GDI+。

  (3) 在應用類中添加ExitInstance的重載,并添加下列代碼用來關閉GDI+:

int CEx_GDIPlusApp::ExitInstance()
{
 Gdiplus::GdiplusShutdown(m_gdiplusToken);
 return CWinApp::ExitInstance();
}

  (4) 在應用類的InitInstance函數中添加GDI+的初始化代碼:

BOOL CEx_GDIPlusApp::InitInstance()
{
 CWinApp::InitInstance();
 Gdiplus::GdiplusStartupInput gdiplusStartupInput;
 Gdiplus::GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, NULL);
 ...
}

  (5) 在需要繪圖的窗口或視圖類中添加GDI+的繪制代碼。

  下面分別就單文檔和基于對話框應用程序為例,說明使用GDI+的一般過程和方法。

  1. 在單文檔應用程序中使用GDI+

  在上面的過程中,我們就是以一個單文檔應用程序Ex_GDIPlus作為示例的。下面列出第5步所涉及的代碼:

void CEx_GDIPlusView::OnDraw(CDC* pDC)
{
 CEx_GDIPlusDoc* pDoc = GetDocument();
 ASSERT_VALID(pDoc);
 using namespace Gdiplus;
 Graphics graphics( pDC->m_hDC );
 Pen newPen( Color( 255, 0, 0 ), 3 );
 HatchBrush newBrush( HatchStyleCross,
 Color(255, 0, 255, 0),
 Color(255, 0, 0, 255));
 // 創建一個填充畫刷,前景色為綠色,背景色為藍色

 graphics.DrawRectangle( &newPen, 50, 50, 100, 60);
 // 在(50,50)處繪制一個長為100,高為60的矩形

 graphics.FillRectangle( &newBrush, 50, 50, 100, 60);
 // 在(50,50)處填充一個長為100,高為60的矩形區域
}

  編譯并運行,結果如圖2所示。


圖2

  2. 在基于對話框應用程序中使用GDI+

  步驟如下:

  (1) 創建一個默認的基于對話框的應用程序Ex_GDIPlusDlg。

  (2) 打開stdafx.h文件添加下列代碼:

#include <gdiplus.h>
#pragma comment( lib, "gdiplus.lib" )

  (3) 打開Ex_GDIPlusDlg.h文件,添加下列代碼:

class CEx_GDIPlusDlgApp : public CWinApp
{
 ...
 public:
 virtual BOOL InitInstance();
 ULONG_PTR m_gdiplusToken;
 ...
};

  (4) 在 CEx_GDIPlusDlgApp類的屬性窗口中,單擊"重寫"工具按鈕,為該添加ExitInstance的重載:

int CEx_GDIPlusDlgApp::ExitInstance()
{
 Gdiplus::GdiplusShutdown(m_gdiplusToken);
 return CWinApp::ExitInstance();
}

  (5) 定位到CEx_GDIPlusDlgApp::InitInstance函數處,添加下列GDI+初始化代碼:

BOOL CEx_GDIPlusDlgApp::InitInstance()
{
 CWinApp::InitInstance();
 Gdiplus::GdiplusStartupInput gdiplusStartupInput;
 Gdiplus::GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, NULL);
 ...
}

  (6) 定位到CEx_GDIPlusDlgDlg::OnPaint函數處,添加下列GDI+代碼:

void CEx_GDIPlusDlgDlg::OnPaint()
{
 if (IsIconic())
 {
  ...
 }
 else
 {
  CPaintDC dc(this); // 用于繪制的設備上下文
  using namespace Gdiplus;
  Graphics graphics( dc.m_hDC );
  Pen newPen( Color( 255, 0, 0 ), 3 );
  HatchBrush newBrush( HatchStyleCross,
  Color(255, 0, 255, 0),
  Color(255, 0, 0, 255));
  graphics.DrawRectangle( &newPen, 50, 50, 100, 60);
  graphics.FillRectangle( &newBrush, 50, 50, 100, 60);
  CDialog::OnPaint();
 }
}

  (7) 編譯并運行,結果如圖3所示。


圖3

  從上述例子可以看出,只要能獲得一個窗口的設備環境指針,就可構造一個Graphics對象,從而可以在其窗口中進行繪圖,我們不必在像以往那樣使用Invalidate/UpdateWindow來防止Windows對對話框窗口進行重繪。


原文轉自:http://www.anti-gravitydesign.com

評論列表(網友評論僅供網友表達個人看法,并不表明本站同意其觀點或證實其描述)
国产97人人超碰caoprom_尤物国产在线一区手机播放_精品国产一区二区三_色天使久久综合给合久久97