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

我的问题是通常用户可以使用向左/向右箭头键在这些按钮之间移动焦点(没有鼠标或触摸屏,只有受限的键盘)。 正如您期望模板中的4个按钮一样,这遵循控制TAB顺序。 但是,这2个动态创建的控件似乎是在TAB顺序的开头插入的,这意味着(因为它们位于屏幕的右侧),直到它们位于“错误”顺序为止。光标键消失了。 换句话说,当焦点移至左侧按钮(TAB顺序1)时,按左箭头会将焦点跳转至右侧的按钮,这简直是令人困惑。

Z顺序(我可以用SetWindowPos()影响)和TAB顺序之间似乎存在某些联系,但这似乎不是简单的一对一:通过更改Z顺序,我可以移动序列以便按钮完全按错误的顺序排列,因此我可以更改Z顺序,但无法弄清楚如何按正确的顺序排列它们。

任何人都可以对TAB顺序的工作原理以及运行时如何控制控件顺序进行简要说明吗?

编辑:下面建议使用SetWindowPos()设置Z顺序的kol。 我之前曾尝试过此操作,但它不能让光标键按预期控制焦点。

但是,通过进行组装,我可以使用TAB(作为测试-这对于最终用户解决方案不切实际),我发现kol的解决方案确实可以解决TAB顺序。 我的问题是,这是一样的光标键使用的顺序!

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

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

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

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

我看着我的对话框模板,就像这样:

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模板中的第四个按钮之后 要解决这个问题,让我感动IDC_QUERY_MSG第一个按钮( IDC_SKEY_1 ):这意味着6个按键不是由静态其间分手了,并且已经解决了这个问题。

感谢大家的帮助!

===============>>#1 票数:1 已采纳

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

==更新==

我创建了一个对话框模板,在其底部有四个按钮,在顶部有一个编辑框,其中的TAB顺序为button1 -> button2 -> button3 -> button4 -> editbox -> button1 -> ...在OnInitDialog中,我添加了两个附加按钮在运行时,并插入到它们之间的现有TAB顺序button4editbox使用SetWindowPosGetNextWindow 反复按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样式指定用户可以通过按TAB键或SHIFT + TAB键将其移动到的控件。

  • WS_GROUP样式标记了一组控件的开始。 如果用户开始按方向键时组中的控件具有输入焦点,则焦点将保留在组中。 通常,组中的第一个控件必须具有WS_GROUP样式,并且组中的所有其他控件都不能具有此样式。 该组中的所有控件都必须是连续的,也就是说,它们必须是连续创建的,没有中间控件。

更多细节可以在MSDN上找到, 在这里

===============>>#2 票数:1

尝试这个:

  1. 创建一个dlg id的向量,并按照您希望按Tab键顺序的顺序填充它:

     typedef std::vector<int> TABLIST; TABLIST lst; lst.push_back( IDC_CONTROL1 ); lst.push_back( IDC_CONTROL2 ); lst.push_back( IDC_CONTROL3 ); 
  2. 然后使用列表调用setTabOrder方法:

     void setTabOrder( TABLIST * plstTabs) { // Iterate through the list and put each item at the top of the tab order. // Remember to do this backwards so the last item is actually the first item // in the tab order HDWP hDefer = BeginDeferWindowPos( (int)plstTabs->size() ); for ( TABLIST::reverse_iterator itTab = plstTabs->rbegin(); itTab != plstTabs->rend(); ++itTab ) { DeferWindowPos( hDefer, GetDlgItem( *itTab )->m_hWnd, HWND_TOP, 0,0,0,0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOREPOSITION ); } EndDeferWindowPos( hDefer ); } 

===============>>#3 票数:0

@snowduded的代码的修改版本 ,可确保也使用WS_TABSTOP样式。

// Build your order in a vector.
std::vector<WORD> vCtrlIds;
vCtrlIds.push_back(IDC_CONTROL1);
vCtrlIds.push_back(IDC_CONTROL2);
vCtrlIds.push_back(IDC_CONTROL3);
// ... keep doing it!

// Iterate through the list and put each item at the top of the tab order.
// Remember to do this backwards so the last item is actually the first item
// in the tab order.
HDWP vDefer = BeginDeferWindowPos(vCtrlIds.size());
for(auto vCtrlId(vCtrlIds.rbegin()); vCtrlId != vCtrlIds.rend(); ++vCtrlId){
    HWND vCtrl(GetDlgItem(*vCtrlId)); // Grab the handle.
    SetWindowLongPtr(vCtrl, GWL_STYLE, // Make sure we have WS_TABSTOP.
        GetWindowLongPtr(vCtrl, GWL_STYLE) | WS_TABSTOP);
    DeferWindowPos(vDefer, vCtrl, HWND_TOP, 0, 0, 0, 0, // Reorder.
        SWP_NOSIZE | SWP_NOMOVE | SWP_NOREPOSITION );
}
EndDeferWindowPos(vDefer);

支持@snowdude以获取出色的可重用解决方案。

===============>>#4 票数:0

如果要讨论对话框中不同控件的选项卡顺序:

尝试此操作在资源中打开dlg,然后按Ctrl + D。现在可以通过依次选择控件来设置顺序。

===============>>#5 票数:-1

您无法在运行时更改选项卡顺序。 可以做的是将这两个按钮放在对话框资源中(按正确的选项卡顺序),并使它们不可见。 然后,您会在需要时立即显示/排列按钮。

  ask by AAT translate from so

未解决问题?本站智能推荐: