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




menu delphi-2009 (3)

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

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

alt text http://www.beholdgenealogy.com/img/menu1.gif

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

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

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

alt text http://www.beholdgenealogy.com/img/menu2.gif

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

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

alt text http://www.beholdgenealogy.com/img/menu3.gif

и все буквы клавиш ускорителя должным образом подчеркнуты.

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

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

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


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

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

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

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

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


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


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

[EDIT]: Нет, это не так. Я просто попробовал, и простой TForm с пунктом меню показывает ускоритель, но как только я добавляю TImageList и устанавливаю ImageIndex из одного элемента меню или просто устанавливаю OwnerDraw в true, тогда подчеркивание ускорителя исчезает. Я думаю, что это действительно ошибка в VCL.

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

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

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

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

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 .