【转载】CMenu自绘---钩子---去除边框
使用默认的CMenu菜单类或者继承CMenu实现的菜单扩展类,在显示的时候最外层都会有边框出现,或者说是具有3D外观(菜单阴影不算),当改变菜单背景色或者需要加个边框线时就会看上去很不美观。看过很多菜单的自定义实现类,一般可以有两种方式来实现外框的移除。
第一种方法就是:自定义窗口,完全模拟菜单的实现,自给自足,倒是能够完全满足开发需要,不过实现的复杂让人头痛,此处略过不提。
下面介绍第二种比较简单直接的方法:安装钩子,在菜单创建时就改变其窗口属性。其实菜单应该也算是一个窗口类,不过实在是无从得知到底在哪创建的窗口,所以下下钩子,过程倒是明了许多。
实现如下:
先在cpp前面申明一下:
static HHOOK g_hook=NULL; // 全局钩子
static LRESULT WINAPI CallWndProc(int, WPARAM, LPARAM); // 安装的钩子的窗口过程
static LRESULT WINAPI MenuWndProc(HWND, UINT, WPARAM, LPARAM); // 用来处理菜单的窗口过程
然后是钩子的实现:
/////////////////////////////////////////////////////////////////////////////
// 如果需要去除菜单的外部边框,需要通过安装钩子,设置外框属性并改变菜单大小
WNDPROC oldWndProc = NULL; // 用来保存被替换的窗口过程
LRESULT WINAPI CallWndProc(int code, WPARAM wParam, LPARAM lParam)
{
CWPSTRUCT* pStruct = (CWPSTRUCT*)lParam;
while (code == HC_ACTION)
{
HWND hWnd = pStruct->hwnd;
// 捕捉创建消息WM_CREATE,后面筛选为是否是菜单的创建
if ( pStruct->message != WM_CREATE)
break;
TCHAR sClassName[10];
int Count = ::GetClassName(hWnd, sClassName, sizeof(sClassName)/sizeof(sClassName[0]));
// 检查是否菜单窗口,#32768为菜单类名
if ( Count != 6 || _tcscmp(sClassName, _T("#32768")) != 0 )
break;
WNDPROC lastWndProc = (WNDPROC)GetWindowLong(hWnd, GWL_WNDPROC);
if (lastWndProc != MenuWndProc)
{
// 替换菜单窗口过程
SetWindowLong(hWnd, GWL_WNDPROC, (long)MenuWndProc);
// 保留原有的窗口过程
oldWndProc = lastWndProc;
}
break;
}
return CallNextHookEx((HHOOK)WH_CALLWNDPROC, code, wParam, lParam);
}
// 处理菜单的窗口过程
LRESULT WINAPI MenuWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
LRESULT lResult;
switch (message)
{
case WM_CREATE:
{
// 首先要去掉菜单窗口的一些扩展风格
// 包括:WS_BORDER、WS_EX_DLGMODALFRAME、WS_EX_WINDOWEDGE
lResult = CallWindowProc(oldWndProc, hWnd, message, wParam, lParam);
DWORD dwStyle = ::GetWindowLong(hWnd, GWL_STYLE);
DWORD dwNewStyle = (dwStyle & ~WS_BORDER);
::SetWindowLong(hWnd, GWL_STYLE, dwNewStyle);
DWORD dwExStyle = ::GetWindowLong(hWnd, GWL_EXSTYLE);
DWORD dwNewExStyle = (dwExStyle & ~(WS_EX_DLGMODALFRAME | WS_EX_WINDOWEDGE));
::SetWindowLong(hWnd, GWL_EXSTYLE, dwNewExStyle);
return lResult;
}
case WM_PRINT: // 此处阻止非客户区地绘制
return CallWindowProc( oldWndProc, hWnd, WM_PRINTCLIENT, wParam, lParam);
case WM_WINDOWPOSCHANGING:
{
// 最后,由于我们在MeasureItem里指定了菜单大小,而系统会自动替菜单加边框,
// 因此必须去掉此部分额外地尺寸,将菜单大小改小
LPWINDOWPOS lpPos = (LPWINDOWPOS)lParam;
lpPos->cx -= 2*GetSystemMetrics(SM_CXBORDER)+4;
lpPos->cy -= 2*GetSystemMetrics(SM_CYBORDER)+4;
lResult = CallWindowProc(oldWndProc, hWnd, message, wParam, lParam);
return 0;
}
case WM_GETICON:
return 0;
default:
return CallWindowProc( oldWndProc, hWnd, message, wParam, lParam);
}
}
/////////////////////////////////////////////////////////////
最后是调用:
下钩子需要调用SetWindowsHookEx,参数包括主窗口的实例句柄theApp.m_hInstance,可以在调用时作为参数传入,同时也设一个参数作为是否安装钩子的标识,以便在退出时判断是否需要卸载钩子(UnhookWindowsHookEx(g_hook))。示例如下:
void CSkinMenu::RemoveMenuBorder(HINSTANCE hInst, BOOL bRemove /* = TRUE */)
{
m_bRemoveBorder = bRemove; // 标识
// 需要移除边框时,要安装钩子
if (m_bRemoveBorder)
{
DWORD id = ::GetCurrentThreadId(); // 获取当前线程的ID
g_hook = SetWindowsHookEx(WH_CALLWNDPROC,CallWndProc,hInst,id);
}
}
这样子,就搞定菜单的边框了,最后要记得,如果安装了钩子,需要卸载掉。
【转载】CMenu自绘---钩子---去除边框的更多相关文章
- 【Android】Android EditText 去除边框
[Android]Android EditText 去除边框 将EditText属性设置修改 android:background="@null" //////////////// ...
- Android Listview 去除边框
最近在做一个时间轴的功能,因为原生效果的Listview有item分隔边框,所以就需要去除边框,调用listview的setDivider方法就可以了: listView.setDivider(nul ...
- WPF去除边框的方法
原文:WPF去除边框的方法 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/yangsen600/article/details/81978125 W ...
- QT自绘标题和边框
在QT中如果想要自绘标题和边框,一般步骤是: 1) 在创建窗口前设置Qt::FramelessWindowHint标志,设置该标志后会创建一个无标题.无边框的窗口. 2)在客户区域的顶部创建一个自绘标 ...
- golang-imagick图片去除边框(黑边,白边,),添加中文字
图片去除边框(黑边,白边) package main import ( "fmt" "github.com/gographics/imagick/imagick" ...
- (webapp)微信和safri 对于html5 部分功能不兼容,多选或单选下拉框去除边框无效果。
1 appearance:none; 2 -moz-appearance:none; /* Firefox */ 3 -webkit-appearance:none; /* Safari 和 Chro ...
- [css小技巧]input去除边框问题
border:none;是不够的 (1)在谷歌浏览器添加 outline: none;去除点击后产生的边框; (2)IE7下border: none;还会有边框存在,改用border: 0;即可,同时 ...
- winform重绘控件边框
首先添加一个用户控件 对于重绘边框有三个需要考虑的东西 1:是否显示边框 2:边框颜色 3:边框宽度 所以定义三个私有变量 /// <summary>/// 是否显示边框/// </ ...
- 去除input边框 input去除边框 去除input获取焦点时的蓝色外边框
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
随机推荐
- Solr记录-solr文档xml
Solr添加文档(XML) 在上一章中,我们学习解释了如何向Solr中添加JSON和.CSV文件格式的数据.在本章中,将演示如何使用XML文档格式在Apache Solr索引中添加数据. 示例数据 假 ...
- Java与groovy混编 —— 一种兼顾接口清晰和实现敏捷的开发方式
有大量平均水平左右的"工人"可被选择.参与进来 -- 这意味着好招人 有成熟的.大量的程序库可供选择 -- 这意味着大多数项目都是既有程序库的拼装,标准化程度高而定制化场景少 开发 ...
- 兼容 IE6+ 获取图片大小
昨天说了 HTML5 的file对象可以获取到文件的 文件名,文件大小,文件类型,最后一次修改日期.其实 IE6-9 也可以变向的获取到,虽然没那么方便,但至少可以取到.来看例子吧: <!doc ...
- 作业:JavaScript(数组篇-poker)给我的徒弟出个题。。。记得早点写完,然后大家3人可以早点打牌了
吐槽一下:“今天实际上我左思右想,写个什么东西好呢!手上的笔转了半天....最后还是给自己留点余地!看着他们什么酒店管理系统,呼叫中心系统之类的....简直是把自己固定死了!感觉一撸到底的感觉!!!我 ...
- 那些年实用但被我忘掉javascript属性.onresize
//获取屏幕宽度并动态赋值 var winWidth = 0; var winHeight = 0; function findDimensions() //函数:获取尺寸 { //获取窗口宽度 if ...
- [转载]AngularJS视图
http://www.yiibai.com/angularjs/angularjs_views.html <html> <head> <title>Angular ...
- ASP.NET自定义服务器控件
本文通过创建一个最简单的服务器控件,演示开发服务器端控件的流程. 文章内容整理自MSDN的编程指南,原文地址在文章末尾的资源中. 本文创建一个简单的服务器控件,名为 RedLabel. 它的使用方式为 ...
- NIO学习(1)-入门学习
一.NIO概念 IO:标准IO,也既阻塞式IO NIO:非阻塞式IO 二.NIO与标准IO的IO工作方式 标准IO基于字节流和字符流进行操作 NIO是基于通道(Channel)和缓冲区(Buffer) ...
- linux网桥浅析
linux网桥浅析 原文链接:http://hi.baidu.com/_kouu/item/25787d38efec56637c034bd0 什么是桥接?简单来说,桥接就是把一台机器上的若干个网络接口 ...
- redis,nodejs,php,pub/sub 实战: 微信语音识别
2015年5月22日 20:20:20 星期五 效果: 这边对微信说话, 浏览器端及时显示语音识别的文字 注意: 在连接socket.io时, 按下浏览器f12, 如果一直有请求不断的刷, 说明so ...