15 мая 2023 года "Исходники.РУ" отмечают своё 23-летие!
Поздравляем всех причастных и неравнодушных с этим событием!
И огромное спасибо всем, кто был и остаётся с нами все эти годы!

Главная Форум Журнал Wiki DRKB Discuz!ML Помощь проекту


Всплывающее меню с заголовком.


Автор: Per Fikse

Здесь представлен класс CTMenu, наследованный от CMenu, который позволяет сделать видимость заголовка в сплывающем меню путём изменения шрифта верхнего пункта.

Чтобы использовать CTMenu, достаточно просто добавить в проект файлы TMENU.H и TMENU.CPP, заменить в исходнике CMenu на CTMenu, и вызвать AddMenuTitle с нужным текстом заголовка.

В обычном обработчике OnContextMenu возможно потребуется использовать Attach/Detach. Например, если у Вас есть загруженный ресурс меню в CMenu* pContextMenu; то необходимо проделать следующее:

CTMenu titlemenu;
titlemenu.Attach(*pContextMenu);
titlemenu.AddMenuTitle("SomeTitle");
//работаем с меню...
titlemenu.Detach();

 

И наконец два главных файла:


----------------------------------- начало TMENU.H

#if !defined(AFX_TMENU_H__3C1D1728_241C_11D3_9CE5_0060973674E2__INCLUDED_)
#define AFX_TMENU_H__3C1D1728_241C_11D3_9CE5_0060973674E2__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// TMenu.h : header file
//

/////////////////////////////////////////////////////////////////////////////
// CTMenu window


class CTMenu : public CMenu
{
// Construction
public:
  CTMenu();

// Attributes
protected:
  CFont m_Font;
  CString m_strTitle;

// Operations
public:
  void AddMenuTitle(LPCTSTR lpszTitle);

protected:
  HFONT CreatePopupMenuTitleFont();

// Implementation
public:
  virtual ~CTMenu();
  virtual void MeasureItem(LPMEASUREITEMSTRUCT lpMIS);
  virtual void DrawItem(LPDRAWITEMSTRUCT lpDIS);

};

/////////////////////////////////////////////////////////////////////////////

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional
// declarations immediately before the previous line.

#endif // !defined(AFX_TMENU_H__3C1D1728_241C_11D3_9CE5_0060973674E2__INCLUDED_)


------------------------------------------- конец TMENU.H

------------------------------------------- начало TMENU.CPP
// TMenu.cpp : implementation file
//

#include "stdafx.h"
#include "TMenu.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CTMenu

CTMenu::CTMenu()
{
  HFONT hfont = CreatePopupMenuTitleFont();
  ASSERT(hfont);
  m_Font.Attach(hfont);
}

CTMenu::~CTMenu()
{
  m_Font.DeleteObject();
}

 


/////////////////////////////////////////////////////////////////////////////
// CTMenu message handlers


HFONT CTMenu::CreatePopupMenuTitleFont()
{
// start by getting the stock menu font
HFONT hfont = (HFONT)GetStockObject(ANSI_VAR_FONT);
if (hfont) {
LOGFONT lf; //get the complete LOGFONT describing this font
if (GetObject(hfont, sizeof(LOGFONT), &lf)) {
lf.lfWeight = FW_BOLD; // set the weight to bold
// recreate this font with just the weight changed
return ::CreateFontIndirect(&lf);
}
}
return NULL;
}


//
// Эта функция добавляет заголовок в меню
//
void CTMenu::AddMenuTitle(LPCTSTR lpszTitle)
{
// вставляем пустой пункт в начало меню, который будет являться заголовком
// обратите внимание, что этот пункт нельзя выбрать, однако он не серый
  m_strTitle=CString(lpszTitle);
  InsertMenu(0, MF_BYPOSITION | MF_OWNERDRAW | MF_STRING | MF_DISABLED, 0);
}

 

void CTMenu::MeasureItem(LPMEASUREITEMSTRUCT mi)
{
// получаем dc экрана чтобы использовать его для получения размеров
  CDC dc;
  dc.Attach(::GetDC(NULL));
// выбираем шрифт заголовка
  HFONT hfontOld = (HFONT)SelectObject(dc.m_hDC, (HFONT)m_Font);
// вычисляем размер заголовка
  CSize size = dc.GetTextExtent(m_strTitle);
// возвращаем шрифт обратно
  ::SelectObject(dc.m_hDC, hfontOld);
// добавляем левый отступ для пункта меню
  size.cx += GetSystemMetrics(SM_CXMENUCHECK)+8;

//Возвращаем ширину и высоту
//+ включая пробел для рамки
  const int nBorderSize = 2;
  mi->itemWidth = size.cx + nBorderSize;
  mi->itemHeight = size.cy + nBorderSize;
}


void CTMenu::DrawItem(LPDRAWITEMSTRUCT di)
{
//Рисуем фон и утопленный прямоугольник...
  COLORREF crOldBk = ::SetBkColor(di->hDC, ::GetSysColor(COLOR_INACTIVECAPTION));
  ::ExtTextOut(di->hDC, 0, 0, ETO_OPAQUE, &di->rcItem, NULL, 0, NULL);
  ::DrawEdge(di->hDC, &di->rcItem, BDR_SUNKENINNER, BF_RECT);

  int modeOld = ::SetBkMode(di->hDC, TRANSPARENT);
  COLORREF crOld = ::SetTextColor(di->hDC, GetSysColor(COLOR_CAPTIONTEXT));
// выбираем шрифт в dc
  HFONT hfontOld = (HFONT)SelectObject(di->hDC, (HFONT)m_Font);

// добавляем к меню отступы
  di->rcItem.left += GetSystemMetrics(SM_CXMENUCHECK)+8;
// рисуем текст с левым выравниванием и отцентрированный по вертикали
  ::DrawText(di->hDC, m_strTitle, -1, &di->rcItem, DT_SINGLELINE|DT_VCENTER|DT_LEFT);

//Восстанавливаем шрифт и цвета...
  ::SelectObject(di->hDC, hfontOld);
  ::SetBkMode(di->hDC, modeOld);
  ::SetBkColor(di->hDC, crOldBk);
  ::SetTextColor(di->hDC, crOld);
}


------------------------------------------- конец TMENU.CPP