Версия для печати темы

Нажмите сюда для просмотра этой темы в обычном формате

Форум «Всё о Паскале» _ Делфи _ Кнопки WinAPI

Автор: TarasBer 28.05.2010 14:19

Созднаю кнопку со стилем ws_Child or ws_Visible or bs_PushButton or ws_TabStop и заголовком &A
Буква подчёркивается, но реакции на альт+А нету. Если создать две кнопки, то переключатель по таб между ними не работает. Горячие клавиши реализуются системой, или надо самому их отдельно регистрировать?

Автор: volvo 28.05.2010 14:44

Цитата
Если создать две кнопки, то переключатель по таб между ними не работает.
WM_TABSTOP работает в диалоговых окнах, то есть, если у родителя существует функция диалогового окна (а это совсем не то же самое, что простая функция окна) и присутствует (у родителя же) стиль WS_EX_CONTROLPARENT...

Автор: TarasBer 28.05.2010 15:07

Так что мне делать для того, чтобы кнопки срабатывали от клавиатуры? RegisterHotKey и всё?

Автор: volvo 28.05.2010 15:36

Можно - RegisterHotKey (это добавит данную комбинацию для всей системы). Если этого не хочется, а хочется - только когда свое приложение активно - можно создать файл ресурсов (*.RC), в нем описать ресурс типа ACCELERATORS, в котором перечислить все нужные горячие клавиши и связанные с ними сообщения, а в программе чуть-чуть изменить основной цикл обработки сообщений:

var hAccel: THandle;
// ...
hAccel := LoadAccelerators(hInstance, 'Accels'); // Accels - название таблицы акселераторов в RC-файле
while GetMessage (Msg, 0, 0, 0) do
if TranslateAccelerator(handleWnd, hAccel, Msg) = 0 then // Вот для чего все это делается
begin
TranslateMessage (Msg);
DispatchMessage (Msg);
end;

Автор: TarasBer 28.05.2010 15:48

Но в глубине души эти акселлераторы всё равно являются хоткеями, которые каждый раз все регистрируются/разрегестрировываются в ответ на wm_Activate?

Автор: volvo 28.05.2010 16:51

Ничего не регистрируется/разрегистрируется.

Для обработке Хоткея Windows проделывает дополнительную работу, и всем приложениям, установившим этот хоткей в очередь сообщений назначенного RegisterHotKey-ем приложения пишет WM_HOTKEY всегда, независимо от того активно это приложение или нет.

А если приложение, ждущее акселератор, активно - то код нажатой клавиши кроме всего прочего поступает в очередь сообщений этого приложения, и естественно обрабатывается TranslateAccelerator-ом. Если НЕактивно - то код нажатой клавиши в очередь не пишется.

Автор: TarasBer 31.05.2010 14:34

> if TranslateAccelerator(handleWnd, hAccel, Msg) = 0

А тут в качестве handleWnd должно быть активное окно или главное? И тогда для каждого окна проекта нужна своя таблица акселераторов?

Автор: volvo 31.05.2010 15:23

Цитата
для каждого окна проекта нужна своя таблица акселераторов?
Да. Техника описана у MS: http://support.microsoft.com/kb/82171

( для случая MDI-интерфейса существует также http://msdn.microsoft.com/en-us/library/ms644926%28VS.85%29.aspx )

Автор: TarasBer 31.05.2010 15:46

На пункты меню действует, на bs_PushButton - тоже, а вот на bs_AutoRadioButton - нет. Что делать?

Автор: volvo 31.05.2010 16:25

В функции окна прописано, что при получении соответствующего сообщения надо включить AutoRadioButton?

TranslateAccelerator не занимается обработкой сообщений, он только переводит код нажатой клавиши в сообщение WM_COMMAND. Там его и надо обрабатывать...

Автор: TarasBer 31.05.2010 17:03

> В функции окна прописано, что при получении соответствующего сообщения надо включить AutoRadioButton?

Не написано. Написал, заработало. Вот только как сделать, чтобы остальные элементы радиогруппы выключились? Я это сделал через ж
SendMessage(H, wm_LButtonDown, 0, 0);
SendMessage(H, wm_LButtonUp, 0, 0);
А как сделать нормально?

Автор: TarasBer 31.05.2010 17:25

А, всё, сообщение bm_Click можно послать. Оно вроде не приводит к рекурсивной обработке wm_Comand?

Автор: volvo 31.05.2010 17:32

Если создавать радио-кнопки так:

  (*
WS_GROUP - значит, началась новая группа радио-кнопок. Все последующие
AUTORADIOBUTTON-ы будут добавляться именно в эту группу. Нужна еще одна -
при создании первой кнопки, которая будет в новой группе, надо опять указать
WS_GROUP
*)
hRBtn_1 := CreateWindowEx(0, 'BUTTON', 'Опция &0',
WS_GROUP or BS_AUTORADIOBUTTON or WS_VISIBLE or WS_CHILD,
15, 132, 95, 25, handleWnd, RBTN_0, hInstance, nil);
hRBtn_2 := CreateWindowEx(0, 'BUTTON', 'Опция &1',
BS_AUTORADIOBUTTON or WS_VISIBLE or WS_CHILD,
15, 154, 155, 25, handleWnd, RBTN_1, hInstance, nil);
hRBtn_3 := CreateWindowEx(0, 'BUTTON', 'Опция &2',
BS_AUTORADIOBUTTON or WS_VISIBLE or WS_CHILD,
15, 176, 155, 25, handleWnd, RBTN_2, hInstance, nil);
CheckRadioButton(handleWnd, RBTN_0, RBTN_2, RBTN_0); // включаем любую кнопку в группе


, а WM_COMMAND обрабатывать так:
  case AMessage of
WM_COMMAND:
begin
case LoWord(WParam) of
RBTN_0 .. RBTN_2: // Смотрим только одну группу. Если есть еще одна - отдельно
begin
// В группе включить нужную. Естественно, остальные выключатся
CheckRadioButton(Window, RBTN_0, RBTN_2, LoWord(WParam));
end;
end

, то не надо никакой эмуляции нажатия на кнопку мыши. Радио-кнопки они на то и радио, что в одной группе может быть одновременно выбрана только одна такая кнопка...

Автор: TarasBer 31.05.2010 17:39

> Если создавать радио-кнопки так:

Ну я так и делал.

> // Смотрим только одну группу. Если есть еще одна - отдельно

Каждую группу отдельно?
Мышкой сэмулировать проще... К тому же позволяет, ничего не меняя, вешать хоткеи на что угодно, например, на поля ввода.

Автор: volvo 31.05.2010 17:51

Цитата
Мышкой сэмулировать проще...
Проще - не всегда правильнее... Дело твое, хочешь потом ловить баги из-за того, что не играл по правилам ОС - лови. Я предпочитаю писать программы по-другому.

Цитата
К тому же позволяет, ничего не меняя, вешать хоткеи на что угодно, например, на поля ввода.
Угу, вон оно, уже позволило тебе словить отсутствие работоспособности. Продолжай в том же духе. Ничего не меняя, главное...

P.S.
Цитата
Я это сделал через ж
, но
Цитата
Мышкой сэмулировать проще...
А потом удивляются, что http://www.gunsmoker.ru/2010/05/90.html