Notice
Link
- Today
- Total
Recent Posts
Recent Comments
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
Tags
- MFC
- 코드로 서버 재실행
- vc++
- springboot 재가동
- mybatis exception
- c언어
- 스크롤적용
- rn
- ffmpeg
- pid 찾아 kill
- kill -9
- 텍스트컬러
- sql exception
- CentOS
- CSS
- MariaDB
- springboot
- 말줌임 CSS
- MySQL
- 터치좌표 view
- Back 키 클릭 감지
- 파티션 빠른 삭제
- 피쉬랜드
- SQL 마지막날
- 가변영역 스크롤
- view 획득
- Activity 전체화면
- reactnative
- DB 계정생성
- SQL 첫날
Archives
개발은 하는건가..
[MFC] 오른쪽 버튼 메뉴 띄우기 (custom contextmenu) 본문
반응형
컨텍스트 메뉴를 띄울 버튼이나 마우스 클릭 이벤트 핸들러를 추가 후 다음과 같이 사용하여 띄운다.
void CMainWnd::OnRButtonDown(UINT nFlags, CPoint pt)
{
CGCSContextMenu cm;
// ::GetCursorPos(&pt);
// ::ScreenToClient(pThis->GetSafeHwnd(), &pt);
cm.CreatePopupMenu();
// cm.AddMenu(커맨드ID, 메뉴텍스트, 메뉴 아이콘 이미지 파일 경로);
cm.AddMenu(4000, _T("메뉴1"), _T("메뉴1용 아이콘 파일 전체경로"));
cm.AddMenu(4001, _T("메뉴2"), _T("메뉴2용 아이콘 파일 전체경로"));
cm.ShowPopupMenu(parentWindow, pt);
// 선택한 메뉴의 커맨드ID 가 parentWindow 의 ON_COMMAND 메세지의 WPARAM 으로 전달된다.
}
OOL CMainWnd::OnCommand(WPARAM wParam, LPARAM lParam)
{
if (wParam == 4000) {
// 메뉴1의 처리
}
else if (wParam == 4001){
// 메뉴2의 처리
}
return CBaseDialog::OnCommand(wParam, lParam);
}
CGCSContextMenu.h 파일 구현체
#pragma once
#include <afxwin.h>
#define MENU_DEF_ITEM_WIDTH 140
#define MENU_DEF_ITEM_HEIGHT 30
#define MENU_DEF_BORDER_COLOR RGB(52, 103, 115)
#define MENU_DEF_NOR_BG_COLOR RGB(15, 25, 40)
#define MENU_DEF_OVER_BG_COLOR RGB(45, 55, 75)
class CGCSContextMenu : public CMenu
{
public:
CGCSContextMenu();
virtual ~CGCSContextMenu();
struct CSMenuItem {
UINT nCmdId;
TCHAR szMenu[32];
void* pGdiIconImg;
CSMenuItem::CSMenuItem() { ZeroMemory(this, sizeof(CSMenuItem)); };
};
void AddMenu(UINT nCmdId, CString strMenu, CString &strIconPath);
void ShowPopupMenu(CWnd *pParent, CPoint &clientPt);
CSMenuItem* GetMenuItem(UINT nCmdId);
inline void SetBorderColor(UINT nColor) { m_nBorderColor = nColor; };
inline void SetBgColor(UINT nNormalColor, UINT nOverColor) { m_nDefaultBgColor = nNormalColor; m_nOverBgColor = nOverColor; };
inline void SetItemSize(UINT nItemWidth, UINT nItemHeight) { m_nMenuItemWidth = nItemWidth; m_nMenuItemHeight = nItemHeight; };
private:
UINT m_nMenuItemWidth;
UINT m_nMenuItemHeight;
UINT m_nBorderColor; // 테두리 라인 색상
UINT m_nDefaultBgColor; // 기본 배경 색상
UINT m_nOverBgColor; // 마우스 오버 배경 색상
CPtrArray m_paMenuItems; // 메뉴 아이템 정보들 배열
void DrawingText(CDC *pDC, TCHAR *pStr, RECT* rc, int size, UINT color, UINT format, UINT bold);
// Override Methods
public:
virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
virtual void MeasureItem(LPMEASUREITEMSTRUCT /*lpMeasureItemStruct*/);
};
class CMemoryDC : public CDC
{
public:
CMemoryDC(CDC *pDC, CWnd *pParentWnd) {
if (pDC == NULL || pParentWnd == NULL)
{
return;
}
pParentWnd->GetClientRect(m_rcParent);
m_pOldBitmap = NULL;
m_pParentWnd = pParentWnd;
m_pDC = pDC;
CreateCompatibleDC(m_pDC);
m_Bitmap.CreateCompatibleBitmap(m_pDC, m_rcParent.Width(), m_rcParent.Height());
m_pOldBitmap = SelectObject(&m_Bitmap);
}
CMemoryDC(CDC *pDC, CRect *pParentRect) {
if (pDC == NULL || pParentRect == NULL)
{
return;
}
m_rcParent = *pParentRect;
m_pOldBitmap = NULL;
m_pDC = pDC;
CreateCompatibleDC(m_pDC);
m_Bitmap.CreateCompatibleBitmap(m_pDC, m_rcParent.Width(), m_rcParent.Height());
m_pOldBitmap = SelectObject(&m_Bitmap);
}
virtual ~CMemoryDC(void) {
if (m_pDC == NULL)
{
return;
}
m_pDC->BitBlt(m_rcParent.left, m_rcParent.top, m_rcParent.right, m_rcParent.bottom, this, 0, 0, SRCCOPY);
SelectObject(m_pOldBitmap);
m_Bitmap.DeleteObject();
DeleteDC();
}
private:
CWnd *m_pParentWnd;
CDC *m_pDC;
CBitmap m_Bitmap;
CBitmap *m_pOldBitmap;
CRect m_rcParent;
};
CGCSContextMenu.cpp 파일 구현체
#include "../pch.h"
#include "GCSContextMenu.h"
CGCSContextMenu::CGCSContextMenu()
{
m_nMenuItemWidth = MENU_DEF_ITEM_WIDTH;
m_nMenuItemHeight = MENU_DEF_ITEM_HEIGHT;
m_nBorderColor = MENU_DEF_BORDER_COLOR;
m_nDefaultBgColor = MENU_DEF_NOR_BG_COLOR;
m_nOverBgColor = MENU_DEF_OVER_BG_COLOR;
}
CGCSContextMenu::~CGCSContextMenu()
{
for (int i = 0; i < m_paMenuItems.GetCount(); i++)
{
CSMenuItem *pMi = (CSMenuItem*)m_paMenuItems.GetAt(i);
if (pMi != NULL)
{
delete pMi;
}
}
m_paMenuItems.RemoveAll();
}
void CGCSContextMenu::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
if (lpDrawItemStruct->hDC == NULL)
{
return;
}
CSMenuItem* pMenuItem = GetMenuItem(lpDrawItemStruct->itemID);
if (pMenuItem == NULL)
{
return;
}
CRect rcItem = lpDrawItemStruct->rcItem;
UINT bgColor;
CDC itemDc;
itemDc.Attach(lpDrawItemStruct->hDC);
if (itemDc.GetSafeHdc() != NULL)
{
// Mem DC 는 소멸 시점에 버퍼에 내용을 Flush 하므로 상위 dc 가 detach 하기 전에 소멸되도록 해야 함.
//CMemDC memDC(itemDc, rcItem);
//CDC *pDC = &memDC.GetDC();
CMemoryDC dc(&itemDc, &rcItem);
CDC *pDC = &dc;
bgColor = (lpDrawItemStruct->itemState == 257) ? m_nOverBgColor : m_nDefaultBgColor;
pDC->FillSolidRect(0, 0, rcItem.Width(), rcItem.Height(), bgColor);
DrawingText(pDC,
pMenuItem->szMenu,
CRect(30, 0, rcItem.Width(), rcItem.Height()),
22,
RGB(230, 240, 250),
DT_LEFT | DT_VCENTER,
FW_NORMAL);
Gdiplus::Image* pIcon = (Gdiplus::Image*)pMenuItem->pGdiIconImg;
if (pIcon != NULL)
{
Gdiplus::Graphics grs(pDC->GetSafeHdc());
int px = 4;
int py = ((rcItem.Height() - pIcon->GetHeight()) / 2); // rcItem 은 컨텍스트 영역 전체 기준의 절대 좌표이다.
grs.DrawImage(pIcon, Gdiplus::Rect(px, py, pIcon->GetWidth(), pIcon->GetHeight()));
}
}
//TRACE(_T("state=%d, type=%d, ctlid=%d, itemId=%d\n"), lpDrawItemStruct->itemState, lpDrawItemStruct->CtlType, lpDrawItemStruct->CtlID, lpDrawItemStruct->itemID);
itemDc.Detach();
}
void CGCSContextMenu::MeasureItem(LPMEASUREITEMSTRUCT lpms)
{
if (lpms->CtlType != ODT_MENU)
return;
lpms->itemWidth = m_nMenuItemWidth;
lpms->itemHeight = m_nMenuItemHeight;
}
void CGCSContextMenu::AddMenu(UINT nCmdId, CString strMenu, CString &strIconPath)
{
CSMenuItem* pMi = new CSMenuItem();
pMi->nCmdId = nCmdId;
_tcsncpy(pMi->szMenu, strMenu, _countof(pMi->szMenu));
if (strIconPath.IsEmpty() == FALSE)
{
pMi->pGdiIconImg = (void*)Gdiplus::Image::FromFile(strIconPath);
}
Gdiplus::Image* m_pTitleImg = (Gdiplus::Image*)pMi->pGdiIconImg;
m_paMenuItems.Add(pMi);
AppendMenu(MF_OWNERDRAW, nCmdId);
}
void CGCSContextMenu::ShowPopupMenu(CWnd *pParent, CPoint &clientPt)
{
MENUINFO MenuInfo = { 0 };
MenuInfo.cbSize = sizeof(MENUINFO);
GetMenuInfo(&MenuInfo);
MenuInfo.hbrBack = ::CreateSolidBrush(RGB(0, 0, 0));
MenuInfo.fMask = MIM_BACKGROUND | MIM_STYLE;
MenuInfo.dwStyle = MIM_APPLYTOSUBMENUS;
SetMenuInfo(&MenuInfo);
CPoint pt = clientPt;
pParent->ClientToScreen(&pt);
TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, pt.x, pt.y, pParent);
DestroyMenu();
}
void CGCSContextMenu::DrawingText(CDC *pDC, TCHAR *pStr, RECT* rc, int size, UINT color, UINT format, UINT bold)
{
if (pStr == NULL || pDC == NULL) {
return;
}
CFont fFont, *pOldFont;
int oldBkMode;
UINT oldColor = pDC->GetTextColor();
CRect rcClient;
fFont.CreateFont(size, 0, 0, 0,
bold,
FALSE, FALSE, FALSE,
DEFAULT_CHARSET,
OUT_CHARACTER_PRECIS,
CLIP_CHARACTER_PRECIS,
PROOF_QUALITY,
DEFAULT_PITCH | FF_DONTCARE,
_T("맑은 고딕"));
pOldFont = (CFont*)pDC->SelectObject(&fFont);
oldBkMode = pDC->SetBkMode(TRANSPARENT);
pDC->SetTextColor(color);
if ((format & DT_VCENTER) && !(format & DT_SINGLELINE))
{
CSize sizeEx = pDC->GetTextExtent(pStr);
if (sizeEx.cx > 0)
{
int lineCnt = (sizeEx.cx / (rc->right - rc->left)) + 1;
// count crlf new line
for (int i = 0; i < _tcslen(pStr); i++)
{
if (pStr[i] == _T('\n'))
{
lineCnt++;
}
}
int predictHeight = lineCnt * sizeEx.cy;
if (predictHeight < (rc->bottom - rc->top))
{
int offset = ((rc->bottom - rc->top) - predictHeight) / 2;
rc->top += offset;
}
}
}
pDC->DrawText(pStr, rc, format);
pDC->SetTextColor(oldColor);
pDC->SetBkMode(oldBkMode);
pDC->SelectObject(pOldFont);
fFont.DeleteObject();
}
CGCSContextMenu::CSMenuItem* CGCSContextMenu::GetMenuItem(UINT nCmdId)
{
for (int i = 0; i < m_paMenuItems.GetCount(); i++)
{
CSMenuItem* pMi = (CSMenuItem*)m_paMenuItems.GetAt(i);
if (pMi->nCmdId == nCmdId)
{
return pMi;
}
}
return NULL;
}
'C, C++, MFC' 카테고리의 다른 글
[MFC] 가상 조이스틱 패드 컨트롤 (0) | 2022.10.27 |
---|---|
특정 좌표의 원점 기준 각도 계산 관련 (0) | 2022.10.25 |
[VC++] 화면을 동영상으로 저장하기 (0) | 2022.09.08 |
MFC UDP Socket Base class (0) | 2022.07.19 |
CListCtrl 선택된 Item 인덱스 (0) | 2022.07.19 |
Comments