8

我已经尽力了,无法弄清楚这里发生了什么。它在 Delphi 4 中运行良好。升级到 Delphi 2009 后,我不知道这是它应该工作的方式,还是有问题:

这是我的程序菜单在 Delphi 2009 下的设计模式下的样子:

在此处输入图像描述

请注意,主菜单和文件子菜单中的每个单词都有一个字母下划线。它应该是这样的。这个带下划线的字母称为加速键,是 Windows 应用程序中的标准,因此您可以使用 Alt 键和该字母快速选择菜单项,然后使用键盘而不是鼠标选择子菜单项。

您可以通过使用“&”字符作为项目标题的一部分来获取它们,例如:Save &As...

当我运行我的应用程序并使用鼠标打开文件菜单时,它看起来像这样:

在此处输入图像描述

字符在主菜单中带有下划线,但在“文件”菜单中没有下划线。

相反,如果我使用 Alt-F 键打开文件子菜单,那么它看起来是正确的,如下所示:

在此处输入图像描述

并且所有加速键字母都有适当的下划线。

我玩过 AutoHotKeys 选项,但这不是问题。

以前有人遇到过这个问题吗?第二张图片中的示例是我不知道的正确行为吗?或者是否有一些我可能遗漏的选项或编码错误?


2009 年 11 月(一年后):mghie 似乎已经找到了问题的根源并找出了问题所在。请参阅下面他接受的答案。

4

4 回答 4

7

有一个标准的 Windows 设置(在显示属性下)通常隐藏这些加速器,除非按住 Alt 键。这可以解释为什么使用 Alt+F10 打开菜单会为您显示它们。也许这就是原因?

[编辑]:不,不是。我刚刚尝试过,一个带有菜单项的简单 TForm 显示了加速器,但是只要我添加一个 TImageList 并设置单个菜单项的 ImageIndex,或者简单地将 OwnerDraw 设置为 true,那么加速器下划线就会消失。我想这确实是 VCL 中的一个错误。

顺便说一句,这是在 Windows XP 上。

解决方法:

我已经在 Windows XP 64 上使用 Delphi 2009 对此进行了调试,缺少加速器的根本原因似乎是 Windows 发送WM_DRAWITEM带有ODS_NOACCEL标志集的消息,如果系统设置为始终显示加速器,则不应该这样做。所以你可以说这不是 VCL 错误,而是 VCL 无法解决的 Windows 问题。

但是,您可以在自己的代码中解决它,您只需在将消息传递给 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消息时调用。

于 2008-11-11T07:57:44.860 回答
6

这是 Windows 2000 引入的“功能”:

旧事物:为什么 Windows 默认隐藏键盘加速器和焦点矩形?

Delphi 4 似乎不支持此 Windows 功能。

要让 2000 和 XP 菜单显示加速键,请右键单击桌面上的空白处,选择属性,单击外观选项卡,然后在效果下,取消选中隐藏键盘导航的下划线字母,直到我按下 Alt 键。单击确定两次。

不知道如何在 Vista 中做到这一点。

于 2008-11-11T08:00:00.690 回答
1

我认为这不是 Delphi 生成的错误,因为您在 Vista 上使用记事本具有相同的行为。顺便说一句,在德尔福本身……
我必须承认,在你的问题之前我没有注意。感谢您指出。

于 2008-11-11T07:50:03.300 回答
0

正如 Jim McKeeth 上面(正确地)指出的那样,这是“设计使然”的行为。如果菜单是通过键盘操作触发的,则应显示加速器,但如果由鼠标触发,则故意不显示加速器。

我将 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 消息,这就是导致使用加速器重绘的原因。

于 2008-12-17T02:01:12.907 回答