【问题标题】:How to show "NUMERIC KEYPAD" for menu item shortcut assigned with `VK_NUMPAD0`?如何为分配有`VK_NUMPAD0`的菜单项快捷方式显示“NUMERIC KEYPAD”?
【发布时间】:2021-06-08 07:33:15
【问题描述】:

在一个 Delphi 10.4.2 Win32 VCL 应用程序中,在 Windows10 X64(德语)上,我以编程方式设置了一些菜单项的快捷方式:

mRasterizedDoubleSize.Shortcut := VK_ADD;
mRasterizedHalveSize.Shortcut := VK_SUBTRACT;
mRasterizedResetToOriginalSVGSize.Shortcut := VK_NUMPAD0;

这会在运行时产生以下菜单:

(“ZEHNERTASTATUR”是德语数字键盘)

为什么第三个菜单项没有显示“Zehnertastatur”(数字键盘)?

如何为分配有VK_NUMPAD0 的菜单项快捷方式显示“ZEHNERTASTATUR”(数字键盘)?

我已在 Vcl.Menus 中针对此错误提交了质量报告:https://quality.embarcadero.com/browse/RSP-33296 请投票!

编辑:我已经尝试过 Andreas 的建议,但它只能在运行时以编程方式工作,而不是在对象检查器中的设计时工作:

mRasterizedResetToOriginalSVGSize.Caption := mRasterizedResetToOriginalSVGSize.Caption + #9 + '0 (NUMPAD)  ';

难道没有在运行时将单词“NUMPAD”翻译成当前系统语言的函数吗?

EDIT2:我试过这个来获取VK_NUMPAD0 快捷方式的单词,但它只返回相同的“0”而没有“NUMPAD”后缀:

var s: TShortCut;
s := ShortCut(VK_NUMPAD0, []);
CodeSite.Send('TformMain.FormCreate: ShortCutToText(s)', ShortCutToText(s));

EDIT3:我现在已经调试了Vcl.Menus:错误似乎在Vcl.Menus.ShortCutToText:而VK_ADD($6B)被GetSpecialName(ShortCut)正确翻译,VK_NUMPAD0( $60) 没有被GetSpecialName(ShortCut)翻译!

EDIT4:我找到了解决方案:

function MyGetSpecialName(ShortCut: TShortCut): string;
var
  ScanCode: Integer;
  KeyName: array[0..255] of Char;
begin
  Result := '';
  ScanCode := Winapi.Windows.MapVirtualKey(LoByte(Word(ShortCut)), 0) shl 16;
  if ScanCode <> 0 then
  begin
    if Winapi.Windows.GetKeyNameText(ScanCode, KeyName, Length(KeyName)) <> 0 then
      Result := KeyName;
  end;
end;

var s: System.Classes.TShortCut;
s := ShortCut(VK_NUMPAD0, []);
CodeSite.Send('ShortCutToText', MyGetSpecialName(s));

【问题讨论】:

  • 可以使用TActionList 并将菜单项连接到它吗?或者至少通过TMenuItem.ShortCut 属性以外的其他方式实现快捷方式?因为无论如何,你都可以做到mRasterizedResetToOriginalSVGSize.Caption := 'Original SVG size'#9'Numpad 0'
  • TActionList 有帮助的原因是您可以使用辅助快捷方式。)
  • 不幸的是,actNumpad0Dummy.Shortcut := VK_NUMPAD0;(当然已经将菜单项的 Ation 属性设置为actNumpad0Dummy)不起作用。它显示的结果与之前相同。
  • 我的想法是你使用 TActionListTAction 命名为 aResetZoomCaption = 'Original SVG size'#9'Numpad 0' 和 NO Shortcut。这个放在主菜单上。然后要让实际的键盘快捷方式起作用,您可以使用aResetZoom.SecondaryShortcuts 或使用Shortcut = VK_NUMPAD0 和相同的OnExecute(您不要放在主菜单上)创建一个虚拟操作。
  • 请看我的问题编辑:难道没有一个函数可以在运行时将单词“NUMPAD”翻译成当前系统语言吗?

标签: delphi keyboard-shortcuts menuitem delphi-10.4-sydney


【解决方案1】:

一种方法是这样的:

使用TActionList。一般来说,这是一种很好的做法。在此列表中定义您的操作,然后简单地将它们映射到菜单项、按钮、复选框等。操作列表工具是 VCL 恕我直言的最佳部分之一。

现在,使用 Caption = 'Reset zoom'#9'Numpad 0' 和 NO ShortCut 创建一个名为 aResetZoom 的操作。把它放在菜单栏上。

然后,创建一个名为aResetZoomShortcut 操作,使用相同的OnExecute(可能还有相同的OnUpdate)和快捷方式Num 0(在设计时设置或在运行时以编程方式设置)。不要把它放在主菜单上。

结果:

当我按下小键盘 0(但不是 alpha 0)时触发操作。

这种方法有很多变体。也许您可以使用没有ShortCut 但在其SecondaryShortCuts 列表中使用Num 0 的单个操作使其工作。或者,您可以使用表单的 KeyPreviewOnKeyPress 属性来代替“虚拟”操作。

许多选项。选择最适合您的特定场景的一种。

奖励说明

请注意,在设计时使用 Object Inspector 设置带有选项卡的标题是完全可能的。见example video

您可能可以使用 Win32 GetKeyNameText 函数进行本地化。以下代码改编自 VCL:

var
  name: array[0..128] of Char;
begin
  FillChar(name, SizeOf(name), 0);
  GetKeyNameText(MapVirtualKey(VK_NUMPAD0, 0) shl 16, @name[0], Length(name));
  // string(name) now is 'NUM 0' on my system

话虽如此,我个人不介意快捷方式描述是非本地化的还是手动本地化的——就像应用程序的其余部分一样。

更新

关于如何使用本地化代码的说明:

procedure TForm5.FormCreate(Sender: TObject);
var
  name: array[0..128] of Char;
  NameAsANormalString: string;
begin
  FillChar(name, SizeOf(name), 0);
  GetKeyNameText(MapVirtualKey(VK_NUMPAD0, 0) shl 16, @name[0], Length(name));
  NameAsANormalString := name;
  ShowMessage(name);
end;

生产

在我的系统上。

【讨论】:

  • 谢谢你的好例子。但是,当使用Caption = 'Reset zoom'#9'Numpad 0' 时,它仅适用于英语。 (我必须翻译其他语言),而TMenuItem.Shortcut 功能会自动将其翻译为当前系统语言。是不是有一个函数可以在运行时将“NUMPAD”这个词翻译成当前的系统语言?
  • 有趣的想法。但它有一个缺点:在具有不同语言环境的 Windows 上运行时,菜单中的快捷方式不会被翻译。
  • @dummzeuch:我不知道它是如何工作的。如果我查看 VCL 源代码,我可以看到 VCL 通常在Vcl.Menus.TMenuItem.AppendTo 中添加快捷方式文本:Caption := Caption + #9 + ShortCutToText(FShortCut);,而ShortCutToTextVcl.Const 中使用SmkcCtrl = 'Ctrl+'; 资源字符串。因此,在我看来,这些快捷方式根本不会自动翻译。如果您有一个带有德语快捷方式名称的德语 VCL 应用程序,并且我在瑞典系统上运行它,我会不会看到 Strg+A 而不是 Ctrl+A
  • 啊,只有“特殊名称”被本地化了。并且它们使用 Win32 GetKeyNameText 本地化。
  • @AndreasRejbrand 在问题中查看我的 EDIT4
猜你喜欢
  • 1970-01-01
  • 2014-02-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-18
  • 2011-04-01
  • 1970-01-01
相关资源
最近更新 更多