如何传递[Ctrl]+[Tab] 到 MDI子窗体

我在MDI 子窗体有个TabControl控件(如PageControl), 当按下Ctrl+Tab 或 Ctrl+Shift+Tab 组合键时,应用程序切换到了下一个MDI子窗口,而不是改变TabControl控件的活动页,我怎样才能强制MDI子窗体传递 Ctrl+Tab 组合键到 TabControl 控件那?


答案:

   这实际上是API层面的冲突,在MDI程序中,消息处理每次都会调用 IsMDImsg 函数,并且这个函数会调用 TranslateMDISysAccel API 函数,Ctr+Tab 在这里就被处理了,所以子窗口永远不会收到这个键值的消息。


   为了能够在子窗口中处理这个消息,我们需要在 IsMDIMsg 函数被调用前干预这个消息, 只要一个机会可以做这件事情,那就是Application.OnMessage 事件,所以要在主窗口的OnCreate 事件里添加一个自定义的处理,暂时叫这个处理方法为AppMessage;(注:实际上我们不用这么麻烦,在Addtional 组件页有个 ApplicationEvents 控件,我们可以把它直接拿下来用,它有一个OnMessage 事件,直接处理这个事件就行了), 一下是他的处理方法的代码

procedure TMainForm.FormCreate(Sender: TObject);
begin
  Application.OnMessage := AppMessage;
end;

procedure TMainform.Appmessage(var Msg: TMsg; var Handled: Boolean);
var
  message: TWMKey;
begin
  if (msg.message = WM_KEYDOWN) and (LoWord(msg.wparam) = VK_TAB) and
    (GetKeyState(VK_CONTROL) < 0) and Assigned(ActiveMDIChild) then
  begin
    Move(msg.message, message.msg, 3 * sizeof(Cardinal));
    message.result := 0;
    Handled := ActiveMDIChild.IsShortcut(message);
  end;
end;


注:如果用我说的控件,直接将Appmessage 过程的代码写到 Application.OnMessage 事件里就行了。


   这样就可以将 Ctrl+Tab (和 Ctrl+Shift+Tab) 重定向到当前活动的子窗口的IsShortCut 函数中,并激发OnShortcut 事件,所以我们就可以在子窗口的OnShortCut 事件里处理Ctrl+Tab 这个键以后的事件了。


function IsOnTabsheet(aControl: TWinControl; var pc: TPageControl): Boolean;
begin
  while Assigned(aControl) and not (aControl is TTabsheet) do
    aControl := aControl.Parent;
  Result := Assigned(aControl);
  if result then
    pc := TTabSheet(aControl).Pagecontrol;
end;

procedure TMDIChild.FormShortCut(var Msg: TWMKey; var Handled: Boolean);
var
  pc: TPageControl;
begin
  if (msg.CharCode = VK_TAB) and (GetKeyState(VK_CONTROL) < 0) then
  begin
    if IsOnTabsheet(ActiveControl, pc) then
    begin
      pc.Perform(CM_DIALOGKEY, msg.CharCode, 0);
      Handled := true;
    end;
  end;
end;



原文:How to pass a [CTRL] [TAB] to a TPageControl on a MDI child form

I have a TabControl inserted into a MDI child form. When one press the Ctrl+Tab or Ctrl+Shift+Tab keys, the application selects the next (previous) MDIChildForm instead of changing the active page of TabControl. How can I force the MDIChild pass the Ctrl+Tab to the TabControl?

Answer:

This is in fact a conflict on the API level. In a MDI application the message loop will call IsMDIMsg on every key message fetched form the message loop, and this function calls the API TranslateMDISysAccel function. This in turn handles the Ctrl-Tab, so the child form never even sees the key event.

To get around this one needs to intervene before IsMDIMsg is even called. There is only one opportunity to do this: the Application.OnMessage event. So add a handler for the main form OnCreate event, and add a private method to the form called AppMessage:

procedure TMainForm.FormCreate(Sender: TObject);
begin
  Application.OnMessage := AppMessage;
end;

procedure TMainform.Appmessage(var Msg: TMsg; var Handled: Boolean);
var
  message: TWMKey;
begin
  if (msg.message = WM_KEYDOWN) and (LoWord(msg.wparam) = VK_TAB) and
    (GetKeyState(VK_CONTROL) < 0) and Assigned(ActiveMDIChild) then
  begin
    Move(msg.message, message.msg, 3 * sizeof(Cardinal));
    message.result := 0;
    Handled := ActiveMDIChild.IsShortcut(message);
  end;
end;

This will redirect Ctrl+Tab (and Ctrl+Shift+Tab) to the active MDI childs IsShortcut function. This fires the OnShortcut event, so we can use that event on the child form to further handle the key event:

function IsOnTabsheet(aControl: TWinControl; var pc: TPageControl): Boolean;
begin
  while Assigned(aControl) and not (aControl is TTabsheet) do
    aControl := aControl.Parent;
  Result := Assigned(aControl);
  if result then
    pc := TTabSheet(aControl).Pagecontrol;
end;

procedure TMDIChild.FormShortCut(var Msg: TWMKey; var Handled: Boolean);
var
  pc: TPageControl;
begin
  if (msg.CharCode = VK_TAB) and (GetKeyState(VK_CONTROL) < 0) then
  begin
    if IsOnTabsheet(ActiveControl, pc) then
    begin
      pc.Perform(CM_DIALOGKEY, msg.CharCode, 0);
      Handled := true;
    end;
  end;
end;

That seems to do the trick.


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值