Клавиши ускорителя меню не отображаются (Delphi 2009)

Я изо всех сил старался и не могу понять, что здесь произошло. Он отлично работал в Delphi 4. После обновления до Delphi 2009 я не знаю, так ли он должен работать или это проблема:

Вот как выглядит меню моей программы в режиме дизайна в Delphi 2009:

введите описание изображения здесь

Обратите внимание, что каждое слово в главном меню и подменю «Файл» подчеркнуто одной буквой. Так должно быть. Эта подчеркнутая буква называется клавишей акселератора и является стандартной для приложений Windows, поэтому вы можете использовать клавишу Alt и эту букву для быстрого выбора пункта меню, а затем элемента подменю с помощью клавиатуры, а не с помощью мыши.

Вы получаете их таким образом, используя символ «&» как часть заголовка элемента, например: Сохранить & как ...

Когда я запускаю свое приложение и использую мышь, чтобы открыть меню «Файл», оно выглядит так:

введите описание изображения здесь

Символы подчеркнуты в главном меню, но не подчеркнуты в меню «Файл».

Если вместо этого я использую клавишу Alt-F, чтобы открыть подменю File, то это выглядит так:

введите описание изображения здесь

и все буквы клавиш-ускорителей правильно подчеркнуты.

Я играл с опцией AutoHotKeys, но проблема не в этом.

Кто-нибудь раньше сталкивался с этой проблемой? Правильно ли ведет себя пример на втором изображении, о котором я не знаю? Или есть какая-то опция или ошибка в коде, которую я мог пропустить?


Ноябрь 2009 г. (год спустя): Кажется, mghie разобрался с корнем и разобрался в проблеме. См. Его принятый ответ ниже.


person lkessler    schedule 11.11.2008    source источник


Ответы (4)


Существует стандартная настройка Windows (в свойствах дисплея), которая обычно скрывает эти ускорители, если не удерживается клавиша Alt. Это объясняет, почему открытие меню с помощью Alt + F10 показывает их вам. Может в этом причина?

[РЕДАКТИРОВАТЬ]: Нет, это не так. Я только что попробовал, и простой TForm с элементом меню показывает ускоритель, но как только я добавляю TImageList и устанавливаю ImageIndex для отдельного элемента меню или просто устанавливаю OwnerDraw в значение true, подчеркивание ускорителя исчезает. Я предполагаю, что это действительно ошибка в VCL.

Кстати, это в Windows XP.

Временное решение:

Я отлаживал это с помощью Delphi 2009 в Windows XP 64, и основная причина отсутствия ускорителей, похоже, заключается в том, что Windows отправляет WM_DRAWITEM сообщения с установленным флагом ODS_NOACCEL, чего не должно быть, если система настроена на постоянное отображение ускорителей. . Таким образом, можно сказать, что это не ошибка VCL, а проблема Windows, которую VCL не может решить.

Однако вы можете обойти это в своем собственном коде, вам просто нужно сбросить флаг перед передачей сообщения в VCL. Переопределить процесс окна

protected
  procedure WndProc(var Message: TMessage); override;

вот так:

procedure TYourForm.WndProc(var Message: TMessage);
const
  ODS_NOACCEL = $100;
var
  pDIS: PDrawItemStruct;
  ShowAccel: BOOL;
begin
  if (Message.Msg = WM_DRAWITEM) then begin
    pDIS := PDrawItemStruct(Message.LParam);
    if (pDIS^.CtlType = ODT_MENU)
      and SystemParametersInfo(SPI_GETKEYBOARDCUES, 0, @ShowAccel, 0)
    then begin
      if ShowAccel then
        pDIS^.itemState := pDIS^.itemState and not ODS_NOACCEL;
    end;
  end;
  inherited;
end;

Это только демонстрационный код, вы не должны вызывать SystemParametersInfo() каждый раз при получении сообщения WM_DRAWITEM, а только один раз при запуске программы, а затем каждый раз, когда ваша программа получает сообщение WM_SETTINGCHANGE.

person mghie    schedule 11.11.2008
comment
Я тоже использую Windows XP. После этих ответов и моих размышлений по этому поводу и вашей помощи я согласен, что это может быть ошибка в VCL. Я сообщу об этом. - person lkessler; 12.11.2008
comment
Кстати, я получаю такое же поведение с Delphi 2007. - person mghie; 15.11.2008
comment
Mghie: Спасибо за дальнейшее исследование этого вопроса (год спустя !!) и за то, что нашли это. Я обновил отчет об ошибке на Embarcadero, добавив вашу информацию. Хотел бы я дать вам ++++++++++ 1 - person lkessler; 22.11.2009
comment
Вероятно, вызов SystemParametersInfo () при запуске программы будет достаточно в 99% случаев. - person lkessler; 22.11.2009
comment
Вдохновленный вашим кодом, я хочу заставить TPopupMenu всегда показывать подчеркивание, поэтому в WndProc я всегда вызываю pDIS^.itemState := pDIS^.itemState and not ODS_NOACCEL;, чтобы убедиться, что флаг ODS_NOACCEL исключен, но, к сожалению, это не работает. Какие-нибудь намеки? Спасибо. - person Edwin Yip; 28.08.2018
comment
@EdwinYip: Простите, не знаю. И я тоже не могу попробовать, у меня уже много лет не было доступа к последней версии Delphi. - person mghie; 28.08.2018
comment
@mghie, хотя в данном случае я использую Delphi XE4, а ОС - 7, вы, должно быть, обратили внимание на недавний выпуск бесплатной версии Community Edition Delphi, которая включает тот же набор функций, что и редакция Professional. , правильно? :) - person Edwin Yip; 28.08.2018
comment
@mghie Наконец-то я нашел время заняться этой маленькой проблемой, и оказалось, что нужно унаследовать от TPopupList и переопределить его метод WndProc. - person Edwin Yip; 13.03.2019

Это «функция», представленная в Windows 2000:

Старая новая вещь: Почему Windows скрывает ускорители клавиатуры и прямоугольники фокуса по умолчанию?

Похоже, что Delphi 4 не поддерживает эту функцию Windows.

Чтобы в меню 2000 и XP отображались клавиши-ускорители, щелкните правой кнопкой мыши пустое место на рабочем столе, выберите «Свойства», перейдите на вкладку «Внешний вид» и в разделе «Эффекты» снимите флажок Скрывать подчеркнутые буквы для навигации с помощью клавиатуры, пока я не нажму клавишу Alt . Дважды щелкните ОК.

Не знаю, как это сделать в Vista.

person Jim McKeeth    schedule 11.11.2008
comment
Я думал, у тебя есть ответ. Но, к сожалению, когда я посмотрел на эту опцию Скрыть подчеркнутые буквы (я никогда не знал об этом раньше), я обнаружил, что она не отмечена. - person lkessler; 11.11.2008
comment
Какая ОС? Ваши скриншоты выглядят как XP. Я просто попробовал его на XP, и он работает (снимите флажок, и появится подчеркивание клавиш-ускорителей). Возможно, вам нужно перезагрузить компьютер. - person Jim McKeeth; 12.11.2008

Я не думаю, что это ошибка, сгенерированная Delphi, так как у вас такое же поведение с Блокнотом в Vista. Также в самой Delphi, кстати ...
Должен признаться, что не обратил внимания на ваш вопрос. Спасибо, что указали на это.

person Francesca    schedule 11.11.2008
comment
Нет. В Delphi 2009 для меня все элементы подменю показывают клавишу акселератора, даже когда я выбираю меню с помощью мыши. Вот почему я подумал, что это какая-то настройка, а не Delphi или операционная система. Это определенно замороченная проблема, я уже потратил около 4 часов, пытаясь ее исправить. - person lkessler; 11.11.2008

Как Джим МакКит заметил выше (правильно), это поведение «задумано». Если меню запускается с помощью клавиатуры, ускорители должны отображаться, но если запускается мышью, ускорители намеренно не отображаются.

Моя XP настроена на постоянное отображение ускорителей, но быстрый тест с измененной опцией подтверждает, что в меню также не должно отображаться подчеркивание (Visual Studio отреагировала, как я и ожидал, подчеркивания при использовании мыши нет). Однако Microsoft Office игнорирует этот параметр и всегда показывает подчеркивание. Так что это похоже на ошибку в том, как меню отображаются в Delphi (у меня самого нет опыта работы с Delphi).

Я нашел вариант для Vista: http://www.vistax64.com/vista-general/42125-always-show-menu-underline-keyboard-accelerators.html

Вы можете включить это в новом Центре специальных возможностей (перейдите в Панель управления, нажмите «Легкость доступа», а затем нажмите «Центр специальных возможностей»). В Центре специальных возможностей нажмите «Сделать клавиатуру проще в использовании» и в самом низу установите флажок «Подчеркнуть сочетания клавиш и клавиши доступа».

В ходе дальнейшего исследования я обнаружил эту связанную ошибку на форумах Delphi: http://qc.codegear.com/wc/qcmain.aspx?d=37403.

Похоже, что в вашем случае дочерние окна (нарисованные меню) не получают или не обрабатывают сообщение WM_UIUPDATESTATE из своего родительского окна, что и вызывает перерисовку с помощью ускорителей.

person Step    schedule 17.12.2008
comment
Похоже, что в вашем случае дочерние окна (нарисованные меню) не получают или не обрабатывают сообщение WM_UIUPDATESTATE из своего родительского окна, что и вызывает перерисовку с помощью ускорителей - Точно! Это ошибка! - person lkessler; 17.12.2008