GDI(Graphics Device Interface)是图形设备接口的英文缩写,主要任务是负责系统与绘图程序之间的信息交换,处理所有Windows程序的图形和图像输出。GDI的出现使程序员无需要关心硬件设备及设备正常驱动,就可以将应用程序的输出转化为硬件设备上的输出和构成,实现了程序开发者与硬件设备的隔离,大大方便了开发工作。
- 消息反射
windows的消息反射机制,通过控件之间的消息反射,用来实现较为复杂的多控件之间的交互问题.
在vs2019中,我们可以通过类向导,来为控件指定对应的消息反射,在类向导中,反射型的消息和单独的消息已经区分开了,反射性质的叫做命令,普通的消息叫为消息:
当然,具体的消息类别,我们可以在逐渐的熟悉使用的过程中,来慢慢了解和学习.
- 成员变量
在类向导中同样可以设置虚函数,成员变量等其他功能,虚函数还不甚了解,这里简单记录下使用到的成员变量,通过类向导来为各个控件设置成员变量主要是快速便捷.
不过比较特殊的是,MFC中有重新封装控件类型,和值类型.当然,在大多时候,MFC封装的类型是更加好用的.但是有时候还是不太适应.
- 三大坐标系
基于MFC的窗口应用程序有三大基本坐标系:基于客户区,非客户区,屏幕.都是以左上角为坐标原点:
- 通过空项目来构建从头构建窗口项目
GDI(Graphics Device Interface)是图形设备接口的英文缩写,主要任务是负责系统与绘图程序之间的信息交换,处理所有Windows程序的图形和图像输出。GDI的出现使程序员无需要关心硬件设备及设备正常驱动,就可以将应用程序的输出转化为硬件设备上的输出和构成,实现了程序开发者与硬件设备的隔离,大大方便了开发工作。
在vs2019中创建一个空项目
创建一个test_gdi.cpp文件,再添加一个dialog资源:
进入资源属性界面,更改一下dialog的id: IDD_MAIN_DLG,设定为主窗口,在之后更改caption 改一下窗口的标题为test_GDI,设定后记得保存一下,查看头文件resource.h中有没有id的声明:
注意这里一定要有控件id的声明,否则cpp文件中是无法识别的.
再进入cpp文件中定义WinMain主函数(WinMain函数是windows窗口程序的入口函数,main函数在windows应用程序中是无法使用的),引入windows.h头文件和我们的resource,h资源头文件,记住四个主要的参数:
#include<Windows.h>
#include"resource.h"
INT_PTR CALLBACK theProc(
HWND hwnDlg,
UINT Msg,
WPARAM wPream,
LPARAM ipream) {
return 0;
}
int WINAPI WinMain(HINSTANCE hInst,HINSTANCE hPrev,LPTSTR sCmdLine,int nCmd) {
DialogBox(hInst, (LPCSTR)IDD_MAIN_DLG, NULL, theProc);
return 0;
}
调试运行,在vs2019中,创建的空项目是不能直接运行窗口程序的,会报错:
这主要是因为vs2019中空项目默认的编译是控制台程序,我们将项目属性中链接器->系统->子系统中的subsystem: console修改为windows.
再次编译运行,输出窗口:
WM_PAINT消息 :功能和发生时间,
beginPaint与EndPaint必须成对使用.
BeginPaint返回的DC句柄,是基于其所关联的窗口的客户区坐标系绘制图形的.
在MFC中是把这两个函数封装为一个类:CPaintDC类的.
MFC第二大类 CDC绘图类.
CDC类的核心句柄就是m_hdDC.它的绘图功能基本都是来自m_hDC句柄原有的功能.封装而成.
派生类有:
CPaint类,客户区标准绘图类,专门提供给WM_PAINT消息提供的.
CClientDC类,客户区临时绘图类.在任何其他消息中都可以使用的.
CWindowDC类: 非客户区标准绘图类,专门在WM_NC_PAINT消息下使用(不常使用,基本不会有使用到在非客户区进行绘制图像的使用场景).
要想在客户区进行标准绘图,首先要在回调函数 theProc中声明一个switch结构,来对各种不同类消息进行不同的处理:
// 窗口句柄参数:HWND hwnDlg, UINT 消息类型参数.
INT_PTR CALLBACK theProc(HWND hwnDlg,UINT uMsg,WPARAM wPream,LPARAM ipream) {
switch (uMsg)
{
// WM_NCPAINT消息是一个非客户区的一个绘制消息.
case WM_NCPAINT:
OnNCPaint(hwnDlg);
return TRUE;
// 绘图非常重要的一个消息,WM_PAINT消息,在客户区内绘制:
case WM_PAINT:
// 调用函数
OnPaint(hwnDlg);
return TRUE;
case WM_COMMAND:
if (wPream == IDCANCEL) {
EndDialog(hwnDlg, IDCANCEL);
return TRUE;
}
return FALSE;
default:
break;
}
return 0;
}
在switch结构中对应的消息支路上,调用对应的绘制函数,即可完成简单的绘制工作任务:
//定义一个OnPint函数,传入一个句柄参数,在MFC中将窗口句柄都封装到类中了:
void OnPaint(HWND hwndDlg) {
// 相当于beginpaint
PAINTSTRUCT ps;
// HDC是一个绘图句柄,相当于指定绘制图形的窗口的作用.
HDC hdc = BeginPaint(hwndDlg, &ps);
// 在beginpaint与endpaint之间就可以进行绘图操作了,可以调用各种封装好的绘制函数来实现绘制各种东西的.
/*
椭圆绘制函数,五个参数,第一个是绘图句柄hdc类型的参数,指定绘制的窗口,
其余四个int变量指定位置和椭圆的高度和宽度,也可以用来绘制圆形.
WM_PAINT消息绘制是基于客户区绘制的.
*/
// textout方法,绘制文本
LPCSTR str = _T("text 测试消息");
TextOut(hdc,100,100,str,strlen(str));
Ellipse(hdc, 0, 0,100,100);
// 结束的位置 endpaint 与beginpaint必须得成对使用才行
EndPaint(hwndDlg,&ps);
// 提供的一个控制台输出函数,相当于printf
OutputDebugString(_T("WM_PAINT_onpaint \n"));
}
WM_NCPAINT 消息是非客户区的标准绘图消息.可以通过该消息来实现在非窗口区的绘制(但是该方法一般不常使用).
void OnNCPaint(HWND hwndDlg) {
// 获取坐标系,相当于屏幕.
RECT rect;
GetWindowRect(hwndDlg,&rect);
// 获取一个窗口的HDC句柄对象.
HDC hdc = GetWindowDC(hwndDlg); // CWindwDC在MFC中封装了getWindDC函数
// 绘制矩形
Rectangle(hdc, 0, 0, rect.right - rect.left, rect.bottom - rect.top);
// 在两个函数之间就可以执行一些绘图,或者文字输出的功能了
LPCTSTR str =_T("testNCPaint消息");
SetTextColor(hdc,RGB(255,0,0));
TextOut(hdc, 2, 2,str,strlen(str));
ReleaseDC(hwndDlg,hdc); //反函数是releaseDC,将hdc与窗口连接
}
2019.12.20
8.42