Визуальный вид меню, и что такое меню?

Rajd

Люди, люди, человеки, помогите будьте так любезны. Я второй день мучаю интернет и свою библиотеку(она маленькая(нужных мне книг мало)). 1) Каким образом у стандартного меню поменять фон, а также как заменить фон у надписей.(к примеру на чисто зеленый или градиентный).А то я сталкиваюсь только с тем как создать меню и через ресурсы и так чистым WINAPI. Как сменить надпись запросто попадается, а вот как поменять цветовые составляющие нет. Еще одна проблема большинство примеров на Delphi, а я в нем как в комнате без окон и дверей(в смысле наощупь) несколько лучше двигаюсь в С++.2) Это немного повеселей, а чем собственно является меню? Это же окно, да?
11 ответов

Rajd

1) насколько я понимаю, цвет фона меню (размер его шрифта и т.п.) меняется не функциями API, а ключами реестра. Какими именно не скажу, самому интересно. В WinXP можно добиться так: контекстное меню на рабочем столе->Свойства->Оформление->Элемент->Строка меню->Цвет 1. Насчет градиентного меню сомневаюсь, что система ШТАТНО такое предусматривает; 2) поскольку меню имеет хендл, то это некий объект системы. Наверное правильно его именовать окном. Ведь скажем чекбоксы, простые кнопки, строка состояния и многие другие, если не все, визуальные элементы, создаются функцией с красноречивым названием CreateWindow().


Rajd

1) насколько я понимаю, цвет фона меню (размер его шрифта и т.п.) меняется не функциями API, а ключами реестра. Какими именно не скажу, самому интересно. В WinXP можно добиться так: контекстное меню на рабочем столе->Свойства->Оформление->Элемент->Строка меню->Цвет 1. Насчет градиентного меню сомневаюсь, что система ШТАТНО такое предусматривает;
Позволь с тобой не согласиться. Реестр указывает лишь на значения, необходимые системе по умолчанию. Однако без добавления манифеста к программе её внешний вид очень похож на 98, и соответсвенно цвета меню тоже, после добавления манифеста оно приобрело визуальный вид системы, правда с некоторыми огрехами. Следовательно вид меню можно изменить через WinAPI. Кроме того существуют функции: SetMenuItemInfo и ModifyMenu которые занимаются изменением всех составляющих меню. Правда я пока не нашел хорошого объяснения как они работают. и Как ими пользоваться.


Rajd

Я склоняюсь к мнению, что внешний вид меню - общесистемная настройка. Поэтому и предположил, что он устанавливается через параметр реестра (или какой-нибудь ini-файл). Я еще не встречал программ, у которых какое-то особенное меню. Вот еще аргумент в пользу сказанного. Есть такая популярная среда разработки Delphi. Так вот, даже в самых последних ее версиях компонент TMainMenu не имеет настроек цвета, градиента и т.п. Зная тщательность Delphi в плане пользовательского интерфейса, невозможно предположить, чтобы в компонент не были включены возможности, стандартно предоставляемые WinAPI. Скидываю тебе описание функций ModifyMenu() и SetMenuItemInfo() из MSDN. Ничего интересного там для тебя нет


Rajd

Цвет фона меню можно менять. Собственно вот меню в стиле Офис 2003 с красным фоном.


Rajd

ээ, меню, которое предоставляют функции winapi никак не настроить. То меню, что в ворде - совсем другое меню


Rajd

Каюсь, про MS Office я как-то забыл :-) А какое же там меню - как оно создается и как с ним работать???


Rajd

ээ, меню, которое предоставляют функции winapi никак не настроить. То меню, что в ворде - совсем другое меню
Это меню созданно средствами WinAPI Они не имеет никакого отношения к меню ворда, это только цветовая гамма совпадает. А меню полностью на API. Прога вообще на бейсике написанна.PS. Что-нибудь про OWNERDRAW слышали?


Rajd

Слышали. А как его использовать? :-)


Rajd

Вот статейка по этому поводу
До сих пор наши меню состояли только из текстовых строк и разделительных линий, однако вы можете сделать меню из произвольных графических изображений. Если вам не нравится стандартная отметка строк меню при помощи галочки, ее можно заменить на любое графическое изображение (небольшого размера). Для того чтобы вместо строк в меню расположить графические изображения bitmap, эти изображения надо загрузить из ресурсов или создать другим способом, а затем идентификатор изображения указать в качестве последнего параметра функций AppendMenu или InsertMenu. Необходимо также использовать флаг MF_BITMAP : AppendMenu(hmenuLineStyle, MF_ENABLED | MF_BITMAP, CM_LINE1, (LPCSTR)(DWORD)hbmpLine1);Если вы загрузили bitmap при помощи функции LoadBitmap, не забудьте перед завершением приложения (или после удаления соответствующего меню) удалить bitmap функцией DeleteObject. Для замены стандартного символа отметки строки меню (галочки) на другой предназначена функция SetMenuItemBitmaps: BOOL WINAPI SetMenuItemBitmaps(HMENU hmenu, UINT idItem, UINT fuFlags, HBITMAP hbmUnckecked, HBITMAP hbmChecked);Эта функция выполняет замену символа отметки для строки idItem меню hmenu. Для параметра fuFlags можно использовать два значения - MF_BYCOMMAND и MF_BYPOSITION . Если указан флаг MF_BYCOMMAND, параметр idItem определяет идентификатор элемента меню, для которого выполняется замена символа отметки. Если указан флаг MF_BYPOSITION, параметр idItem определяет порядковый номер элемента меню. Параметр hbmUnckecked представляет собой идентификатор изображения, которое будет расположено слева от неотмеченной строки меню, параметр hbmChecked - идентификатор изображения символа отметки. Любой из последних параметров или оба можно указывать как NULL. В этом случае будет использовано изображение по умолчанию (т. е. слева от неотмеченной строки не будет никакого изображения, слева от отмеченной - галочка). Однако есть небольшая тонкость. Вы не можете использовать для отметки строк меню изображения bitmap любого размера. Нужные размеры изображения необходимо определить при помощи функции GetMenuCheckMarkDimensions : DWORD WINAPI GetMenuCheckMarkDimensions(void);Младшее слово возвращаемого значения содержит ширину изображения, старшее - высоту: DWORD dwMark; WORD wWidth, wHeight; dwMark = GetMenuCheckMarkDimensions(); wWidth = LOWORD(dwMark); wHeight = HIWORD(dwMark);Тонкость заключается в том, что на момент трансляции исходного текста приложения вы не можете знать требуемые размеры изображения. Так как на этапе сборки загрузочного модуля приложения размеры изображения неизвестны, вы (строго говоря) не можете просто загрузить соответствующие изображения bitmap из ресурсов приложения. Выход заключается в том, чтобы в процессе инициализации приложения определить требуемые размеры изображения, вызвав функцию GetMenuCheckMarkDimensions, а затем подготовить нужные изображения bitmap в памяти. Однако, так как мы еще не рассказывали вам подробно об изображениях bitmap, в примере GMENU, приведенном в следующем разделе, мы для простоты (данная глава посвящена меню, а не изображениям bitmap) все-таки загрузили изображения размером 10 х 10 пикселов из ресурсов. При создании строки меню вы можете указать константу MF_OWNERDRAW. В этом случае функция окна, работающая с данным меню, должна будет сама нарисовать строку меню. Можно нарисовать любое изображение. Перед тем как отобразить меню, содержащее строки со стилем MF_OWNERDRAW , операционная система Windows посылает в функцию окна сообщение WM_MEASUREITEM . В ответ на это сообщение функция должна сообщить Windows размеры окна, необходимые для изображения строки меню. Когда надо отобразить строку меню, Windows посылает в родительское окно сообщение WM_DRAWITEM . Вместе с этим сообщением передается вся информация, необходимая родительскому окну для того чтобы нарисовать строку меню. Параметр lParam сообщения WM_MEASUREITEM содержит указатель на структуру MEASUREITEMSTRUCT , описанную в файле windows.h: typedef struct tagMEASUREITEMSTRUCT { UINT CtlType; UINT CtlID; UINT itemID; UINT itemWidth; UINT itemHeight; DWORD itemData; } MEASUREITEMSTRUCT;В этом же файле описаны ближний и дальний указатели на эту структуру: typedef MEASUREITEMSTRUCT NEAR* PMEASUREITEMSTRUCT; typedef MEASUREITEMSTRUCT FAR* LPMEASUREITEMSTRUCT;Когда функция окна получает сообщение WM_MEASUREITEM, поле CtlType содержит значение ODT_MENU, в поле itemID находится идентификатор строки меню, а в поле itemData - 32-разрядное значение, переданное через параметр lpNewItem функций AppendMenu, InsetMenu, ModifyMenu. Поле CtlID не используется. Получив сообщение WM_MEASUREITEM, функция окна должна, пользуясь значением указателя из lParam, записать в поле itemWidth ширину строки меню, а в поле itemHeight - высоту строки меню. Параметр lParam сообщения WM_DRAWITEM содержит указатель на структуру DRAWITEMSTRUCT . Эта структура и соответствующие указатели описаны в файле windows.h следующим образом: typedef struct tagDRAWITEMSTRUCT { UINT CtlType; UINT CtlID; UINT itemID; UINT itemAction; UINT itemState; HWND hwndItem; HDC hDC; RECT rcItem; DWORD itemData; } DRAWITEMSTRUCT; typedef DRAWITEMSTRUCT NEAR* PDRAWITEMSTRUCT; typedef DRAWITEMSTRUCT FAR* LPDRAWITEMSTRUCT;Приведем назначение отдельных полей структуры DRAWITEMSTRUCT при ее использовании для меню. Имя поля Описание CtlType Тип органа управления. Для меню принимает значение ODT_MENU CtlID Идентификатор органа управления. Для меню не используется itemID Идентификатор строки меню itemAction Действия, которые необходимо выполнить при изображении строки меню. Определен в виде отдельных битовых флагов: ODA_DRAWENTIRE - требуется перерисовать всю строку; ODA_FOCUS этот бит устанавливается в 1, если строка меню получила или потеряла фокус ввода, новое состояние строки можно узнать, проанализировав содержимое поля itemState; ODA_SELECT изменилось состояние строки меню, для уточнения состояния необходимо использовать поле itemState itemState Вид, в котором необходимо изобразить строку меню. Определен в виде отдельных битовых флагов: ODS_CHECKED выбрана строка меню; ODS_DISABLED - строка неактивна; ODS_FOCUS строка получила фокус ввода; ODS_GRAYED строка меню должна быть изображена серым цветом; ODS_SELECTED - строка выбрана hwndItem Идентификатор меню hDC Контекст устройства, который необходимо использовать для рисования строки меню rcItem Прямоугольные границы, внутри которых необходимо нарисовать строку itemData Содержит 32-битовое значение, полученное через параметр lpNewItem функций AppendMenu, InsetMenu, ModifyMenu
Смысл в том, что программа сама должна прорисовывать меню. Тогда получится то, что я выложил в качестве примера. А ещё есть DLLка coolmenu.dll, облегчающая создание своего стиля меню


Rajd

Смысл в том, что программа сама должна прорисовывать меню.
Так я и думал. Ок. Спасибо за разъяснение, спасибо за помощь. Пошел разбираться как это работает.
Есть такая популярная среда разработки Delphi.
Либо я дурак, либо лыжи не едут, о языке Delphi слышал, а вот о среде разработки впервые.


Rajd

Либо я дурак, либо лыжи не едут, о языке Delphi слышал, а вот о среде разработки впервые.
Вообще-то язык, используемый в Delphi, называется Pascal. Еще он используется в таких средах разработки как Turbo Pascal, Free Pascal, Kylix, Lazarus. Если следовать твоей логике, то Visual Studio C++, Borland C++ Builder и Watcom C++ - суть три разных языка программирования. Полная чушь. P.S. Я о сути дела, а не о маркетинговых ходах Borland