您的位置:首页 > 其它

第五章 图形基础part2

2009-11-17 16:32 274 查看
5.3画点和线

设定图素:

SetPixel(hdc, x, y, crColor) ;//在指定的x和y坐标以特定的颜色设定图素.最后一个参数是COLORREF型态指定了颜色。
crColor = GetPixel(hdc, x, y) ;//传回指定坐标处的图素颜色

直线:

Windows可以画直线、椭圆线(椭圆圆周上的曲线)和贝塞尔曲线。

MoveToEx(hdc, xBeg, yBeg, NULL) ;//实际上不会画线,它只是设定了设备内容的「目前位置」属性
LineTo(hdc, xEnd, yEnd) ;//从目前的位置到它所指定的点画一条直线

如果在呼叫LineTo之前没有设定目前位置,那么它将从显示区域的左上角开始画线。如果您需要目前位置,就可以通过以下呼叫获得:GetCurrentPositionEx (hdc, &pt) ; pt是POINT结构的。

将数组中的点连接成线时使用Polyline (hdc, apt, 5) ;最后一个参数是点的数目。PolylineTo有些不同,这个函数使用目前位置作为开始点。

SINEWAVE

#include <windows.h>
#include <math.h>
#define NUM 1000
#define TWOPI            (2 * 3.14159)
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT ("SineWave") ;
HWND          hwnd ;
MSG           msg ;
WNDCLASS      wndclass ;
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        = szAppName;

if (!RegisterClass (&wndclass))
{
MessageBox(NULL, TEXT ("Program requires Windows NT!"),
szAppName, MB_ICONERROR) ;
return 0 ;
}

hwnd = CreateWindow( szAppName, TEXT ("Sine Wave Using Polyline"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL);
ShowWindow (hwnd, iCmdShow);
UpdateWindow (hwnd);

while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam,
LPARAM lParam)
{
static int    cxClient, cyClient ;
HDC         hdc ;
int         i ;
PAINTSTRUCT ps ;
POINT       apt [NUM] ;

switch (message)
{
case WM_SIZE:
//当前窗口的大小
cxClient = LOWORD(lParam);
cyClient = HIWORD(lParam);
return 0 ;

case WM_PAINT:
hdc = BeginPaint (hwnd, &ps);
//设定了设备内容的「目前位置」属性,这里设定为当前窗口的一半
MoveToEx(hdc, 0, cyClient / 2, NULL);
LineTo(hdc, cxClient, cyClient / 2); //画直线

for (i = 0 ; i < NUM ; i++)
{  //结构的x成员设定为从0递增到数值cxClient
apt[i].x = i * cxClient / NUM;
//结构的y成员设定为一个周期的正弦曲线值,并被放大以填满显示区域。
apt[i].y = (int) (cyClient / 2 * (1 - sin(TWOPI * i / NUM)));
}
//将数组中的点连接成线,这个函数使用目前位置作为开始点
Polyline(hdc, apt, NUM);
return 0;

case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}


边界框函数:

画一个矩形Rectangle(hdc, xLeft, yTop, xRight, yBottom);点(xLeft, yTop)是矩形的左上角,(xRight, yBottom)是矩形的右下角。
画椭圆 Ellipse(hdc, xLeft, yTop, xRight, yBottom);
画圆角矩形的函数RoundRect(hdc, xLeft, yTop, xRight, yBottom, xCornerEllipse, yCornerEllipse);

Arc(hdc, xLeft, yTop, xRight, yBottom, xStart, yStart, xEnd, yEnd);
Chord(hdc, xLeft, yTop, xRight, yBottom, xStart, yStart, xEnd, yEnd);
Pie(hdc, xLeft, yTop, xRight, yBottom, xStart, yStart, xEnd, yEnd);

LINEDEMO

#include <windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT ("LineDemo") ;
HWND         hwnd;
MSG          msg;
WNDCLASS     wndclass;

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= szAppName;

if (!RegisterClass (&wndclass))
{
MessageBox(NULL, TEXT ("Program requires Windows NT!"),
szAppName, MB_ICONERROR);
return 0;
}

hwnd = CreateWindow(szAppName, TEXT ("Line Demonstration"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL);

ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd);

while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static int    cxClient, cyClient ;
HDC           hdc ;
PAINTSTRUCT   ps ;

switch (message)
{
case WM_SIZE:
cxClient = LOWORD(lParam);
cyClient = HIWORD(lParam);
return 0 ;

case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
//矩形
Rectangle(hdc, cxClient / 8, cyClient / 8,
7 * cxClient / 8, 7 * cyClient / 8);
//两条贯穿直线
MoveToEx(hdc, 0, 0, NULL);
LineTo(hdc, cxClient, cyClient);

MoveToEx(hdc, 0, cyClient, NULL);
LineTo(hdc, cxClient, 0);
//画椭圆
Ellipse(hdc,cxClient / 8,cyClient / 8,
7 * cxClient / 8, 7 * cyClient / 8);
//画圆角
RoundRect(hdc, cxClient/4, cyClient/4,
3 * cxClient / 4, 3 * cyClient / 4,
cxClient / 8, cyClient / 8) ;

EndPaint(hwnd, &ps);
return 0;

case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}


贝塞尔曲线:

贝塞尔曲线的参数方程,起点是(x0,y0),终点是(x3,y3),两个控制点是(x1,y1)和(x2,y2),随着t的值从0到1的变化,
x(t) = (1 - t)3 x0 + 3t (1 - t)2 x1 + 3t2 (1 - t) x2 + t3 x3
y(t) = (1 - t)3 y0 + 3t (1 - t)2 y1 + 3t2 (1 - t) y2 + t3 y3

PolyBezier(hdc, apt, iCount);
PolyBezierTo(hdc, apt, iCount);apt都是POINT结构的数组。对PolyBezier,前四个点(按照顺序)给出贝塞尔曲线的起点、第一个控制点、第二个控制点和终点。

使用现有画笔(Stock Pens):
Windows表头文件WINDEF.H中包含一个叫做HPEN的型态定义,即画笔的句柄。HPEN hPen;呼叫GetStockObject,可以获得现有画笔的句柄。
画笔的建立、选择和删除:使用函数CreatePen或CreatePenIndirect建立一个「逻辑画笔」。

GDI对象有画笔、画刷、位图、区域、字体和调色盘。除了调色盘之外,这些对象都是通过SelectObject选进设备内容的。

在使用画笔等GDI对象时应该注意:
1.最后要删除自己建立的所有GDI对象。
2.当GDI对象正在一个有效的设备内容中使用时,不要删除它。
3.不要删除现有对象。

LOGPEN(「逻辑画笔」)的结构,并呼叫CreatePenIndirect来建立画笔。hPen = CreatePenlndirect(&logpen);
typedef struct tagLOGPEN { kk1}
POINT lopnWidth;
COLORREF lopnColor;
}LOGPEN;
CreatePen和CreatePenIndirect函数不需要设备内容句柄作为参数。这些函数建立与设备内容没有联系的逻辑画笔。 直到呼叫SelectObject之后,画笔才与设备内容发生联系。

填入空隙:
空隙的着色取决于设备内容的两个属性-背景模式和背景颜色。可以通过如下呼叫来改变Windows用来填入空隙的背景色:SetBkColor (hdc, crColor);通过将背景模式转换为TRANSPARENT,可以阻止Windows填入空隙:SetBkMode (hdc, TRANSPARENT);GetBkMode来取得目前背景模式。

BEZIER

#include <windows.h>
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT ("Bezier") ;
HWND          hwnd ;
MSG           msg ;
WNDCLASS           wndclass ;

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= szAppName ;

if (!RegisterClass (&wndclass))
{
MessageBox (NULL, TEXT ("Program requires Windows NT!"),
szAppName, MB_ICONERROR) ;
return 0 ;
}

hwnd = CreateWindow (szAppName, TEXT ("Bezier Splines"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL) ;

ShowWindow (hwnd, iCmdShow) ;
UpdateWindow (hwnd) ;

while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
return msg.wParam ;
}

void DrawBezier (HDC hdc, POINT apt[])
{
PolyBezier(hdc, apt, 4);
//两根引导线
MoveToEx(hdc, apt[0].x, apt[0].y, NULL);
LineTo(hdc, apt[1].x, apt[1].y);

MoveToEx(hdc, apt[2].x, apt[2].y, NULL);
LineTo(hdc, apt[3].x, apt[3].y);
}

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam,
LPARAM lParam)
{
static POINT apt[4] ;
HDC          hdc ;
int          cxClient, cyClient ;
PAINTSTRUCT  ps ;

switch (message)
{
case WM_SIZE:
cxClient = LOWORD (lParam);
cyClient = HIWORD (lParam);
//起点
apt[0].x = cxClient / 4;
apt[0].y = cyClient / 2;
//两个控制点
apt[1].x = cxClient / 2;
apt[1].y = cyClient / 4;

apt[2].x = cxClient / 2;
apt[2].y = 3 * cyClient / 4;
//终点
apt[3].x = 3 * cxClient / 4;
apt[3].y = cyClient / 2;
return 0;
case WM_LBUTTONDOWN:
case WM_RBUTTONDOWN:
case WM_MOUSEMOVE:
//鼠标左键被按下或者鼠标右键被按下
if (wParam & MK_LBUTTON || wParam & MK_RBUTTON)
{
hdc = GetDC(hwnd);
//选择了一个画笔对象
//因为是白色的线,所以作用是销去先前的线
HPEN hPenOld;
hPenOld = CreatePen(PS_SOLID,3,RGB(255,255,255));
SelectObject(hdc, hPenOld/*GetStockObject(WHITE_PEN)*/);
DrawBezier(hdc, apt);
DeleteObject(hPenOld);
//鼠标左键控制第一个控制点
if (wParam & MK_LBUTTON)
{
apt[1].x = LOWORD(lParam);
apt[1].y = HIWORD(lParam);
}
//鼠标右键控制第二个控制点
if (wParam & MK_RBUTTON)
{
apt[2].x = LOWORD(lParam);
apt[2].y = HIWORD(lParam);
}
//画鼠标变更后的线
HPEN hPen;
hPen = CreatePen(PS_SOLID,3,RGB(128,128,128));
SelectObject(hdc, hPen/*GetStockObject(BLACK_PEN)*/);
//画贝塞尔曲线
DrawBezier(hdc, apt);
DeleteObject(hPen);
ReleaseDC(hwnd, hdc);
}
return 0;
case WM_PAINT:
InvalidateRect(hwnd, NULL, TRUE);
hdc = BeginPaint(hwnd, &ps);
DrawBezier(hdc, apt);
EndPaint(hwnd, &ps);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0 ;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: