【问题标题】:How do I make tab key work within this dialog control?如何使 tab 键在此对话框控件中工作?
【发布时间】:2020-12-24 00:15:26
【问题描述】:

我将IsDialogMessage() 添加到我的主循环中,tab 键确实有效,但它卡在了选项卡控件的顶部,并且没有进入对话框内的控件。我该如何解决?我已经在第一个控件中尝试了WS_GROUP,并在接下来创建的所有控件中尝试了WS_TABSTOP,但它不起作用。

标签控件是这样创建的:

hTabControl =
          CreateWindowW(WC_TABCONTROLW, NULL,
            WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_TABSTOP | WS_GROUP | WS_EX_CONTROLPARENT,
            10, 30, 400, 250,
            hwnd,
            (HMENU) ID_MAIN_TABCONTROL,
            NULL,
            NULL);

还有对话框:

      CreateWindowExW(WS_EX_TOOLWINDOW | WS_EX_CONTROLPARENT,
            "DialogBox",
            L"Dialog Box",
            WS_SYSMENU | WS_CHILD | WS_GROUP | WS_TABSTOP | WS_VISIBLE,
            10, 30, 350, 150,
            hTabControl, NULL, ghInstance,  NULL
      );

      // ...

  WNDCLASSEXW wc = {0};
  wc.cbSize           = sizeof(WNDCLASSEXW);
  wc.lpfnWndProc      = DialogProc;
  wc.hInstance        = ghInstance;
  wc.hbrBackground    = GetSysColorBrush(COLOR_3DFACE);
  wc.lpszClassName    = "DialogClass";
  RegisterClassExW(&wc);

然后是 DialogProc 过程:

LRESULT CALLBACK DialogProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
  switch(msg)
  {
  
    case WM_CREATE:
        CreateWindowW(L"button", L"A",
          WS_VISIBLE | WS_CHILD | WS_TABSTOP | WS_GROUP,
          50, 50, 80, 25, hwnd, (HMENU) ID_TAB1_BUTTONA, NULL, NULL);  
        CreateWindowW(L"button", L"B", 
          WS_VISIBLE | WS_CHILD | WS_TABSTOP,
          150, 50, 80, 25, hwnd, (HMENU) ID_TAB1_BUTTONB, NULL, NULL);
        CreateWindowW(L"button", L"C",
          WS_VISIBLE | WS_CHILD | WS_TABSTOP,
          250, 50, 80, 25, hwnd, (HMENU) ID_TAB1_BUTTONC, NULL, NULL);
        CreateWindowW(L"button", L"D",
          WS_VISIBLE | WS_CHILD | WS_TABSTOP,
          50, 100, 80, 25, hwnd, (HMENU) ID_TAB1_BUTTOND, NULL, NULL);
        CreateWindow(L"Edit", NULL,
          WS_VISIBLE | WS_CHILD | WS_BORDER | ES_AUTOHSCROLL | WS_TABSTOP,
          150, 100, 80, 20, hwnd, (HMENU) ID_TAB1_EDIT1, NULL, NULL);
    break;

    case WM_COMMAND:
        
        switch(LOWORD(wParam))
        {
          // didn't do anything
          default: 
          break;

          case ID_TAB1_BUTTONA:
          {
            MessageBox(NULL, L"Click on A button", L"Welcome to the jungle!", MB_OK);
          }
          break;
        }

    break;

    case WM_CLOSE:
        DestroyWindow(hwnd);
    break;

  }
  
  return DefWindowProcW(hwnd, msg, wParam, lParam);
}

还有主循环:

  while (GetMessage(&msg, NULL, 0, 0))
  {
      if (!IsDialogMessage(hwnd, &msg)) {
          TranslateMessage(&msg);
          DispatchMessage(&msg);
      }
  

}

【问题讨论】:

  • 为什么你的(内部)对话框有 WS_EX_TOOLWINDOW 样式?
  • 我想这在我试图从 ALT+TAB 隐藏选项卡控件时被遗漏了

标签: c windows winapi


【解决方案1】:

您通常不会将交互式窗口/控件创建为选项卡控件的子控件,这很奇怪但确实如此。将内部对话框创建为外部对话框的子级,而不是选项卡控件。

This MSDN example 创建内部对话框作为主对话框的子对话框。

正如in this blog post 所解释的,WS_EX_CONTROL­PARENT 将窗口/控件从标签顺序中移除。

这是一个纯Win32的东西,Delphi/C++Builder等带有自定义UI工具包的环境,往往将tab控件实现为真正的容器。

【讨论】:

  • 这真的很奇怪,我来自 C# 的世界,所以我试图模仿我认为正确的行为,使那些 windows 选项卡控件的孩子。但是阅读 Raymond 的博客文章,我明白了为什么会这样,以及犯这个错误是多么普遍。为了使这些控件选项卡控件的兄弟姐妹,我在Windows程序LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { ... } 中更改为CreateWindowExW(WS_EX_CONTROLPARENT,... , hwnd)。现在这样正确吗?我不知道WS_EX_CONTROL­PARENT 接受订单,删除了
  • 通过这个对话框,我试图用 WINAPI 模拟一个容器,因为我在 WINAPI 中没有找到类似的东西。但是通常如何使用 WINAPI 完成它是另一个问题的主题。制表键工作正常,现在我在第一个控件中将它们与WS_GROUP 结合,然后在过程中创建的所有后续窗口中结合WS_TABSTOP。这是使用 WINAPI 完成选项卡的方式吗?
  • 您通常只使用带有单选按钮的组样式,这是唯一需要它们的地方。如果您使用组样式,其他地方只是支持箭头键导航。对于普通控件,您通常只需在每个控件上使用选项卡。
  • 我明白了,然后删除了 WS_GROUP。我读到的内容具有误导性。
  • 但我创建这些控件的方式是否正确?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-15
  • 1970-01-01
相关资源
最近更新 更多