创建窗口步骤:

(1)注册窗口类(RegisterClassEx)

(2)创建窗口(CreateWindowEx)

(3)在桌面显示窗口(ShowWindow)

(4)更新窗口客户区(UpdateWindow)

(5)进入无限的消息获取和处理的循环:获取消息(GetMessage);分派消息至窗口函数处理(DisPatchMessage);

如果是WM_QUIT,函数(GetMessage)返回False,消息循环结束,程序退出。

注册窗口类需要初始化一个窗口类结构,将其写成一个函数如下:

ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEXW wcex; //窗口类结构
wcex.cbSize = sizeof(WNDCLASSEX); //结构大小
wcex.style = CS_HREDRAW | CS_VREDRAW|CS_OWNDC;//CS:class style此窗口类派生的窗口具有的风格
//CS_OWNDC使得windows将每次对DC的设置保存下来,CS_HREDRAW | CS_VREDRAW窗口大小变化就刷新
wcex.lpfnWndProc = WndProc; //窗口函数指针
wcex.cbClsExtra = ; //紧跟在窗口类结构后的附加字节数
wcex.cbWndExtra = ; //紧跟在窗口事例后的附加字节数
wcex.hInstance = hInstance;//本模块的实例句柄
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_CLOCKWINDOW));//窗口左上角图标句柄
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);//光标句柄
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW); //背景画刷句柄
wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_CLOCKWINDOW);//菜单名
//wcex.lpszMenuName =NULL; //无菜单
wcex.lpszClassName = szWindowClass; //此窗口类名
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));//小图标句柄
return RegisterClassExW(&wcex); //注册此窗口类
}

创建窗口、显示窗口、刷新客户区写成一个函数如下:

BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance; // 将实例句柄存储在全局变量中
HWND hWnd = CreateWindowW(szWindowClass, //窗口类名
szTitle, //窗口标题
WS_OVERLAPPEDWINDOW, //窗口风格 WS:window style
CW_USEDEFAULT, //初始位置X坐标
CW_USEDEFAULT, //初始位置Y坐标
, //宽度
, //高度
nullptr, //父窗口句柄
nullptr, //菜单句柄
hInstance, //程序实例句柄
nullptr); //用户数据
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow); //显示窗口
UpdateWindow(hWnd); //刷新客户区
return TRUE;
}

因此主函数可以写为:

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// 初始化全局字符串
LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadStringW(hInstance, IDC_CLOCKWINDOW, szWindowClass, MAX_LOADSTRING); MyRegisterClass(hInstance);
// 执行应用程序初始化:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
} HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_CLOCKWINDOW)); MSG msg;
// 主消息循环:
while (GetMessage(&msg, nullptr, , ))//GetMessage返回False程序结束
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam; //程序结束时返回最后一个MSG的wParam。
}

在窗口作图

测试一:先打开notepad,之后运行此代码

    HWND hWnd;
HDC hDC;
hWnd = ::FindWindow(_TEXT("Notepad"), NULL);
hDC = ::GetDC(hWnd);
while (::IsWindow(hWnd))
{
::SetTextColor(hDC, RGB(, , ));
::SetBkColor(hDC, RGB(, , ));
::TextOut(hDC, , , _T("this is a test."), sizeof("this is a test.") - ); HPEN hPen = CreatePen(NULL,,RGB(,,));
::SelectObject(hDC, hPen);
::SelectObject(hDC, ::GetStockObject(BLACK_BRUSH));
Ellipse(hDC, , , , );
Sleep();
::SelectObject(hDC, ::GetStockObject(WHITE_BRUSH));
Ellipse(hDC, , , , );
Sleep();
::SelectObject(hDC, ::GetStockObject(LTGRAY_BRUSH));
Ellipse(hDC, , , , );
Sleep();
::SelectObject(hDC, ::GetStockObject(GRAY_BRUSH));
Ellipse(hDC, , , , );
Sleep();
::SelectObject(hDC, ::GetStockObject(DKGRAY_BRUSH));
Ellipse(hDC, , , , );
Sleep();
::SelectObject(hDC, ::GetStockObject(DKGRAY_BRUSH));
Ellipse(hDC, , , , );
Sleep();
}
ReleaseDC(hWnd, hDC);

绘图首先要取得设备环境句柄

            PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps); //取得(窗口客户区无效区域)设备环境句柄
//绘图代码
//EndPaint(hWnd, &ps);
HDC hdcW = ::GetWindowDC(hWnd); //取得整个窗口设备环境句柄
HDC hdcD = ::GetDC(hWnd); //取得窗口客户区设备环境句柄(函数可用在任何地方)

接着有时为了作图方便需要修改默认坐标系

void SetIsotropic(HWND hWnd,HDC hdc)
{
RECT rect;
GetClientRect(hWnd, &rect); //取得客户区大小
::SetMapMode(hdc, MM_ANISOTROPIC); //自定义坐标系MM_ANISOTROPIC:X!=Y,MM_ISOTROPIC:X=Y
::SetWindowExtEx(hdc, , , NULL); //逻辑刻度,第四个参数可用于返回原来的大小
::SetViewportExtEx(hdc, rect.right, -rect.bottom, NULL); //像素刻度(坐标方向),第四个参数可用于返回原来的大小
::SetViewportOrgEx(hdc, rect.right / , rect.bottom / , NULL);
//修改坐标系(参照之前坐标系的位置坐标),第四个参数可用于返回原来的原点
}

修改完坐标系后开始绘制时钟表面

void paintClock(HWND hWnd,HDC hdc)
{
HPEN hPenTri, hPenTime, hPenCent;
HBRUSH hBrushTr, hBrushTime, hBrushCent;
int colorUseR = (rand() % ( - + )) + ; //(rand() % (b-a+1))+ a; a~b随机数
int colorUseG = (rand() % ( - + )) + ;
int colorUseB = (rand() % ( - + )) + ;
hPenTri = CreatePen(NULL, , RGB(, colorUseG, ));
hBrushTr = ::CreateSolidBrush(RGB(, colorUseG, ));
bankColor = RGB(, colorUseG, );
hPenTime = CreatePen(NULL, , RGB(colorUseR, , ));
hBrushTime = ::CreateSolidBrush(RGB(colorUseR, , ));
hPenCent = ::CreatePen(NULL, , RGB(, , colorUseB));
hBrushCent = ::CreateSolidBrush(RGB(, , colorUseB)); SetIsotropic(hWnd,hdc);
///三角形////////////////////////////////////////////////////////////////////////////////////
//SetDCBrushColor(hdc, RGB(255, 255, 255));//(无效)
::SelectObject(hdc, hPenTri);
::SelectObject(hdc, hBrushTr);
//POINT Mypoint[12] = { (250,10),(375,33.5),(466.5,125),(490,250),(466.5,375),(375,466.5),(250,490),(125,466.5),(33.5,375),(10,250),(33.5,125),(125,33.5) };//写法错误
POINT Mypoint[] = { ,,,207.84,207.84,,,,207.84,-,,-207.84,,-,-,-207.84,-207.84,-,-,,-207.84,,-,207.84 };
//::ClientToScreen(hWnd, point); //投射到屏幕坐标,返回至point
POINT Mypoint1[] = { Mypoint[],Mypoint[],Mypoint[] };
POINT Mypoint2[] = { Mypoint[],Mypoint[],Mypoint[] };
POINT Mypoint3[] = { Mypoint[],Mypoint[],Mypoint[] };
POINT Mypoint4[] = { Mypoint[],Mypoint[],Mypoint[] };
//POINT Mypoint5[4]={ Mypoint1 ,Mypoint2,Mypoint3,Mypoint4}//不好用for循环简化操作,二维数组用不了??
Polygon(hdc, Mypoint1, );
Polygon(hdc, Mypoint2, );
Polygon(hdc, Mypoint3, );
Polygon(hdc, Mypoint4, );
//圆形=============================================================== ::SelectObject(hdc, hPenTime);
::SelectObject(hdc, hBrushTime);//图形填充色
for (int i = ; i < ; i++)
{
Ellipse(hdc, Mypoint[i].x - , Mypoint[i].y - , Mypoint[i].x + , Mypoint[i].y + );
}
//中心点加文本=======================================================
::SelectObject(hdc, hPenCent);
::SelectObject(hdc, hBrushCent);
::Ellipse(hdc, -, , , -);
::SetTextColor(hdc, RGB(, , )); //文字颜色
//::SetBkColor(hdc, TRANSPARENT); //文字背景色,设置为透明无效
::SetBkMode(hdc, TRANSPARENT); //文字背景透明 CString strText = _T("时钟");
TextOut(hdc, -, , (LPCWSTR)strText, sizeof(strText) - );
}

绘制时钟的指针函数

void DrawHand(HDC hdc, int nLength, int nWidth, int nDegrees, COLORREF clrColor)
{
double nRadians = (double)nDegrees * * 3.1415926 / ;
POINT pt[];
pt[].x = (int)(nLength*sin(nRadians));
pt[].y = (int)(nLength*cos(nRadians));
pt[].x = pt[].x /-;
pt[].y = pt[].y /-;
HPEN hPen = ::CreatePen(PS_SOLID, nWidth, clrColor);
HPEN oldPen = (HPEN)::SelectObject(hdc, hPen);
::MoveToEx(hdc, pt[].x, pt[].y, NULL);
LineTo(hdc, pt[].x, pt[].y); ::SelectObject(hdc, oldPen);
::DeleteObject(hPen);
}

在窗口函数WM_CREATE下设置定时器

    case WM_CREATE:
//当一个应用程序通过CreateWindowEx函数或者CreateWindow函数请求创建窗口时发送此消息,(此消息在函数返回之前发送)。
SYSTEMTIME time;
::GetLocalTime(&time);
s_PreHour = time.wHour%;//取余
s_PreMinute = time.wMinute;
s_PreSecond = time.wSecond;
SetTimer(hWnd, //窗口句柄
IDT_CLOCK,//TimerID
, //间隔
NULL); //计时器函数指针
return ;
//它应当返回0以使得窗口的创建过程得以继续。如果对于这个消息程序返回-1,窗口将会被销毁。
//并且CreateWindowEx或者CreateWindow函数将会返回一个值为NULL的句柄。

在WM_TIMER下控制指针的变化与重画

    case WM_TIMER:
paintClock(hWnd, hDC);
//paintClock(hWnd, hDC);重画了时钟面板,使得覆盖了旧的时钟指针
if (::IsIconic(hWnd)) //如果窗口是最小化
{
return ;
}
::GetLocalTime(&time);
//HDC hDC = ::GetDC(hWnd);//(无法写在这里)
SetIsotropic(hWnd, hDC);//建立坐标系
if (time.wMinute != s_PreMinute)
{
//DrawHand(hDC, 140, 8, s_PreHour * 30 + s_PreMinute / 2, bankColor);//使用时钟面板颜色覆盖原指针
//DrawHand(hDC, 170, 6, s_PreMinute * 6, bankColor);
//覆盖失败(不能使得指针颜色完全消失,如同在相同的两点好几条画好几条线,看起来线条变粗并不像一条直线) s_PreHour = time.wHour;
s_PreMinute = time.wMinute;
}
if (time.wSecond != s_PreSecond)
{
//DrawHand(hDC, 170, 1, s_PreSecond * 6, bankColor);//使用时钟面板颜色覆盖原指针
DrawHand(hDC, , , s_PreHour * + s_PreMinute / , RGB(,,));
DrawHand(hDC, , , s_PreMinute * , RGB(, , ));
DrawHand(hDC, , , s_PreSecond * , RGB(, , ));
s_PreSecond = time.wSecond;
}
//::MessageBeep(MB_ICONASTERISK);//发出“嘟嘟”声
break;

效果图

VC++窗口创建过程,图形绘制,时钟程序的更多相关文章

  1. 创建Win32图形界面应用程序

    没有什么比创建一个Win32图形界面应用程序能让Win32汇编初学者更兴奋的了! 然而,对于像我这样没有代码便会陷入困境的人来说,看到下面的代码总能让人为之一振,百余行的代码使得Win32GUI编程并 ...

  2. Win32窗口创建过程

    编写窗口程序的步骤:    1 定义WinMain函数    2 定义窗口处理函数–自己定义处理消息    3 注册窗口类(往OS写入数据)    4 创建窗口 (在内存中创建窗口)    5 显示窗 ...

  3. Hystrix核心基础 - 滑动窗口创建过程及demo

    前言 RxJava可能有些小伙伴没有听过是什么东西,可能是因为大家平时在做业务需求的时候对异步编程了解得比较少,而RxJava就是这么一个响应式编程框架,RxJava在安卓上面用得非常多,做安卓的朋友 ...

  4. vc++窗口的创建过程(MFC消息机制的经典文章)

    一.什么是窗口类  在Windows中运行的程序,大多数都有一个或几个可以看得见的窗口,而在这些窗口被创建起来之前,操作系统怎么知道该怎样创建该窗口,以及用户操作该窗口的各种消息交给谁处理呢?所以VC ...

  5. MFC应用程序创建窗口的过程 good

    MFC应用程序中处理消息的顺序 1.AfxWndProc()      该函数负责接收消息,找到消息所属的CWnd对象,然后调用AfxCallWndProc 2.AfxCallWndProc()  该 ...

  6. Win10系列:VC++ Direct3D图形绘制1

    通过前面的介绍,相信读者已经了解了如何新建一个用于开发Direct3D应用程序的项目模版,以及这个项目模版中用于绘制立体图形的主要函数.在本小节中,将通过一个具体的示例来介绍如何使用Visual St ...

  7. 有谁知道Delphi中"窗口"的创建过程?

      求助:有谁知道Delphi中窗口的创建过程,此“窗口”不仅仅指 TForm 类型, 还包括一般的窗口控件,如TButton,TEdit等等,希望有能够十分详细的运作 过程,比如说CreatPara ...

  8. 深入解析Windows窗口创建和消息分发(三个核心问题:怎么将不同的窗口过程勾到一起,将不同的hwnd消息分发给对应的CWnd类去处理,CWnd如何简单有效的去处理消息,由浅入深,非常清楚) good

    笔记:争取不用看下面的内容,只看自己的笔记,就能记住这个流程,就算明白了: _tWinMain-->AfxWinMain,它调用四个函数: -->AfxWinInit用于做一些框架的初始化 ...

  9. VC图形绘制双缓存的代码复用性讨论

    在前文中已经讨论了如何实现界面绘制双缓存的问题,前文网址如下: http://www.2cto.com/kf/201111/112429.html 双缓存的主要思路是:先把图形绘制到内存DC中,然后再 ...

随机推荐

  1. Android-Kotlin-Activity直接的跳转

    1.选中应用包名packageName,右键: 2.选中Kotlin: 3.创建Kotlin的Activity完成: 第一个Activity,MainActivity package cn.kotli ...

  2. EF查询返回DataTable

    using (SchoolContext dbCOntext = new SchoolContext()) { string str = "select * from student&quo ...

  3. ModelValidator基于元数据的验证

    ModelValidator主要是应用在ModelMetadata元数据的类型上或类型属性上.它是验证的基础类型,所有的ModelValidatorProviders.DataAnnotationVa ...

  4. 使用jQuery实现一个类似GridView的编辑,更新,取消和删除的功能

    先来看看下面实时效果演示: 用户点击编辑时,在点击行下动态产生一行.编辑铵钮变为disabled.新产生的一行有更新和取消的铵钮,点击“取消”铵钮,删除刚刚动态产生的行.编辑铵钮状态恢复. 更新与删除 ...

  5. Java反射机制介绍

    1. 文档概述 Java反射是Java被视为动态(或准动态)语言的一个关键性质,Java反射机制容许程序在运行时加载.探知.使用编译期间完全未知的classes.换言之,Java可以加载一个运行时才得 ...

  6. Spring Cloud实践之服务注册与发现Eureka

    一.简述: 服务提供者producer与服务消费者consumer都注册到eureka server,然后服务consumer在其应用内直接调用producer的服务名来调用服务,而不是像之前一样调用 ...

  7. vscode 学习笔记 —— 调试 (以 node 为例)

    一.建立配置文件 1.选择你的项目 2.选择你项目的语言 3.当前项目路径下生成 .vscode/launch.json { // Use IntelliSense to learn about po ...

  8. redis之事务

    一.是什么 可以一次执行多个命令,本质是一组命令集合.一个事务中的所有命令都会序列化,按顺序的串行化执行而不被其他命令插入,不许加塞.一个队列中,一次性.顺序性.排他性的执行一系列命令. 二.事务常用 ...

  9. java单例类的几种实现

    一,最简单的方式 public class Singleton{ private Singleton(){}; private static Singleton instance = new Sing ...

  10. 字符、字符串和文本的处理之Char类型

    .Net Framework中处理字符和字符串的主要有以下这么几个类: (1).System.Char类 一基础字符串处理类 (2).System.String类 一处理不可变的字符串(一经创建,字符 ...