VC之GDI

以前在Delphi下用Canvas用惯了,很少直接使用GDI API,今天转换到VC下了,哪只有重新温习GDI了,首先先简单说说GDI体系结构。

GDI是微软设计的一套API,为应用程序提供设备无关的接口,包括视频显示、打印机、画图仪和传真机。GDI提供 几百个Windows程序可以调用的函数。这些函数大多数是从Win32的子系统GDI32.DLL中导出。有兴趣的话找个工具看看GDI32.Dll的 导出函数。

GDI的功能太多了,MSDN库就将GDI API分为17个领域(位图、画刷、剪裁、颜色、坐标和变换、设备上下文、填充形状、字体和文本、直线和曲线、元文件、多显示监视器、画图和绘图、路径、 画笔、打印和打印池、矩形、区域)。除了这些分类外,还有一些没有文档记载的函数。有一些在DDK中说明,还有一些没文档但系统DLL使用的函数。

主要的Windows图形编程API就是GDI,这些API与设备无关,编写出来的程序可在不同的设备上运行。哪 GDI怎样实现设备无关的呢?为了与图形设备驱动程序交互,windows图形系统采用了了称之为设备上下文的内部数据结构,是用指针链接在一起的结构和 对象组成的网状结构。设备上下文有两个重要的作用,最主要的用途在于提供图形设备逻辑,使的设备驱动程序以上的事物,包括图形引挚、win32客户端以及 用户应用程序都独立于设备。另一个用途是存储常用的绘图属性,比如前景色,画笔、刷子......,这样不同的绘图调用就不需要重复这些设置。Win32 GDI的客户端向用户应用程序屏蔽了真正的设备上下文,应用只得到了设备上下文的句柄,GDI在创建设备上下文时返回句柄,然后将句柄反馈给GDI,以查 询新的绘图操作。

 

// 通过使用指定的名字为一个设备创建设备上下文环境
/*

CreateDC(LPCTSTR pszDriver,只能是"DISPLAY"、NULL、"WINSPOOL"            
            LPCTSTR pszDevice,可以是EnumDisplayDevices返回的显示设备名,也可是打印名(如.//DISPLAY1)或NULL
            LPCTSTR pszOutput,用于可以接收打印作业的端口名,win32 API使用新的函数调用StartDoc传递端口名,因此必须为NULL
            CONST DEVMODE *pdvmInit   指向DEVMODE结构的指针,DocumentProperties函数检索指定设备获取已填充的结构,如果设备驱动程序使用用户指定的缺省初始化值。 则lplnitData参数必须为Null
          );  
*/
   HDC hdc
= CreateDC(_T( " DISPLAY " ), NULL, NULL, NULL); // 整个屏幕的设备上下文句柄
   MoveToEx(hdc, 0 , 0 ,NULL);
   LineTo(hdc,
100 , 100 );    // 绘制一条直线

   DeleteDC(hdc);

  

// 获取指定窗口客户区设备上下文句柄
/*

GetDC(HWND hWnd);
*/

    hdc
= ::GetDC( this -> m_hWnd);
    MoveToEx(hdc,
0 , 0
,NULL);
    LineTo(hdc,
100 , 100
);
    ::ReleaseDC(
this -> m_hWnd,hdc);

 

 

// 获取指定窗口设备上下文件句柄
/*

BeginPaint(HWND hWnd,//窗口句柄
            CONST PAINTSTRUCT *lpPaint   //获取显示参数
           )

PAINTSTRUCT结构定义
typedef struct tagPAINTSTRUCT {
HDC hdc;
BOOL fErase;
RECT rcPaint;
BOOL fRestore;
BOOL fIncUpdate;
BYTE rgbReserved[32];
} PAINTSTRUCT, *PPAINTSTRUCT
*/

   PAINTSTRUCT ps;
   hdc
= ::BeginPaint( this -> m_hWnd, & ps);
   MoveToEx(hdc,
200 , 200
,NULL);
   LineTo(hdc,
1300 , 1300
);
   ::EndPaint(
this -> m_hWnd, & ps);

 

接着练GDI对像

Windows的GDI对象类型是通过MFC中的类来表示的,而CGdiObject正是所有GDI对象类的抽象基 类,即Windows的GDI对象是通过CGdiObject派生类的C++对象来表示的。如:CBitmap、CBrush、CFont、 CPallete、CPen、CRgn.......

GDI对象存储在什么地方呢?GDI对象存储在系统范围内的固定大小的对象表中,称之为对象句柄表,GDI对象表是 一个固定大小的表,在win2000/NT允许最多有16384个GDI句柄。GDI对象有许多专用的例程以创建该类型的一个新的GDI对象。一旦创建完 成GDI对象,GDI将返回一个GDI对象句柄,当GDI对象不用时,要用DeleteObject函数删除哦,但要确保没该对象没有处在设备上下文中, 不然会导致潜在的GDI对象泄露

HGDIOBJ SelectObject(HDC hdc,HGDIOBJ hgdiobj); // 将GDI对象和一个设备上下文相连接
BOOL DeleteObject(HGDIOBJ hgdiobj); // 删除GDI对象
DWORD GetObjectType(HGDIOBJ h); // 确定指定对象类型
int GetObject(HGDIOBJ hgdiobj, int cbBuffer,LPVOID lpvObject); // 将指定对象的信息写入到缓冲区

 

下面以CPen对象来练练上面的四个函数。

// SelectObject和DeleteObject用法

CPen p,
* oldPen;
p.CreatePen(PS_SOLID,
1 ,RGB( 255 , 255 , 0
));
HDC hdc
= ::GetDC( this ->
m_hWnd);
oldPen
= (CPen *
)SelectObject(hdc,p.GetSafeHandle());
MoveEx(hdc,
0 , 0
,NULL);
LineTo(hdc,
100 , 100
);
SelectObject(hdc,oldPen);
DeleteObject(p.GetSafehandle());
::ReleaseDC(
this -> m_hWnd,hdc);

 

/*
DWORD GetObjectType(HGDIOBj h);
返回值:
OBJ_BITMAP(位图Bitmap)
OBJ_BRUSH(刷子Brush)
OBJ_PAL(调色版Palette)
OBJ_PEN(画笔Pen)
OBJ_EXTPEN(扩展画笔Extended pen)
OBJ_REGION(区域 Regioin)
OBJ_DC(设备上下文 Device context)
OBJ_MEMDC(存储设备上下文Memory DC)
OBJ_METAFILE(元文件Metafile)
OBJ_METADC(元文件设备上下文Metafile DC)
OBJ_ENHMETAFILE(扩展元文件Enhanced metafile)
OBJ_ENHMATADC(扩展元文件设备上下文Enhanced metafileD C)
*/
CPen p;
p.CreatePen(PS_SOLID,
1 ,RGB( 255 , 255 , 0 ));

if (OBJ_PEN ==
GetObjectType(p.GetSafeHandle()))
{
    MessageBox(_T(
" CPen对象 " ), " 信息 "
);
}

p.DeleteObject();

 

 

GDI画笔对象

GDI中的画笔对象包含了直线和曲线的宽度、形式、颜色、端点形状、交点以及样式。你画出来的线是啥颜色,好宽,都由它决定的。

缺省的DC画笔是单个象素宽的黑色画笔。一旦画笔被选入设备上下文后,只有颜色是可以改变的,可通过下面两个函数来访问设置和得到DC画笔颜色。

COLORREF GetDCPenColor(HDC hdc);
COLORREF SetDCPenColor(HDC hdc,COLORREF crColor);

GetDCPenColor函数获取设备上下文中DC画笔的当前颜色,SetDCPenColor函数设置一个新的颜色,并返回旧的颜色。

hdc = ::GetDC( this -> m_hWnd);
COLORREF crCol;
crCol
= GetDCPenColor(hdc); // 默认为黑色

MoveToEx(hdc, 0 , 200 ,NULL);
LineTo(hdc,
100 , 200 ); // 绘制一条黑色的直线

HGDIOBJ   hld = SelectObject(hdc,GetStockObject(DC_PEN));
SetDCPenColor(hdc,RGB(
255 , 0 , 0
));
MoveToEx(hdc,
0 , 220
,NULL);
LineTo(hdc,
100 , 220 ); // 绘制一条红色的直线

SelectObject(hdc,hOld);
::ReleaseDC(
this -> m_hWnd,hdc);

上面的GetStockObject是啥?

原来GDI定义了四种预定义的画笔对象,叫库存画笔,为了获取库存画笔,那就要用到GetStockObject这 个函数了。GetStockObject(BLACK_PEN)黑色、GetStockObject(White_PEN)白色、 GetStockObject(NULL_PEN)什么都不画、GetStockObject(DC_PEN)。

下面用下面两个函数来创建画笔。

HPEN CreatePen( int fnPenStyle, int nwidth,COLORREF crColor);
HPEN CreatePenIndirect(CONST LOGPEN
* lgPen);

fnPenStyle画笔样式有下面这些样式。

PS_SOLID---------------纯色,所有象素都画

PS_DASH---------------虚线

PS_DOT-----------------点画线

PS_DASHDOT---------虚线和点画线交替出现

PS_DASHDOTDOT---虚线和两交点画线交替出现

PS_NULL----------------不画线

PS_INSIDEFRAME----纯色,所有象素都画

hdc = ::GetDC( this -> m_hWnd);
HPEN p_SOLID,p_DASH,p_DOT,p_DASHDOT,p_DASHDOTDOT;
p_SOLID
= CreatePen(PS_SOLID, 1 ,RGB( 255 , 0 , 0
));
p_DASH
= CreatePen(PS_DASH, 1 ,RGB( 255 , 0 , 0
));
p_DOT
= CreatePen(PS_DOT, 1 ,RGB( 255 , 0 , 0
));
p_DASHDOT
= CreatePen(PS_DASHDOT, 1 ,RGB( 255 , 0 , 0
));
p_DASHDOTDOT
= CreatePen(PS_DASHDOTDOT, 1 ,RGB( 255 , 0 , 0
));
hOld
=
SelectObject(hdc,p_SOLID);
MoveToEx(hdc,
0 , 10
,NULL);
LineTo(hdc,
10 , 10
);
SelectObject(hdc,p_DASH);
MoveToEx(hdc,
0 , 20
,NULL);
LineTo(hdc,
0 , 20
);
SelectObject(hdc,p_DOT);
MoveToEx(hdc,
0 , 30
,NULL);
LineTo(hdc,
0 , 30
);
SelectObject(hdc,p_DASHDOT);
MoveToEx(hdc,
0 , 40
,NULL);
LineTo(hdc,
0 , 40
);
SelectObject(hdc,p_DASHDOTDOT);
MoveToEx(hdc,
0 , 50
,NULL);
LineTo(hdc,
0 , 50
);
SelectObject(hdc,hOld);
DeleteObject(p_SOLID);
DeleteObject(p_DASH);
DeleteObject(p_DOT);
DeleteObject(p_DASHDOT);
DeleteObject(p_DASHDOTDOT);
::ReleaseDC(
this -> m_hWnd,hdc);

 

CreatePenIndirect函数

结构LOGPEN存储了逻辑画笔的三个参数,画笔样式、宽度、颜色。

typedef struct tagLOGPEN{
   UINT lopnStyle;     
// 样式

   POINT lopnWidth;     // 宽度
   COLORREF lopnColor; // 颜色
}LOGPEN, * PLOGPEN;

 

LOGPEN logpen;
HPEN p;
HGDIOBJ hOld;
HDC hdc
= ::GetDC( this ->
m_hWnd);
logpen.lopnWidth.x
= 1
;
logpen.lopnColor
= RGB( 255 , 0 , 0
);
logpen.lopnStyle
=
PS_SOLID;
p
= CreatePenIndirect( &
logpen);
hOld
=
SelectObject(hdc,p);
MoveToEx(hdc,
0 , 10
,NULL);
LineTo(hdc,
50 , 10
);
SelectObject(hdc,hOld);
DeleteObject(p);
::ReleaseDC(
this -> m_hWnd,hdc);

 

ExtCreatePen函数

      上面CreatePen和CreatePenIndirect(CreatePenIndirect也是调用的CreatePen函数)创建的画笔,当宽 度大于一个象素时,画笔不能画真实形式的直线,例如虚线和点划线。绘制的直线画端是圆角的,这时这两个函数将不能满足需要了。这时就可用到 ExtCreatePen函数。ExtCreaetPen可以创建几何画和装饰性画笔。

 

HPEN ExtCreatePen(DWORD dwPenStylek,
                   DWORD dwWidth,
                   CONST LOGBRUSH
*
lplb,
                   DWORD dwStyleCont,
                   CONST DWORD
* lpStyle);

用ExtCreatePen创建装饰性画笔

dwPenStyle:为画笔类型和型式(类型包括 PS_COSMETIC和 PS_GEOMETRIC,PS_COSMETIC为装饰画笔, PS_GEOMETRIC为几何画笔,型式包括前面说的画笔的样式PS_SOLID....,在2000/nt以上还包括PS_USERSTYLE、PS_ALTERNATE)。

 

dwWidth:装饰性画笔只能画单个象素宽的线,因此dwWidth参数只能为1;

lplb:画笔的属性;

dwStyleCont:是自定义样式数组的个数。

lpStyle:自定义样式数组

     LOGBRUSH lb;
     HDC hdc
= ::GetDC( this ->
m_hWnd);
     HGDIOBJ hOld;
    
     lb.lbStyle
=
BS_SOLID;
     lb.lbColor
= RGB( 255 , 0 , 0
);
     lb.lbHatch
= 0
;
     HPEN p
= ExtCreatePen(PS_COSMETIC | PS_SOLID, 1 , & lb, 0
,NULL);
     hOld
=
SelectObject(hdc,p);
     MoveToEx(hdc,
0 , 20
,NULL);
     LineTo(hdc,
100 , 20
);
     SelectObject(hdc,hOld);
     DeleteObject(p);
     ::ReleaseDC(
this -> m_hWnd,hdc);

下面使用PS_USERSTYLE来创建自定义的装饰性画笔,lpSyle数组中的第一个元素象素长度,第二个元素 为间距长度,第三个元素为象素长度......,里面元素的单位为三个象素,例如{4,3,2,1}则绘出的线为12个象素的线,9象素的间距,6象素的 线,3象素的间距。

     LOGBRUSH lb;
     HDC hdc
= ::GetDC( this ->
m_hWnd);
     HGDIOBJ hOld;
     DWORD cy[
4 ] = { 4 , 3 , 2 , 1
};
    
     lb.lbStyle
=
BS_SOLID;
     lb.lbColor
= RGB( 255 , 0 , 0
);
     lb.lbHatch
= 0
;
     HPEN p
= ExtCreatePen(PS_COSMETIC | PS_USERSTYLE, 1 , & lb, 4
, cy);  
     hOld
=
SelectObject(hdc,p);
     MoveToEx(hdc,
0 , 20
,NULL);
     LineTo(hdc,
100 , 20
);
     SelectObject(hdc,hOld);
     DeleteObject(p);
     ::ReleaseDC(
this -> m_hWnd,hdc);

使用ExtCreatePen建立几何画笔

 

     LOGBRUSH lb;
     HDC hdc
= ::GetDC( this ->
m_hWnd);
     HGDIOBJ hOld;
     DWORD cy[
4 ] = { 4 , 3 , 2 , 1
};
    
     lb.lbStyle
=
BS_SOLID;
     lb.lbColor
= RGB( 255 , 0 , 0
);
     lb.lbHatch
= 0
;
        
// 创建一个平面端点几何画笔(PS_ENDCAP_FLAT平面端点,PS_ENDCAP_ROUND圆角端点)

     HPEN p = ExtCreatePen(PS_GEOMETRIC | PS_SOLID | PS_ENDCAP_FLAT, 16 , & lb, 0 , NULL);  
     hOld
=
SelectObject(hdc,p);
     MoveToEx(hdc,
0 , 20
,NULL);
     LineTo(hdc,
100 , 20
);
     SelectObject(hdc,hOld);
     DeleteObject(p);
     ::ReleaseDC(
this -> m_hWnd,hdc);

GDI画刷对象

GDI中的画刷对象的颜色决定了区域填充中前景色。

缺省的DC画刷是白色画刷。一旦画笔被选入设备上下文后,可通过下面两个函数来访问设置和得到DC画笔颜色。

GDI预定义了7个库存画刷,可以使用GetStockObject函数带入以下参数获取库存画刷。

BLACK_BRUSH---------------黑色画刷

DKGRAY_BRUSH-------------暗灰色画刷

GRAY_BRUSH----------------灰色画刷

LTGRAY_BRUSH-------------浅灰色画刷

WHITE_BRUSH--------------白色画刷

NULL_BRUSH----------------空画刷

DC_BRUSH------------------DC画刷

COLORREF GetDCBrushColor(HDC hdc);
COLORREF SetDCBrushColor(HDC hdc,COLORREF clColor);

GetDCBrushColor函数获取设备上下文中DC画刷的当前颜色,SetDCBrushColor函数为当关DC画刷设置一个新的颜色,并返回旧的颜色。

自定义画刷

 

HBRUSH CreateSolidBrush(COLORREF clColor);                             // 创建纯色画刷
HBRUSH CreateHatchBrush( int fnStyle,COLORREF crRef);                   // 创建阴影画刷
HBRUSH CreatePatternBrush(HBITMAP hbmp);                               // 创建位图画刷
HBRUSH CreateDIBPatternBrushPt(CONST VOID * lpPackedDIB,UINT iUsage);   // 创建设备无关位图画刷
HBRUSH CreateDIBPatternBrush(HGLOBAL hglbDIBPacked,UINT iUsage);       // 创建设备无关位图画刷
HBRUSH GetSysColorBursh( int nIndex);                                   // 创建系统颜色画刷
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
VC中绘制样条曲线,可以使用GDI+库提供的功能。样条曲线可以是基数样条或贝塞尔样条。基数样条由一系列点和张力参数定义,而贝塞尔样条由两个端点和两个控制点定义。以下是一个示例代码,演示如何在VC中绘制基数样条曲线: ```cpp #include <windows.h> #include <gdiplus.h> using namespace Gdiplus; void DrawSplineCurve(HDC hdc) { Graphics graphics(hdc); Pen pen(Color::Blue, 2.0f); Point points\[\] = { Point(0, 100), Point(50, 80), Point(100, 20), Point(150, 80), Point(200, 100) }; graphics.DrawCurve(&pen, points, 5); } ``` 这段代码使用了GDI+库中的Graphics类和Pen类来绘制基数样条曲线。首先创建一个Graphics对象,然后创建一个Pen对象来指定曲线的颜色和宽度。接下来,定义一个Point数组来存储曲线上的点的坐标。最后,使用Graphics对象的DrawCurve方法来绘制曲线。 如果你想绘制填充的封闭曲线,可以使用以下代码: ```cpp void DrawClosedCurve(HDC hdc) { Graphics graphics(hdc); Pen pen(Color::Blue, 2.0f); SolidBrush brush(Color::Red); Point points\[\] = { Point(10, 30), Point(50, 80), Point(100, 20), Point(150, 80), Point(150, 50) }; graphics.DrawClosedCurve(&pen, points, 5); graphics.FillClosedCurve(&brush, points, 5); } ``` 这段代码在绘制封闭曲线之前,先创建了一个SolidBrush对象来指定填充的颜色。然后使用Graphics对象的DrawClosedCurve方法绘制封闭曲线,再使用FillClosedCurve方法填充曲线内部。 请注意,以上代码只是示例,你可以根据自己的需求进行修改和扩展。 #### 引用[.reference_title] - *1* *2* *3* [GDI+ 绘制曲线方法总结](https://blog.csdn.net/lizhichao410/article/details/124448475)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值