winapi 中子窗口编辑控件上的 WS_TABSTOP

2024-03-12

在我的 WinAPI 应用程序中,我的子窗口中有一系列编辑控件。我希望用户能够通过按 Tab 键前进并按 Shift-Tab 键返回来在它们之间移动,但我似乎不知道如何使用WS_TABSTOP与子窗口。我想要发生的是,当用户单击 Tab 键时,选择后续的编辑控件。但是,当我单击以下代码窗口中的选项卡时,光标就会消失。

这是一个最小的可重现示例:

    //libraries
#pragma comment ("lib", "Comctl32.lib")
#pragma comment ("lib", "d2d1.lib")


#define WIN32_LEAN_AND_MEAN             // Exclude rarely-used stuff from Windows headers
// Windows Header Files
#include <windows.h>
#include <CommCtrl.h>
// C RunTime Header Files

#include <vector>
#include <string>


#define IDS_APP_TITLE           103
#define IDI_PRACTICE            107
#define IDI_SMALL               108
#define IDC_PRACTICE            109

#define MAX_LOADSTRING          100

// Global Variables:
HINSTANCE hInst;                                // current instance
WCHAR szTitle[MAX_LOADSTRING];                  // The title bar text
WCHAR szWindowClass[MAX_LOADSTRING];            // the main window class name

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK WndProcChild(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

ATOM MyRegisterClass(HINSTANCE hInstance);

HWND childHWND;

HWND InitInstance(HINSTANCE hInstance, int nCmdShow);

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
    _In_opt_ HINSTANCE hPrevInstance,
    _In_ LPWSTR    lpCmdLine,
    _In_ int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);
    // Initialize global strings
    LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    LoadStringW(hInstance, IDC_PRACTICE, szWindowClass, MAX_LOADSTRING);
    MyRegisterClass(hInstance);

    SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);

    // Perform application initialization:
    HWND hWnd = InitInstance(hInstance, nCmdShow);
    if(!hWnd)
    {
        return FALSE;
    }
    HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_PRACTICE));
    MSG msg;
    // Main message loop:
    while (GetMessage(&msg, nullptr, 0, 0))
    {
        if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
        {
            if (!IsDialogMessage(hWnd, &msg))
            {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
        }
    }
    return (int)msg.wParam;
}


LRESULT CALLBACK WndProcChild(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_CREATE:
    {
        HWND edit1 = CreateWindow(WC_EDIT, L"", WS_CHILD | WS_BORDER | WS_VISIBLE | WS_TABSTOP, 100, 100, 100, 100, hWnd, (HMENU)1, hInst, NULL);
        HWND edit2 = CreateWindow(WC_EDIT, L"", WS_CHILD | WS_BORDER | WS_VISIBLE | WS_TABSTOP, 300, 100, 100, 100, hWnd, (HMENU)2, hInst, NULL);
        break;
    }
    }
    return DefWindowProc(hWnd, message, wParam, lParam);
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;

}

ATOM MyRegisterClass(HINSTANCE hInstance)
{
    WNDCLASSEXW wcex;
    wcex.cbSize = sizeof(WNDCLASSEX);
    wcex.style = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc = WndProc;
    wcex.cbClsExtra = 0;
    wcex.cbWndExtra = 0;
    wcex.hInstance = hInstance;
    wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_PRACTICE));
    wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
    wcex.hbrBackground = (HBRUSH)(GetStockObject(WHITE_BRUSH));
    wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_PRACTICE);
    wcex.lpszClassName = L"Parent";
    wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));


    //Child wnd class
    WNDCLASSEXW wcexChild;
    wcexChild.cbSize = sizeof(WNDCLASSEX);
    wcexChild.style = CS_HREDRAW | CS_VREDRAW;
    wcexChild.lpfnWndProc = WndProcChild;
    wcexChild.cbClsExtra = 0;
    wcexChild.cbWndExtra = 0;
    wcexChild.hInstance = hInstance;
    wcexChild.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_PRACTICE));
    wcexChild.hCursor = LoadCursor(nullptr, IDC_ARROW);
    wcexChild.hbrBackground = (HBRUSH)(GetStockObject(WHITE_BRUSH));
    wcexChild.lpszMenuName = MAKEINTRESOURCEW(IDC_PRACTICE);
    wcexChild.lpszClassName = L"Child";
    wcexChild.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
    return RegisterClassExW(&wcexChild) && RegisterClassExW(&wcex);
}


HWND InitInstance(HINSTANCE hInstance, int nCmdShow)
{
    hInst = hInstance; // Store instance handle in our global variable
    HWND hWnd = CreateWindowW(L"Parent", L"PARENT", WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, nullptr, nullptr, hInstance, nullptr);

    childHWND = CreateWindowW(L"Child", L"", WS_CHILD | WS_VISIBLE | WS_EX_CONTROLPARENT,
        0, 0, 700, 700, hWnd, nullptr, hInstance, nullptr);

    if (!hWnd)
    {
        return NULL;
    }
    ShowWindow(childHWND, nCmdShow);
    UpdateWindow(childHWND);

    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);
    return hWnd;
}

这里的问题是if (!IsDialogMessage(hWnd, &msg))在错误的窗口上被调用。

将该行替换为if (!IsDialogMessage(childHWND, &msg))让 TAB 导航正常工作。

来自IsDialogMessage https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-isdialogmessagew文档:

尽管 IsDialogMessage 函数适用于非模式对话框, 您可以将它与任何包含控件的窗口一起使用, 使窗口能够提供与对话框中使用的相同的键盘选择。

在发布的代码中,“包含控件的窗口" 是编辑控件的直接父级,即childHWND.


[ EDIT]   评论中指出的另外一个问题(感谢@IInspectable https://stackoverflow.com/users/1889329/iinspectable) 是扩展样式WS_EX_CONTROLPARENT错误地与样式标志一起传递,而不是extended风格标志。要解决这个问题,请调用childHWND = CreateWindowW(L"Child", L"", WS_CHILD | WS_VISIBLE | WS_EX_CONTROLPARENT, ...应该改为childHWND = CreateWindowExW(WS_EX_CONTROLPARENT, L"Child", L"", WS_CHILD | WS_VISIBLE, ...反而。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

winapi 中子窗口编辑控件上的 WS_TABSTOP 的相关文章

随机推荐

  • 使用嵌套转发器对一组数据集进行分组

    假设我有一些这样的书籍数据 我有一个查询 例如SELECT FROM BookData以上述格式输出 我想使用嵌套的转发器控件来输出 html 中的数据 table 看起来像这样 数据结果按作者分组 到目前为止 我的 asp net Web
  • 对热图的刻度线进行分组

    I have a heatmap that looks like this from Plotting a 2D heatmap with Matplotlib https stackoverflow com questions 33282
  • 使用 JTable 作为 JTree 单元格编辑器

    我想使用 JTable 来编辑 JTree 我扩展了 DefaultTreeCellEditor 并实现了 isCellEditable getTreeCellEditorComponent 在 getTreeCellEditorCompo
  • 有 DGML 查看器吗? [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我已经开始玩了DGML http en wikipedia org wiki DGML用于基于某些制造
  • 现在 x86 上有多少指令? [关闭]

    这个问题不太可能对任何未来的访客有帮助 它只与一个较小的地理区域 一个特定的时间点或一个非常狭窄的情况相关 通常不适用于全世界的互联网受众 为了帮助使这个问题更广泛地适用 访问帮助中心 help reopen questions 我正在尝试
  • 仅使用套接字的 Python 邮件客户端(无 smtplib)

    我正在尝试编写一个 python 程序 它将在不使用 smtplib 的情况下发送电子邮件 我尝试查看有关此问题的其他帖子 但找不到解决方案 from socket import msg r n My email s content end
  • Spring MVC 项目无法发布和运行...消息:无法自省注释

    我有一个 Spring MVC 应用程序 4 1 1 发布版本 当我尝试发布并在服务器上运行时 我收到以下错误 附加信息 使用Spring工具套件3 6 1 春季版本 4 1 1 RELEASE 这是一个maven项目 它没有任何编译错误
  • OCMock - 部分模拟 [UIAlertView alloc]

    我有一个问题OCMockiOS 框架 我本质上是想嘲笑UIAlertView s initWithTitle message delegate 方法 下面的示例不起作用 因为当我调用时 未返回存根返回值initWithTitle metho
  • 使用 Gson 2.3.1 反序列化包含在 Java 中不起作用的接口的 Json 字符串

    我正在尝试使用 Gson 将包含接口和哈希图 具有接口类型和包含接口类型的列表 的 json 字符串反序列化为 java 对象 但我越来越 java lang RuntimeException 无法调用接口 com abc Dummy 的无
  • R - 使用匹配运算符时保留顺序 (%in%)

    我正在使用匹配运算符从单独的数据框中获取矩阵中出现的值 但是 生成的矩阵的值按照它们在数据框中出现的顺序排列 而不是按原始矩阵排列 有没有办法使用匹配运算符来保留原始矩阵的顺序 这是一个简单的例子 vec c b a c vec df da
  • jQuery 克隆表行

    我有一个表 末尾有一个 添加 按钮 当您单击此按钮时 我希望在当前行下方创建一个新的表行 我还希望该行的输入字段为空 我尝试使用 clone 来执行此操作 但它会克隆页面上的所有行 请帮忙 谢谢 Script input tr clone
  • 位置侦听器从服务工作,但不是 IntentService

    我有一个应用程序 我试图定期获取用户位置并将其发送到服务器 我有一项服务附加到AlarmManager每分钟执行一次 用于测试 该服务正确找到用户位置并注销 GPS 坐标 一旦出现 GPS 锁定 我就会取消位置请求并停止服务 当我请求位置更
  • C++ 2D 曲面细分库?

    我有一些凸多边形存储为点的 STL 向量 或多或少 我想要镶嵌 http en wikipedia org wiki Tesselate它们非常快 最好分成大小相当均匀的块 并且没有 条子 我将用它来将一些物体分解成小碎片 有谁知道一个很好
  • 如何使用线程在java中暂停执行

    我以编程方式创建了一个向导 它包含 3 个面板 第二个是devicePane 第三个是detailsPane 第三个面板包含一个进度条 我希望我的程序启动一个功能process 显示第三个面板后 可以使用线程吗 else if Parser
  • HTML+CSS 中的不确定进度条

    我想创建一个不确定的HTML CSS进度条所以它看起来像 Vista 上的那个 source microsoft com http i msdn microsoft com dynimg IC121865 png 我想 水平调整进度条宽度
  • 在同一终端中同时运行多个命令

    I want to run a few commands each of which doesn t quit until Ctrl C is pressed Is there something I can run to run all
  • 客户愤怒,与未知的 DLL 依赖项作斗争

    我是一位为客户开发 C Windows 应用程序的单人秀 在过去的几个月里 我们一直遇到同样的问题 即客户计算机上缺少 DLL 依赖项 尽管我尽了最大努力 但问题仍然存在 我们收到了愤怒的电子邮件 我的老板和我老板的老板对我很生气 顾客也不
  • 如何在 Swift 中将*正数*转换为数字数组

    我想转换一个positive数字到相应的数字列表中 数字也应该是整数 转换时 例如 1024 它应该返回 1 0 2 4 在 Swift 4 1 或更高版本中 let number 1024 let digits String number
  • 部署时使 Google Cloud Function 的 Firebase 缓存失效

    我最近使用 Cloud Functions 和 Firebase Hosting 实现了 SSR 当 JS 包构建时 它会收到一个缓存突发后缀 main 1 js 在我的函数内部 我有以下代码段用于缓存云函数的结果 res set Cach
  • winapi 中子窗口编辑控件上的 WS_TABSTOP

    在我的 WinAPI 应用程序中 我的子窗口中有一系列编辑控件 我希望用户能够通过按 Tab 键前进并按 Shift Tab 键返回来在它们之间移动 但我似乎不知道如何使用WS TABSTOP与子窗口 我想要发生的是 当用户单击 Tab 键