参考学习源码:https://bbs.pediy.com/thread-185555.htm
推荐开源的图形库libuidk:https://github.com/iUIShop/LibUIDK
阅读重绘类时候,不要盲目的粘贴复制.h与.cpp,应该看类向导,该类是否关联了窗口ID,如果关联了Dlg需要添加资源一个窗口在生成类,根据函数调用的方法来阅读重绘类中函数,逻辑才能清晰。
个人阅读,一般先流程顺下来。而不是见到重绘类就要去放下当前梳理深入学习,先把流程顺下来,比如按钮、字体用了那个类,调用的函数,先怎么做后怎么做,能够编译实现效果后在看原理。先会用,后深入,也许效率应该会高一些。
梳理作者代码后,作者创建了几个全局List容器保存按钮、字体属性,包括界面中的布局,先从背景图梳理,有很多种方式,OnPaint进行背景填充:
绘制图标,文字、三种状态。选中,点击,正常效果是不一样的,要有三种标志区分, 作者用了List链表容器m_ButtonList去装在这些数据对象,调用CImageInfo类,绘制图标按钮,我们展示部门代码与逻辑,重在理解作者思路与代码:
结构体如下:
OnCreate用来初始化位置,名字,资源ID添加到结构体,保存到List容器中
OnPaint用来重绘界面,因为OnCreate初始化了按钮相关数据,保存在了m_ButtonList,所以遍历容器中的元素ButtonInfo结构,利用DrawImage的方法进行绘画:
绘制文字,有个问题:当用纯白背景色的时候,字体颜色如果是白色会覆盖的,而并不是没有显示字体,所以注意颜色搭配,并不是BUG:
三种状态按钮,ID资源使用PNG图片不一样,其余完全一样。
其实到这里作者代码逻辑很清晰,OnCreate初始化按钮、字体等控件数据,OnPaint通过容器遍历绘画界面。先来看一下当前效果,如下所示:
上述可以看出按钮、字体效果都是没有问题,只不过布局比较难看.....,这些都是微调整而已,无需太折腾。
下面思考如何响应按钮?进行不同页面切换与操作。正常来说需要点击按钮,发送WM消息至消息队列,处理分发函数。因为是绘画出来的按钮与字体,没有实体控件BUTTON控件可以给响应,那么应该是通过鼠标响应来找到对应的按钮布局(按钮位置固定)。如果你不想读源码那么麻烦,百度:MFC如何捕获鼠标移动与响应消息应该就能找到,自己实现也可以:
这里还是读源码为主,先看原类中有那些WM消息,如下所示:
找到与鼠标移动Mouse相关的WM,后面再看按钮消息WM_LBUTTONDOWN相关数据,不熟悉百度就完事了:
OnMouseLeave、OnMouseHover、OnMouseMove阅读源码,以前没用过这三个消息响应,百度一下用法,如何协作工作,然后对比源码进行理解与修改:
需要写函数获取跟踪当前鼠标移动,鼠标移动到按钮或者点击按钮,设置标志位全局变量,单纯鼠标移动不需要获取当前移动到第几个按钮,直接用坐标重绘,而点击,需要判断是否在当前按钮上,然后在重绘与响应,根据坐标OnPaint绘画出图片效果,选中框与鼠标移动:
按键消息需要响应,按钮状态切换与展示页面切换。响应按钮消息WM_LBUTTONDOWN,然后判断当前鼠标是否在按钮坐标内,初始化时候已经将按钮坐标x,y保存在容器中,对比切换。
后续List重绘我选择用了控件,当按钮响应的时候进行显示与控件风格初始化就好,所以没有使用绘画来去响应,抛砖引玉。
1. 也许变量会没有数据,善用查找所有引用,看在变量被初始化或者函数,便可快速定位到函数与关键点。
2. 当头文件交互错乱,一些.h添加到自己工程会出现重定义,不明确编译失败,需要排查头文件是否相互包含,解决不明确最快的有效的方法,包含命名空间与类,如下:
有些作者喜欢析构函数初始化(标准写法),查看析构函数是否初始化了全局变量,也许会有很多莫名的问题,如Gid Image类对象获取不到图片资源等,因为没有初始化,要去看构造函数是是否对类进行初始化了变量(读源码排了好久BUG这个),如下:
GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdiplusToken;
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdiplusToken;
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
- OninitDialog 初始化一般控件风格与数据
- OnCreate 创建重绘的控件,如按钮控件,文本控件等
- OnPaint 应用重绘
- OnColor 颜色重绘
// 需要先初始化,没用过所以不知道,排查了好久
GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdiplusToken;
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
// 获取窗口矩形位置
CRect rcPaint;
dcMem.GetClipBox(&rcPaint);
Gdiplus::Graphics graphics(dcMem.m_hDC);
// Image类加载资源
Image *aImage;
switch (g_index)
{
// 这里用了一张白色白色背景
case 0:aImage = Image::FromFile(L"repos\\NetworkFilter\\resource\\skin\\frame.jpg"); break;
}
// DrawImage方法画背景图
graphics.DrawImage(aImage, 0, 0, cClientRect.Width(), cClientRect.Height());
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
最后于 2019-12-2 21:55
被一半人生编辑
,原因: