ShortCut什么时候开火? [英] When does a ShortCut fire?

查看:102
本文介绍了ShortCut什么时候开火?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

昨天我发现一个情况,一个键盘ShortCut在我期待的时候没有触发。



具体情况是:我按下ShortCut组合键而MDI窗体上的一个侧边栏则集中在MDI子窗口上的ActionList操作。



我总是觉得ShortCuts会在全球范围内工作。

解决方案

这是一个非常简单的问题,令人惊讶的是长时间的答案。首先,我将处理一些基础知识,然后通过VCL代码跟随ShortCut终于到达 - 希望 - 一个令人满意的结论。



什么是ShortCut? h3>

ShortCut表示导致操作的一个或多个键的特殊键盘组合。 在 Word 范围(0..65535)中声明为整数的TShortCut 。 ShortCut通常由几个键构成,例如:



CTRL + K = scCtrl + Ord('K') = 16384 + 75 = 16459



如何指定ShortCut?



ShortCuts可以分配给一个Action的 ShortCut SecondaryShortCuts 属性或$菜单项的 ShortCut 属性,从而调用Action的 OnExecute 事件或MenuItem的 OnClick 事件当ShortCut的键盘组合被按下。



对于要处理的Action的ShortCut,需要启用Action,并添加到未挂起的ActionList或附加到启用的MenuItem。同样,对于要处理的MenuItem的ShortCut,需要将MenuItem添加到菜单。



ShortCuts也可以从应用程序的一个表单 ApplicationEvents ' OnShortCut 事件。在这些事件中, Msg 参数在其 CharCode 成员中保存键码,可能是特殊键,如 Shift Ctrl Alt 可以使用 GetKeyState

  procedure TForm1.FormShortCut(var Msg:TWMKey; var Handled:Boolean); 
begin
if(Msg.CharCode = Ord('K'))和(GetKeyState(VK_CONTROL)< 0)then
begin
Caption:='CTRL + ';
处理:= True;
结束
结束

如果处理参数设置为 True ,任何后续的密钥处理将被跳过。



ShortCut如何捕获?



VCL不保留所有指定的ShortCuts的列表。 (怎么可能?)因此,所有的击键可能是ShortCut。这就是VCL如何解释ShortCuts:通过评估按下的每个键。



Peter下面写了一篇非常全面的文章,与 A Key's Odyssey 通过VCL。简而言之,ShortCut被捕获如下:




  • TApplication.Run 每个Windows消息发送到应用程序,

  • TApplication.ProcessMessage 调用 IsKeyMsg 它传递消息 - 如果 WM_KEYDOWN 消息发送到重点控件的 CN_KEYDOWN 消息处理程序/ strong>。



如何处理ShortCut?



TWinControl.CNKeyDown 检查键是否是菜单键(我们将看到这个菜单的定义超出了物理菜单):




  • TWinControl.IsMenuKey 首先检查密钥是否是控件内的ShortCut或其父项的 PopupMenu 之一,

    • < a href =http://docwiki.embarcadero.com/Libraries/XE7/en/所有的全部它的(子类别) TMenu.IsShortCut )菜单项,并调用启用的MenuItem的 OnClick 事件处理程序,使用ShortCut(如果有)


  • 如果未处理,则会通过调用 2)

    • OnShortCut

    • 如果没有处理,表单事件将被调用,它会检查密钥是否是窗体的MainMenu中的ShortCut strong>(见 1)),如果有的话,

    • 如果没有处理,它会将密钥发送到Form ActionLists (还在谈论活跃的For m)。在Delphi版本10(BDS2006)之前,这些ActionLists需要由Form直接拥有,并保存在受保护的(在需要时可以进行干预)字段 FActionLists 这被认为是一个错误,从BDS2006开始,该领域被淘汰,ActionLists可以间接由表格也拥有。

      • TCustomActionList.IsShortCut 遍历其所有操作,并调用中设置的ShortCut启用的Action的 HandleShortCut ShortCut SecondaryShortCuts 属性(如果有)



      • 如果未处理, Application.IsShortCut 被调用(通过 CM_APPKEYDOWN ),

        • OnShortCut 应用程序事件被触发,其中包括 OnShortCut 项目中所有ApplicationEvents组件的事件,如果已分配,

        • 如果未处理,它会调用 MainForm IsShortCut 例程(请参阅 2)),但只有当MainForm启用时才能。例如。当活动窗体为模态窗体时,MainForm将被禁用。这将触发MainForm OnShortCut 事件,或者将遍历MainForm 的所有直接或间接拥有的 ActionLists(依赖于在上面提到的Delphi版本上)。




      那么, ?



      当它是:




      • 在PopupMenu中设置启用的MenuItem它附加到当前聚焦的控件或其任何父母,

      • 为当前活动窗体或MainForm上显示的MainMenu中的启用MenuItem设置,但仅当MainForm已启用,

      • 设置为在当前活动的窗体或MainForm所有的未挂起的ActionList中的启用的操作,但仅当启用MainForm时,才能设置

      • 在当前活动的Form或MainForm的 OnShortCut 事件中捕获,但只有启用MainForm时,

      • OnShortCut 应用程序或任何ApplicationEvents组件的事件。



      什么时候是ShortCut未处理?



      设置为:




      • 禁用的MenuItem,

      • 没有菜单的MenuItem

      • MainMenu中没有附加到表单的MenuItem

      • 附加到兄弟姐妹的PopupMenu中的MenuItem

      • 禁用的操作

      • 没有ActionList的操作

      • ActionList中不是当前活动窗体或MainForm所有的Action。例如:另一个表单,DataModule,应用程序,公用程序单元等...

      • ActionList中的Action并不直接由Delphi版本中当前活动的Form或MainForm所有低于BDS2006。


      Yesterday I discovered a situation wherein a keyboard ShortCut did not fire when I was expecting it to.

      The specific situation was: I pressed the ShortCut key combination for an Action of an ActionList on an MDI child, while a side bar on the MDI form was focussed.

      I always was under the impression that ShortCuts would work globally. In exactly which circumstances do or do they not fire?

      解决方案

      That's a deceptively simple question with a surprisingly long answer. First I will deal with some basics and then follow the ShortCut through the VCL code to finally arrive at - I hope - a satisfying conclusion.

      What is a ShortCut?

      A ShortCut represents a special keyboard combination of one or more keys that cause an operation. Special means special to the programmer who gives meaning to the specific key combination.

      In Delphi a ShortCut is of type TShortCut which is declared as a whole number within the Word range (0..65535). A ShortCut is often constructed out of several keys, e.g.:

      CTRL+K = scCtrl + Ord('K') = 16384 + 75 = 16459.

      How to specify a ShortCut?

      ShortCuts can be assigned to the ShortCut or SecondaryShortCuts property of an Action or to the ShortCut property of a MenuItem, thus invoking that Action's OnExecute event or MenuItem's OnClick event when the ShortCut's keyboard combination is pressed.

      For an Action's ShortCut to be processed, it is required that the Action is enabled, and added to a not suspended ActionList or attached to an enabled MenuItem. Likewise, for a MenuItem's ShortCut to be processed, it is required that the MenuItem is added to a Menu.

      ShortCuts can also be interpreted from the Application's, a Form's or from an ApplicationEvents' OnShortCut event. Within those events, the Msg parameter holds the keycode in its CharCode member, and possibly special keys like Shift, Ctrl or Alt can be extracted using GetKeyState:

      procedure TForm1.FormShortCut(var Msg: TWMKey; var Handled: Boolean);
      begin
        if (Msg.CharCode = Ord('K')) and (GetKeyState(VK_CONTROL) < 0) then
        begin
          Caption := 'CTRL+K pressed';
          Handled := True;
        end;
      end;
      

      If the Handled parameter is set to True, any subsequent processing for the key will be skipped.

      How is a ShortCut catched?

      The VCL does not keep a list of all specified ShortCuts. (How could it?). Thus all keystrokes could potentially be a ShortCut. And that is exactly how the VCL interprets ShortCuts: by evaluating every key that is pressed.

      Peter Below wrote an excellent and comprehensive article dealing with A Key's Odyssey through the VCL. In short, a ShortCut is catched as follows:

      • TApplication.Run picks up every Windows message send to the application,
      • TApplication.ProcessMessage calls IsKeyMsg which passes the message - if a WM_KEYDOWN message - on to the CN_KEYDOWN message handler of the focussed Control.

      How is the ShortCut processed?

      TWinControl.CNKeyDown examines whether the key is a menu key (we'll see the definition of this menu is beyond a physical Menu):

      • TWinControl.IsMenuKey first examines whether the key is a ShortCut within the Control's or one of its parent's PopupMenu,
        • TMenu.IsShortCut 1) traverses all its (sub)menu items and calls the OnClick event handler of the enabled MenuItem with the ShortCut, if any,
      • If not processed, it examines whether the key is a ShortCut of the Form on which the Control resides by calling TCustomForm.IsShortCut 2),
        • The OnShortCut event of the Form is called, if assigned,
        • If not processed, it examines whether the key is a ShortCut within the Form's MainMenu (see 1)), if any,
        • If not processed, it dispatches the key to all ActionLists owned by the Form (still talking about the active Form). Prior to Delphi version 10 (BDS2006), these ActionLists need to be directly owned by the Form and were kept in a protected (which made intervention possible when needed) field FActionLists. That was considered a bug and as from BDS2006, the field was eliminated and the ActionLists could be indirectly owned by the Form too.
          • TCustomActionList.IsShortCut traverses all its Actions and calls HandleShortCut of the enabled Action with the ShortCut set in its ShortCut or SecondaryShortCuts property, if any,
      • If not processed, Application.IsShortCut is called (via CM_APPKEYDOWN),
        • The OnShortCut event of the Application is fired, this includes OnShortCut events of all ApplicationEvents components within the project, if any assigned,
        • If not processed, it calls the IsShortCut routine of the MainForm (see 2)), but only when the MainForm is enabled. E.g. when the active Form is a modal Form, then the MainForm will be disabled. This will fire the OnShortCut event of the MainForm or will traverse all directly or indirectly owned ActionLists of the MainForm (depending on Delphi version as mentioned above).

      So, when is the ShortCut processed?

      When it is:

      • Set for an enabled MenuItem in a PopupMenu which is attached to the currently focussed Control or to any of its parents,
      • Set for an enabled MenuItem in a MainMenu which is shown on the currently active Form or on the MainForm, but only when the MainForm is enabled,
      • Set for an enabled Action in a not suspended ActionList which is owned by the currently active Form or by the MainForm, but only when the MainForm is enabled,
      • Catched in the OnShortCut event of the currently active Form or of the MainForm, but only when the MainForm is enabled,
      • Catched in the OnShortCut event of the Applicaton or any ApplicationEvents components.

      And when is the ShortCut not processed?

      When it is set for:

      • A disabled MenuItem,
      • A MenuItem without Menu,
      • A MenuItem in a MainMenu that is not attached to a Form,
      • A MenuItem in a PopupMenu that is attached to a sibling,
      • A disabled Action,
      • An Action without ActionList,
      • An Action in an ActionList that is not owned by the currently active Form or the MainForm. E.g.: another Form, a DataModule, Application, a utilities unit, etc...
      • An Action in an ActionList that is not directly owned by the currently active Form or the MainForm in Delphi versions below BDS2006.

      这篇关于ShortCut什么时候开火?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆