【EasyUse】一键式检索框-界面美化参考。MFC自绘对话框加图和Button
MFC无标题栏自绘对话框可拖动按钮三态仿QQ弹窗样式
代码提供下载,想边看程序源码边看文章的朋友直接去下载:http://download.csdn.net/detail/panshiqu/5926325
看我前几天的bolg我实现了右下角弹窗功能,但是怎么美化自己的弹窗呢,像腾讯QQ右下角弹腾讯大豫网新闻那样的样式。
首先感谢一篇重要的文章:http://bbs.csdn.net/topics/390170722 作者:邓学彬
但是也需要指出的大凡已经很牛的人,对初学者的求助往往是漠不关心的,我对他文章的回复至今还没有回我的问题,我给的留言也没有收到回音,为什么要感谢他,因为它用Win32(SDK)开发出来的程序,虽然我不想直接拿来用,但是它让我坚信,假以时日我用MFC也可以实现的...
直接上图:
单文档的美化我尝试过,用的是重绘非客户区的方法,遇到各种各样的问题,一言难尽,现在我把这段时间美化对话框应用程序的经验整理出来希望对初学者有点用。首先美化界面不靠其他界面库的话,就要自己贴图了,提到贴图就要提一下在那个函数里贴图比较好,孙鑫VC++教程第10课的样子,提到在OnPaint() 和 OnEraseBkgnd()两个函数中绘制的区别,区别就是OnEraseBkgnd是直接网上贴图,OnPaint贴图之前则是先调用OnEraseBkgnd擦除背景,这样一样在OnEraseBkgnd中贴图就会相对好些。一些没有看过教程的朋友初次绘图发现一切正常,怎么就是不出绘图效果呢,看一下MSDN对OnEraseBkgnd的介绍,“如果擦除成功返回非零,否则是零值”。这样你就要修改函数添加后的返回值了。
- return CDialogEx::OnEraseBkgnd(pDC);
改成
- return TRUE;
说到贴图不得不要提到三个函数:(请去看MSDN,示例看我的源代码)
- BOOL BitBlt(
- int x,
- int y,
- int nWidth,
- int nHeight,
- CDC* pSrcDC,
- int xSrc,
- int ySrc,
- DWORD dwRop
- );
- BOOL StretchBlt(
- int x,
- int y,
- int nWidth,
- int nHeight,
- CDC* pSrcDC,
- int xSrc,
- int ySrc,
- int nSrcWidth,
- int nSrcHeight,
- DWORD dwRop
- );
- BOOL TransparentBlt(
- int xDest,
- int yDest,
- int nDestWidth,
- int nDestHeight,
- CDC* pSrcDC,
- int xSrc,
- int ySrc,
- int nSrcWidth,
- int nSrcHeight,
- UINT clrTransparent
- );
用到这三个函数贴图,贴图的主体思想也是从邓学斌那里学来的,分成区域绘图,这样就不需要你的BMP皮肤文件和你的程序一样的大小了,发现贴图贴的有模有样了,突然发现我的程序不能拖动呀,这是肯定不行的呀,百度搜一下有解决办法,响应OnNcHitTest() 函数就好了,网上很多文章有讲,原理都有说的很清楚,先放上这段代码看看程序是不是可以拖动了
- UINT uRet = CDialog::OnNcHitTest(point);
- return (HTCLIENT == uRet) ? HTCAPTION : uRet;
这样还是没有完成,按钮三态变化还没有实现,我就自定义一个成员函数如下
- BOOL CDialogExDlg::OnChangeState(UINT control, UINT state)
- {
- // control: 标识那个按钮
- // state: 按钮当前变化状态
- CClientDC dc(this);
- // 创建兼容DC
- m_dcCompatible.CreateCompatibleDC(&dc);
- m_dcCompatible.SelectObject(&m_bitmapSkin);
- if (control)
- {
- // BMP文件高度80出开始是查看按钮
- switch(state)
- {
- case 0:
- dc.TransparentBlt(m_nWndWidth-m_nMoreWidth-5, m_nWndHeight-m_nMoreHeight-5, m_nMoreWidth, m_nMoreHeight,
- &m_dcCompatible, 0, 80, m_nMoreWidth, m_nMoreHeight, 0xFF00FF);
- // 鼠标未点下不然在点这按钮移出松开
- // 此时再放上去程序以为按钮处于按下状态
- m_bLButtonDown = false;
- break;
- case 1:
- dc.TransparentBlt(m_nWndWidth-m_nMoreWidth-5, m_nWndHeight-m_nMoreHeight-5, m_nMoreWidth, m_nMoreHeight,
- &m_dcCompatible, m_nMoreWidth, 80, m_nMoreWidth, m_nMoreHeight, 0xFF00FF);
- // 鼠标未点下不然在点这按钮移出松开
- // 此时再放上去程序以为按钮处于按下状态
- m_bLButtonDown = false;
- break;
- case 2:
- dc.TransparentBlt(m_nWndWidth-m_nMoreWidth-5, m_nWndHeight-m_nMoreHeight-5, m_nMoreWidth, m_nMoreHeight,
- &m_dcCompatible, 2*m_nMoreWidth, 80, m_nMoreWidth, m_nMoreHeight, 0xFF00FF);
- break;
- }
- }
- else
- {
- // BMP文件高度60出开始是关闭按钮
- switch(state)
- {
- case 0:
- dc.TransparentBlt(m_nWndWidth-m_nCloseWidth, 1, m_nCloseWidth, m_nCloseHeight,
- &m_dcCompatible, 0, 60, m_nCloseWidth, m_nCloseHeight, 0xFF00FF);
- // 鼠标未点下不然在点这按钮移出松开
- // 此时再放上去程序以为按钮处于按下状态
- m_bLButtonDown = false;
- break;
- case 1:
- dc.TransparentBlt(m_nWndWidth-m_nCloseWidth, 1, m_nCloseWidth, m_nCloseHeight,
- &m_dcCompatible, m_nCloseWidth, 60, m_nCloseWidth, m_nCloseHeight, 0xFF00FF);
- // 鼠标未点下不然在点这按钮移出松开
- // 此时再放上去程序以为按钮处于按下状态
- m_bLButtonDown = false;
- break;
- case 2:
- dc.TransparentBlt(m_nWndWidth-m_nCloseWidth, 1, m_nCloseWidth, m_nCloseHeight,
- &m_dcCompatible, 2*m_nCloseWidth, 60, m_nCloseWidth, m_nCloseHeight, 0xFF00FF);
- break;
- }
- }
- // 这里最好删除一下
- m_dcCompatible.DeleteDC();
- return TRUE;
- }
这个有了,就可以当鼠标在按钮上的时候,和鼠标按下的时候进行不同的调用,来贴上不同的按钮图片,但是重点来了,在那里贴呢,脑子里首先想到的是 OnMouseMove 函数里,但是经过试验,问题各种有,感觉就想已经有一个 OnNcHitTest 函数来捕获鼠标的操作输入了,在用 OnMouseMove 就不灵的那种,各位朋友也可以做一下测试,也欢迎有发现的朋友和我讨论共同进步,话说回来 OnNcHitTest 本身可以实现的哦,我这样写的:
- LRESULT CDialogExDlg::OnNcHitTest(CPoint point)
- {
- // TODO: 在此添加消息处理程序代码和/或调用默认值
- if (m_rectClose.PtInRect(point))
- {
- if (m_bLButtonDown)
- {
- // 关闭按钮被按下
- OnChangeState(0, 2);
- }
- else
- {
- // 鼠标在关闭按钮上
- OnChangeState(0, 1);
- }
- }
- else if (m_rectMore.PtInRect(point))
- {
- if (m_bLButtonDown)
- {
- // 查看按钮被按下
- OnChangeState(1, 2);
- }
- else
- {
- // 鼠标在查看按钮上
- OnChangeState(1, 1);
- }
- }
- else
- {
- // 关闭按钮普通状态
- OnChangeState(0, 0);
- // 查看按钮普通状态
- OnChangeState(1, 0);
- // 移动对话框
- return HTCAPTION;
- }
- return CDialogEx::OnNcHitTest(point);
- }
现在程序已经更加显得有模有样,接下来要赋予点击按钮的操作,在OnLButtonDown()和OnLButtonUp()里面来实现
- void CDialogExDlg::OnLButtonDown(UINT nFlags, CPoint point)
- {
- // TODO: 在此添加消息处理程序代码和/或调用默认值
- m_bLButtonDown = true;
- // 坐标转换成屏幕坐标
- ClientToScreen(&point);
- if (m_rectClose.PtInRect(point))
- {
- // 关闭按钮被按下
- OnChangeState(0, 2);
- }
- if (m_rectMore.PtInRect(point))
- {
- // 查看按钮被按下
- OnChangeState(1, 2);
- }
- CDialogEx::OnLButtonDown(nFlags, point);
- }
- void CDialogExDlg::OnLButtonUp(UINT nFlags, CPoint point)
- {
- // TODO: 在此添加消息处理程序代码和/或调用默认值
- m_bLButtonDown = false;
- // 坐标转换成屏幕坐标
- ClientToScreen(&point);
- if (m_rectClose.PtInRect(point))
- {
- CDialogEx::OnOK();
- }
- if (m_rectMore.PtInRect(point))
- {
- ShellExecute(NULL, _T("open"), _T("http://www.baidu.com"), NULL, NULL, SW_SHOWNORMAL);
- CDialogEx::OnOK();
- }
- CDialogEx::OnLButtonUp(nFlags, point);
- }
看源码看到 m_bLButtonDown 这个成员变量,其实注释已经说的很清楚了,我说一个情况,大家不加这个变量控制看看是什么情况,对话框弹出,我点关闭按钮,突然发现内容我感兴趣,鼠标在关闭按钮中移动一下,关闭按钮的状态就变成未按下的状态了,如果仅在 Down Up 函数中赋值 m_bLButtonDown 变量也有一个情况,点关闭按钮,鼠标移出松开鼠标,程序没有关闭,鼠标再放上关闭按钮,关闭按钮直接显示的就是鼠标按下的状态。大家可以试试哦。
程序都写到这里啦,可千万不要出问题呀,可以问题还是出来了,我打开程序,移动了一下程序,去关闭程序,突然不能关闭,稍微一下就知道问题出到那里了,我们是通过判断鼠标点击是不是在关闭按钮的矩形区域内,在的话就退出程序,但是从程序启动,如果不是界面需要重绘,OnEraseBkgnd 是不会再调用的,移动程序不会触发界面重绘,强制界面重绘有函数的,但是我们不如重新计算关闭按钮的矩形区域。那样不是省事多了吗,这个时候我就开始百度“程序拖动响应什么函数”类似的关键字,没有找到,没有办法,但是我觉得应该有函数,我想就借此机会看看都有那些消息,点了CDialogEx类视图,点了消息,一个一个看了简单的介绍,发现一个消息可能就是我想要的 WM_EXITSIZEMOVE VS2010上面的简短介绍是:在窗口退出移动或大小调整模式循环后向窗口发送一次,添加一下,就是这个函数呵呵。
- void CDialogExDlg::OnExitSizeMove()
- {
- // TODO: 在此添加消息处理程序代码和/或调用默认值
- // (更新)获取窗口位置
- GetWindowRect(m_rectWnd);
- m_nWndWidth = m_rectWnd.Width();
- m_nWndHeight = m_rectWnd.Height();
- // 取关闭按钮的矩形范围(参照屏幕)
- m_rectClose.SetRect(m_nWndWidth-m_nCloseWidth, 1, m_nWndWidth, m_nCloseHeight+1);
- m_rectClose.OffsetRect(m_rectWnd.TopLeft().x, m_rectWnd.TopLeft().y); // 加上左上角坐标成为屏幕坐标
- // 取查看按钮的矩形范围(参照屏幕)
- m_rectMore.SetRect(m_nWndWidth-m_nMoreWidth-5, m_nWndHeight-m_nMoreHeight-5, m_nWndWidth-5, m_nWndHeight-5);
- m_rectMore.OffsetRect(m_rectWnd.TopLeft().x, m_rectWnd.TopLeft().y); // 加上左上角坐标成为屏幕坐标
- CDialogEx::OnExitSizeMove();
- }
我是追求完美的人,在测试的时候,发现关闭按钮在按下的时候,鼠标移出程序,只要鼠标不进入程序,关闭按钮一直是被按下的状态,这可如何是好,这个时候我看到了一篇文章:http://bbs.csdn.net/topics/120102520 虽然他是在论坛上提问他,但是他的问题对新人来说明显帮助是很大的!但是我只懂定时器,没有办法,硬着头皮看了一下他的第二中方法,结合着搜索了一下,又找到一篇文章:http://www.cnblogs.com/lzjsky/archive/2010/09/15/1826733.html 这下就可以下手了,其实我没有看懂开头他说的“在对话框类中定义一个变量来标识是否追踪当前鼠标状态,之所以要这样定义是要避免鼠标已经在窗体之上时,一移动鼠标就不断重复产生WM_MOUSEHOVER” 我还是按照我定义变量的风格(可能根本和这没有关系)
- void CDialogExDlg::OnMouseLeave()
- {
- // TODO: 在此添加消息处理程序代码和/或调用默认值
- // 再次允许追踪鼠标
- m_bMouseTrack = true;
- // 关闭按钮普通状态
- OnChangeState(0, 0);
- // 查看按钮普通状态
- OnChangeState(1, 0);
- CDialogEx::OnMouseLeave();
- }
- void CDialogExDlg::OnMouseMove(UINT nFlags, CPoint point)
- {
- // TODO: 在此添加消息处理程序代码和/或调用默认值
- if (m_bMouseTrack) // 若允许追踪则...
- {
- TRACKMOUSEEVENT csTME;
- csTME.cbSize = sizeof(csTME);
- csTME.dwFlags = TME_LEAVE|TME_HOVER;
- csTME.hwndTrack = m_hWnd; // 指定要追踪的窗口
- csTME.dwHoverTime = 10; // 鼠标在按钮上停留超过10ms,才认为状态为HOVER
- ::_TrackMouseEvent(&csTME); // 开启Windows的WM_MOUSELEAVE,WM_MOUSEHOVER事件支持
- m_bMouseTrack = false; //若已经追踪,则停止追踪
- }
- CDialogEx::OnMouseMove(nFlags, point);
- }
这样就搞定了,其实还是那句话,追求完美的我又发现了一个小问题,我点击关闭按钮,鼠标《猛》(一定要快)的移出程序窗口,停止操作,这是关闭按钮就一直是按下的状态了,直到鼠标有动作才会退出按下状态(这是的有动作就是在窗口外的动作也算,因为加了上面那两个函数吗呵呵)本来也想着看看能不能解决这个问题(因为发现腾讯的弹窗并没有这个问题,我会说我这几天每天都希望腾讯弹窗,弹出来都是不关的,好用来和我的程序比对)但是后来测试了邓学斌的程序,也是有这个问题,我想还是算了吧,我还有一大堆工作要做呢,先隔一隔。
程序写到这,终于算完了,拿给老板看了一下样式(他的电脑系统是XP,我的电脑系统是Win7)出现问题,问题还都是那些问题,Debug Assertion Failed 运行时出错,我呢,就在我的虚拟机中运行了一下程序(虚拟机win2003),打开没有问题,拖动出现问题,幸运的是我想到的和重新绘制有关,我菜鸟,排除类似这样的问题就是重现个别功能,看在重写的到那部分的时候会出问题,我这个程序,在刚一实现基本绘制的时候就出问题,我这个时候看到一个可以的对象。
- BOOL CDialogExDlg::OnEraseBkgnd(CDC* pDC)
- {
- // TODO: 在此添加消息处理程序代码和/或调用默认值
- // 创建兼容DC
- m_dcCompatible.CreateCompatibleDC(pDC);
- m_dcCompatible.SelectObject(&m_bitmapSkin);
我以前写这个的都好像要删除,关闭之类的,但是,孙鑫老师第10课最后确实没有提到,更重要的是 MSDN 中的例子都是这样的,叫我情何以堪!!!
- // This handler loads a bitmap from system resources,
- // centers it in the view, and uses BitBlt() to paint the bitmap
- // bits.
- void CDCView::DrawBitmap(CDC* pDC)
- {
- // load IDB_BITMAP1 from our resources
- CBitmap bmp;
- if (bmp.LoadBitmap(IDB_BITMAP1))
- {
- // Get the size of the bitmap
- BITMAP bmpInfo;
- bmp.GetBitmap(&bmpInfo);
- // Create an in-memory DC compatible with the
- // display DC we're using to paint
- CDC dcMemory;
- dcMemory.CreateCompatibleDC(pDC);
- // Select the bitmap into the in-memory DC
- CBitmap* pOldBitmap = dcMemory.SelectObject(&bmp);
- // Find a centerpoint for the bitmap in the client area
- CRect rect;
- GetClientRect(&rect);
- int nX = rect.left + (rect.Width() - bmpInfo.bmWidth) / 2;
- int nY = rect.top + (rect.Height() - bmpInfo.bmHeight) / 2;
- // Copy the bits from the in-memory DC into the on-
- // screen DC to actually do the painting. Use the centerpoint
- // we computed for the target offset.
- pDC->BitBlt(nX, nY, bmpInfo.bmWidth, bmpInfo.bmHeight, &dcMemory,
- 0, 0, SRCCOPY);
- dcMemory.SelectObject(pOldBitmap);
- }
- else
- {
- TRACE0("ERROR: Where's IDB_BITMAP1?\n");
- }
- }
当我差不多快排除他没有错的时候,我尝试性的加了一下 m_dcCompatible.DeleteDC(); 问题解决了,我去呀!!!
但是问题解决了,在我自定义的函数里有用到 m_dcCompatible 呀,这是只能在 OnChangeState() 里重新创建兼容DC啦,其实大家大可不必像我这样,直接定义成普通变量也行的,因为随用随创建已经失去了成员变量的方便性,就没有必要让它是成员变量了
写文章记录的时候想想,也是呀,我看的是VS2010的MSDN,XP时估计VC++6.0吧,那时的MSDN可能例子有提到删除吧
注:原文红色字体为有错误,加以修改。
原文:http://blog.csdn.net/panshiqu/article/details/9945027
【EasyUse】一键式检索框-界面美化参考。MFC自绘对话框加图和Button相关推荐
- Qt界面美化-飞扬青云自绘控件插件的使用-避免采坑
1.先上一个集成到QtCreater中的效果图: 2.飞扬青云自绘控件插件下载地址:https://gitcode.net/mirrors/feiyangqingyun/qucsdk?utm_sour ...
- qt 串口助手 界面美化
一.最终预览 二.添加资源文件 添加样式表css 三.初始化.引入样式表 ui->setupUi(this);//初始化样式表 this->initStyle();/*** @brief ...
- 一框式检索和高级检索
0. 学习内容 2022年12月8日15:38:07CNKI学习 ·学会多种检索方式检索基础文献· 1. 一框式检索 1.1 简单使用 左侧选择检索字段 根据需求选择 输入想要的检索词 输入想要的检索 ...
- PCA/PCC软件中一键式超高密度的无人机LiDAR点云滤波和精细地形提取
激光雷达是一种方兴未艾的测量技术.基于搭载平台类型,可以细分为星载.机载.地面.车载.背包.船载LiDAR等.其中,机载LiDAR测量技术较为常见,主要用于获取被测量区域的高精度.高分辨率的数字高程模 ...
- python复杂美观的图形界面_Python图形界面美化的方法论
很多人都吐槽,使用 Tkinter.PyQt5等工具制作出来的图形界面程序太丑了.既然觉得它丑,我们来想想,它为什么会那么丑. 文章目录 功能性是开发的第一要务 模块提供的都是原生组件 界面的美化的几 ...
- 会声会影2022正式版一键式视频剪辑软件
多场景适用,会声会影2022适用于个人.商店或是企业,可满足vlog视频.影视混剪.游戏解说.电子相册制作.淘宝主图视频.企业宣传片.线上网课制作等需求!下载末尾会声会影教程参考! 基础剪辑,一应俱全 ...
- 像素测量工具_一键式测量仪在手,磁性元件尺寸测量无忧
智能手机元年已经迈入了折叠屏时代,厂商们都在公布自己在相关领域的突破,无论是内折还是外折,每一种都让消费者欣喜若狂.其中有一个功能,各厂商都实现了意见统一,那就是闭合功能需要使用磁铁佢支持.当前所发布 ...
- [附下载]史上最简单的深度学习工具“一键式智能AI标注训练平台软件”终于免费公测了,没显卡也可以训练,会点鼠标就可以
你将收获 掌握如何一键标注缺陷或目标图片 掌握如何一键生成配置文件 掌握如何一键训练 适用人群 对人工智能机器视觉感兴趣的朋友们和从业者 软件环境: Windows10 x64; cuda 10.2( ...
- 台式计算机系统重新安装软件,一键式安装系统步骤,用于重新安装台式计算机系统磁盘...
现在计算机已经进入了成千上万户家庭,每个人都无法没有计算机,那么如何安装台式计算机来重新安装系统?以Cloud Knight的win10系统安装为例,一键式分享如何在台式计算机上重新安装win10系统 ...
- 《introduction to information retrieval》信息检索学习笔记3 词典和容错式检索
第3章 词典和容错式检索 3.1 用于词典的搜索结构 给定一个反向索引和一个查询,我们的第一个任务是确定每个查询词是否存在于词汇表中,如果是,则返回指向相应倒排记录表的指针.涉及在数据结构中定位词项. ...
最新文章
- 高并发场景下创建多少线程才合适?一条公式帮你搞定!!
- bottleneck resnet网络_关于ResNet及其变体的总结(上)
- 皮一皮:这解释...没毛病!
- 美国25大最具价值博客网站出炉
- CSS基础(part2)--CSS选择器
- 黑马h5学习代码_如何零基础制作酷炫实用的H5页面
- 手把手带你写Node.JS版本小游戏
- AWS ec2 安装手记
- 何为领导力 —— 《Working Backwards》书评
- 原型工具axure7.0下载及汉化
- IDEA鼠标光标变黑块问题解决
- JS-WebAPI练习
- truncate table很慢之enq: RO - fast object reuse和local write wait等待分析
- 用python整个活(6)——完全数
- 如何以正确地姿势AK SQL查询50题(精华篇)
- 目标拦截问题—微分对策
- 批量修改Excel单元格内某些文字的颜色
- Jquery-canvas动态粒子背景动画-适用于登陆注册页面背景
- visual studio code教程
- 如何还原MySQL备份文件.xb