实验3-1 GDI绘图实验
理解设备环境在绘图中的作用
掌握绘图工具的创建,理解绘图工具和设备环境之间的关系
掌握绘图步骤,掌握绘图函数的使用
将实验二中的窗口代码修改,在窗口处理函数中添加绘图代码:响应WM_PAINT
消息,在其中按照绘图步骤,用BeginPaint方法获取设备环境句柄,创建彩色的、具有某种样式的画笔和画刷,选入设备环境,在窗口上画椭圆、矩形等图形,这时创建并选入设备环境的画笔、画刷将作用在绘制图形上,最后删除画笔画刷、用EndPaint释放设备环境。调试运行,观察程序效果。
在第1题的基础上,修改代码,在键盘按键消息(WM_KEYDOWN)中,使用GetDC/ReleaseDC方法获取/释放设备环境,实现原来的画图操作。编译运行,把窗口拖动、最小化之后再还原窗口,看看出现什么问题,结合大课的ppt考虑原因。
用GDI绘制一个游戏界面,如下图所示。其中,左边绿色部分,是游戏控制面板,上面有两个按钮或文本框,记录玩家姓名、分数等,右边是个类似棋盘的游戏内容面板,其中分布了很多条线,构成棋盘的样子。窗口不可以最大化、不可以调整大小。注意:游戏面板中的多条线段,可以循环多次绘制;窗口的类型,可以查询MSDN中CreateWindow的style参数。
#pragma comment(lib, "User32.lib")
#pragma comment(lib, "kernel32.lib")
#pragma comment(lib, "Gdi32.lib")
#include
#include
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT("NueXini");
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("Error"), szAppName, MB_ICONERROR | MB_OK);
return 0;
}
hWnd = CreateWindow(
szAppName,
szAppName,
WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX, // 状态条 包括标题栏 最小化按钮 菜单
CW_USEDEFAULT,
CW_USEDEFAULT,
750, // 窗口大小 width
700, // 窗口大小 height
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)
{
HDC hdc;
PAINTSTRUCT ps;
RECT rect;
HGDIOBJ hPen, hOldPen, hBrush, hOldBruch;
switch (message)
{
case WM_KEYDOWN:
hdc = GetDC(hwnd);
GetClientRect(hwnd, &rect);
TextOut(hdc, 0, 10, _text, strlen(_text));
ReleaseDC(hwnd, hdc);
return 0;
case WM_SIZE:
GetClientRect(hwnd, &rect);
return 0;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
GetClientRect(hwnd, &rect);
// 外边框
hPen = CreatePen(PS_SOLID, 5, RGB(142, 202, 142));
hOldPen = SelectObject(hdc, hPen);
// 矩形内部
hBrush = CreateSolidBrush(RGB(90, 150, 90));
hOldBruch = SelectObject(hdc, hBrush);
// 绘制绿色圆角矩形
RoundRect(hdc, 40, 50, 200, 600, 10, 20);
// 释放
DeleteObject(hOldBruch);
DeleteObject(hOldPen);
// 外边框
hPen = CreatePen(PS_SOLID, 3, RGB(180, 118, 119));
hOldPen = SelectObject(hdc, hPen);
// 矩形内部
hBrush = CreateSolidBrush(RGB(160, 100, 100));
hOldBruch = SelectObject(hdc, hBrush);
// 绘制两个红色矩形在绿色矩形内部
RoundRect(hdc, 50, 450, 190, 480, 10, 20);
RoundRect(hdc, 50, 500, 190, 530, 10, 20);
// 释放
DeleteObject(hOldBruch);
DeleteObject(hOldPen);
// 绘制右边那个棋盘
hPen = CreatePen(PS_SOLID, 3, RGB(255, 177, 177));
hOldPen = SelectObject(hdc, hPen);
hBrush = CreateSolidBrush(RGB(255, 130, 130));
hOldBruch = SelectObject(hdc, hBrush);
RoundRect(hdc, 210, 50, 700, 600, 10, 20);
DeleteObject(hOldBruch);
DeleteObject(hOldPen);
// 绘制竖线
hPen = GetStockObject(BLACK_PEN);
hOldPen = SelectObject(hdc, hPen);
for (size_t i = 1; i < 14; i++)
{
MoveToEx(hdc, 210 + (i * 35), 50, NULL);
LineTo(hdc, 210 + (i * 35), 600);
}
// 绘制横线
for (size_t i = 1; i < 15; i++)
{
MoveToEx(hdc, 210, 50 + (i * 37), NULL);
LineTo(hdc, 700, 50 + (i * 37));
}
// 释放
DeleteObject(hOldPen);
EndPaint(hwnd, &ps);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
查询MSDN,学习Polygon函数的使用,画出黄色五角星,然后尝试画五星红旗。注意观察五星红旗的样子,其中每个五角星每个角都严格相同,每个小五角星都朝向大五角星,所以在你的程序中应该有严格的计算来控制大小、位置,而不是随意设置一些值。
#pragma comment(lib, "User32.lib")
#pragma comment(lib, "kernel32.lib")
#pragma comment(lib, "Gdi32.lib")
#include
#include
#include
#define PI 3.1415926
void CalculateStarPosition(POINT *stars, size_t nCount, size_t r, size_t angle, POINT BigStar);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT("NueXini");
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("Error"), szAppName, MB_ICONERROR | MB_OK);
return 0;
}
hWnd = CreateWindow(
szAppName,
szAppName,
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)
{
HDC hdc;
PAINTSTRUCT ps;
RECT rect;
HGDIOBJ hPen, hOldPen, hBrush, hOldBrush;
// 把左上角矩形宽分为15份,高分为10份
size_t flagWidth = 450 / 15;
size_t flagHeight = 300 / 10;
POINT stars[5] = {0};
// 第1颗
POINT BigStar1 = {(LONG)flagWidth * 5, (LONG)flagHeight * 5};
CalculateStarPosition(stars, 5, flagHeight * 3, 90, BigStar1);
POINT star1[5] = {stars[0], stars[2], stars[4], stars[1], stars[3]};
// 第2颗
POINT BigStar2 = {(LONG)flagWidth * 10, (LONG)flagHeight * 2};
CalculateStarPosition(stars, 5, flagHeight, 70, BigStar2);
POINT star2[5] = {stars[0], stars[2], stars[4], stars[1], stars[3]};
// 第3颗
POINT BigStar3 = {(LONG)flagWidth * 12, (LONG)flagHeight * 4};
CalculateStarPosition(stars, 5, flagHeight, 120, BigStar3);
POINT star3[5] = {stars[0], stars[2], stars[4], stars[1], stars[3]};
// 第4颗
POINT BigStar4 = {(LONG)flagWidth * 12, (LONG)flagHeight * 7};
CalculateStarPosition(stars, 5, flagHeight, 90, BigStar4);
POINT star4[5] = {stars[0], stars[2], stars[4], stars[1], stars[3]};
// 第5颗
POINT BigStar5 = {(LONG)flagWidth * 10, (LONG)flagHeight * 9};
CalculateStarPosition(stars, 5, flagHeight, 70, BigStar5);
POINT star5[5] = {stars[0], stars[2], stars[4], stars[1], stars[3]};
switch (message)
{
case WM_SIZE:
GetClientRect(hwnd, &rect);
return 0;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
GetClientRect(hwnd, &rect);
// 红色画刷
hBrush = CreateSolidBrush(RGB(255, 0, 0));
hOldBrush = SelectObject(hdc, hBrush);
// 创建3:2矩形
Rectangle(hdc, 0, 0, 900, 600);
DeleteObject(hOldBrush);
// 把矩形分为四个相等的矩形
MoveToEx(hdc, 0, 300, nullptr);
LineTo(hdc, 900, 300);
MoveToEx(hdc, 450, 0, nullptr);
LineTo(hdc, 450, 600);
// 绘制横线
for (size_t i = 0; i < 10; i++)
{
MoveToEx(hdc, 0, flagHeight * i, nullptr);
LineTo(hdc, 450, flagHeight * i);
}
// 绘制竖线
for (size_t i = 0; i < 15; i++)
{
MoveToEx(hdc, flagWidth * i, 0, nullptr);
LineTo(hdc, flagWidth * i, 300);
}
// 绘制
hBrush = CreateSolidBrush(RGB(255, 255, 0));
hOldBrush = SelectObject(hdc, hOldBrush);
hPen = CreatePen(PS_SOLID, 1, RGB(255, 255, 0));
hOldPen = SelectObject(hdc, hPen);
SetPolyFillMode(hdc, WINDING);
Polygon(hdc, star1, 5);
Polygon(hdc, star2, 5);
Polygon(hdc, star3, 5);
Polygon(hdc, star4, 5);
Polygon(hdc, star5, 5);
DeleteObject(hOldPen);
DeleteObject(hOldBrush);
EndPaint(hwnd, &ps);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
void CalculateStarPosition(POINT *stars, size_t nCount, size_t r, size_t angle, POINT BigStar)
{
for (size_t i = 0; i < nCount; i++)
{
stars[i].x = BigStar.x + (LONG)(r * cos((angle + i * 72) * PI / 180));
stars[i].y = BigStar.y - (LONG)(r * sin((angle + i * 72) * PI / 180));
}
}
五星之位置与画法如下:
(1)为便于确定五星之位置,先将旗面对分为四个相等的长方形,将左上方之长方形上下划为十等分,左右划为十五等分。
(2)大五角星的中心点,在该长方形上五下五、左五右十之处。其画法为:以此点为圆心,以三等分为半径作一圆。在此圆周上,定出五个等距离的点,其一点须位于圆之正上方。然后将此五点中各相隔的两点相联,使各成一直线。此五直线所构成之外轮廓线,即为所需之大五角星。五角星之一个角尖正向
(3)四颗小五角星的中心点,第一点在该长方形上二下八、左十右五之处,第二点在上四下六、左十二右三之处,第三点在上七下三、左十二右三之处,第四点在上九下一、左十右五之处。其画法为:以以上四点为圆心,各以一等分为半径,分别作四个圆。
在每个圆上各定出五个等距离的点,其中均须各有一点位于大五角星中心点与以上四个圆心的各联结线上。然后用构成大五角星的同样方法,构成小五角星。此四颗小五角星均各有一个角尖正对大五角星的中心点。
// 把左上角矩形宽分为15份,高分为10份
size_t flagWidth = 450 / 15;
size_t flagHeight = 300 / 15;
// 定位 大五角星圆心
POINT BigStar = {(LONG)flagWidth * 5, (LONG)flagHeight * 5};
size_t r = flagHeight * 3;
// 第1个点90度
POINT star1;
star1.x = BigStar.x + (r * cos(90 * PI / 180));
star1.y = BigStar.y - (r * sin(90 * PI / 180));
// 第2个点162度
POINT star2;
star2.x = BigStar.x + (r * cos(162 * PI / 180));
star2.y = BigStar.y - (r * sin(162 * PI / 180));
// 第3个点234度
POINT star3;
star3.x = BigStar.x + (r * cos(234 * PI / 180));
star3.y = BigStar.y - (r * sin(234 * PI / 180));
// 第4个点306度
POINT star4;
star4.x = BigStar.x + (r * cos(306 * PI / 180));
star4.y = BigStar.y - (r * sin(306 * PI / 180));
// 第5个点378度
POINT star5;
star5.x = BigStar.x + (r * cos(378 * PI / 180));
star5.y = BigStar.y - (r * sin(378 * PI / 180));
POINT stars[5] = {star1, star3, star5, star2, star4};
void CalculateStarPosition(POINT *stars, size_t nCount, size_t r, size_t angle, POINT BigStar)
{
#define PI 3.1415926
for (size_t i = 0; i < nCount; i++)
{
stars[i].x = BigStar.x + (LONG)(r * cos((angle + i * 72) * PI / 180));
stars[i].y = BigStar.y - (LONG)(r * sin((angle + i * 72) * PI / 180));
}
}
明明把画刷颜色设置成了黄色,但就是不生效,直接变成了白色,不知道怎么解决这个
enjoy it ~