Rambler's Top100
"Knowledge itself is power"
F.Bacon
Поиск | Карта сайта | Помощь | О проекте | ТТХ  
 Сокровищница
  
 

Фильтр по датам

 
 К н и г и
 
Книжная полка
 
 
Библиотека
 
  
  
 


Поиск
 
Поиск по КС
Поиск в статьях
Яndex© + Google©
Поиск книг

 
  
Тематический каталог
Все манускрипты

 
  
Карта VCL
ОШИБКИ
Сообщения системы

 
Форумы
 
Круглый стол
Новые вопросы

 
  
Базарная площадь
Городская площадь

 
   
С Л С

 
Летопись
 
Королевские Хроники
Рыцарский Зал
Глас народа!

 
  
ТТХ
Конкурсы
Королевская клюква

 
Разделы
 
Hello, World!
Лицей

Квинтана

 
  
Сокровищница
Подземелье Магов
Подводные камни
Свитки

 
  
Школа ОБЕРОНА

 
  
Арсенальная башня
Фолианты
Полигон

 
  
Книга Песка
Дальние земли

 
  
АРХИВЫ

 
 

Сейчас на сайте присутствуют:
 
  
 
Во Флориде и в Королевстве сейчас  19:34[Войти] | [Зарегистрироваться]

Меню на основе панели инструментов

Peter Taran
дата публикации 20-03-2001 00:00

Меню на основе панели инструментов

Наверное многие видели меню, которое используется в 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;
Здесь правда возникает другая проблема -- становится недоступным через клавиатуру системное меню (которое с Переместить/Закрыть и пр.), но это уже не самое страшное.
Вот теперь всё! Можете запускать программу и смотреть что получилось.

Несколько замечаний.
  1. Описанное меню, по сравнению со стандартным имеет и дополнительные преимущества. Ведь созданные popup-менюшки можно использовать и отдельно, именно в качестве popup. Есть у Вас к примеру popup с операциями над каким-то объектом. Вы настраиваете этот объект так, чтобы по правому клику выскакивало меню и записываете соответствующий элемент в главное меню. Когда объект выделяется, кнопке в главном меню ставится Visible := TRUE, когда теряет фокус: Visible := FALSE. Вот и программа сразу солидней стала :) Можно вместо Visible использовать Enabled. Не забывайте и про событие OnPopup у класса TPopupMenu - это хорошее место для динамического скрытия или запрещения отдельных пунктов, в зависимости от состояния программы.
  2. Можно ещё создать обычное 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 и не мучаться больше -- всё остальное оформление он выполнит сам.




Смотрите также материалы по темам:
[TFont] [TMainMenu] [TPopupMenu] [TToolBar] [TToolButton] [Работа с меню] [Меню (WinAPI)]

 Обсуждение материала нет сообщений
  
Время на сайте: GMT минус 5 часов

Если вы заметили орфографическую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter.
Функция может не работать в некоторых версиях броузеров.

Web hosting for this web site provided by DotNetPark (ASP.NET, SharePoint, MS SQL hosting)  
Software for IIS, Hyper-V, MS SQL. Tools for Windows server administrators. Server migration utilities  

 
© При использовании любых материалов «Королевства Delphi» необходимо указывать источник информации. Перепечатка авторских статей возможна только при согласии всех авторов и администрации сайта.
Все используемые на сайте торговые марки являются собственностью их производителей.

Яндекс цитирования