如何傳遞[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.


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章