【问题标题】:TMenuItem-Shortcuts overwrite Shortcuts from Controls (TMemo)TMenuItem-Shortcuts 覆盖 Controls 中的 Shortcuts (TMemo)
【发布时间】:2009-07-09 14:48:53
【问题描述】:

我该怎么做才能使菜单项的快捷方式不会覆盖本地控件中的快捷方式? 想象一下屏幕截图中的这个简单的应用程序。它有一个“撤消”菜单项,并分配有快捷键 CTRL+Z(德语中的 Strg+Z)。当我在备忘录中编辑一些文本并按 CTRL+Z 时,我假设备忘录中的最后一个输入被还原,而是执行菜单项。

这在这个虚构的应用程序中尤其糟糕,因为撤消功能现在将删除我上次添加的“项目 3”,我正在编辑哪些属性。

CTRL+Z 只是一个例子。其他流行的快捷方式会导致类似的问题(复制和粘贴:CTRL+X/C/V,全选:CTRL+A)。

Mini Demo with menu item with CTRL+Z short-cut http://img31.imageshack.us/img31/9074/ctrlzproblem.png

【问题讨论】:

  • 当您使用的控件已经内置了一个功能时,为什么还要添加撤消功能?
  • 如果编辑框有焦点,他想撤消对文本的更改。如果有其他内容有焦点,他想撤消对上次保存时所做的整体更改。

标签: delphi delphi-2009


【解决方案1】:

VCL 旨在为菜单项快捷方式提供优先级。但是,当 ActiveControl 为 TCustomEdit(调用 Undo 等)时,您可以编写您的项目单击处理程序(或操作执行处理程序)来进行一些特殊处理

编辑:我知道您不喜欢在代码的许多地方(所有菜单项或操作处理程序)处理所有可能的特殊情况。恐怕我不能给你一个完全满意的答案,但也许这会帮助你找到更通用的解决方案。在您的表单上尝试以下 OnShortCut 事件处理程序:

procedure TMyForm.FormShortCut(var Msg: TWMKey; var Handled: Boolean);
var
  Message: TMessage absolute Msg;
  Shift: TShiftState;
begin
  Handled := False;
  if ActiveControl is TCustomEdit then
  begin
    Shift := KeyDataToShiftState(Msg.KeyData);
    // add more cases if needed
    Handled := (Shift = [ssCtrl]) and (Msg.CharCode in [Ord('C'), Ord('X'), Ord('V'), Ord('Z')]);
    if Handled then
      TCustomEdit(ActiveControl).DefaultHandler(Message);
  end
  else if ActiveControl is ... then ... // add more cases as needed
end;

您还可以以类似的方式覆盖 IsShortCut 方法,并从这个新的 TCustomForm 后代派生项目的表单。

【讨论】:

  • 在这种情况下,我必须知道所有控件。实际上,它是一个更复杂的应用程序,具有动态创建的视图(甚至来自插件),因此很容易忘记某些控件或在无法访问外部插件控件的情况下。
  • 不幸的是,这甚至不起作用。过程 TForm1.Undo1Click(Sender: TObject);如果 ActiveControl 是 TMemo 则开始,然后退出; ShowMessage('撤消');结尾;我阻止执行撤消功能,但备忘录也不执行自己的撤消功能。
  • 对不起,我没有仔细阅读。您的建议是直接调用备忘录的撤消功能,而不是我自己的撤消。这确实有效,但需要对所有类型的控件进行特殊处理……而且 CTRL+Z 不是唯一的快捷方式。 CTRL+A(全选)、CTRL+X/C/V(复制和粘贴)是下一个有问题的快捷方式。
【解决方案2】:

您可能需要一个类似的解决方案,如下所示。是的,感觉很麻烦,但这是我当时能想到的最简单的方法。要是 Delphi 允许鸭式打字就好了!

  { you need to derive a class supporting this interface 
    for every distinct control type your UI contains }
  IEditOperations = interface(IInterface)
    ['{C5342AAA-6D62-4654-BF73-B767267CB583}']
    function CanCut: boolean;
    function CanCopy: boolean;
    function CanPaste: boolean;
    function CanDelete: boolean;
    function CanUndo: boolean;
    function CanRedo: boolean;
    function CanSelectAll: Boolean;

    procedure CutToClipBoard;
    procedure Paste;
    procedure CopyToClipboard;
    procedure Delete;
    procedure Undo;
    procedure Redo;
    procedure SelectAll;
  end;

// actions....

procedure TMainDataModule.actEditCutUpdate(Sender: TObject);
var intf: IEditOperations;
begin
  if Supports(Screen.ActiveControl, IEditOperations, intf) then
    (Sender as TAction).Enabled := intf.CanCut
  else
    (Sender as TAction).Enabled := False;
end;

procedure TMainDataModule.actEditCutExecute(Sender: TObject);
var intf: IEditOperations;
begin
  if Supports(Screen.ActiveControl, IEditOperations, intf) then
    intf.CutToClipBoard;
end;

....

【讨论】:

    猜你喜欢
    • 2018-12-25
    • 2019-04-14
    • 2019-06-18
    • 2020-01-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-13
    • 2022-12-18
    相关资源
    最近更新 更多