Практика
ActionList – укрощение клавиатуры

:: Меню ::
:: На главную ::
:: FAQ ::
:: Заметки ::
:: Практика ::
:: Win API ::
:: Проекты ::
:: Скачать ::
:: Секреты ::
:: Ссылки ::

:: Сервис ::
:: Написать ::

:: MVP ::

:: RSS ::

Яндекс.Метрика


Использование горячих клавиш в приложении – тема, которая всегда будет актуальной. И чем “крупнее” ваше приложение, тем нагруженнее меню и тем чаще пользователь будет желать пользоваться горячими клавишами. Добавить горячие клавиши в приложение можно различными способами. Так, к примеру, если горячие клавиши дублируют действие какого либо пункта главного меню, то и прописать их логичнее в свойстве ShortCut этого пункта меню. Но в это свойство можно записать лишь одну комбинацию, а как быть в случае, если за выполнение одного действия должны отвечать два (или более) сочетания горячих клавиш (например, за действие “обновить” могут отвечать клавиши F5 и Ctrl + R, как это реализовано в различных Web браузерах). Или другой случай – сочетание горячих клавиш должно запускать функционал, доступа к которому нет из главного меню? И тут у нас есть выбор, можно зарегистрировать горячие клавиши с помощью функции RegisterHotKey и потом обрабатывать сообщение WM_HOTKEY, а можно воспользоваться компонентом ActionList. Лично мне второй вариант нравится больше, и именно о нем пойдет дальше речь.

Казалось бы, заезженная тема, все и так понятно – бросили компонент, создали Action, в свойстве ShortCut выбрали из списка комбинацию, которая нас устраивает и все готово, можно пользоваться. И все вроде бы хорошо, кроме того, что этот список достаточно скуден. Что же нам делать, если в нем не оказалось нужной нам комбинации? Сейчас разберемся, а в качестве демонстрации создадим обработчик для пункта меню на основе экшена. Бросим на форму ActionList, создадим Action, напишем его обработчик, определим свойства ShortCut и Caption, и пропишем его в свойстве Action у пункта меню. Сразу бросается в глаза то, что значения свойств Caption и ShortCut у пункта меню изменились, и стали такими же, как у экшена, а сама комбинация горячих клавиш отображается в пункте главного меню, справа от заголовка. Теперь разберемся с назначением нескольких сочетаний горячих клавиш на одно действие. И для этого вовсе не обязательно создавать несколько Action’ов, достаточно обратить внимание на свойство SecondaryShortcuts, являющееся объектом класса TShortCutList (TStringList). В его свойстве Items хранятся названия горячих клавиш: те, которые вводятся в Object Inspector. А в свойстве Objects список «закодированных» в тип TShortCut горячих клавиш, соответствующих тем, что находятся в свойстве Items.

А вот это уже интересно! Список горячих клавиш представляет собой список строк, а кодирование в тип TShortCut очевидно происходит во время компиляции программы. Свойство ShortCut так же имеет тип TShortCut, а, следовательно, все сказанное выше относится и к нему. Покопавшись в модуле Menus можно найти функции TextToShortCut и ShortCutToText, отвечающие за это преобразование. Посмотрев реализацию функции TextToShortCut, замечаем, что она обращается к массиву MenuKeyCaps:

type
  TMenuKeyCap = (mkcBkSp, mkcTab, mkcEsc, mkcEnter, mkcSpace, mkcPgUp,
    mkcPgDn, mkcEnd, mkcHome, mkcLeft, mkcUp, mkcRight, mkcDown, mkcIns,
    mkcDel, mkcShift, mkcCtrl, mkcAlt);

var
  MenuKeyCaps: array[TMenuKeyCap] of string = (
    SmkcBkSp, SmkcTab, SmkcEsc, SmkcEnter, SmkcSpace, SmkcPgUp,
    SmkcPgDn, SmkcEnd, SmkcHome, SmkcLeft, SmkcUp, SmkcRight,
    SmkcDown, SmkcIns, SmkcDel, SmkcShift, SmkcCtrl, SmkcAlt);

Элементы массива – обычные строковые константы, объявленные в модуле Consts:

SmkcBkSp = 'BkSp';
SmkcTab = 'Tab';
SmkcEsc = 'Esc';
SmkcEnter = 'Enter';
SmkcSpace = 'Space';
SmkcPgUp = 'PgUp';
SmkcPgDn = 'PgDn';
SmkcEnd = 'End';
SmkcHome = 'Home';
SmkcLeft = 'Left';
SmkcUp = 'Up';
SmkcRight = 'Right';
SmkcDown = 'Down';
SmkcIns = 'Ins';
SmkcDel = 'Del';
SmkcShift = 'Shift+';
SmkcCtrl = 'Ctrl+';
SmkcAlt = 'Alt+';

Значит, из этих строк мы можем собирать свои комбинации горячих клавиш, в том числе и такие, которые отсутствуют в выпадающем списке свойства ShortCut. Вот несколько примеров – 'Ctrl+Up', 'Ctrl+Alt+Down', 'Shift+Tab', 'Alt+BkSp', 'Ctrl+Alt+Enter'. Разумеется, сочетания клавиш, занятые системой (например, 'Ctrl+Shift+Esc'), в приложении работать не будут.

Движемся дальше. Допустим, нам нужно задействовать в своем приложении цифровую клавиатуру, мы хотим при нажатии комбинации клавиш 'Ctrl +' и 'Ctrl –' осуществлять масштабирование чего либо. Но как это записать в свойство ShortCut в виде строки? За строчку 'Ctrl++' Delphi ругнется на нас чем-то вроде 'Invalid property value', а строка 'Ctrl+-' хоть и запишется, но работать не будет. Как же быть? Оказывается, для такого случая можно использовать слово 'Num', хотя найти в Delphi константу с таким значением мне не удалось (может быть плохо искал). И так, нужные нам строки будут выглядеть следующим образом 'Ctrl+Num +' и 'Ctrl+Num -' (пробел после Num является обязательным).

Вполне может возникнуть ситуация, когда вы захотели использовать одну из дополнительных функциональных клавиш, для которых нет строкового эквивалента. К примеру, вы запустили в отдельном потоке длительную операцию, и готовы предоставить пользователю возможность приостановить/возобновить поток нажатием на кнопку Pause. Как быть? Выход есть, установим это свойство программно:

uses
  Menus;

procedure TForm1.FormCreate(Sender: TObject);
begin
   Action1.ShortCut := ShortCut( VK_PAUSE, [] );
end;

Аналогично следует поступать в случае, когда нам хочется задействовать в своем приложении мультимедийные клавиши, такие например, как Home, Back, Forward, Refresh, Stop и т.д. Загвоздка с ними такая же – для них нет специального строкового эквивалента, кроме того они не эмулируют нажатие той или иной комбинации, а имеют собственные коды:

Название Код Константа Вызываемое приложение (по умолчанию)
Группа - Internet
Back 166 VK_BROWSER_BACK
Forward 167 VK_BROWSER_FORWARD
Stop 169 VK_BROWSER_STOP
Favorites 171 VK_BROWSER_FAVORITES
Search 170 VK_BROWSER_SEARCH Windows Search
Refresh 168 VK_BROWSER_REFRESH
Home 172 VK_BROWSER_HOME Браузер по умолчанию
Mail 180 VK_LAUNCH_MAIL Почтовый клиент по умолчанию
Группа - Audio
Mute 173 VK_VOLUME_MUTE Включает/выключает звук в системе
-Vol 174 VK_VOLUME_DOWN Уменьшает уровень звука в системе
+Vol 175 VK_VOLUME_UP Увеличивает уровень звука в системе
Media 181 VK_LAUNCH_MEDIA_SELECT Windows Media Player
Stop 178 VK_MEDIA_STOP
Play/Pause 179 VK_MEDIA_PLAY_PAUSE
Next 176 VK_MEDIA_NEXT_TRACK
Prev 177 VK_MEDIA_PREV_TRACK
Другие
Calculator 183 VK_LAUNCH_APP2 Калькулятор
My Computer 182 VK_LAUNCH_APP1 Мой компьютер

За подробностями и кодами других клавиш обращайтесь к модулю Windows.pas.

Мы можем поступить как в случае с клавишей Pause, а можем вспомнить про свойство Objects, которое хранит «закодированные» в тип TShortCut горячие клавиши. В дизайнере с ним сделать ничего не получится, зато в RunTime нет никаких проблем:

procedure TForm1.FormCreate(Sender: TObject);
begin
   Action1.SecondaryShortCuts.AddObject( '', TObject( ShortCut( VK_PAUSE, [] ) ) );
end;

Вот мы и добились того, чего хотели – получили контроль над клавиатурой. На последок хотелось бы сказать несколько слов о функциях TextToShortCut и ShortCutToText. Они прекрасно подойдут в случае, если вы хотите предоставить пользователю возможность самостоятельной настройки горячих клавиш в приложении. В таком случае эти функции можно использовать для сохранения пользовательских горячих клавиш в конфигурационном файле и считывании их оттуда. Но следует помнить – не все горячие клавиши можно преобразовать в строку (внимательно смотрим на массив MenuKeyCaps и константы, являющиеся значениями этого массива). Убедиться в этом нам поможет следующий код:

Action1.ShortCut := TextToShortCut( ShortCutToText( ShortCut( VK_F1, [] ) ) ); // Будет работать
Action1.ShortCut := TextToShortCut( ShortCutToText( ShortCut( VK_PAUSE, [] ) ) ); // Не будет работать

Удачного программирования!

.: Пример к данной статье :.


При использовании материала - ссылка на сайт обязательна