8
votes

I've tried my best and cannot figure out what happened here. It worked fine in Delphi 4. After upgrading to Delphi 2009, I don't know if this is the way it is supposed to work, or if it's a problem:

This is what my program's menu looks like in Design Mode under Delphi 2009:

enter image description here

Notice that every word in the Main Menu and the File submenu have one letter underlined. It is supposed to be like this. This underlined letter is called the Accelerator Key and is standard in Windows applications so that you can use the Alt-key and that letter to quickly select the menu item and then submenu item with the keyboard rather than with your mouse.

You get them this way by using the "&" character as part of the caption of the item, for example: Save &As...

When I run my application, and use the mouse to open the File menu, it looks like this:

enter image description here

The characters are underlined in the main menu, but are not underlined in the File menu.

If instead, I use the Alt-F key to open up the File submenu, then it looks correct like this:

enter image description here

and all the Accelerator Key letters are properly underlined.

I've played with the AutoHotKeys option but that's not the problem.

Has someone encountered this problem before? Is the example in the 2nd image correct behavior that I don't know of? Or is there some option or coding mistake that I might have missed?


Nov 2009 (one year later): mghie seems to have got to the root of this and figured out the problem. See his accepted answer below.

4

4 Answers

7
votes

There is a standard Windows setting (under display properties) to normally hide those accelerators unless the Alt key is held down. That would explain why opening the menu with Alt+F10 shows them for you. Maybe that's the cause?

[EDIT]: No, it's not. I just tried, and a simple TForm with a menu item shows the accelerator, but as soon as I add a TImageList and set the ImageIndex of the single menu item, or simply set OwnerDraw to true, then the accelerator underline disappears. I guess that really is a bug in the VCL.

BTW, this is on Windows XP.

Workaround:

I have debugged this using Delphi 2009 on Windows XP 64, and the root cause for the missing accelerators seems to be that Windows sends WM_DRAWITEM messages with the ODS_NOACCEL flag set, which it shouldn't if the system is set to show accelerators at all times. So you could say that it is not a VCL bug, but a Windows problem which the VCL does not work around.

However, you can work around it in your own code, you just need to reset the flag before passing the message to the VCL. Override the window proc

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

like so:

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;

This is demonstration code only, you should not call SystemParametersInfo() every time a WM_DRAWITEM message is received, but once at program start, and then every time your program receives a WM_SETTINGCHANGE message.

6
votes

It is a "feature" introduced with Windows 2000:

The Old New Thing: Why does Windows hide keyboard accelerators and focus rectangles by default?

It would appear that Delphi 4 didn't support this Windows feature.

To have 2000 and XP menus show accelerator keys, right-click an empty spot on the desktop, choose Properties, click the Appearance tab, and under Effects, uncheck Hide Underlined Letters for Keyboard Navigation until I Press the Alt Key. Click OK twice.

Not sure how to do it in Vista.

1
votes

I don't think it is a Delphi generated bug as you have the same behavior with Notepad on Vista. Also in Delphi itself BTW...
I must confess that I did not pay attention before your question. Thanks for pointing it out.

0
votes

As Jim McKeeth noted above (correctly), this is "by design" behavior. If the menus are triggered through keyboard action the accelerators should be shown, but if triggered by the mouse the accelerators are intentionally not shown.

I have my XP configured to show accelerators at all times, but a quick test with that option changed confirms that the menus should not show underlines either (Visual Studio responded as I expected, no underlines when using the mouse). However, Microsoft Office ignores this setting and always shows the underlines. So it looks like a bug in how the menus are drawn in Delphi (I don't have any experience with Delphi myself).

I found the option for Vista as well: http://www.vistax64.com/vista-general/42125-always-show-menu-underline-keyboard-accelerators.html

You can turn this on in the new Ease of Access Center (go to Control Panel, click Ease of Access and then click Ease of Access Center). In the Ease of Access Center, click Make the keyboard easier to use, and at the very bottom select the Underline keyboard shortcuts and access keys check box.

While doing further research I found this related bug on Delphi forums: http://qc.codegear.com/wc/qcmain.aspx?d=37403

It looks like in your case the child windows (the drawn menus) aren't getting or aren't handling WM_UIUPDATESTATE message from their parent window, which is what causes the redraw with accelerators.