欢迎访问 生活随笔!

生活随笔

当前位置: 首页 >

为子控件添加自定义绘图方式

发布时间:2023/12/9 49 豆豆
生活随笔 收集整理的这篇文章主要介绍了 为子控件添加自定义绘图方式 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

在MFC应用程序中,有时会遇到需要让指定的控件实现自绘。但是看该控件的事件,没有一个像是能承担这种责任的。

我们都知道控件也是窗口,也都有消息循环。所以:

方案一:写个新类,继承自某个窗口类,在它的WM_PAINT消息中实现自绘。这种方法需要定义一个新类,不是太方便。


方法二:利用SetWindowLong修改该控件的消息处理函数,在WM_PAINT消息中实现自绘。本文就采用此方案。


------------------------------------------------------------

方案二实现过程,环境:Win XP + VC2010(MFC)

完整源码


1. 界面:


2. 为Button1添加点击事件

void CdelDlg::OnBnClickedButton1() {m_bgIndex = (m_bgIndex + 1) % 7;Invalidate(); // 刷新背景 }

3. 添加2个全局变量和2个全局函数(绘图函数和子控件新的消息处理函数)

// 定义全局变量和全局函数 WNDPROC oldProc_PIC1 = 0; // 保存IDC_PIC1控件默认的消息处理函数地址 CString imgPath; // 保存背景图片地址BOOL DrawPic(HWND hWnd) // 在指定的控件上画图 {CImage img;if(SUCCEEDED(img.Load(imgPath))){CWnd *pWnd = CWnd::FromHandle(hWnd);CPaintDC dc(pWnd); // dc必须用指定的控件窗口来初始化,否则将看不到绘图结果CRect rect;pWnd->GetClientRect(rect); // 获取控件的大小img.Draw(dc.m_hDC, rect);return TRUE;}return FALSE; // 绘图失败 }LRESULT NewProc_PIC1(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) // IDC_PIC1控件对应的新的消息函数 {switch (message){case WM_PAINT:if(DrawPic(hWnd))return S_OK;elsebreak;default:break;}return CallWindowProc(oldProc_PIC1, hWnd, message, wParam, lParam); // 调用默认的消息函数 }
4. 在对话框的OnInitDialog()中为子控件IDC_PIC1 指定新的消息循环函数

BOOL CdelDlg::OnInitDialog() {CDialogEx::OnInitDialog();// 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动// 执行此操作SetIcon(m_hIcon, TRUE); // 设置大图标SetIcon(m_hIcon, FALSE); // 设置小图标oldProc_PIC1 = (WNDPROC)SetWindowLong(GetDlgItem(IDC_PIC1)->m_hWnd, GWL_WNDPROC, (LONG)NewProc_PIC1); // 为控件设置新的消息处理函数return TRUE; // 除非将焦点设置到控件,否则返回 TRUE }

5. 处理对话框的WM_PAINT和子控件(IDC_PIC1)的WM_PAINT消息

5.1 主对话框的WM_PAINT消息处理

void CdelDlg::OnPaint() {if (IsIconic()){CPaintDC dc(this); // 用于绘制的设备上下文SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);// 使图标在工作区矩形中居中int cxIcon = GetSystemMetrics(SM_CXICON);int cyIcon = GetSystemMetrics(SM_CYICON);CRect rect;GetClientRect(&rect);int x = (rect.Width() - cxIcon + 1) / 2;int y = (rect.Height() - cyIcon + 1) / 2;// 绘制图标dc.DrawIcon(x, y, m_hIcon);}else{CString file[] = {"1.jpg", "2.jpg", "3.jpg", "11.jpg", "12.bmp", "Smiley.png", "11.gif"};m_imgPath.Format("res\\%s", file[m_bgIndex]);imgPath = m_imgPath;DrawPic(this->m_hWnd); // 在控件上绘图//CDialogEx::OnPaint();} }
5.2 子控件(IDC_PIC1)的WM_PAINT消息处理,即步骤3中的NewProc_PIC1()


点滴经验

1. 本来我想在对话框的PreTranslateMessage()中拦截子控件的WM_PAINT消息的,但是经过试验才知道,窗口在第一次启动时不会触发WM_PAINT消息的,只有失去焦点或重新获得焦点时才会触发WM_PAINT消息。所以放弃使用该方法。

2. CPaintDC的构造函数有个参数的,一般看到的代码中都是用dc(this)来初始化的,因为这个代码是在类的成员函数中,所以没问题。另外在进行绘图时,所指定的rect要与初始化dc的这个参数(如pWnd)对应的坐标(pWnd->GetClientRect(rect))相对应,否则可能看不到绘图结果或绘图的位置不对。

3. 在对话框的自绘处理中,要屏蔽掉其基类的OnPaint(),否则自绘上去的图形将被覆盖。但是,将基类的OnPaint()语句放在自绘语句的最后,是可以的,即我文中的代码可以取消对CDialogEx::OnPaint()的注释。

总结

以上是生活随笔为你收集整理的为子控件添加自定义绘图方式的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。