【转载】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自绘---钩子---去除边框,码迷,mamicode.com

时间: 2024-08-04 09:47:37

【转载】CMenu自绘---钩子---去除边框的相关文章

input 去除边框

<input type="text" style="border: #ffffff; border-style: solid; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; font-family: 宋体; font-size: 9pt;" > <html> <head> input

QT自绘标题和边框

在QT中如果想要自绘标题和边框,一般步骤是: 1) 在创建窗口前设置Qt::FramelessWindowHint标志,设置该标志后会创建一个无标题.无边框的窗口. 2)在客户区域的顶部创建一个自绘标题栏. 3)给窗口绘制一个背景作为边框. 4)如果想要鼠标拖动效果,可以在WM_NCHITTEST消息中返回HTCAPTION,具体方法百度这里不再详述. 但是这样做会导致一个问题: 在win7系统上,将窗口移动到屏幕边缘会自动排列(在屏幕顶部,左边,右边都会自动排列)的功能失效. 如果你的窗口没有

golang-imagick图片去除边框(黑边,白边)

图片去除边框(黑边,白边) package main import ( "fmt" "github.com/gographics/imagick/imagick" "io/ioutil" "os" "strconv" ) func ReadFile(path string) (string, error) { fi, err := os.Open(path) if err == nil { defer fi

转载:poi设置excel表格边框,字体等

转载自:http://z3sm2012.iteye.com/blog/1446669 POI中可能会用到一些需要设置EXCEL单元格格式的操作小结: 先获取工作薄对象: HSSFWorkbook wb = new HSSFWorkbook(); HSSFSheet sheet = wb.createSheet(); HSSFCellStyle setBorder = wb.createCellStyle(); 一.设置背景色: setBorder.setFillForegroundColor((

Android开发之使用VideoView实现视频的横屏播放、去除边框

做项目需要播放一个引导视频,本以为很简单,结果动手时发现总有瑕疵,幸好有度娘,现把收获总结如下: 一.实现视频播放: 注明我这里要播放的是Android项目中的资源文件,而不是访问SD卡播放视频. 1.先把要播放的视频放到res/raw目录下 2.视频格式必须是Android支持的格式(3gp,mp4,wmv),据说swf不支持,暂未试过.并且视频文件命名不能有大写字母,必须是小写字母.数字或下划线. 3.布局文件中添加VideoView组件 4.创建个String类型对象保存uri 5.调用V

[css小技巧]input去除边框问题

border:none;是不够的 (1)在谷歌浏览器添加 outline: none;去除点击后产生的边框; (2)IE7下border: none;还会有边框存在,改用border: 0;即可,同时兼容其他版本浏览器. 综合,写法如下: border: 0; outline: none;

微信小程序按钮去除边框线,分享页面

有一个需求是分享当前页面,使用美工的分享按钮图片来分享,而小程序分享功能只有button有 open-type="share"这个属性,使用image标签肯定不行.我是这样做的: <button open-type="share" style="height:85rpx;width:215rpx;padding:0;background-color:#fff;border-color:#fff;margin-right:10rpx" >

去除input边框 input去除边框 去除input获取焦点时的蓝色外边框

1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="UTF-8"> 5 <title>去除input的边框</title> 6 <style> 7 input{text-indent: 1em;} 8 #search1{ } 9 #search2{ border-width: 0; } 10 #search3{ border:1px solid re

QTabWiget Remove Line Border 去除边框

Qt中的QTabWiget 类提供了一个标签控件,但是这个控件默认是有边框的,如果我们不想要边框,也可以去掉这个边框,我们可以在cpp文件中添加一行代码: tabwidget.setStyleSheet("QTabWidget::pane { border: 0; }"); 也可以在Qt Designer中在控件属性中找到styleSheet项,在打开的面板中之间加入下面一行代码: QTabWidget::pane { border: 0; } 如果想改变控件的背景颜色,可以参见我之前