跟我一起玩Win32开发(9):绘图(B)
我们今天继续涂鸦,实践证明,涂鸦是人生一大乐趣。
首先,我们写一个程序骨架子,以便做实验。
- #include <Windows.h>
- LRESULT CALLBACK MainWinProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
- int WINAPI WinMain(
- HINSTANCE hThisApp,
- HINSTANCE hPrevApp,
- LPSTR lpsCmdln,
- int iShow)
- {
- WNDCLASS wc;
- wc.cbClsExtra = 0;
- wc.cbWndExtra = 0;
- wc.hbrBackground = CreateSolidBrush(RGB(0,0,0));
- // 默认光标类型为箭头
- wc.hCursor = LoadCursor(hThisApp, IDC_ARROW);
- // 默认应用程序图标
- wc.hIcon = LoadIcon(hThisApp, IDI_APPLICATION);
- wc.hInstance = hThisApp;
- wc.lpfnWndProc = MainWinProc;
- wc.lpszClassName = L"MyAppTest";
- wc.lpszMenuName = NULL;
- wc.style = CS_HREDRAW | CS_VREDRAW;
- // 注册窗口类
- RegisterClass(&wc);
- // 创建窗口
- HWND hwnd = CreateWindow(
- L"MyAppTest",
- L"绘画课",
- /* 使用 WS_VISIBLE 就不用调用ShowWindow了 */
- WS_VISIBLE | WS_OVERLAPPEDWINDOW,
- 100,
- 45,
- 500,
- 380,
- NULL,
- NULL,
- hThisApp,
- NULL);
- // 消息循环
- MSG msg;
- while(GetMessage(&msg, NULL, 0, 0))
- {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
- return 0;
- }
- LRESULT CALLBACK MainWinProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
- {
- switch(msg)
- {
- case WM_DESTROY:
- PostQuitMessage(0);
- return 0;
- case WM_PAINT:
- PAINTSTRUCT ps;
- BeginPaint(hwnd, &ps);
- /*
- 待实现
- */
- EndPaint(hwnd, &ps);
- return 0;
- }
- return DefWindowProc(hwnd, msg, wParam, lParam);
- }
CreatePen函数
我们要进行素描画创作,所以我们必须想清楚要使用什么样的钢笔,画出什么样的线条。故,画图之前得创建一支钢笔,不然,巧妇难为无米之炊。
- HPEN CreatePen(
- int iStyle, //钢笔的样式,如虚线、实线
- int cWidth, //线条宽度
- COLORREF color //线条是啥颜色的
- );
第一个参数指定线条的样式,如
- /* Pen Styles */
- #define PS_SOLID 0
- #define PS_DASH 1 /* ------- */
- #define PS_DOT 2 /* ....... */
- #define PS_DASHDOT 3 /* _._._._ */
- #define PS_DASHDOTDOT 4 /* _.._.._ */
- #define PS_NULL 5
- #define PS_INSIDEFRAME 6
- #define PS_USERSTYLE 7
- #define PS_ALTERNATE 8
函数成功创建钢笔后就会返回HPEN,H开头的你就要知道它表示句柄。Pen也是系统资源,所以创建笔后系统要为它一个标识。
SelectObject函数
上过美术课,你会知道,有了用于进行素描创作的钢笔还不能动手干活,我们还需要有纸。接下来,调用SelectObject函数,把刚才创建的钢笔与绘图纸关联,就等于把我们创建的绘图资源放进DC工具箱中,
- HGDIOBJ WINAPI SelectObject(
- HDC hdc, //设备描述表的句柄
- HGDIOBJ h //要放到DC中的资源的句柄
- );
调用成功后,返回原先的资源句柄。
MoveToEx和LineTo
MoveToEx是设置绘制的起点,下次绘图将从这个点开始。它的最后一个参数将被设置为当前点,即Move后的坐标。LineTo从当前坐标开始,到指定坐标之间绘制一条线段。
- // 创建钢笔
- HPEN pen = CreatePen(PS_DASH, 1, RGB(0,255,50));
- // 把笔选到DC中
- SelectObject(ps.hdc, pen);
- // 设定线段的起点
- MoveToEx(ps.hdc, 15, 25, NULL);
- // 绘制线条
- LineTo(ps.hdc, 65, 49);
- LineTo(ps.hdc, 12, 120);
- LineTo(ps.hdc, 250, 78);
- LineTo(ps.hdc, 312, 185);
- DeleteObject(pen);
记住,只要是我们创建的句柄,用完后调用DeleteObject函数将其销毁。
PolyBezier函数和PolyBezierTo函数
两个函数都是用来绘制贝塞尔曲线的,不同的是,PolyBezier函数包含指定的起点和终点,PolyBezierTo是从当前点开始绘制贝塞尔曲线。
- // 绘制贝塞尔曲线
- pen = CreatePen(PS_DOT, 1, RGB(0,3,255));
- SelectObject(ps.hdc, pen);
- POINT* pts = new POINT[4];
- pts[0].x = 421;
- pts[0].y = 16;
- pts[1].x = 7;
- pts[1].y = 197;
- pts[2].x = 480;
- pts[2].y = 320;
- pts[3].x = 30;
- pts[3].y = 350;
- PolyBezier(ps.hdc, pts, 4);
- delete [] pts;
- // 第二段贝塞尔曲线
- POINT* pts2 = new POINT[3];
- pts2[0].x = 176;
- pts2[0].y = 84;
- pts2[1].x = 17;
- pts2[1].y = 247;
- pts2[2].x = 400;
- pts2[2].y = 490;
- // 移动当前点
- MoveToEx(ps.hdc, 395, 270, NULL);
- PolyBezierTo(ps.hdc, pts2, 3);
- delete [] pts2;
PolyPolyline绘制复合线条
PolyPolyline函数可以绘制多段复合线条。它的声明如下:
- BOOL PolyPolyline(
- HDC hdc,
- const POINT *lppt,
- const DWORD *lpdwPolyPoints,
- DWORD cCount
- );
lppt参数指向一个POINT的数组,它包含绘制复合线条所需的所有点;lpdwPolyPoints指向一个数组,这个数字数组指明如何分配点数组。
例如,lppt有7个点,我计划,前2个点绘制第一条线,接着3个点绘制第二条线,最后2个点绘制第三条线,这样一来,lpdwPolyPolyPoints得值应为:
{ 2, 3, 2 }
nCount里包含lpdwPolyPolyPoints中的数量,我们上面的例子是3.
由于两点决定一条线段,因此,lpdwPolyPolyPoints里面的值记得要>=2。
- // 复杂图形
- pen = CreatePen(PS_DASHDOTDOT, 1, RGB(80,20,160));
- SelectObject(ps.hdc, pen);
- POINT plpts[10] =
- {
- {47,3}, {11,46}, {28,199}, {203,305}, {94,22},
- {402,377}, {21,45}, {237,7}, {300,398}, {175,25}
- };
- DWORD arr[4] = { 2, 3, 3, 2};
- PolyPolyline(ps.hdc, &plpts[0], &arr[0], 4);
上面的代码将画出以下图形。
完整的代码清单如下:
- #include <Windows.h>
- LRESULT CALLBACK MainWinProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
- int WINAPI WinMain(
- HINSTANCE hThisApp,
- HINSTANCE hPrevApp,
- LPSTR lpsCmdln,
- int iShow)
- {
- WNDCLASS wc;
- wc.cbClsExtra = 0;
- wc.cbWndExtra = 0;
- wc.hbrBackground = CreateSolidBrush(RGB(0,0,0));
- // 默认光标类型为箭头
- wc.hCursor = LoadCursor(hThisApp, IDC_ARROW);
- // 默认应用程序图标
- wc.hIcon = LoadIcon(hThisApp, IDI_APPLICATION);
- wc.hInstance = hThisApp;
- wc.lpfnWndProc = MainWinProc;
- wc.lpszClassName = L"MyAppTest";
- wc.lpszMenuName = NULL;
- wc.style = CS_HREDRAW | CS_VREDRAW;
- // 注册窗口类
- RegisterClass(&wc);
- // 创建窗口
- HWND hwnd = CreateWindow(
- L"MyAppTest",
- L"绘画课",
- /* 使用 WS_VISIBLE 就不用调用ShowWindow了 */
- WS_VISIBLE | WS_OVERLAPPEDWINDOW,
- 100,
- 45,
- 500,
- 380,
- NULL,
- NULL,
- hThisApp,
- NULL);
- // 消息循环
- MSG msg;
- while(GetMessage(&msg, NULL, 0, 0))
- {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
- return 0;
- }
- LRESULT CALLBACK MainWinProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
- {
- switch(msg)
- {
- case WM_DESTROY:
- PostQuitMessage(0);
- return 0;
- case WM_PAINT:
- PAINTSTRUCT ps;
- BeginPaint(hwnd, &ps);
- // 创建钢笔
- HPEN pen = CreatePen(PS_DASH, 1, RGB(0,255,50));
- // 把笔选到DC中
- SelectObject(ps.hdc, pen);
- // 设定线段的起点
- MoveToEx(ps.hdc, 15, 25, NULL);
- // 绘制线条
- LineTo(ps.hdc, 65, 49);
- LineTo(ps.hdc, 12, 120);
- LineTo(ps.hdc, 250, 78);
- LineTo(ps.hdc, 312, 185);
- // 绘制贝塞尔曲线
- pen = CreatePen(PS_DOT, 1, RGB(0,3,255));
- SelectObject(ps.hdc, pen);
- POINT* pts = new POINT[4];
- pts[0].x = 421;
- pts[0].y = 16;
- pts[1].x = 7;
- pts[1].y = 197;
- pts[2].x = 480;
- pts[2].y = 320;
- pts[3].x = 30;
- pts[3].y = 350;
- PolyBezier(ps.hdc, pts, 4);
- delete [] pts;
- // 第二段贝塞尔曲线
- POINT* pts2 = new POINT[3];
- pts2[0].x = 176;
- pts2[0].y = 84;
- pts2[1].x = 17;
- pts2[1].y = 247;
- pts2[2].x = 400;
- pts2[2].y = 490;
- // 移动当前点
- MoveToEx(ps.hdc, 395, 270, NULL);
- PolyBezierTo(ps.hdc, pts2, 3);
- delete [] pts2;
- // 复杂图形
- pen = CreatePen(PS_DASHDOTDOT, 1, RGB(80,20,160));
- SelectObject(ps.hdc, pen);
- POINT plpts[10] =
- {
- {47,3}, {11,46}, {28,199}, {203,305}, {94,22},
- {402,377}, {21,45}, {237,7}, {300,398}, {175,25}
- };
- DWORD arr[4] = { 2, 3, 3, 2};
- PolyPolyline(ps.hdc, &plpts[0], &arr[0], 4);
- DeleteObject(pen);
- EndPaint(hwnd, &ps);
- return 0;
- }
- return DefWindowProc(hwnd, msg, wParam, lParam);
- }
跟我一起玩Win32开发(9):绘图(B)的更多相关文章
- 跟我一起玩Win32开发(转自CSDN-东邪独孤)
跟我一起玩Win32开发(1):关于C++的几个要点 跟我一起玩Win32开发(2):完整的开发流程 跟我一起玩Win32开发(3):窗口的重绘 跟我一起玩Win32开发(4):创建菜单 跟我一起玩W ...
- 跟我一起玩Win32开发(17):启动和结束进程
这里我再次说明一下,我不知道为什么,现在的人那么喜欢走极端,估计是价值观都“升级”了的缘故吧. 我撰写这一系列Win32相关的文章,并不是叫大家一定要用Win32去开发项目,仅仅是给大家了解一下,Wi ...
- 跟我一起玩Win32开发(18):使用对话框的两个技巧
相信大家知道对话框怎么用了,就是先用“资源编辑器”设计一个对话框,然后在代码中加载处理.今天,我向大家分享两个使用对话框的技巧,还是比较实用的.不用担心,先喝杯茶,很简单的,一点也不复杂,总之,看俺写 ...
- 跟我一起玩Win32开发(10):绘图(C)
今天我们来欣赏一下用于填充图形的函数,当然我不会逐个去介绍,因为我们参考MSDN直接套参数就可以了. SetDCBrushColor函数有必要扯一下,它的声明如下: COLORREF SetDCBru ...
- 跟我一起玩Win32开发(8):绘图(A)
从本篇开始,我就不吹牛皮,那就吹吹兔皮吧.说说与绘图有关的东东. 要进行绘制,首先要得到一个DC,啥是DC呢?按字面翻译叫设备上下文,也可以翻译为设备描述表,它主要指API为我们封装了一些与显示设备相 ...
- 跟我一起玩Win32开发(19):浏览和打开文件
在应用程序中,我们很经常要实现的功能,是Open文件或保存文件对话框,让用户来选择一个或N个文件.本文我将介绍两种思路,第一种方法较为复杂,第二种方法较为简单. 方法一:老规矩 这是一种传统方法,使用 ...
- 跟我一起玩Win32开发(12):使用控件——单选按钮
今天,咱们还是接着玩“控件斗地主”,这是我原创的超级游戏,有益身心健康,玩一朝,十年少. 哦,对,脑细胞极速运动了一下,想起了一个问题,这个破问题虽然网上有很多种解决方案,但是,并没有让所有人都解决问 ...
- 跟我一起玩Win32开发(23):渐变颜色填充
GradientFill函数可以对特定的矩形区域或者三角形区域进行渐变颜色的填充.我们先来看看GradientFill函数到底长得什么样子,帅不帅. BOOL GradientFill( _In_ ...
- 跟我一起玩Win32开发(21):复制&粘贴&剪贴板操作
我要提醒一下大家,看了我的博文学到的知识,千万不要用于实际开发,不然你会被你的上司骂:“妈的,这些东西哪来的,从来没有人这样做过.”不信你试试,脑细胞被冻结的经理或者技术总监们肯定会这样说的. 如果是 ...
随机推荐
- 中科燕园GIS外包---交通运输综合地理信息平台
集地图.服务.应用于一身交通运输综合性的GIS门户 交通运输综合地理信息平台,是集地图.服务.应用于一身交通运输综合性的GIS门户.无需复杂的设置和部署,就可以高速创建交互式地图和应用程序,并 ...
- mysql 环境变量之 group_concat_max_len
今天使用mysql group_concat()函数,对查询的数据进行字符串连接操作. 不过由于查询的结果较多,连接后的结果很长导致不能完全显示. 查询手册发现如下说明: (先说说group_conc ...
- Liunx之Lamp搭建笔记
1:LAMP源代码搭建用户关系 a. apache服务以daemon用户的处理请求.以root身份作为主进程. b. php源代码安装,会在httpd.conf文件里自己主动增加调用模块.可是在该文 ...
- XHTML中button加入超链接以及使插入图片与屏幕一样大
1.button加入超链接 (1)假设是在本页跳转到新页面.用 <span style="font-size:18px;"><input type="b ...
- 【bzoj4653】[Noi2016]区间
离散化+线段树 #include<algorithm> #include<iostream> #include<cstdlib> #include<cstri ...
- springboot实现定时任务的两种方式
方式一:在springboot启动类上添加@EnableScheduling注解,然后创建具体的任务类,在方法上添加@Scheduled注解,并指明执行频率即可.如下: @Componentpubli ...
- HDU 5651xiaoxin juju needs help
xiaoxin juju needs help Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/ ...
- Vue : props 使用细节(父组件传递数据给子组件)
props使用细节 在Vue.js中我们可以使用 props 实现父组件传递数据给子组件,下面我们总结一下props的使用细节 1.基础类型检查 2.必填数据 3.默认值 4.自定义验证函数 其中每一 ...
- 织梦DEDE多选项筛选_联动筛选功能的实现_二次开发
织梦默认的列表页没有筛选功能,但有时候我们做产品列表页的时候,产品的字段比较多,很多人都需要用到筛选功能,这样可以让用户更方便的找到自己所需要的东西,实现这个联动筛选功能需要对织梦进行二次开发,下面就 ...
- iOS在一个label中显示不同颜色的字体
UILabel *Label = [[UILabel alloc] initWithFrame:CGRectMake(20, 300, 300, 30)]; NSMutableAttributedSt ...