VC 菜单栏的自绘(二)

没人看我代码一贴完事


//cpp文件

#include "StdAfx.h"
#include "MenuBar.h"
#include "resource.h"

HHOOK gMsgFilterHook=NULL;
CMenuBar* g_MenuBar;
CMenuItem* gOldMenuItem = NULL;
CMenuItem* gNewMenuItem = NULL;
BOOL g_bPressed = FALSE;

LRESULT CALLBACK MessageProc( int code, WPARAM wParam, LPARAM lParam)
{
if ( code == MSGF_MENU )
{
MSG *pMsg = (MSG *)lParam;
switch ( pMsg->message )
{
case WM_MOUSEMOVE:
{
CPoint pt;
pt.x = LOWORD(pMsg->lParam);
pt.y = HIWORD(pMsg->lParam);

if ( NULL == g_MenuBar ) break;
g_MenuBar->ScreenToClient(&pt);

int nItem = g_MenuBar->HitTest(pt);
if ( nItem >= 0 )
{
CMenuItem *pMenuItem = g_MenuBar->m_vecMenuItem.at(nItem);
if ( pMenuItem == gOldMenuItem ) break;

::SendMessage(g_MenuBar->m_hWnd, WM_CANCELMODE, 0, 0);

gNewMenuItem = pMenuItem;
g_MenuBar->OnMouseMove(0, pt);
}
}
break;

default:
break;
}
}
return ::CallNextHookEx(gMsgFilterHook, code, wParam, lParam);
}

CMenuItem::CMenuItem()
{

}

CMenuItem::~CMenuItem()
{

}

void CMenuItem::DrawMenu(CDC* pDC)
{
int OldbkMode = pDC->SetBkMode(TRANSPARENT);
switch(m_state)
{
case Normal:
{

}
break;

case Pressed:
{
CPen pen(PS_SOLID,1,0x123456);
CPen*pOldPen = pDC->SelectObject(&pen);
pDC->Rectangle(m_rcMenu);
pDC->SelectObject(pOldPen);
}
break;

case Hover:
{
CPen pen(PS_SOLID,1,0x888888);
CPen*pOldPen = pDC->SelectObject(&pen);
pDC->Rectangle(m_rcMenu);
pDC->SelectObject(pOldPen);
}
break;
default:
ASSERT(FALSE);
break;
}
pDC->DrawTextEx(m_strText,m_rcMenu,DT_SINGLELINE|DT_CENTER|DT_VCENTER,NULL);
pDC->SetBkMode(OldbkMode);
}

void CMenuItem::ShowPopUpMenu(CWnd* pWnd)
{
CMenuBar* pMenuBar = (CMenuBar*)pWnd;
CPoint pt;
pt.x = m_rcMenu.left;
pt.y = m_rcMenu.bottom;
pMenuBar->ClientToScreen(&pt);

if (m_hPopUpMenu)
{
DWORD dwThreadId = GetCurrentThreadId();

if (gMsgFilterHook == NULL )
{
gMsgFilterHook = SetWindowsHookEx(WH_MSGFILTER,MessageProc,NULL, dwThreadId);
}
BOOL bRet = ::TrackPopupMenuEx(m_hPopUpMenu,TPM_VERTICAL|TPM_LEFTBUTTON|TPM_RIGHTBUTTON|TPM_LEFTALIGN,pt.x,pt.y,pMenuBar->m_hWnd,NULL);
if (gMsgFilterHook)
{
UnhookWindowsHookEx(gMsgFilterHook);
gMsgFilterHook = NULL;
}
}
}

CMenuBar::CMenuBar(void)
{
g_MenuBar = this;
}

CMenuBar::~CMenuBar(void)
{
int nCount = GetMenuItemCount();
if (nCount==0) return;
for (int i = 0;i<nCount;i++)
{
CMenuItem* pMenuItem = m_vecMenuItem.at(i);
delete pMenuItem ;
}
}
BEGIN_MESSAGE_MAP(CMenuBar, CPanel)
ON_WM_PAINT()
ON_WM_CREATE()
ON_WM_MOUSEMOVE()
ON_MESSAGE(WM_MOUSELEAVE,OnMouseLeave)
ON_WM_LBUTTONDOWN()
END_MESSAGE_MAP()

void CMenuBar::OnPaint()
{
CPaintDC dc(this); // device context for painting

int nCount = GetMenuItemCount();//子项个数
CRect rcClient;
GetClientRect(rcClient);
//m_imgBk.Draw(dc.m_hDC,rcClient);
CFont font;
font.CreateFont(14,0,0,0,FW_MEDIUM,FALSE,FALSE,0,ANSI_CHARSET,OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,DEFAULT_PITCH | FF_SWISS,_T("Arial"));
dc.SelectObject(&font);
for (int i = 0; i<nCount;i++)
{
CMenuItem * pMenuItem = m_vecMenuItem.at(i);
pMenuItem->DrawMenu((CDC*)&dc);
}
}

int CMenuBar::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CPanel::OnCreate(lpCreateStruct) == -1)
return -1;

return 0;
}

void CMenuBar::LoadMenuFromResource(UINT nIDResource)
{
m_Menu.LoadMenu(nIDResource);
int nCount = m_Menu.GetMenuItemCount();
for (int i = 0;i<nCount;i++)
{
CString strText;
m_Menu.GetMenuString(i,strText,MF_BYPOSITION);
CMenuItem* pMenuItem = new CMenuItem;
pMenuItem->m_strText = strText;
pMenuItem->m_hPopUpMenu = m_Menu.GetSubMenu(i)->m_hMenu;
pMenuItem->m_rcMenu = CRect(i*50,0,i*50+50,22);
pMenuItem->m_state = CMenuItem::Normal;
m_vecMenuItem.push_back(pMenuItem);
}
Invalidate();
}

int CMenuBar::GetMenuItemCount()
{
return (int)m_vecMenuItem.size();
}

int CMenuBar::HitTest(CPoint pt)
{
int nItem = HTERROR;
int nCount = GetMenuItemCount();
for (int i = 0;i<nCount;i++)
{
CMenuItem* pMenuItem = m_vecMenuItem.at(i);
if (pMenuItem)
{
BOOL bInRect = pMenuItem->m_rcMenu.PtInRect(pt);
if (bInRect)
{
if (pMenuItem->m_state != CMenuItem::Hover)
{
pMenuItem->m_state = CMenuItem::Hover;
InvalidateRect(pMenuItem->m_rcMenu);
}
nItem = i;
}
else
{
if (pMenuItem->m_state != CMenuItem::Normal)
{
pMenuItem->m_state = CMenuItem::Normal;
InvalidateRect(pMenuItem->m_rcMenu);
}
}
}
}
if (nItem == HTERROR)
{
if (gMsgFilterHook)
{
UnhookWindowsHookEx(gMsgFilterHook);
gMsgFilterHook = NULL;
g_bPressed = FALSE;
}
else
{
g_bPressed = TRUE;
}
gOldMenuItem = NULL;
}

return nItem;
}
void CMenuBar::OnMouseMove(UINT nFlags, CPoint point)
{
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof(TRACKMOUSEEVENT);
tme.dwFlags = TME_LEAVE;
tme.dwHoverTime = 1;
tme.hwndTrack= this->m_hWnd;
TrackMouseEvent(&tme);

int nItem = HitTest(point);
if (nItem>=0)
{
if (gOldMenuItem!=NULL)
{
if (gNewMenuItem !=NULL && g_bPressed == TRUE)
{
gNewMenuItem->ShowPopUpMenu(this);
gOldMenuItem = gNewMenuItem;
}
}
}
CPanel::OnMouseMove(nFlags, point);
}

LRESULT CMenuBar::OnMouseLeave(WPARAM,LPARAM)
{
int nCount = GetMenuItemCount();
for (int i = 0;i<nCount;i++)
{
CMenuItem* pMenuItem = m_vecMenuItem.at(i);
if (pMenuItem)
{
if (pMenuItem->m_state != CMenuItem::Normal)
{
pMenuItem->m_state = CMenuItem::Normal;
InvalidateRect(pMenuItem->m_rcMenu);
}
}
}
return 0;
}

void CMenuBar::OnLButtonDown(UINT nFlags, CPoint point)
{
g_bPressed = TRUE;
int nItem = HitTest(point);
if (nItem>=0)
{
gOldMenuItem = m_vecMenuItem.at(nItem);
gOldMenuItem->m_state = CMenuItem::Pressed;
InvalidateRect(gOldMenuItem->m_rcMenu);

if (gOldMenuItem)
{
BOOL bInRect = gOldMenuItem->m_rcMenu.PtInRect(point);
if (bInRect)
{
gOldMenuItem->ShowPopUpMenu(this);
}
}

}
CPanel::OnLButtonDown(nFlags, point);
}

头文件


#pragma once
#include "panel.h"
#include <vector>
using namespace std;

class CMenuItem
{
public:
CMenuItem();
~CMenuItem();
public:
void DrawMenu(CDC* pDC);
public:
enum STATE{Normal=1,Hover,Pressed};
public:
CRect m_rcMenu;
STATE m_state;
CString m_strText;
HMENU m_hPopUpMenu;
public:
void Draw(CDC* pDc);
void ShowPopUpMenu(CWnd* pWnd);
};

class CMenuBar :
public CPanel
{
public:
CMenuBar(void);
~CMenuBar(void);
public:
void LoadMenuFromResource(UINT nIDResource);
int GetMenuItemCount();
int HitTest(CPoint pt);
public:
CMenu m_Menu;
vector<CMenuItem*> m_vecMenuItem;
public:
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnPaint();
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
public:
afx_msg void OnMouseMove(UINT nFlags, CPoint point);
afx_msg LRESULT OnMouseLeave(WPARAM,LPARAM);
public:
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
};

VC 菜单栏的自绘(二)

时间: 2024-10-23 13:00:17

VC 菜单栏的自绘(二)的相关文章

你也可以手绘二维码(二)纠错码字算法:数论基础及伽罗瓦域GF(2^8)

摘要:本文讲解二维码纠错码字生成使用到的数学数论基础知识,伽罗瓦域(Galois Field)GF(2^8),这是手绘二维码填格子理论基础,不想深究可以直接跳过.同时数论基础也是Hash算法,RSA算法等密码学的入门基础. 二维码生成算法最为核心的就是编码规则和纠错码字的生成.本篇专门讲解纠错涉及到的伽罗瓦域(Galois Field).本文内容大部分是阅读<密码编码学与网络安全>后参考相关PPT编写,如有遗漏或不严谨地方请参考专业书籍. 数论基础 整除,因数,素数 设 a , b(b≠0)

VC++杂七杂八的笔记(二)

在Windows中,不仅用户程序可以调用系统的API函数,系统也会调用用户程序,这个调用是通过消息来进行的.wParam和lParam表示的信息随消息的不同而不同. 每一个Windows应用程序开始执行后,系统都会为该程序创建一个消息队列,这个消息队列用来存放该程序创建的窗口消息. Windows程序中的消息分为进队消息和不进队消息.进队消息将由系统放入到应用程序的消息队列中,然后由应用程序取出并发送.不进队消息在系统调用窗口过程时直接发送给窗口.不管进队消息还是不进队消息,最终都由系统调用窗口

VC++ 之 输入/输出类库(二)

本节对cin,cout,cerr,clog,>>和<<(提取和插入运算符)的使用细节作进一步讨论. 提高标准输入/输出的健壮性 ◆ 1.标准设备输入使用要点: cin为缓冲流.键盘输入的数据保存在缓冲区中,当要提取时,是从缓冲区中拿.如果一次输入过多,会留在那儿慢慢用,如果输入错了,必须在回车之前修改,如果回车键按下就无法挽回了.只有把输入缓冲区中的数据取完后,才要求输入新的数据.不可能用刷新来清除缓冲区,所以不能输错,也不能多输! 输入的数据类型必须与要提取的数据类型一致,否则出

菜单栏

1.菜单相关问题 Win32--HMENU MFC--CMenu类对象 2.相关类 CMenu - 封装了关于菜单的各种操作,还封装了一个非常重要的成员 m_hMenu(菜单句柄) 3.菜单项被点击的处理 WM_COMMAND 消息 ON_COMMAND 4.程序的类对菜单命令的响应顺序 顺序依次是:视图类->文档类->框架类->应用程序类 菜单命令消息路由的过程:点击某个菜单项,框架类最先接收到这个命令消息,并交给视图类,视图类查找自身是否对此消息进行了响应,如果响应了,就用相应的响应

Computer Science Theory for the Information Age-5: 学习理论——VC维的定义以及一些例子

学习理论--VC维的定义以及一些例子 本文主要介绍一些学习理论上的东西.首先,我们得明确,从训练集上学习出来的分类器的最终目标是用于预测未知的样本,那么我们在训练的时候该用多少的样本才能使产生的分类器的效果尽可能的好呢?这些就是VC-理论要解决的问题.在介绍这个理论之前,我们得先介绍一个比较抽象的概念--VC维.这个指标是用与衡量假设空间的复杂程度.为了能更好的理解VC维,本文还会举一些例子来加深理解. (一)由一个例子引出的动机 为了更好的说明为什么我们要定义这个VC维,我们先来看一个例子.假

统计机器学习理论:随机熵、vc熵、退火VC熵、生长函数、VC维定义理解

一.定义: 有n个训练样本Zn={zi(xi,yi), i=1,2,...,n},定义N(Zn)为函数集中的函数能对样本分类的数目.        解释:xi 代表特征向量如d维特征向量,yi代表一个标记如0或1, 因此zi就是对一个特征的标记,Zn中有n个样本,可能的标记方式2n种,一种标记方式就生成一种样本集: N(Zn)为Zn的标记空间中能被正确分类的标记数量. 举例:在二维特征空间中,不共线的3个二维特征向量,其标记方式有23=8种,每一种标记方式都能被指示函数集二维线性分类器正确分类,

让你提前认识软件开发(51):VC++集成开发环境中Linux下Pclint工程的配置方法及常见错误修改

第3部分 软件研发工作总结 VC++集成开发环境中Linux下Pclint工程的配置方法及常见错误修改 [文章摘要] Pclint是一种C/C++软件代码静态分析工具.它是一种更加严格的编译器,能够发现普通编译器所不能发现的代码中的很多问题,因此被广泛应用于软件开发项目中. 本文介绍了如何在VC++集成开发环境中配置Linux下的Pclint工程,给出了C语言中pclint规则A检查的常见错误,并描述了对应的修改办法. [关键词] VC++  Pclint  配置  操作  修改 1. 前言 P

VC++中使用智能指针,visual assist 不能智能提示其内部方法,字段等的解决方法

最近在VS2008中使用VC++对Arcgis Engine进行二次开发,使用一段时间后会发现对于部分智能指针,不能智能的提示其中包含的属性.方法等,最明显的一点就是声明的智能指针变量没有被按照变量的颜色显示(默认应该是蓝色,现在只是黑色显示),究其原因是visual assist解析当前工程产生的缓存越来越大(我个人认为其内部使用了增量式解析,其中存在以前的解析记录,导致后续不在解析此接口,最终不能在代码编辑页面正常),解决办法 在visual assist 的工具栏中,单击第一个按钮(vis

VC++6.0打开文件出错的解决办法

1.下载http://support.microsoft.com/kb/241396里面的一个叫FileTool.exe的文件并解压,解压后是一个vc工程,用vc6.0打开工程,编译,得到FileTool.dll,把它拷到vc6.0安装目录下. 2.点vc菜单栏里面的Tools(工具)->Customizes(定制)->Add-ins and Macro Files(附加项和宏文件) 点 Browse(浏览),选择类型为*.dll, 找到刚刚那个FileTool.dll文件,点确定,vc界面上