c++ - 如何设置运行时创建的 Windows 控件之间的移动顺序?

标签 c++ mfc dialog windows-ce

我们的应用程序中有一系列对话框,对话框模板在屏幕底部定义了 4 个按钮。然而(取决于应用程序运行的硬件版本)我们有时会创建 2 个额外的按钮,然后将 6 个按钮(4 个来自模板,2 个通过调用 CButton::Create() 创建)排列在底部。

我遇到的问题是,通常用户可以使用左/右箭头键在这些按钮之间移动焦点(没有鼠标或触摸屏,只有受限的键盘)。正如您对模板中的 4 个按钮所期望的那样,这遵循控件 TAB 顺序。 但是 2 个动态创建的控件似乎插入在 TAB 顺序的开头,这意味着(因为它们被放在屏幕的右侧)它们在“就光标键而言,错误的顺序。换句话说,当焦点到达左侧按钮(TAB 顺序 1)时,按向左箭头会将焦点跳到右侧的按钮,这很容易混淆...

Z 顺序(我可以用 SetWindowPos() 影响)和 TAB 顺序之间似乎有一些联系,但它似乎不是简单的一对一:更改 Z 顺序我可以移动顺序,使按钮完全顺序错误,这样我可以更改 Z 顺序,但我不知道如何让它们进入正确的顺序。

谁能简明扼要地解释 TAB 顺序的工作原理,以及如何在运行时控制控件的顺序?

编辑: kol 在下面建议使用 SetWindowPos() 来设置 Z 顺序。这我以前试过,但它不能让光标键按预期控制焦点。

但是,通过装配它以便我可以使用 TAB(作为测试——这对于最终用户解决方案来说不切实际)我发现 kol 的解决方案确实解决了 TAB 顺序.我遇到的问题是,这与光标键使用的顺序相同!

因此,修改后的问题:如何指定左/右光标键在控件之间移动焦点的顺序?

解决方案: 在 kol 和 MarkRansom 的帮助下,我现在已经开始工作了。

我按照 kol 的建议使用 SetWindowPos() 将我的新按钮按 TAB 顺序放在现有按钮之后,然后(如 Mark 所建议的那样)制作第一个按钮 WS_GROUP | WS_TABSTOP清除 其他按钮的那些标志。

但这还不足以解决问题,当使用箭头键(不是 TAB)移动时,2 个新按钮仍然出现在第一个按钮之前而不是第二个按钮之后。

我查看了我的对话框模板,它是这样的:

IDD_QUERY DIALOG  0, 0, 156, 34
STYLE DS_SETFONT | WS_POPUP | WS_CAPTION
FONT 8, "MS Sans Serif"
BEGIN
    PUSHBUTTON      "+++Skey1+++",IDC_SKEY_1,1,21,36,12
    PUSHBUTTON      "+++Skey2+++",IDC_SKEY_2,40,21,37,12
    PUSHBUTTON      "+++Skey3+++",IDC_SKEY_3,79,21,36,12
    PUSHBUTTON      "+++Skey4+++",IDC_SKEY_4,118,21,36,12
    LTEXT           "Static",IDC_QUERY_MSG,2,1,153,15
END

因此用于向用户显示信息的静态IDC_QUERY_MSG 模板中的第 4 个按钮之后。为解决该问题,我将 IDC_QUERY_MSG 第一个按钮 (IDC_SKEY_1) 移动:这意味着 6 个按钮不会被中间的静态分开, 并解决了问题。

感谢大家的帮助!

最佳答案

使用 SetWindowPos你的按钮成员。在按钮 A 上调用它并将其第一个参数设置为按钮 B,按 TAB 顺序将按钮 A 放在按钮 B 之后。如果你想设置两个控件的顺序,你必须知道它们之前和之后的控件在 TAB 顺序中 - this example展示了如何执行此操作(它不是 MFC,而是纯 WinAPI,但很容易理解)。

== 更新 ==

我创建了一个对话框模板,底部有四个按钮,顶部有一个编辑框,使用 TAB 键顺序 button1 -> button2 -> button3 -> button4 -> editbox -> button1 -> ... 在 OnInitDialog 中,我在运行时添加了两个额外的按钮,并使用 SetWindowPos获取下一个窗口。反复按 TAB 显示 TAB 顺序正确:button1 -> button2 -> button3 -> button4 -> button5 -> button6 -> editbox -> button1 -> ...

class CTestDlg : public CDialogEx
{
public:
    CTestDlg() : CDialogEx(CTestDlg::IDD) {}
    enum { IDD = IDD_TESTDIALOG };

protected:
    CButton button5;
    CButton button6;
    virtual BOOL OnInitDialog();
};

BOOL CTestDlg::OnInitDialog()
{
    CDialogEx::OnInitDialog();

    CButton* button4 = (CButton*)GetDlgItem(IDBUTTON4);
    CWnd* next = button4->GetNextWindow(GW_HWNDNEXT);

    button5.Create("Button5", WS_CHILD|WS_VISIBLE|WS_TABSTOP|BS_PUSHBUTTON, CRect(340, 172, 415, 195), this, 1005);
    button5.SetWindowPos(button4, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE); 

    button6.Create("Button6", WS_CHILD|WS_VISIBLE|WS_TABSTOP|BS_PUSHBUTTON, CRect(422, 172, 497, 195), this, 1006);
    button6.SetWindowPos(&button5, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE); 

    if (next != NULL)
        next->SetWindowPos(&button6, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE); 

    return TRUE;
}

void CDynamicMfcButtonTestApp::OnTestRun()
{
    CTestDlg testDlg;
    testDlg.DoModal();  
}

== 更新 2 ==

可以使用 SetWindowPosGetNextWindow 设置控件的顺序,如上所述。可以通过设置控件的 WS_TABSTOP 和 WS_GROUP 样式来设置“跳位顺序”和“箭头顺序”:

  • WS_TABSTOP 样式指定了用户可以访问的控件 按 T​​AB 键或 SHIFT+TAB 键移动。

  • WS_GROUP 风格 标记一组控件的开始。如果组中的一个控件 当用户开始按下方向键时具有输入焦点, 焦点仍然在小组中。一般来说,一组中的第一个控制 必须具有 WS_GROUP 样式并且组中的所有其他控件必须 没有这种风格。组中的所有控件必须 连续的——也就是说,它们必须是连续创建的,没有 干预控制。

可以在 MSDN 上找到更多详细信息,here .

关于c++ - 如何设置运行时创建的 Windows 控件之间的移动顺序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8467649/

相关文章:

c++ - 德语字符使用 SetDlgItemText 显示不正确

android - 对话暂停调用 Activity ?

Android:进度对话框不显示

c++ - 使用不依赖于方法模板参数的 enable_if

c++ - OgreBullet RigidBOdy 碰撞检测

c++ - 如何更改 AfxMessageBox 中的语言?

c++ - 使用 MFC 实现队列的正确方法?

c++ - GL_SPOT_CUTOFF 的意外行为

windows - ckeditor对话框定位

c++ - Xcode 4 : why "Continue to current line" is grayed out?