C++ MFC 界面美化------自绘菜单栏

article/2025/9/5 9:45:45

最终效果

 

一: 点击菜单栏标题后弹出菜单,在OnNcHitTest中增加代码 ,使得当鼠标在 菜单标题的区域点击后,触发对应的函数

LRESULT CMFCDrawnTitleDlg::OnNcHitTest(CPoint point)
{// TODO: 在此添加消息处理程序代码和/或调用默认值UINT nHitTest = CDialogEx::OnNcHitTest(point);CRect rect;GetClientRect(&rect);rect.bottom = 70;//函数参数point是相对于屏幕坐标的,需要将其转换为//客户区坐标才能使用PtInRect(),否则会因为坐标的不同使判断失误//rect.left = rect.left + 200;ScreenToClient(&point);if (rect.PtInRect(point)){if (HTCLIENT == nHitTest)nHitTest = HTCAPTION;//如果鼠标点中的是关闭按钮的位置,需要将上一步的设置还原,if (m_rtBtnfile.PtInRect(point) || m_rtBtnSelect.PtInRect(point) || m_rtBtnHelp.PtInRect(point)){nHitTest = HTCLIENT;}}return nHitTest;
}

二:添加消息afx_msg void OnLButtonDown(UINT nFlags, CPoint point);增加代码

void CMFCDrawnTitleDlg::OnLButtonDown(UINT nFlags, CPoint point)
{// TODO: Add your message handler code here and/or call defaultif (m_rtBtnfile.PtInRect(point)){CMenuEx m_MenuEx;m_MenuEx.CreatePopupMenu();m_MenuEx.SetItemHeight(30);m_MenuEx.SetFontInfo(14);m_MenuEx.SetBorderColor(RGB(45, 51, 60));m_MenuEx.SetMenuWidth(60);m_MenuEx.InstallHook(theApp.m_hInstance);m_MenuEx.AppendItem(MF_STRING, MSG_MENU_START,_T("开始"), _T(""), 0);m_MenuEx.AppendItem(MF_STRING, MSG_MENU_STOP, _T("停止"), _T(""), 0);CRect rectDlg;GetWindowRect(rectDlg);//获得窗体的大小m_MenuEx.TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, rectDlg.left + 10, rectDlg.top + static_cast<int>((rectDlg.bottom - rectDlg.top) * 0.104), this);m_MenuEx.DestroyMenu();m_MenuEx.UnInstallHook();}if (m_rtBtnSelect.PtInRect(point)){CRect rectDlg;GetWindowRect(rectDlg);//获得窗体的大小CMenuEx m_MenuEx;m_MenuEx.CreatePopupMenu();m_MenuEx.SetItemHeight(30);m_MenuEx.SetFontInfo(14);m_MenuEx.SetBorderColor(RGB(45, 51, 60));m_MenuEx.SetMenuWidth(130);m_MenuEx.InstallHook(theApp.m_hInstance);m_MenuEx.AppendItem(MF_STRING, MSG_MENU_BEGIN, _T("开始"), _T(""), 0);m_MenuEx.AppendItem(MF_STRING, MSG_MENU_END, _T("停止"), _T(""), 0);m_MenuEx.AppendItem(MF_STRING, MSG_MENU_STOP, _T("重启"), _T(""), 0);m_MenuEx.AppendItem(MF_STRING, MSG_MENU_RELOAD, _T("打开"), _T(""), 0);m_MenuEx.TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, rectDlg.left + 70, rectDlg.top + static_cast<int>((rectDlg.bottom - rectDlg.top) * 0.104), this);m_MenuEx.DestroyMenu();m_MenuEx.UnInstallHook();}if (m_rtBtnHelp.PtInRect(point)){CRect rectDlg;GetWindowRect(rectDlg);//获得窗体的大小CMenuEx m_MenuEx;m_MenuEx.CreatePopupMenu();m_MenuEx.SetItemHeight(30);m_MenuEx.SetFontInfo(14);m_MenuEx.SetBorderColor(RGB(45, 51, 60));m_MenuEx.SetMenuWidth(130);m_MenuEx.InstallHook(theApp.m_hInstance);m_MenuEx.AppendItem(MF_STRING, MSG_MENU_HELP, _T("关于 MFC"), _T(""), 0);m_MenuEx.TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, rectDlg.left + 130, rectDlg.top + static_cast<int>((rectDlg.bottom - rectDlg.top) * 0.104), this);m_MenuEx.DestroyMenu();m_MenuEx.UnInstallHook();}//CDialogEx::OnLButtonDown(nFlags, point);}

三:对菜单栏进行重绘

#pragma once#include <string>
#include <vector>using namespace std;// 项类型
typedef enum _EnumItemType
{ITEMTYPE_STRING,		// 字符串项ITEMTYPE_SEPARATOR,		// 分隔符项ITEMTYPE_SUBMENU,		// 子菜单项
}EnumItemType;// 顺序类型
typedef enum _EnumaOrderType
{ORDERTYPE_FIRST,		// 第一个ORDERTYPE_CENTER,		// 中间ORDERTYPE_LAST,			// 最后一个
}EnumaOrderType;// 项信息
typedef struct StruItemInfo  
{  int				nFlags;int				nID;  HICON			hIcon;CString			strText;		// 字符串CString			strShortcut;	// 快捷键说明EnumItemType	eItemType;		// 项类型EnumaOrderType	eOrderType;		// 顺序类型
}StruItemInfo;typedef vector<StruItemInfo*>	ItemInfoVec;
typedef ItemInfoVec::iterator	ItemInfoIter;// CMenuEx 对话框class CMenuEx : public CMenu
{public:CMenuEx();   // 标准构造函数virtual ~CMenuEx();private:virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);virtual void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct);// 获取系统默认字体大小int GetSysFontSize();// 获取系统默认字体风格//string GetSysFontFaceName();LPCTSTR	 GetSysFontFaceName();// 生成顺序类型EnumaOrderType GenerateOrderType();HHOOK		m_hook;					// 钩子句柄int			m_nFontSize;			// 字体大小int			m_nItemHeight;			// 项高度//string		m_strFontFaceName;		// 字体风格LPCTSTR		m_strFontFaceName;int			m_nLeftWidth;			// 图标区域宽度int			m_nIconWidth;			// 图标宽度int			m_nIconHeight;			// 图标高度int			m_nMenuWidth;			// 菜单宽度int			m_nSeparatorHeight;		// 分隔符高度bool		m_bHasIcon;				// 是否有图标COLORREF	m_clrBk;				// 背景色COLORREF	m_clrBkHover;			// 经过背景色COLORREF	m_clrText;				// 字体颜色COLORREF	m_clrTextDisable;		// 无效字体颜色COLORREF	m_clrSeparator;			// 分割线颜色COLORREF	m_clrBorder;			// 边框颜色ItemInfoVec m_ItemList;
public:// 钩子void InstallHook(HINSTANCE hInst);void UnInstallHook();// 添加一项void AppendItem(UINT nFlags, UINT nID, CString strText, CString strShortcut, UINT nIconID);// 添加一个子菜单void AppendSubMenu(UINT nFlags, UINT nID, CMenuEx* subMenu, CString strText, UINT nIconID);// 添加分隔符void AppendSeparator(UINT nFlags, UINT nID);void DestroyMenu();// 设置字体大小void SetFontInfo(int nSize, const char* szFontFaceName=NULL);// 设置项高度void SetItemHeight(int nItemHeight) { m_nItemHeight = nItemHeight; }// 设置菜单的宽度void SetMenuWidth(int nWidth) { m_nMenuWidth = nWidth; }// 设置边框颜色void SetBorderColor(COLORREF clr) { m_clrBorder = clr; }};
// MenuEx.cpp : 实现文件
//#include "pch.h"
#include "MenuEx.h"#pragma warning ( disable : 4311 )
#pragma warning ( disable : 4302 )
#pragma warning ( disable : 4172 )
#define GWL_WNDPROC         (-4)
CMenuEx::CMenuEx()
{m_hook = NULL;m_nItemHeight = ::GetSystemMetrics(SM_CYMENU);m_nFontSize = GetSysFontSize();//m_strFontFaceName = GetSysFontFaceName();m_strFontFaceName = _T("黑体");m_nLeftWidth = 30;m_nIconWidth = 16;m_nIconHeight = 16;m_clrBk = RGB(57, 63, 73);m_clrBkHover = RGB(19,68,93);m_clrText = RGB(255,255,255);m_clrText = RGB(255, 255, 255);m_clrSeparator = RGB(230,230,230);m_clrTextDisable = RGB(180,180,180);m_nMenuWidth = 150;m_bHasIcon = false;m_nSeparatorHeight = 7;}CMenuEx::~CMenuEx()
{
}void CMenuEx::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{// TODO:  添加您的代码以绘制指定项CString strText;   CDC *pDC = CDC::FromHandle(lpDrawItemStruct->hDC); //获取菜单项的设备句柄   StruItemInfo *pStruItemInfo =(StruItemInfo*)lpDrawItemStruct->itemData;  if(pStruItemInfo == NULL){return;}CRect rect(lpDrawItemStruct->rcItem);  if(pStruItemInfo->eItemType == ITEMTYPE_SEPARATOR)		//分隔条  {  // 画背景pDC->FillSolidRect(rect, m_clrBk);  // 画线CRect rcSeparator(rect);  rcSeparator.top = rcSeparator.top + rcSeparator.Height() / 2;  rcSeparator.bottom = rcSeparator.top + 1; rcSeparator.left += 5;rcSeparator.right -= 5;  pDC->Draw3dRect(rcSeparator, m_clrSeparator, m_clrSeparator);}else{// 画背景if(lpDrawItemStruct->itemState & ODS_GRAYED)	// 无效变灰{  pDC->FillSolidRect(rect, m_clrBk);  pDC->SetTextColor(m_clrTextDisable);  }      else if(lpDrawItemStruct->itemState & ODS_SELECTED )	// 经过{   //在菜单项上自绘矩形框的背景颜色   pDC->FillSolidRect(rect, m_clrBkHover);  //设置菜单文字颜色  pDC->SetTextColor(m_clrText);  }   else  {  pDC->FillSolidRect(rect, m_clrBk);  pDC->SetTextColor(m_clrText);  }pDC->SetBkMode(TRANSPARENT);  CRect rcIcon(rect);rcIcon.left += (m_nLeftWidth - m_nIconWidth) / 2;rcIcon.right = rcIcon.left + m_nIconWidth;rcIcon.top += (rcIcon.Height() - m_nIconHeight) / 2;if(pStruItemInfo->hIcon != NULL)  {  DrawIconEx(pDC->m_hDC, rcIcon.left, rcIcon.top, pStruItemInfo->hIcon, m_nIconWidth, m_nIconHeight, 0, NULL, DI_NORMAL);  }   // 文字字体和字号设置  LOGFONT fontInfo;  pDC->GetCurrentFont()->GetLogFont(&fontInfo);  fontInfo.lfHeight = m_nFontSize;lstrcpy(fontInfo.lfFaceName, m_strFontFaceName); CFont fontCh;  fontCh.CreateFontIndirect(&fontInfo);  pDC->SelectObject(&fontCh);  CRect rcText(rect);if (m_bHasIcon){rcText.left += m_nLeftWidth;}else{rcText.left += 10;}rcText.top += (rcText.Height() - m_nFontSize) / 2;rcText.bottom = rcText.top + m_nFontSize;//子菜单项if(pStruItemInfo->eItemType == ITEMTYPE_SUBMENU)	{  pDC->TextOut(rcText.left, rcText.top, pStruItemInfo->strText, pStruItemInfo->strText.GetLength()); // 换上自定义小箭头//::ExcludeClipRect(pDC->m_hDC,rect.right-15,rect.top,rect.right,rect.bottom);  //DrawIconEx(pDC->m_hDC,rect.right-40,rect.top+7,AfxGetApp()->LoadIconA(IDI_ICON1),32,32,1,NULL,DI_NORMAL);          }  else if (pStruItemInfo->eItemType == ITEMTYPE_STRING)		{  // 字符串项pDC->TextOut(rcText.left, rcText.top, pStruItemInfo->strText, pStruItemInfo->strText.GetLength());  //fontInfo.lfHeight = 16;  //CFont fontEn;  //lstrcpy(fontInfo.lfFaceName, _T("Arial"));  //fontEn.CreateFontIndirect(&fontInfo);  //pDC->SelectObject(&fontEn);  pDC->TextOut(rcText.left, rcText.top, pStruItemInfo->strShortcut, pStruItemInfo->strShortcut.GetLength());  }    }// 画边框CPen penBorder(PS_SOLID, 1, m_clrBorder);CPen *pOldPen = pDC->SelectObject(&penBorder);pDC->MoveTo(rect.left, rect.top);pDC->LineTo(rect.left, rect.bottom);pDC->MoveTo(rect.right-1, rect.top);pDC->LineTo(rect.right-1, rect.bottom);if (m_ItemList.size() == 1){// 如果只有一项的话就上下边都画pDC->MoveTo(rect.left, rect.top);pDC->LineTo(rect.right-1, rect.top);pDC->MoveTo(rect.left, rect.bottom-1);pDC->LineTo(rect.right-1, rect.bottom-1);}else{// 有多项的话,第一项画上边,最后一项画下边if (pStruItemInfo->eOrderType == ORDERTYPE_FIRST){pDC->MoveTo(rect.left, rect.top);pDC->LineTo(rect.right-1, rect.top);} else if (pStruItemInfo->eOrderType == ORDERTYPE_LAST){pDC->MoveTo(rect.left, rect.bottom-1);pDC->LineTo(rect.right-1, rect.bottom-1);}}pDC->SelectObject(pOldPen);}void CMenuEx::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)
{// TODO:  添加您的代码以确定指定项的大小StruItemInfo *pStruItemInfo =(StruItemInfo*)lpMeasureItemStruct->itemData;  if (pStruItemInfo->eItemType == ITEMTYPE_SEPARATOR){// 设置分隔符项高度lpMeasureItemStruct->itemHeight = m_nSeparatorHeight;}else{lpMeasureItemStruct->itemHeight = m_nItemHeight;}// 设置项宽度lpMeasureItemStruct->itemWidth = m_nMenuWidth;}void CMenuEx::AppendSeparator(UINT nFlags, UINT nID)  
{  StruItemInfo *pStruItemInfo = new StruItemInfo;pStruItemInfo->nID = nID;pStruItemInfo->hIcon = NULL;pStruItemInfo->strText = "";pStruItemInfo->strShortcut = "";pStruItemInfo->eItemType = ITEMTYPE_SEPARATOR;nFlags |= MF_SEPARATOR|MF_OWNERDRAW;pStruItemInfo->nFlags = nFlags;pStruItemInfo->eOrderType = GenerateOrderType();m_ItemList.push_back(pStruItemInfo);CMenu::AppendMenu(nFlags, 0, (LPCTSTR)pStruItemInfo);  
}  void CMenuEx::AppendSubMenu(UINT nFlags, UINT nID, CMenuEx* subMenu, CString strText,UINT nIconID)   
{  StruItemInfo *pStruItemInfo = new StruItemInfo;  pStruItemInfo->nID = nID;  if(nIconID == 0)  {  pStruItemInfo->hIcon = NULL;  }  else  {  pStruItemInfo->hIcon = (HICON)::LoadImage(AfxGetInstanceHandle(),MAKEINTRESOURCE(nIconID),IMAGE_ICON, m_nIconWidth, m_nIconHeight, 0);if (pStruItemInfo->hIcon != NULL){m_bHasIcon = true;}}  pStruItemInfo->strText = strText;  pStruItemInfo->strShortcut = "";  pStruItemInfo->eItemType = ITEMTYPE_SUBMENU;      nFlags |= MF_POPUP|MF_OWNERDRAW;  pStruItemInfo->nFlags = nFlags;  pStruItemInfo->eOrderType = GenerateOrderType();m_ItemList.push_back(pStruItemInfo);CMenu::AppendMenu(nFlags, (UINT)subMenu->GetSafeHmenu(), (LPCTSTR)pStruItemInfo);
} void CMenuEx::AppendItem(UINT nFlags, UINT nID, CString strText, CString strShortcut, UINT nIconID)   
{  StruItemInfo *pStruItemInfo = new StruItemInfo;  pStruItemInfo->nID = nID;  if(nIconID == 0)  {  pStruItemInfo->hIcon = NULL;  }  else  {  pStruItemInfo->hIcon = (HICON)::LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(nIconID), IMAGE_ICON, m_nIconWidth, m_nIconHeight, 0);  //pStruItemInfo->hIcon = AfxGetApp()->LoadIcon(nIconID) ;  if (pStruItemInfo->hIcon != NULL){m_bHasIcon = true;}}  pStruItemInfo->strText = strText;  pStruItemInfo->strShortcut = strShortcut;  pStruItemInfo->eItemType = ITEMTYPE_STRING;  nFlags |= MF_OWNERDRAW;  pStruItemInfo->nFlags = nFlags;  pStruItemInfo->eOrderType = GenerateOrderType();m_ItemList.push_back(pStruItemInfo);CMenu::AppendMenu(nFlags, pStruItemInfo->nID, (LPCTSTR)pStruItemInfo);      
}  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)//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)GetWindowLongPtr(hWnd, GWL_WNDPROC); //获得指定窗口的信息 GWL_WNDPROC得到窗口回调函数的地址或句柄  //获取传入进程中窗口的窗口过程,这个窗口过程用于接收和处理系统向窗口发送的消息  if(lastWndProc != MenuWndProc)   {   // 替换菜单窗口过程   SetWindowLongPtr(hWnd, GWL_WNDPROC, (LONG_PTR)MenuWndProc);// 保留原有的窗口过程   oldWndProc = lastWndProc;   }  break;   }  //每一个钩子函数在进行处理时都要考虑是否需要把事件传递给下一个钩子处理函数。如果需要传递,就要调用函数CallNestHookEx()。  //在实际使用时还是强烈建议无论是否需要进行事件传递都要在过程的最后调用一次CallNextHookEx( ),否则将会引起一些无法预知的系统行为或是系统锁定。  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);   }   
}  void CMenuEx::InstallHook(HINSTANCE hInst)  
{  // 需要移除边框时,要安装钩子  if(m_hook == NULL)  {  DWORD id = ::GetCurrentThreadId(); // 获取当前线程的ID          m_hook = SetWindowsHookEx(WH_CALLWNDPROC,CallWndProc,hInst,id);//负责将回调函数放置于钩子链表的开始位置。  //HHOOK SetWindowsHookEx(int idHook;HOOKPROC lpfn;HINSTANCE hMod;DWORD dwThreadId);  //idHook 指定了钩子的类型,WH_CALLWNDPROC 系统将消息发送到指定窗口之前的“钩子”   //参数lpfn为指向钩子函数的指针,也即回调函数的首地址;  //参数hMod标识了钩子处理函数所处模块的句柄;  //参数dwThreadId 指定被监视的线程,如果明确指定了某个线程的ID就只监视该线程,此时的钩子即为线程钩子;  //如果该参数被设置为0,则表示此钩子为监视系统所有线程的全局钩子。  //此函数在执行完后将返回一个钩子句柄。  }  
}  void CMenuEx::UnInstallHook()  
{  if(m_hook != NULL)  {  UnhookWindowsHookEx(m_hook);  m_hook = NULL;  }  
} int CMenuEx::GetSysFontSize()
{HFONT hFont = (HFONT)::GetStockObject(DEFAULT_GUI_FONT);if (hFont == NULL){return 12;}LOGFONT lf;GetObject(hFont, sizeof(LOGFONT), &lf);return abs(lf.lfHeight);
}LPCTSTR	 CMenuEx::GetSysFontFaceName()
{HFONT hFont = (HFONT)::GetStockObject(DEFAULT_GUI_FONT);if (hFont == NULL){return _T("");}LOGFONT lf;GetObject(hFont, sizeof(LOGFONT), &lf);return lf.lfFaceName;
}void CMenuEx::SetFontInfo(int nSize, const char* szFontFaceName/*=NULL*/)
{m_nFontSize = nSize;if (szFontFaceName != NULL){m_strFontFaceName = (LPCTSTR)szFontFaceName;}
}void CMenuEx::DestroyMenu()
{ItemInfoIter it = m_ItemList.begin();for ( ; it != m_ItemList.end(); it++){StruItemInfo* pStruItemInfo = (StruItemInfo*)*it;if (pStruItemInfo != NULL){delete pStruItemInfo;pStruItemInfo = NULL;}}CMenu::DestroyMenu();
}EnumaOrderType CMenuEx::GenerateOrderType()
{size_t nSize = m_ItemList.size();if (nSize == 0){return ORDERTYPE_FIRST;} else{ItemInfoIter it = m_ItemList.begin();for ( ; it != m_ItemList.end(); it++){if ((*it)->eOrderType == ORDERTYPE_LAST){(*it)->eOrderType = ORDERTYPE_CENTER;break;}}return ORDERTYPE_LAST;}
}

四:这里去除菜单栏的边框使用了钩子技术,实际上处理菜单消息会跑到我们定义的这个函数里面去LRESULT WINAPI MenuWndProc

注意注册了Hook记得注销。

五:关于踩的坑。我编译的版本是x64,之前在网上查资料,一般设置自己的处理菜单函数都是用的这两个函数GetWindowLong ,SetWindowLong

但是在64位系统下面要使用这两个GetWindowLongPtr,SetWindowLongPtr

SetWindowLongPtr(hWnd, GWL_WNDPROC, (LONG_PTR)MenuWndProc);

这个函数注册我们自己的窗口处理函数,传递一个函数指针过去,x64形式的要传递64位的函数指针,即这种形式(LONG_PTR)MenuWndProc,LONG_PTR类型就表示一个64位的 指针。

之前我传的是(long)MenuWndProc,传了32位的指针,这样如果你是x64的编译形式,就会产生截断,程序报错。

六:设置MFC界面的背景颜色

HBRUSH CMFCDrawnTitleDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{HBRUSH hbr = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor);// TODO:  在此更改 DC 的任何特性// TODO:  如果默认的不是所需画笔,则返回另一个画笔switch (nCtlColor){case CTLCOLOR_DLG:HBRUSH aBrush;aBrush = CreateSolidBrush(RGB(30, 34, 39));hbr = aBrush;break;}if (nCtlColor == CTLCOLOR_STATIC){}return hbr;
}


http://chatgpt.dhexx.cn/article/KmKrBfVQ.shtml

相关文章

MFC界面编程基础(02):MFC窗口的创建

上一篇&#xff1a;MFC界面编程基础&#xff08;01&#xff09;&#xff1a;Windows 编程模型下一篇&#xff1a;MFC界面编程基础&#xff08;03&#xff09;&#xff1a;消息映射、窗口绘制、文档/视图结构体系 MFC是什么? 微软基础类库&#xff08;英语&#xff1a;Micros…

MFC界面编程基础(01):Windows 编程模型

上一篇&#xff1a;MFC界面编程基础&#xff08;00&#xff09;&#xff1a;基本概念下一篇&#xff1a;MFC界面编程基础&#xff08;02&#xff09;&#xff1a;MFC窗口的创建 WinMain函数 当 Windows 操作系统启动一个程序时&#xff0c;它调用的就是该程序的 WinMain 函数…

简单聊天室的设计 C++ MFC

b站有更高级教学视频 https://www.bilibili.com/video/av38700336/ 一、要求 要求&#xff1a;分别设计基于对话框的客户端和服务器端的程序&#xff0c;实现两端的通信&#xff0c;服务器端能接受客户端的消息&#xff0c;并且显示客户端的连接信息&#xff0c;把客户端信息…

MFC 中使用QT开发界面

首先创建一个基于对话框的MFC工程&#xff0c;当然其他的像是多文档、单文档工程也是可以的&#xff0c;只是为了简单起见我这里用的是对话框 然后通过鼠标右键点击项目&#xff0c;然后依次点击属性 --> C/C -->常规在工程的附加头文件中添加上QCore、QGui、QWidget和QT…

第六篇--MFC美化界面

1.MFC如何设置背景颜色 首先,为对话框添加WM_CTLCOLOR消息,方法为:右击Dialog窗口 --> Class Wizard --> Messages --> WM_CTLCOLOR --> Add Handler --> Edit Code 然后,在Dlg.h文件中添加成员变量CBrush m_brush; 接着,在之前Edit Code的位置,写上 HB…

MFC界面类库Xtreme Toolkit Pro 下载及使用教程介绍

Xtreme Toolkit Pro 是针对Windows程序员的一套先进的用户界面套包&#xff0c;强大的功能可使您的应用程序具有专业的、现代感的外观。 Xtreme Toolkit Pro 由8个专业级的构件组成&#xff0c;Xtreme CommandBars, Xtreme Docking Pane, Xtreme Property Grid, Xtreme Report …

wxWidgets界面设计工具DialogBlocks

工欲善其事&#xff0c;必先利其器。在MFC上开发&#xff0c;有VS系列强大的可视化工具&#xff0c;基于wx的开发工具虽然没有VS、QT的界面设计器强大&#xff0c;但在灵活度上VS的界面设计器是没法比的&#xff08;QT的没有用过&#xff0c;不做评论&#xff09;。 如…

Visual Studio开发MFC如何打开可视化窗口编辑界面

在使用Visual Studio 2019开发工具开发MFC工程项目时&#xff0c;如果把可视化界面窗口编辑界面关闭后如何打开&#xff1f; 1、项目关闭后重新打开时的界面&#xff0c;没有可视化窗口界面显示。 2、在右侧的解决方案资源管理器中&#xff0c;选择资源文件下的 MFCApplicati…

VisualStudio2022 MFC对话框窗体托盘图标设计

目录 效果展示头文件1.1 头文件声明 CPP文件2.1 初始化2.2 功能实现 环境&#xff1a;VisualStudio2022 框架: MFC 对话框窗体 功能&#xff1a;托盘 对话框类&#xff1a;CBLToolsDlg 作者&#xff1a;CDamogu 时间&#xff1a;20220308 效果展示 头文件 1.1 头文件声明 头文…

MFC界面美化---自绘标题栏

做MFC项目的时候&#xff0c;会经常遇到需要美化界面的时候。mfc的原始界面比较丑&#xff0c;今天主要记录一下对MFC标题栏重绘的过程&#xff0c;最终效果是这样的。 1.因为要对标题栏进行重绘&#xff0c;我们要把MFC的原生标题栏给去掉&#xff0c;在MFC对话框的属性那里&a…

Windows界面编程:MFC

前言 大家之前在学C/C语言时&#xff0c;基本都是通过控制台实现“人机交流”的。但大家每次在写控制台程序时&#xff0c;看到黑框框应该都会有些许不爽吧&#xff1a;“输入输出为什么不能基于图形用户界面而非要使用文本用户界面呢&#xff1f;”事实上&#xff0c;在各个环…

MFC-登录界面(可修改密码)

登录界面的博客有很多&#xff0c;参考了这一篇文章&#xff0c;下面给出链接。 MFC做一个登录界面&#xff08;用户名&#xff0c;密码以及密码的明文密文切换&#xff09;_umarutyan的博客-CSDN博客 但这里无法修改密码&#xff0c;下面做出一些补充。 由于用不到数据库&a…

MFC界面工具BCGControlBar入门:如何使用工具栏编辑器

BCGControlBar ("Business Components Gallery ControlBar")是MFC扩展库&#xff0c;使您可以创建具有完全自定义选项&#xff08;功能区、可自定义工具栏、菜单等&#xff09;以及一组专业设计的丰富Microsoft Office和Microsoft Visual Studio的应用程序 GUI控件&a…

MFC程序中使用QT开发界面

如果你有一个现成的MFC项目在做维护&#xff0c;但是你厌倦了使用MFC繁琐的操作来做界面美化&#xff0c;或者你需要在这个项目中用到QT里面好用的某些功能&#xff1b;亦或者是你需要使用某些只能在MFC中使用的组件&#xff0c;但是界面这部分已经用QT做好了。那么这篇文章可能…

一、MFC登陆界面

一、新建项目 打开VS2022——>创建新项目——>选择MFC应用&#xff0c;点击下一步——>修改项目名称和位置&#xff0c;点击创建——>修改应用程序类型、项目样式经典菜单选项 二、添加预处理指令 VS建议采用带_s的函数&#xff0c;如scanf_s、strcpy_s&#xff0…

MFC基础知识与课程设计思路

引言 本文致力于提供MFC的相关知识&#xff0c;以方便大家更好地认识MFC的使用方法。介绍将会分为以下几个部分&#xff1a;MFC初始文件的理解、MFC我们所使用的框架理解、MFC的进阶用法、MFC我在使用过程中遇到的问题及解决方法。 MFC初始文件的理解 MFC的初始文件中有两项文…

MFC添加程序关闭时时的提示界面

文章目录 MFC一.简介二.方法 MFC 一.简介 在应用程序退出的时候&#xff0c;不能点击叉直接退出&#xff0c;我们想添加一个退出提示。在点击叉后&#xff0c;弹出是否确定退出的界面&#xff0c;如下面的界面&#xff0c;具体操作往下看 二.方法 找到我们需要操作的主界面…

【MFC】模拟采集系统——界面设计(17)

功能介绍 启动界面 开始采集&#xff1a; PS&#xff1a;不涉及 数据保存&#xff0c;重现等功能 界面设计 界面分为三块&#xff1a;顶部黑条带关闭按钮、左边对话框&#xff0c;右边的主界面 资源&#xff1a; 顶部黑条 top.bmp 2* 29 &#xff08;宽 * 高 像素点&…

MFC界面设计入门篇

点击C里的MFC再点击MFCApplication&#xff0c;到下面改名字和路径&#xff0c;然后OK 然后点击Next&#xff0c; 选择single document&#xff0c;MFCstandard&#xff0c;简体中文&#xff0c;然后Finish 这时候可以先直接运行&#xff0c;看看工程的样子&#x…

最最简单的几个Mac终端命令

几个简单的Mac终端命令 目录切换相关 cd空格/ 回到根目录cd空格… &#xff08;或者 cd空格…/&#xff09; 回到上一级目录cd空格. 回到当前目录pwd 显示从根目录到当前目录的完整目录 vi操作相关 注意&#xff1a;vi操作的文件如果不存在&#xff0c;则先自动创建一个该名字…