程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> 關於GDI+

關於GDI+

編輯:關於C語言

轉載請注明出處

作者:小馬

 

一 介紹
其實本人對GDI+不能算是專家,只是在幾個小項目中應用了一些而已, 算是入門了. 剛好最近有點時間, 把自己掌握的東東做個總結.

 

如果你以前用過GDI, 那麼恭喜你,因為你轉到GDI+易如反掌. 如果你沒用過GDI,那麼也恭喜你, 因為你可以直接學GDI+,不用經歷學習GDI的那種痛苦. 因為GDI+相對於GDI,更加抽象,更加上層, 隱藏了更多底層的東西, 整體架構更加清晰明了.

 

GDI+通過c++ class的形式對外引出接口, 程序員直接調用這些接口來完成相應的功能. 共有40個相關的類, 50個枚舉常量和6個結構體. 它的局限性是只能運行在windows XP和windows server2003的系統上.

 

簡單說幾個GDI+與GDI不同的地方.
1 GDI+很重要一個改進就是增了對多種圖像格式的支持.它目前支持下面幾中格式的圖像:
BMP
Graphics Interchange Format (GIF)
JPEG
 Exif
 PNG
TIFF
ICON
WMF
EMF


2 DC(設備環境內容)的概念變得模糊,基本對程序員是透明了.
用GDI的人都知道, 不懂DC可不行, 這個DC保存著顯示設備的屬性和功能信息, 每當你想要drawing時, 你得先獲取DC的句柄, 然後把這個句柄作為參數傳給GDI的API, 另外還要考慮關於”選到設備(selectObjec),釋放設備”等繁瑣的操作.
GDI+對方面的處理簡單明了很多,它有一個Graphics類,一個Graphics的對象就類似於DC的角色, 而且它跟pen,brush等的關系也變得獨立, 不用再”選來選去”, 在GDI+裡,像pen,brush這些東西都是獨立的對象,用的時候只需把它們的實例作為參數傳給Graphics的接口就可以了(在下面的示例中會看到).


3 增加了對漸變顏色效果的支持.
原來在GDI裡做漸變效果, 那叫一復雜呀. 下面的示例中會具體說說GDI+裡的漸變.


二 應用


前期准備

使用GDI+, 首先要包含相關的頭文件, 只有一個,如下:
#include <gdiplus.h>
gdiplus.h這個文件vs2005的include目錄下, 所以在vs2005下, 你可以直接以”<>”的形式包含.

還需要用到一個lib, 就是Gdiplus.lib, 你可以在源文件中通過
#pragma comment (lib,"Gdiplus.lib")
的形式鏈接進來, 也可以直接在”項目屬性-linker-input裡添加, 效果是一樣的.


為了不使GDI+專用的相關類,常量,結構體與其它應用混淆,GDI+有自己的命名空間, 叫Gdiplus, 當你要用到GDI+的相關API時,就要用到下面的語句:
using namespace Gdiplus;


最後, GDI+有個應用開關, GdiplusStartup和GdiplusShutdown, 一個開,一個關, 使用GDI+任何功能前,先調用GdiplusStartup,程序結束時,調用GdiplusShutdown關閉. 比如在基於mfc的對話框應用中, 我一般這樣做, 假設我的工程為MyGDIPlusTest, 首先在MyGDIPlusTest.cpp的InitInstance函數中打開GDI+,如下:
…..
CWinApp::InitInstance();
GdiplusStartup(&m_gdiPlusToken, &m_gdiPlusStartupInput, NULL);
…..
然後重載ExitInstance函數, 在這個函數裡關閉GDI+
GdiplusShutdown(m_gdiPlusToken);//程序退出時關閉
return CWinApp::ExitInstance();

兩個函數的參數,自己去查吧 ,不說了.

 

示例
1 先看一個msdn中的示例


view plaincopy to clipboardprint?#include <stdafx.h>  
#include <windows.h>  
#include <objidl.h>  
#include <gdiplus.h>  
using namespace Gdiplus; 
#pragma comment (lib,"Gdiplus.lib")  
 
VOID OnPaint(HDC hdc) 

   Graphics graphics(hdc); 
   Pen      pen(Color(255, 0, 0, 255)); 
   graphics.DrawLine(&pen, 0, 0, 200, 100); 

 
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); 
 
INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, PSTR, INT iCmdShow) 

   HWND                hWnd; 
   MSG                 msg; 
   WNDCLASS            wndClass; 
   GdiplusStartupInput gdiplusStartupInput; 
   ULONG_PTR           gdiplusToken; 
    
   // Initialize GDI+.  
   GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL); 
    
   wndClass.style          = CS_HREDRAW | CS_VREDRAW; 
   wndClass.lpfnWndProc    = WndProc; 
   wndClass.cbClsExtra     = 0; 
   wndClass.cbWndExtra     = 0; 
   wndClass.hInstance      = hInstance; 
   wndClass.hIcon          = LoadIcon(NULL, IDI_APPLICATION); 
   wndClass.hCursor        = LoadCursor(NULL, IDC_ARROW); 
   wndClass.hbrBackground  = (HBRUSH)GetStockObject(WHITE_BRUSH); 
   wndClass.lpszMenuName   = NULL; 
   wndClass.lpszClassName  = TEXT("GettingStarted"); 
    
   RegisterClass(&wndClass); 
    
   hWnd = CreateWindow( 
      TEXT("GettingStarted"),   // window class name  
      TEXT("Getting Started"),  // window caption  
      WS_OVERLAPPEDWINDOW,      // window style  
      CW_USEDEFAULT,            // initial x position  
      CW_USEDEFAULT,            // initial y position  
      CW_USEDEFAULT,            // initial x size  
      CW_USEDEFAULT,            // initial y size  
      NULL,                     // parent window handle  
      NULL,                     // window menu handle  
      hInstance,                // program instance handle  
      NULL);                    // creation parameters  
    
   ShowWindow(hWnd, iCmdShow); 
   UpdateWindow(hWnd); 
    
   while(GetMessage(&msg, NULL, 0, 0)) 
   { 
      TranslateMessage(&msg); 
      DispatchMessage(&msg); 
   } 
    
   GdiplusShutdown(gdiplusToken); 
   return msg.wParam; 
}  // WinMain  
 
LRESULT CALLBACK WndProc(HWND hWnd, UINT message,  
   WPARAM wParam, LPARAM lParam) 

   HDC          hdc; 
   PAINTSTRUCT  ps; 
    
   switch(message) 
   { 
   case WM_PAINT: 
      hdc = BeginPaint(hWnd, &ps); 
      OnPaint(hdc); 
      EndPaint(hWnd, &ps); 
      return 0; 
   case WM_DESTROY: 
      PostQuitMessage(0); 
      return 0; 
   default: 
      return DefWindowProc(hWnd, message, wParam, lParam); 
   } 
} // WndProc 
#include <stdafx.h>
#include <windows.h>
#include <objidl.h>
#include <gdiplus.h>
using namespace Gdiplus;
#pragma comment (lib,"Gdiplus.lib")

VOID OnPaint(HDC hdc)
{
   Graphics graphics(hdc);
   Pen      pen(Color(255, 0, 0, 255));
   graphics.DrawLine(&pen, 0, 0, 200, 100);
}

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, PSTR, INT iCmdShow)
{
   HWND                hWnd;
   MSG                 msg;
   WNDCLASS            wndClass;
   GdiplusStartupInput gdiplusStartupInput;
   ULONG_PTR           gdiplusToken;
  
   // Initialize GDI+.
   GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
  
   wndClass.style          = CS_HREDRAW | CS_VREDRAW;
   wndClass.lpfnWndProc    = WndProc;
   wndClass.cbClsExtra     = 0;
   wndClass.cbWndExtra     = 0;
   wndClass.hInstance      = hInstance;
   wndClass.hIcon          = LoadIcon(NULL, IDI_APPLICATION);
   wndClass.hCursor        = LoadCursor(NULL, IDC_ARROW);
   wndClass.hbrBackground  = (HBRUSH)GetStockObject(WHITE_BRUSH);
   wndClass.lpszMenuName   = NULL;
   wndClass.lpszClassName  = TEXT("GettingStarted");
  
   RegisterClass(&wndClass);
  
   hWnd = CreateWindow(
      TEXT("GettingStarted"),   // window class name
      TEXT("Getting Started"),  // window caption
      WS_OVERLAPPEDWINDOW,      // window style
      CW_USEDEFAULT,            // initial x position
      CW_USEDEFAULT,            // initial y position
      CW_USEDEFAULT,            // initial x size
      CW_USEDEFAULT,            // initial y size
      NULL,                     // parent window handle
      NULL,                     // window menu handle
      hInstance,                // program instance handle
      NULL);                    // creation parameters
  
   ShowWindow(hWnd, iCmdShow);
   UpdateWindow(hWnd);
  
   while(GetMessage(&msg, NULL, 0, 0))
   {
      TranslateMessage(&msg);
      DispatchMessage(&msg);
   }
  
   GdiplusShutdown(gdiplusToken);
   return msg.wParam;
}  // WinMain

LRESULT CALLBACK WndProc(HWND hWnd, UINT message,
   WPARAM wParam, LPARAM lParam)
{
   HDC          hdc;
   PAINTSTRUCT  ps;
  
   switch(message)
   {
   case WM_PAINT:
      hdc = BeginPaint(hWnd, &ps);
      OnPaint(hdc);
      EndPaint(hWnd, &ps);
      return 0;
   case WM_DESTROY:
      PostQuitMessage(0);
      return 0;
   default:
      return DefWindowProc(hWnd, message, wParam, lParam);
   }
} // WndProc

 

這個示例是畫線的,如果是打印字符串, 只用修改OnPaint中的內容,如下:


view plaincopy to clipboardprint?VOID OnPaint(HDC hdc) 

   Graphics    graphics(hdc); 
   SolidBrush  brush(Color(255, 0, 0, 255)); 
   FontFamily  fontFamily(L"Times New Roman"); 
   Font        font(&fontFamily, 24, FontStyleRegular, UnitPixel); 
   PointF      pointF(10.0f, 20.0f); 
    
   graphics.DrawString(L"Hello World!", -1, &font, pointF, &brush); 

VOID OnPaint(HDC hdc)
{
   Graphics    graphics(hdc);
   SolidBrush  brush(Color(255, 0, 0, 255));
   FontFamily  fontFamily(L"Times New Roman");
   Font        font(&fontFamily, 24, FontStyleRegular, UnitPixel);
   PointF      pointF(10.0f, 20.0f);
  
   graphics.DrawString(L"Hello World!", -1, &font, pointF, &brush);
}


 

2 自己寫的一個顯示圖片的簡單示例
基於mfc的對話框應用,點一下按鈕,顯示一張圖片. 只顯示關鍵代碼

view plaincopy to clipboardprint?void CGDI_Plus_TestDlg::OnBnClickedButtonPen() 

 // TODO: Add your control notification handler code here  
 HDC hdc = this->GetDC()->m_hDC; 
 Graphics graphics(hdc); 
 Image image(L"c:\\image\\ip.jpg"); 
 graphics.DrawImage(&image, 200, 200); 

void CGDI_Plus_TestDlg::OnBnClickedButtonPen()
{
 // TODO: Add your control notification handler code here
 HDC hdc = this->GetDC()->m_hDC;
 Graphics graphics(hdc);
 Image image(L"c:\\image\\ip.jpg");
 graphics.DrawImage(&image, 200, 200);
}


有以下幾點要說明,
第一點, Image只支持通過路徑和流的形式提供實例初始化,不支持資源句柄, 如果要用資源句柄的形式,可以先把資源數據讀到流裡,這裡不說了.
第二點, 關於DrawImage,有很多重載函數, 提供了幾乎你能想到的所有功能,我這裡用了下面這個重載
Status DrawImage(      Image *image,INT x,INT y);
也就是在指定位置顯示加載的圖像.

 

3 漸變效果

前面說了,GDI+支持漸變, 分為兩種, linear gradient和path gradient, 這裡討論第一種.
linear gradient又分為

Horizontal Linear Gradients,

Customizing Linear Gradients,

Diagonal Linear Gradients

三種. 這些比較好理解. 下面的代碼示例來自msdn,我做了一些修改.

view plaincopy to clipboardprint?void CGDI_Plus_TestDlg::OnBnClickedButtonPen() 

 // TODO: Add your control notification handler code here  
 HDC hdc = this->GetDC()->m_hDC; 
 Graphics graphics(hdc); 
 LinearGradientBrush linearBrush(Point(0, 10), Point(200, 10),  
  Color(255,255,0,0),Color(255,0,0,255)); 
 
 Pen pen(&linearBrush, 4); 
 graphics.DrawLine(&pen, 100,100, 200, 100); 
 graphics.FillEllipse(&linearBrush, 100, 150, 200, 100); 
 graphics.FillRectangle(&linearBrush, 100, 255, 500, 30); 

void CGDI_Plus_TestDlg::OnBnClickedButtonPen()
{
 // TODO: Add your control notification handler code here
 HDC hdc = this->GetDC()->m_hDC;
 Graphics graphics(hdc);
 LinearGradientBrush linearBrush(Point(0, 10), Point(200, 10),
  Color(255,255,0,0),Color(255,0,0,255));

 Pen pen(&linearBrush, 4);
 graphics.DrawLine(&pen, 100,100, 200, 100);
 graphics.FillEllipse(&linearBrush, 100, 150, 200, 100);
 graphics.FillRectangle(&linearBrush, 100, 255, 500, 30);
}

 

 

程序運行的效果如下圖

 \


附: GDI+與GDI混合編程
GDI+提供了一種機制, 可以和GDI混合使用, 主要是利用Graphics中的ReleaseHDC和GetHDC, 下面的代碼示例來自msdn:


view plaincopy to clipboardprint?VOID Example_GetReleaseHDC(Graphics* g) 

   Pen pen(Color(255, 0, 0, 255)); 
   g->DrawEllipse(&pen, 10, 10, 100, 50);  // GDI+  
   HDC hdc = g->GetHDC(); 
      // Make GDI calls, but don't call any methods  
      // on g until after the call to ReleaseHDC.  
      Rectangle(hdc, 120, 10, 220, 60);  // GDI    
   g->ReleaseHDC(hdc); 
   // Ok to call methods on g again.  
   g->DrawLine(&pen, 240, 10, 340, 60);   

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved