Вы не авторизированы! Логин:  Пароль:  Запомнить:    Зарегистрироваться
Забыл пароль
 
 
 

Меню в стиле MS Office

SVD programming - Программирование Delphi, HTML, PHP, CGI. Обзоры софта, ReactOS и многое другое...
 
Главная - Новости - Публикации - Файлы - Ссылки - Форум Обратная связь
 


Друзья сайта ::

Сайтом управляют ::

Друзья сайта ::
Delphi » Меню в стиле MS Office
Автор: Таран Петр / Дата: 21:08 27.02.2006
Комментарии: Комментарии (0)
Рейтинг статьи: 0
Наверное многие видели меню, которое используется в MS Office или в самой среде Delphi: главные пункты выглядят как flat-кнопки -- плоские, но при перемещении над ними мыши как бы вспухающие. Кроме того, меню оформлено как панель инструментов и может пристыковываться к окну в любом месте.

Я предлагаю вариант реализации такого меню стандартными средствами VCL. Сразу замечу, что чтобы двигать меню произвольным образом нужно возиться дополнительно — TToolBar такой возможности не предоставляет.

Само меню оформляется как объект класса TToolBar, главные пункты меню — стандартные для панели инструментов кнопки TToolButton, выпадающие подменю — объекты TPopupMenu.

Итак, по пунктам.
1. Создаётся обычная панель инструментов MenuBar: TToolBar
У неё устанавливаются следующие свойства:

Код:
Color = clMenu //цвет как у меню
AutoSize = TRUE //авторазмер
Flat = TRUE //плоские кнопки, иначе на меню непохоже
List = TRUE //рекомендую, иначе картинки сверху будут, а не слева
ShowCaptions = TRUE //рисовать и надписи, не только картинки
BorderWidth = 0..2 //необязательно, ширина отступа
EdgeBorders = [ebBottom] //тоже по вкусу


Свойствами Align, Left, Top, Width, Height а так же Anchors выберите способ привязки и положение меню (панели инструментов) на форме.
Размер кнопок не задаётся и менять его нельзя.
2. Создаются кнопки-главные элементы меню, класс TToolButton.
У каждой кнопки устанавливаются свойства:

Код:
AllowAllUp = TRUE
AutoSize = TRUE
Grouped = TRUE
Caption = "Название пункта меню"


3. Для каждой кнопки создаётся своё подменю — объект класса TPopupMenu
В каждом из подменю задаётся соответствующий список пунктов. У кнопок на панели MenuBar свойство DropdownMenu заполняется ссылкой на соответствующий объект TPopupMenu. Всё? Нет. К сожалению установленный в системе шрифт нельзя задать в design-режиме, а потому:
4. Когда-нибудь, до использования меню (например в обработчике события формы OnCreate) должен исполниться следующий код:

Код:
var
nc: TNonClientMetrics;
s: TFontStyles; . . . .

begin

. . . .

//читаем системные настройки в структуру nc
nc.cbSize := sizeof(nc);
SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(nc), @nc, 0);

with MenuBar.Font do begin
Charset := nc.lfMenuFont.lfCharSet; //устанавливаем charset
Height := nc.lfMenuFont.lfHeight; //высоту шрифта
Name := nc.lfMenuFont.lfFaceName; //гарнитуру шрифта

//далее определяем набор стилей
s := [];
if nc.lfMenuFont.lfWeight >= FW_BOLD then
s := s + [fsBold];
if nc.lfMenuFont.lfItalic <> 0 then
s := s + [fsItalic];
if nc.lfMenuFont.lfUnderline <> 0 then
s := s + [fsUnderline];
if nc.lfMenuFont.lfStrikeOut <> 0 then
s := s + [fsStrikeOut];
Style := s;
end;


5. Есть ещё один существенный недостаток.
Созданное описанным образом меню не считается таковым с точки зрения Windows. Самое явное последствие — оно не подсвечивается по нажатию клавши Alt. Исправить данный недостаток удалось написанием обработчика сообщения WM_SYSCOMMAND, которое вызывается, в частности, для выделения пункта меню по горячей клавише. Заведите новый метод в private-секции формы с меню (имя метода и параметра роли не играет):

Код:
procedure SysCommand(var M: TWMSysCommand); message WM_SYSCOMMAND;


Реализация метода такова (код основан на исходниках TToolBar):

Код:
procedure TMain.SysCommand(var M: TWMSysCommand);
begin
//проверяется, что это команда - menu accelerator key, что дополнительной
//кнопки не нажато (только Alt), что никто не захватил (capture) мышь
if (M.CmdType and $FFF0 = SC_KEYMENU) and (M.Key = 0) and
(GetCapture() = 0) then begin
MenuBar.TrackMenu(nil);
//аргумент это кнопка, подменю которой вывалится; nil-никакой, такова
//стандартная реакция; если хотите, чтобы подменю первой кнопки
//сразу развернулось напишите
MenuBar.TrackMenu(MenuBar.Buttons[0]);
//можно и просто указать компонент-кнопку:
MenuBar.TrackMenu(mb_Options);
end else
inherited;
//условие не выполнили - обрабатываем по умолчанию
end;


Здесь правда возникает другая проблема -- становится недоступным через клавиатуру системное меню (которое с Переместить/Закрыть и пр.), но это уже не самое страшное.
Вот теперь всё! Можете запускать программу и смотреть что получилось. Несколько замечаний.
Описанное меню, по сравнению со стандартным имеет и дополнительные преимущества. Ведь созданные popup-менюшки можно использовать и отдельно, именно в качестве popup. Есть у Вас к примеру popup с операциями над каким-то объектом. Вы настраиваете этот объект так, чтобы по правому клику выскакивало меню и записываете соответствующий элемент в главное меню. Когда объект выделяется, кнопке в главном меню ставится Visible := TRUE, когда теряет фокус: Visible := FALSE. Вот и программа сразу солидней стала :) Можно вместо Visible использовать Enabled. Не забывайте и про событие OnPopup у класса TPopupMenu - это хорошее место для динамического скрытия или запрещения отдельных пунктов, в зависимости от состояния программы.
Можно ещё создать обычное TMainMenu (но не ссылаться на него в свойстве Menu у главной формы) и кнопкам в панели задавать не DropdownMenu, MenuItem и ссылаться не на отдельные popup-меню, а на пункты главного меню. Единственное преимущество такого способа это то, что меню создаётся реальное, системное. Пятый пункт, с обработкой WM_SYSCOMMAND в данном случае становится бессмысленным. Тем не менее этот вариант мне понравился меньше, поскольку первый более гибок. Смешать оба варианта не удалось -- с выпадением подменю проблемы начались. Так что рекомендую использовать TPopupMenu, как описано.
Примерчик, иллюстрирующий всё здесь написанное, а так же содержащий копию текста, который Вы сейчас читаете, содержится в архиве MSMenuExmpl.zip (10 K)

P.S. Уже после публикации статьи ко мне поступила просьба поместить ссылку на ресурс, который содержит интересную реализацию toolbar-меню:

http://www.akzhan.midi.ru/devcorner/samples/menubar/menubar.html
По сути, это pas-файл, описывающий компонент - наследник TToolBar, в который добавлены дополнительные возможности. А именно: (а) необходимые свойства TToolBar (см. выше) устанавливаются сразу в нужные значения; (б) добавлено свойство Menu: TMainMenu, позволяющее автоматически создать toolbar-меню, на основе существующего главного меню.

Основным недостатком можно считать отсутствие синхронизации между обычным главным меню и создаваемым toolbar-меню. Плюс, учтите всё сказанное во втором замечании.

Достоинство в том, что это законченный компонент, которому достаточно задать свойство Menu и не мучаться больше -- всё остальное оформление он выполнит сам.
Источник: http://www.ssgroup.fatal.ru
Автор : Таран Петр
Комментарии: Комментарии (0)

Внимание!

Друзья сайта
Голосование ::
Случайные статьи ::
Добавления в форуме ::
Новые комментарии ::
Пользователи on-line ::
0 пользователь, 165 гостей
 
Страница создана за 0.013 секунд

SQL общее время: 0.004 секунд
SQL запросов всего: 15
Администрация сайта не несет ответственности за содержание рекламных материалов, а так же за информацию размещаемой посетителями. При использовании материалов сайта ссылка на svdpro.info обязательна.

Powered by LDU 802

Рейтинг@Mail.ru
Copyright © 2005 - 2011 «SVD Programming»
Версия сайта для коммуникаторов
Обратная связь - Карта сайта