![]() |
|
Модераторы: Daevaorn |
![]()
|
|
| SeregaLBN |
|
|||
![]() Бывалый ![]() Профиль Группа: Участник Сообщений: 178 Регистрация: 3.10.2003 Где: Киев Репутация: нет Всего: нет |
Есть проблема. Рисую своё popup меню.
В обработчике сообщения WM_MEASUREITEM надо задавать размеры элемента меню. Из начальных данных у меня есть текст, сопоставленный с этим элементом меню. Зная размеры области в которую поместится текст, я мог бы задать размеры элемента меню, но для этого мне надо знать каким шрифтом в системе рисуется меню. Вопрос - как мне узнать системный HFONT для меню? И второй вопрос. При отрисовке моего пункта меню вся область для рисования больше чем я задавал. Слева, самой Виндой, отводится ещё область для рисунка "check'a" - рисунок точки, галочки (если данный пункт меню отмечен как ODS_CHECKED). Как мне узнать ширину данной области? А то получается, что текст в отображаемых мною пунктах меню не выровнен по сравнению с пунктами меню отображаемыми самой системой. Ниже приведён рабочий код //////////////////////////////////////////////////////////////////////////////// #define UNICODE #ifdef UNICODE #pragma comment(linker, "/ENTRY:wWinMainCRTStartup") #define _UNICODE #else #pragma comment(linker, "/ENTRY:WinMainCRTStartup") #endif // UNICODE #include <stdio.h> #include <windows.h> #include <windowsx.h> #include <tchar.h> #include <time.h> //////////////////////////////////////////////////////////////////////////////// // global variables //////////////////////////////////////////////////////////////////////////////// HINSTANCE ghInstance; //////////////////////////////////////////////////////////////////////////////// // My types //////////////////////////////////////////////////////////////////////////////// struct structMyMenuItemData { TCHAR caption[64]; POINT sizeMenuItem; /* ... // прочие мои данные для меню */ structMyMenuItemData(TCHAR* szStr) { sizeMenuItem.x = sizeMenuItem.y = 0; if (szStr && (_tcslen(szStr)<64)) _tcscpy(caption, szStr); } void SetSize(LONG x, LONG y) {sizeMenuItem.x = x; sizeMenuItem.y = y;} }; //////////////////////////////////////////////////////////////////////////////// // forward declaration //////////////////////////////////////////////////////////////////////////////// LRESULT CALLBACK WndProcTest(HWND, UINT, WPARAM, LPARAM); void InsertMenuItemData(HMENU, UINT, structMyMenuItemData*); POINT center(const RECT &rc); BOOL Cls_OnCreate (HWND, LPCREATESTRUCT); // WM_CREATE void Cls_OnDestroy (HWND); // WM_DESTROY void Cls_OnMeasureItem(HWND, MEASUREITEMSTRUCT*); // WM_MEASUREITEM void Cls_OnDrawItem (HWND, const DRAWITEMSTRUCT*); // WM_DRAWITEM //////////////////////////////////////////////////////////////////////////////// // IMPLEMENTATION //////////////////////////////////////////////////////////////////////////////// int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpszCmdLine, int nCmdShow) { ghInstance = hInstance; const WNDCLASS wc = { 0, WndProcTest, 0, 0, hInstance, LoadIcon (NULL, IDI_APPLICATION), LoadCursor(NULL, IDC_ARROW), GetSysColorBrush(COLOR_BTNFACE), NULL, TEXT("ClassWndProject") }; RegisterClass(&wc); const HWND hWnd = CreateWindow( TEXT("ClassWndProject"), TEXT("Menu Draw Test"), WS_OVERLAPPED | WS_THICKFRAME | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX, 100, 100, 500, 300, NULL, (HMENU)0, hInstance, NULL ); ShowWindow(hWnd, nCmdShow); MSG msg; while ( GetMessage(&msg, NULL, 0, 0)){ DispatchMessage(&msg); } return msg.wParam; } //////////////////////////////////////////////////////////////////////////////// // Прцедура обработки сообщений //////////////////////////////////////////////////////////////////////////////// LRESULT CALLBACK WndProcTest(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam){ switch(msg){ HANDLE_MSG(hwnd, WM_CREATE , Cls_OnCreate); HANDLE_MSG(hwnd, WM_DESTROY , Cls_OnDestroy); HANDLE_MSG(hwnd, WM_MEASUREITEM, Cls_OnMeasureItem); HANDLE_MSG(hwnd, WM_DRAWITEM , Cls_OnDrawItem); } return DefWindowProc(hwnd, msg, wParam, lParam); } //////////////////////////////////////////////////////////////////////////////// // Обработчики сообщений //////////////////////////////////////////////////////////////////////////////// // WM_CREATE BOOL Cls_OnCreate(HWND hWnd, LPCREATESTRUCT lpCreateStruct) { srand((unsigned)time(NULL)); // создаю popup меню HMENU hMenuPop = CreatePopupMenu(); AppendMenu(hMenuPop, MF_STRING, 0, TEXT("MenuItem №0")); //AppendMenu(hMenuPop, MF_STRING, 1, TEXT("MenuItem №1\tQWE")); AppendMenu(hMenuPop, MF_SEPARATOR, 0, NULL); for (int i=3; i<8; i++) { TCHAR szStr[16]; _stprintf(szStr, TEXT("MenuItem №%i"), i); InsertMenuItemData(hMenuPop, i, new structMyMenuItemData(szStr)); // на освобождение памяти забиваю if (rand() < RAND_MAX/2) CheckMenuItem (hMenuPop, i, MF_CHECKED); if (rand() < RAND_MAX/2) EnableMenuItem(hMenuPop, i, MF_GRAYED); } // создаю главное меню HMENU hMenu = CreateMenu(); SetMenu(hWnd, hMenu); // добавляю к главному меню popup меню MENUITEMINFO menuItemInfo = { sizeof(MENUITEMINFO), // UINT cbSize; MIIM_SUBMENU | MIIM_TYPE, // UINT fMask; MFT_STRING, // UINT fType; 0, // UINT fState; 0, // UINT wID; hMenuPop, // HMENU hSubMenu; NULL, // HBITMAP hbmpChecked; NULL, // HBITMAP hbmpUnchecked; NULL, // DWORD dwItemData; TEXT("DrawMenu"), // LPTSTR dwTypeData; 0, // UINT cch; }; InsertMenuItem(hMenu, 0, TRUE, &menuItemInfo); // отображаю меню DrawMenuBar(hWnd); return TRUE; } // WM_DESTROY void Cls_OnDestroy(HWND){ PostQuitMessage(0); } // WM_MEASUREITEM void Cls_OnMeasureItem(HWND hwnd, MEASUREITEMSTRUCT * mi) { // задаю размеры пункта меню ((structMyMenuItemData*)mi->itemData)->SetSize( mi->itemWidth = 80, mi->itemHeight = 20 ); } // WM_DRAWITEM void Cls_OnDrawItem(HWND hwnd, const DRAWITEMSTRUCT * dis) { if (dis->CtlType != ODT_MENU) // error return; // Размеры пункта меню dis->rcItem по ширине больше чем я задавал... // 1. К моим размерам, слева, добаляется область в которой обтображается // рисунок "check'a" - рисунок точки, галочки или прочий рисунок. // Отображатся рисунок должен мной. Проблема в том что я не понимаю // как верно узнать размер этой области. // 2. К моим размерам, справа, иногда, добавляется ещё область. // В этой области, если пункт меню ссылается на др. подменю, отображается // самой Wind'ой треугольник. structMyMenuItemData *pMyMenuItemData = (structMyMenuItemData*)dis->itemData; LONG h = dis->rcItem.bottom - dis->rcItem.top; // высота пункта меню // rcImg - прямоугольник рисунка "check'a" // считаю что его размеры равны высоте пункта меню RECT rcImg = {dis->rcItem.left, dis->rcItem.top, dis->rcItem.left+h, dis->rcItem.bottom}; // rcTxt - прямоугольник в котором будет отображаться текст меню RECT rcTxt = {dis->rcItem.left+h, dis->rcItem.top, dis->rcItem.left+h+pMyMenuItemData->sizeMenuItem.x, dis->rcItem.bottom}; bool isCheck = !!(dis->itemState & ODS_CHECKED); bool isSelect = !!(dis->itemState & ODS_SELECTED); bool isGrayed = !!(dis->itemState & ODS_GRAYED); // fill menu item SelectObject(dis->hDC, GetSysColorBrush(isSelect ? COLOR_HIGHLIGHT : COLOR_MENU)); PatBlt(dis->hDC, dis->rcItem.left, dis->rcItem.top, dis->rcItem.right-dis->rcItem.left, dis->rcItem.bottom-dis->rcItem.top, PATCOPY); // draw image "check" if (isCheck) { SelectObject(dis->hDC, GetStockObject(isSelect ? WHITE_BRUSH : BLACK_BRUSH)); SelectObject(dis->hDC, GetStockObject(NULL_PEN)); Ellipse(dis->hDC, center(rcImg).x-4, center(rcImg).y-4, center(rcImg).x+4, center(rcImg).y+4); } // draw text int len = _tcslen(pMyMenuItemData->caption); SetBkMode(dis->hDC, TRANSPARENT); if (isGrayed) { if (isSelect){ SetTextColor(dis->hDC, GetSysColor(COLOR_GRAYTEXT)); DrawText(dis->hDC, pMyMenuItemData->caption, len, &rcTxt, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_EXPANDTABS); } else { RECT rcTxt2 = {rcTxt.left+1, rcTxt.top+1, rcTxt.right+1, rcTxt.bottom+1}; SetTextColor(dis->hDC, 0xFFFFFF); DrawText(dis->hDC, pMyMenuItemData->caption, len, &rcTxt2, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_EXPANDTABS); SetTextColor(dis->hDC, GetSysColor(COLOR_GRAYTEXT)); DrawText(dis->hDC, pMyMenuItemData->caption, len, &rcTxt , DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_EXPANDTABS); } } else { SetTextColor(dis->hDC, GetSysColor(isSelect ? COLOR_HIGHLIGHTTEXT : COLOR_MENUTEXT)); DrawText(dis->hDC, pMyMenuItemData->caption, len, &rcTxt, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_EXPANDTABS); } } //////////////////////////////////////////////////////////////////////////////// // Прочие функции //////////////////////////////////////////////////////////////////////////////// void InsertMenuItemData(HMENU hMenu, UINT item_ID, structMyMenuItemData *pMyMenuItemData) // вставка отрисовываемого мной меню { MENUITEMINFO mi = {sizeof(MENUITEMINFO), MIIM_ID | MIIM_TYPE | MIIM_DATA, MFT_OWNERDRAW, 0,item_ID,0,0,0, (ULONG)pMyMenuItemData, 0,0 }; InsertMenuItem( hMenu, item_ID, FALSE, &mi); } POINT center(const RECT &rc) { POINT result = { rc.left + (rc.right -rc.left)/2, rc.top + (rc.bottom-rc.top )/2}; return result; } //////////////////////////////////////////////////////////////////////////////// |
|||
|
||||
| Ars |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 325 Регистрация: 28.8.2003 Где: Московская обл. Репутация: 2 Всего: 2 |
Вот тебе пример:
-------------------- Есть многое на свете, друг Горацио, С чем очень долго можно прое..! |
|||
|
||||
| SeregaLBN |
|
|||
![]() Бывалый ![]() Профиль Группа: Участник Сообщений: 178 Регистрация: 3.10.2003 Где: Киев Репутация: нет Всего: нет |
Спасибо за примерчик.
Но в нём, к сожалению, реализовано по своему, а не так как в Винде: 1. Для меню создаётся свой HFONT, а не текущий системный. Я тоже изначально брал HFONT из GetStockObject(SYSTEM_FONT) или из GetStockObject(DEFAULT_GUI_FONT), но они возвращают HFONT в системе по умолчанию, а не текущий (указанный в теме(схеме) Windows). 2. Отступ текста слева в примере вычисляется как LOWORD(GetMenuCheckMarkDimensions()). Я тожже вычислял изначально это смещение из аналогичной функции GetSystemMetrics(SM_CXMENUCHECK). Но эта ф-ция, как сказано в хелпе, возвращает размеры битмапа check'a, а не само смещение текста. Т.е. те же вопросы остаются: 1. Как узнать текущий системный HFONT меню. 2. Как узнать смещение текста слева для пункта меню. Ниже приведена изменнёная ф-ция Cls_OnDrawItem, где о всём вышесказанном можно убедиться: // WM_DRAWITEM void Cls_OnDrawItem(HWND hwnd, const DRAWITEMSTRUCT * dis) { if (dis->CtlType != ODT_MENU) // error return; HFONT hFontOld = (HFONT)SelectObject(dis->hDC, (HFONT)GetStockObject(DEFAULT_GUI_FONT)); //HFONT hFontOld = (HFONT)SelectObject(dis->hDC, (HFONT)GetStockObject(SYSTEM_FONT)); //HFONT hFontOld = (HFONT)SelectObject(dis->hDC, (HFONT)GetStockObject(ANSI_FIXED_FONT)); // Размеры пункта меню dis->rcItem по ширине больше чем я задавал... // 1. К моим размерам, слева, добаляется область в которой обтображается // рисунок "check'a" - рисунок точки, галочки или прочий рисунок. // Отображатся рисунок должен мной. Проблема в том что я не понимаю // как верно узнать размер этой области. // 2. К моим размерам, справа, иногда, добавляется ещё область. // В этой области, если пункт меню ссылается на др. подменю, отображается // самой Wind'ой треугольник. structMyMenuItemData *pMyMenuItemData = (structMyMenuItemData*)dis->itemData; //LONG h = dis->rcItem.bottom - dis->rcItem.top; // высота пункта меню int checkX = GetSystemMetrics(SM_CXMENUCHECK); // Dimensions, in pixels, of the default menu check-mark bitmap // rcImg - прямоугольник рисунка "check'a" RECT rcImg = {dis->rcItem.left, dis->rcItem.top, dis->rcItem.left+checkX, dis->rcItem.bottom}; // rcTxt - прямоугольник в котором будет отображаться текст меню RECT rcTxt = {dis->rcItem.left+checkX, dis->rcItem.top, dis->rcItem.left+checkX+pMyMenuItemData->sizeMenuItem.x, dis->rcItem.bottom}; bool isCheck = !!(dis->itemState & ODS_CHECKED); bool isSelect = !!(dis->itemState & ODS_SELECTED); bool isGrayed = !!(dis->itemState & ODS_GRAYED); // fill menu item SelectObject(dis->hDC, GetSysColorBrush(isSelect ? COLOR_HIGHLIGHT : COLOR_MENU)); PatBlt(dis->hDC, dis->rcItem.left, dis->rcItem.top, dis->rcItem.right-dis->rcItem.left, dis->rcItem.bottom-dis->rcItem.top, PATCOPY); // draw image "check" if (isCheck) { SelectObject(dis->hDC, GetStockObject(isSelect ? WHITE_BRUSH : BLACK_BRUSH)); SelectObject(dis->hDC, GetStockObject(NULL_PEN)); Ellipse(dis->hDC, center(rcImg).x-4, center(rcImg).y-4, center(rcImg).x+4, center(rcImg).y+4); } // draw text int len = _tcslen(pMyMenuItemData->caption); SetBkMode(dis->hDC, TRANSPARENT); if (isGrayed) { if (isSelect){ SetTextColor(dis->hDC, GetSysColor(COLOR_GRAYTEXT)); DrawText(dis->hDC, pMyMenuItemData->caption, len, &rcTxt, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_EXPANDTABS); } else { RECT rcTxt2 = {rcTxt.left+1, rcTxt.top+1, rcTxt.right+1, rcTxt.bottom+1}; SetTextColor(dis->hDC, 0xFFFFFF); DrawText(dis->hDC, pMyMenuItemData->caption, len, &rcTxt2, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_EXPANDTABS); SetTextColor(dis->hDC, GetSysColor(COLOR_GRAYTEXT)); DrawText(dis->hDC, pMyMenuItemData->caption, len, &rcTxt , DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_EXPANDTABS); } } else { SetTextColor(dis->hDC, GetSysColor(isSelect ? COLOR_HIGHLIGHTTEXT : COLOR_MENUTEXT)); DrawText(dis->hDC, pMyMenuItemData->caption, len, &rcTxt, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_EXPANDTABS); } SelectObject(dis->hDC, hFontOld); } |
|||
|
||||
![]()
|
| Правила форума "С++:Общие вопросы" | |
|
|
Добро пожаловать!
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn |
| 0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
| 0 Пользователей: | |
| « Предыдущая тема | C/C++: Общие вопросы | Следующая тема » |
|
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |