簡體   English   中英

是否有內置的快捷鍵用於選擇當前活動表單的所有者?

[英]Is there a built-in shortcut key for selecting the owner of the currently active form?

我有一個帶有兩個子非模態表單的主表單,例如,所有表單都可以同時處於活動狀態:

class MainForm : Form
{
    Form child1;
    Form child2;

    public MainForm()
    {
        Text = "MainForm";
        child1 = new Form { Text = "Child1" };
        child2 = new Form { Text = "Child2" };
        child1.Show(this);
        child2.Show(this);
    }
}

我想允許用戶將Alt+Tab到所有這些表單中,但是令人驚訝的是,我發現,如果任何子表單處於活動狀態,則無法從Alt+Tab菜單中選擇所有者表單。

這三種形式都顯示在列表中,但是很顯然,當您選擇所有者窗口並且有一個活動的子代時,將選擇該子代而不是所有者。 在任務欄中選擇表單時也會發生同樣的事情。

我想念什么嗎? 我開始考慮明確配置快捷鍵以允許從無模式子窗體導航到所有者窗口,但是在此之前,我想確認是否已經有一些內置的鍵盤快捷鍵可以執行此操作,因為我不想破壞用戶的期望。

令人驚訝的是,我找不到任何提及此行為的問題,我也覺得很奇怪。

設置窗體的所有者會使該窗體作為非模式窗口停留在其所有者的頂部。
如果擁有的窗體的ShowInTaskbar屬性設置為true ,則用於迭代系統中打開的Windows的標准ALT+TABWIN+TAB組合鍵會將前面的下一個擁有的窗體(而不是所有者)放在前面(激活)。
哪個窗體被激活,取決於窗體在任務欄中的當前位置。

如果將子級的ShowInTaskbar屬性設置為false ,則會激活所有者表單。
請注意,如果可以最小化子窗體,則可以觀察到一些尷尬的行為:Alt或Control-Tab鍵,導致子窗體以不愉快的方式出現和消失。

無論如何, CONTROL+F6鍵的標准組合可用於將焦點移到已打開的子窗體(以及這種形式的所有者窗體)上,並在必要時(如果窗體已最小化)也可以放在前面。
在此,重寫ProcessCmdKey ,因此無論哪個子控件捕獲了光標,都將攔截鍵的組合。

此處的代碼激活同時按下CONTROL+F6CONTROL+SHIFT+F6窗體,將焦點移至每個打開的子窗體和所有者。 當子窗體(或所有它們)最小化時,它也適用。

在所有者表格中:

protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
    bool isControlF6 = keyData == (Keys.Control | Keys.F6);
    bool isCtrlShiftF6 = keyData == (Keys.Control | Keys.Shift | Keys.F6);

    if (isControlF6 || isCtrlShiftF6)
    {
        Form frm = isCtrlShiftF6 
                 ? Application.OpenForms.OfType<Form>().LastOrDefault(f => f.Owner == this)
                 : Application.OpenForms.OfType<Form>().FirstOrDefault(f => f.Owner == this);
        if (frm is null) return true;
        frm.WindowState = FormWindowState.Normal;
        frm.Focus();
        return true;
    }
    return base.ProcessCmdKey(ref msg, keyData);
}

在子表格中:

protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
    bool isControlF6 = keyData == (Keys.Control | Keys.F6);
    bool isCtrlShiftF6 = keyData == (Keys.Control | Keys.Shift | Keys.F6);
    if (isControlF6 || isCtrlShiftF6) {
        int frmNext = 0;
        var formsList = Application.OpenForms.OfType<Form>()
                                   .Where(f => (f.Owner == this.Owner) || (f == this.Owner)).ToList();
        for (int i = 0; i < formsList.Count; i++) {
            if (formsList[i] == this) {
                if (isCtrlShiftF6) { frmNext = i == 0 ? formsList.Count - 1 : i - 1; }
                if (isControlF6) { frmNext = i == formsList.Count - 1 ? 0 : i + 1; }
                formsList[frmNext].WindowState = FormWindowState.Normal;
                formsList[frmNext].Focus();
                return true;
            }
        }
    }
    return base.ProcessCmdKey(ref msg, keyData);
}

編輯答案:

我不知道為什么,但我不能放手。 似乎應該有一個簡單的解決方案。

@glopes我相信這是您根據評論所要查找的內容。

這段代碼將在子窗口失去焦點之前將焦點設置回父窗口。 這類似於單擊窗口,並允許您將Alt-Tab切換到所需的任何窗口。

public class MainForm : Form
{
    Form child1;
    Form child2;

    public MainForm()
    {
        Text = "MainForm";
        child1 = new ChildForm { Text = "Child1", ParentPtr = Handle };
        child2 = new ChildForm { Text = "Child2", ParentPtr = Handle };
        child1.Show(this);
        child2.Show(this);
    }
}

public class ChildForm : Form
{
    [DllImport("user32.dll")]
    public static extern bool SetFocus(IntPtr hWnd);

    private const int WM_KILLFOCUS = 0x0008;

    public IntPtr ParentPtr { get; set; }

    protected override void WndProc(ref Message m)
    {
        if (m.Msg == WM_KILLFOCUS) SetFocus(ParentPtr);

        base.WndProc(ref m);
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM