lke*_*ler 5 delphi keyboard-shortcuts modal-dialog non-modal
我在主菜单上使用标准的剪切、复制、粘贴操作。他们有捷径Ctrl-X,Ctrl-C和Ctrl-V。
当我打开一个模态表单时,例如 FindFilesForm.ShowModal,然后所有的快捷方式都在表单中工作。
但是当我打开一个非模态表单时,例如 FindFilesForm.Show,那么快捷方式就不起作用了。
如果 FindFilesForm 是活动表单,我认为这些操作应该有效。它的模态应该与它无关,还是我的想法错了?
尽管如此,我怎样才能获得在非模态表单上工作的快捷方式?
在 Cary 的回应之后,我进一步研究了它。对于某些控件,例如 TMemo 或 TEdit,这不是问题。
但它适用于其他一些人。具体来说,它发生的地方包括:
我会看看是否还有其他人并将他们添加到列表中。
这些都是我程序中重要的非模态形式。
所以我仍然需要一个解决方案。
好的。我真的需要这方面的帮助。所以这成为我悬赏的第一个问题。
我与 Cary 的讨论是通过他的回答以及那里的评论更详细地描述了我的问题。
正如我在其中一条评论中提到的,这里似乎讨论了一个相关的问题。
我需要的是一个解决方案或变通方法,这将允许Ctrl-X,Ctrl-C和Ctrl-V始终在非模态窗口中的 TComboBox 和 TFindDialog 中工作。如果这两个问题得到解决,我相信我的 TElTreeInplaceEdit 也能正常工作。
正如 Cary 所描述的,设置一个简单的测试程序只需要几分钟。希望有人能够解决这个问题。
只是要小心,似乎有些东西可以让它有时工作,但有时却不起作用。如果我可以更详细地隔离它,我会在这里报告。
感谢您为我提供的任何帮助。
Mghie 非常努力地寻找解决方案,他的 OnExecute 处理程序与他的 ActionListUpdate 处理程序相结合,可以解决问题。所以为了他的努力,我给了他公认的解决方案和赏金点。
但是他的 actionlist 更新处理程序并不简单,您需要在其中指定要处理的所有情况。假设还有您可能想要的Ctrl+A全选或Ctrl-Y撤消。一般的程序会更好。
因此,如果您在寻找答案时确实遇到了这个问题,请先尝试我提供的添加 IsShortcut 处理程序的答案。它对我有用,应该处理每种情况,不需要 OnExecute 处理程序,所以简单得多。Peter Beyond 编写了该代码,Uwe Molzhan 获得了发现者费用。
感谢 Cary、mghie、Uwe 和 Peter 帮助我解决了这个问题。没有你就做不到。(也许我可以,但可能花了我 6 个月的时间。)
好的,首先要做的事情是:这与模态或非模态形式无关,它是 Delphi 操作组件工作方式的限制(如果您想这样称呼它)。
让我通过一个简单的示例来证明这一点:使用新表单创建一个新应用程序,将 aTMemo和 aTComboBox放入其中,然后运行该应用程序。两个控件都将具有系统提供的包含编辑命令的上下文菜单,并将对其做出正确的反应。他们将对菜单快捷方式执行相同的操作,但组合框不支持Ctrl+除外。A
现在添加一个TActionList具有剪切、复制和粘贴三个标准操作的组件。一切仍然有效,行为没有变化。
现在添加主菜单,并从模板添加编辑菜单。删除除剪切、复制和粘贴之外的所有命令。为菜单项设置相应的操作组件,然后运行应用程序。观察组合框如何仍然具有上下文菜单,并且其中的命令仍然有效,但快捷方式不再起作用。
问题在于标准编辑操作被设计为TCustomEdit仅适用于控件。查看TEditAction.HandlesTarget()StdActns.pas 中的方法。由于组合框中的编辑控件、树控件中的就地编辑器或本机对话框中的编辑控件不会被捕获,因此它们不会被处理。当这些控件之一获得焦点时,菜单命令将始终被禁用。至于仅在某些时候起作用的快捷方式 - 这取决于 VCL 是否在某些时候将快捷方式映射到操作命令。如果没有,那么它们最终将到达本机窗口过程并启动编辑命令。在这种情况下,快捷方式仍然有效。我假设对于模式对话框,操作处理被暂停,因此模式对话框和非模式对话框之间的行为是不同的。
要解决此问题,您可以为OnExecute这些标准操作提供处理程序。例如对于粘贴命令:
procedure TMainForm.EditPaste1Execute(Sender: TObject);
var
FocusWnd: HWND;
begin
FocusWnd := GetFocus;
if IsWindow(FocusWnd) then
SendMessage(FocusWnd, WM_PASTE, 0, 0);
end;
Run Code Online (Sandbox Code Playgroud)
以及用于剪切命令 ( WM_CUT) 和复制命令 ( WM_COPY) 的类似处理程序。在小演示应用程序中执行此操作可以使组合框再次正常工作。您应该在您的应用程序中尝试一下,但我认为这会有所帮助。正确启用和禁用所有本机编辑控件的主菜单命令是一项艰巨的任务。也许您可以发送EM_GETSEL消息来检查聚焦的编辑控件是否有选择。
编辑:
更多信息为什么模态对话框和非模态对话框上的组合框之间的行为不同(在 Delphi 2009 上进行的分析):有趣的代码位于TWinControl.IsMenuKey()- 它尝试在父窗体的操作列表之一中查找操作组件处理快捷方式的焦点控件。如果失败,它会发送一条CM_APPKEYDOWN消息,最终导致对应用程序主窗体的操作列表执行相同的检查。但事情是这样的:只有在启用应用程序主窗体的窗口句柄时才会执行此操作(请参阅TApplication.IsShortCut()代码)。现在调用ShowModal()表单将禁用所有其他表单,因此除非模式对话框本身包含具有相同快捷方式的操作,否则本机快捷方式处理将起作用。
编辑:
我可以重现这个问题 - 关键是要以某种方式禁用编辑操作。回想起来,这是显而易见的,Enabled动作的属性当然也需要更新。
请尝试使用此附加事件处理程序:
procedure TForm1.ActionList1Update(Action: TBasicAction; var Handled: Boolean);
var
IsEditCtrl, HasSelection, IsReadOnly: boolean;
FocusCtrl: TWinControl;
FocusWnd: HWND;
WndClassName: string;
SelStart, SelEnd: integer;
MsgRes: LRESULT;
begin
if (Action = EditCut1) or (Action = EditCopy1) or (Action = EditPaste1) then
begin
IsEditCtrl := False;
HasSelection := False;
IsReadOnly := False;
FocusCtrl := Screen.ActiveControl;
if (FocusCtrl <> nil) and (FocusCtrl is TCustomEdit) then begin
IsEditCtrl := True;
HasSelection := TCustomEdit(FocusCtrl).SelLength > 0;
IsReadOnly := TCustomEdit(FocusCtrl).ReadOnly;
end else begin
FocusWnd := GetFocus;
if IsWindow(FocusWnd) then begin
SetLength(WndClassName, 64);
GetClassName(FocusWnd, PChar(WndClassName), 64);
WndClassName := PChar(WndClassName);
if AnsiCompareText(WndClassName, 'EDIT') = 0 then begin
IsEditCtrl := True;
SelStart := 0;
SelEnd := 0;
MsgRes := SendMessage(FocusWnd, EM_GETSEL, WPARAM(@SelStart),
LPARAM(@SelEnd));
HasSelection := (MsgRes <> 0) and (SelEnd > SelStart);
end;
end;
end;
EditCut1.Enabled := IsEditCtrl and HasSelection and not IsReadOnly;
EditCopy1.Enabled := IsEditCtrl and HasSelection;
// don't hit the clipboard three times
if Action = EditPaste1 then begin
EditPaste1.Enabled := IsEditCtrl and not IsReadOnly
and Clipboard.HasFormat(CF_TEXT);
end;
Handled := TRUE;
end;
end;
Run Code Online (Sandbox Code Playgroud)
我没有检查本机编辑控件是否为只读,这可能可以通过添加以下内容来完成:
IsReadOnly := GetWindowLong(FocusWnd, GWL_STYLE) and ES_READONLY <> 0;
Run Code Online (Sandbox Code Playgroud)
注意:我已经给了 mghie 答案,因为他做了很多工作并且他的答案是正确的,但我已经实现了一个更简单的解决方案,我自己添加为答案
| 归档时间: |
|
| 查看次数: |
4098 次 |
| 最近记录: |