【问题标题】:create scrollable area with controls in dynamically created dialog box by winapi在winapi动态创建的对话框中创建带有控件的可滚动区域
【发布时间】:2015-12-01 06:28:24
【问题描述】:

我创建了允许通过 DialogBoxIndirectParam 动态创建对话框的库。并提供来自 DlgProc 和控件的任何消息。 现在我的任务是通过这个库展示很多控件,所以它们应该放在任何可滚动的区域。

我从 InitCommonControlsEx 提供的标准控件和控件中搜索了简单的决策,但没有找到。

我通过 CreateWindow 和 RegisterClass 创建带有可滚动区域的测试应用程序。效果很好。

然后我尝试在我的库中重复创建这样的窗口。

我在 WM_INITDIALOG 中调用 RegisterClass 和 CreateWindow,但 CreateWindow 返回 NULL,GetLastError 返回 0。

更新:添加寄存器类的代码

WNDCLASSEX wcex;

wcex.cbSize = sizeof(WNDCLASSEX);

wcex.style          = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc    = (WNDPROC) DlgProc;
wcex.cbClsExtra     = 0;
wcex.cbWndExtra     = 0;
wcex.hInstance      = GetModuleHandle(NULL);
wcex.hIcon          = NULL;
wcex.hCursor        = NULL;
wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName   = NULL;
wcex.lpszClassName  = "XMYSCROLL";
wcex.hIconSm        = NULL;

if (! RegisterClassEx(&wcex) ){
    // message box with error
}

【问题讨论】:

  • 你为什么在WM_INITDIALOG中打电话给RegisterClass()?对话结束时您是否取消注册课程?听起来您正在尝试多次注册同一个课程。除此之外,我们还需要查看代码。
  • 你说得对,RegisterClass 我应该放在 LoadLibrary 中并在 UnLoad 中取消注册。但它没有帮助。
  • Casting DlgProc to WNDPROC is wrong. 为你的窗口类写一个窗口过程;不要使用对话过程。更改DlgProc 的函数签名也不起作用,因为对话框过程和窗口过程的工作方式完全不同,特别是因为窗口过程不会接收诸如WM_INITDIALOG 之类的消息并且返回返回不同;您需要通过并将所有对话 gunk 更改为 window gunk。如果您对外部对话框使用相同的DlgProc,则必须拆分它们。

标签: winapi dialog scrollbar


【解决方案1】:

我在内部调用 DlgProc 来制作单独的 WndProc:

WNDCLASSEX wcex;

wcex.lpfnWndProc    = (WNDPROC) WndProc;
wcex.hInstance      = GetModuleHandle(NULL);
wcex.lpszClassName  = "XMYSCROLL";
...
if (! RegisterClassEx(&wcex) ){
    ...
}

....

在 WndProc 中我们不知道对话框的句柄,所以 我们需要将它保存到 WM_INITDIALOG 的 GWL_USERDATA 中。

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    if (message==WM_VSCROLL || message==WM_HSCROLL ){
        HWND dialog = (HWND)GetWindowLong(hWnd,GWL_USERDATA);
        if (dialog && IsWindow(dialog) ){
            if (DlgProc(dialog, message, wParam, (DWORD)hWnd) ){
                return 0;
            }
        }
    }
    return DefWindowProc(hWnd, message, wParam, lParam);
}

同样在 WM_INITDIALOG 中,我们需要直接为在 DialogBoxIndirectParam 中创建的所有子项设置父项。否则“xmyscroll”窗口将隐藏其所有子窗口。

我们还需要在使用滚动时将对话框控件的大小转换为“xmyscroll”窗口。但是有some problem with GetDialogBaseUnits,所以我使用了MapDialogRect中的虚拟值来获得对话框尺寸和“xmyscroll”窗口尺寸之间的真实转换系数。

因此,在代码 (RSL) 中,使用库我编写了下一个来处理滚动消息(MapDWY 使用 koeff 执行多个对话框单元作为高度):

scroll_visible_height = dialog.MapDWY( scroll_height_in_dialog_units );
scroll_inner_height = dialog.MapDWY( (total_controls+1)*controls_step_in_dialog_units );
controls_step = dialog.MapDWY( controls_step_in_dialog_units );

var page = scroll_visible_height + controls_step;

yMaxScroll = max(scroll_inner_height - page, 0);
yCurrentScroll = min(yCurrentScroll, yMaxScroll);
dialog.Set_ScrollInfo(scroll_control_id,
            SB_VERT,
            SIF_RANGE + SIF_PAGE + SIF_POS,
            yMinScroll,
            scroll_inner_height,
            page,
            yCurrentScroll
        );

从这里可以看出编写重要“scroll_inner_height”参数的正确定义的关键时刻。

【讨论】:

    猜你喜欢
    • 2021-06-20
    • 1970-01-01
    • 2020-02-21
    • 1970-01-01
    • 1970-01-01
    • 2012-07-29
    • 2012-06-24
    • 2011-01-23
    • 1970-01-01
    相关资源
    最近更新 更多