【问题标题】:How do you place sub controls inside a group box?如何在组框内放置子控件?
【发布时间】:2008-10-18 04:06:28
【问题描述】:

当我启用通用控件视觉样式支持 (InitCommonControls()) 并且我使用 Windows 经典主题以外的任何主题时,组框内的按钮会显示为带有方角的黑色边框。

Windows 经典主题显示正常,当我关闭视觉样式时也是如此。

我正在使用以下代码:

group_box = CreateWindow(TEXT("BUTTON"), TEXT("BS_GROUPBOX"), 
    WS_CHILD | WS_VISIBLE | BS_GROUPBOX | WS_GROUP,
    10, 10, 200, 300,
    hwnd, NULL, hInstance, 0);

push_button = CreateWindow(TEXT("BUTTON"), TEXT("BS_PUSHBUTTON"),
    WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
    40, 40, 100, 22,
    group_box, NULL, hInstance, 0);

编辑:单选按钮也会出现问题

编辑:我没有使用任何对话框/资源,仅使用 CreateWindow/Ex。

我在 Visual C++ 2008 Express SP1 下编译,带有一个通用的 manifest 文件

Screenshot http://img.ispankcode.com/black_border_issue.png

【问题讨论】:

  • 黑色边框是出现在所有按钮周围,还是只出现在您提供的图像中?
  • 所有按钮。如果我使用 Windows 经典主题,它们会正常显示。
  • 父对话框本身的 CreateWindow 调用是什么样的?只是想知道是否发生了某种继承。
  • hwnd = CreateWindow(appName,TEXT("Window Skeleton"), WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,435,360,NULL,NULL,hInstance,0);
  • 嗯。如果按钮也在组框之外,会发生这种情况吗?

标签: c user-interface winapi


【解决方案1】:

问题在于将 groupbox 作为控件的父级。 Groupboxes 不应该有任何孩子,将它们用作父母会导致各种错误(包括绘画、键盘导航和消息传播)。只需将按钮的 CreateWindow 调用中的父级从 group_box 更改为 hwnd(即对话框)。

我猜您使用 groupbox 作为父级以便在其中轻松定位其他控件。正确的方法是获取 groupbox 客户区的位置并将其映射到对话框的客户区。然后,放置在生成的 RECT 中的所有内容都将出现在 groupbox 中。由于组框实际上没有客户区,因此可以这样计算:

// Calculate the client area of a dialog that corresponds to the perceived
// client area of a groupbox control. An extra padding in dialog units can
// be specified (preferably in multiples of 4).
//
RECT getClientAreaInGroupBox(HWND dlg, int id, int padding = 0) {
    HWND group = GetDlgItem(dlg, id);
    RECT rc;
    GetWindowRect(group, &rc);
    MapWindowPoints(0, dlg, (POINT*)&rc, 2);

    // Note that the top DUs should be 9 to completely avoid overlapping the
    // groupbox label, but 8 is used instead for better alignment on a 4x4
    // design grid.
    RECT border = { 4, 8, 4, 4 };
    OffsetRect(&border, padding, padding);
    MapDialogRect(dlg, &border);

    rc.left += border.left;
    rc.right -= border.right;
    rc.top += border.top;
    rc.bottom -= border.bottom;
    return rc;
}

请注意,这同样适用于 Tab 控件。他们也不是为父母而设计的,并且会表现出类似的行为。

【讨论】:

  • 究竟是如何“获取groupbox客户区的位置”的? GetClientRect 给出了包括边框和标题在内的区域,不允许在不绘制内容的情况下放置。
  • @nwp,好问题。我找不到原始实现,但我已经用可能的解决方案更新了我的答案。它基本上是一个涉及对话单元的 hack。
【解决方案2】:

这里只是一个猜测,但看起来您正在从您的主题继承静态边缘或客户端边缘样式。我从资源编辑器创建了大部分对话框,并在那里设置了这些属性。

在您的情况下,您可以将 CreateWindow 替换为 CreateWindowEx 以设置这些扩展样式,这些样式可能在 CreateWindow 中被默认设置。具体查看WS_EX_STATICEDGE, WS_EX_WINDOWEDGE and WS_EX_CLIENTEDGE

编辑:我假设这没有发生,因为您的按钮是对话框中的默认控件,这也会产生黑边。

【讨论】:

    【解决方案3】:

    显然,分组框并不意味着对控件进行分组(作为父 hwnd)

    因此,为了摆脱黑色边框/绘画问题,我必须对组框进行子类化并实现 WM_PAINT 和 WM_PRINTCLIENT

    【讨论】:

      【解决方案4】:

      啊,是的,带有单选按钮和组框的黑色背景。虽然我不确定这是否适用于 VC++ 2008,但过去 VB6 主题应用程序的解决方案是先将无线电控件放在 PictureBox(实际上是一个通用容器)上,然后将其添加到组框。

      值得一试!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-07-29
        • 1970-01-01
        • 2012-10-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多