【问题标题】:how to set a static control background as a dialog background?如何将静态控件背景设置为对话框背景?
【发布时间】:2015-09-04 08:41:32
【问题描述】:

我的主代码中有一个回调函数,它包含在 Switch case 语句中。在每个案例之后,我定义了一个 SetWindowText 函数来打印在对话框(或父窗口)上创建的静态控件中的文本,如下所示:

::SetWindowText(GetDlgItem(IDC_STATIC)->m_hWnd, "loading");

我打算将静态控件的背景设置为对话框的背景。一切都很顺利,除了所有案例的文本相互重叠,我收到一个带有重叠文本的静态控件,如下所示:

我不知道为什么在每个步骤中它都没有关闭静态窗口以避免此类问题。 我添加了OnEraseBkgndOnDestroyOnCtlColor 消息如下:

BOOL CmainDlg::OnEraseBkgnd(CDC* pDC)
{
    // TODO: Add your message handler code here and/or call default

    CDC dcMemory;
    dcMemory.CreateCompatibleDC(pDC);
    CBitmap* pOldbitmap = dcMemory.SelectObject(&CBmp);
    CRect rcClient;
    GetClientRect(&rcClient);
    const CSize& sbitmap = bitmapSize;
    pDC->BitBlt(0, 0, sbitmap.cx, sbitmap.cy, &dcMemory, 0, 0, SRCCOPY);
    dcMemory.SelectObject(pOldbitmap);
    return TRUE;

}
    HBRUSH CmainDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
    HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);



    if (pWnd->GetDlgCtrlID() == IDC_STATIC)
        //Example of changing Text colour specific to a certain 
        //Static Text Contol in this case IDC_STATIC.
    {
        pWnd->GetExStyle() & (WS_EX_TRANSPARENT);
        pDC->SetBkMode(TRANSPARENT);
        pDC->SetTextColor(RGB(255, 255, 255));

    }
    if (pWnd->GetDlgCtrlID() == IDC_OPERATION)

    {
        pWnd->GetExStyle() & (WS_EX_TRANSPARENT);
        pDC->SetBkMode(TRANSPARENT);
        pDC->SetTextColor(RGB(255, 255, 0));

        // Return handle to our CBrush object
    }
        return reinterpret_cast<HBRUSH>(GetStockObject(NULL_BRUSH));
    }

void CmainDlg::OnDestroy()
{
    CDialog::OnDestroy();

    // TODO: Add your message handler code here
    Background.DeleteObject(); // Delete Background bitmap
    BrushHol.DeleteObject();
}
//subclass the static control, just to make sure the code is the only one handling WM_ERASEBKGND and WM_PAINT messages.
void CmainDlg::PreSubclassWindow()
{
    CWnd::PreSubclassWindow();

    const LONG_PTR exStyle = GetWindowLongPtr(m_hWnd, GWL_EXSTYLE);
    SetWindowLongPtr(m_hWnd, GWL_EXSTYLE, exStyle | WS_EX_TRANSPARENT);
}

更新:

我评论了OnEraseBkgndOnDestroyOnCtlColor 函数。所以我收到了相同的重叠文本,现在我可以更确定地说问题来自setWindowText,因为在完成每个 Case 后,文本仍保留在我在每个开关中定义的静态控制窗口上案例陈述。 我尝试使用以下命令,但没有任何反应:

EnableWindow( GetDlgItem(m_hWnd, IDC_STATIC), FALSE);
m_static.EnableWindow(FALSE);

::SetDlgItemText(m_hWnd, IDC_STATIC, "");

我将不胜感激。

【问题讨论】:

  • 您将背景设置为透明,这是正确的行为吗?如果您在主循环中的同一区域渲染相同的文本,这意味着文本不会被替换,而是会保留在那里并且会重叠...尝试将背景更改为不透明。打印文本时是否使用相同的坐标?
  • 原来你其实并不喜欢 SetBkMode(TRANSPARENT)
  • @KostasRim 没有SetBkMode(TRANSPARENT) 函数,静态控件失去其父背景!
  • @HansPassant 如果没有 SetBkMode(TRANSPARENT),它会再次回到非透明模式。我的意思是父背景没有设置为静态背景!
  • 查看当您将某些内容设置为透明时,在同一位置呈现文本的循环的每次迭代都会重叠。这就是透明物体的全部意义所在。除了透明,你还有其他选择吗?现在,如果您真的不关心性能,那么为什么不在每次循环迭代中再次尝试设置背景呢?你能试试这个吗?如果您这样做,它将清除整个屏幕,并准备好再次呈现文本。

标签: c++ visual-c++ mfc dialog


【解决方案1】:

最简单的解决方案是:

  1. 不要将文本背景模式设置为透明。
  2. 将文本背景颜色(SetBkColor)设置为对话框的颜色。

唯一的技巧是将对话框的颜色作为 COLORREF。如果您使用的是标准的东西,您可能只需使用其中一个常用颜色常量调用 GetSysColor。

如果对话框背景不是纯色(例如渐变填充),您将不得不做一些更复杂的事情:

  1. Add WS_EX_TRANSPARENT 到静态控件的扩展窗口样式。
  2. 继续使用透明文本模式。然后,您的文本将被绘制在对话框位的新副本上。

WS_EX_TRANSPARENT 样式应该使静态控件下方的对话框部分在静态控件之前绘制。这应该“擦除”以前的文本,然后静态控件将绘制新文本。

请注意,WS_EX_TRANSPARENT 也使控件 transparent to hit testing(例如,用于鼠标单击)。由于它是静态控件,因此没关系。但这就是为什么这不是其他类型控件的通用解决方案。

【讨论】:

  • 请查看修改后的代码。但是我仍然有相同的输出!
  • pWnd-&gt;GetExStyle() &amp; (WS_EX_TRANSPARENT); 什么都不做。您应该在创建静态控件时设置 WS_EX_TRANSPARENT 标志。如果您使用的是对话框模板,它会出现在其中。如果您以编程方式创建控件,它会进入您的 CreateWindow 调用。
  • 我不知道如何设置 WS_EX_TRANSPARENT 标志,也看不到静态控件的创建位置。我正在使用一个对话框模板(框),所以从静态控件的 Properties 我将 TRANSPARENT 模式更改为 TRUE,然后在 .rc 文件中我将 WS_EX_TRANSPARENT 添加到这行代码:CONTROL "",IDC_STATIC,"Static",SS_SIMPLE | WS_GROUP | 0x20,259,8,185,17 但是又什么都没发生!
【解决方案2】:

绘图不透明:

使用CreateSolidBrush 初始化m_Brush 并使用SetBkMode(OPAQUE) 而不是TRANSPARENT

绘制透明:

按照 Adrian McCarthy 的回答和 return (HBRUSH)GetStockObject(NULL_BRUSH) 进行静态控制,而不是返回 m_Brush

确保对话框没有 WS_CLIPCHILDREN 标志,否则在静态控件中重写文本时会遇到相同的重叠问题。

应该可以的。

另一种选择,此代码将其他控件与背景图像混合(编辑控件、单选按钮和复选框)对话框可以有WS_CLIPCHILDREN 标志,但如果要重绘静态控件,则需要一个正的 id (@987654329 @ 通常设置为 -1)。对话框项目也需要WS_EX_TRANSPARENT 标志。我没有测试这么多。

不要忘记将ON_WM_DESTROY 添加到消息映射中。

class TDlg : public CDialogEx
{
public:
    std::map<int, HBRUSH> BrushMap;
    CBitmap Bitmap;

    TDlg(int id, CWnd *wnd) : CDialogEx(id, wnd){};
    void MakeBrush(CDC *pdc, CDC &memdc, int id);
    BOOL OnEraseBkgnd(CDC* pDC);
    void OnDestroy();
    BOOL OnInitDialog();
    HBRUSH OnCtlColor(CDC* pDC, CWnd* wnd, UINT nCtlColor);

    DECLARE_MESSAGE_MAP()
};

BOOL TDlg::OnInitDialog()
{
    CDialogEx::OnInitDialog();
    Bitmap.LoadBitmap(IDB_BITMAP1);
    return 1;
}

void TDlg::OnDestroy()
{
    CDialogEx::OnDestroy();
    Bitmap.DeleteObject();
    for (std::map<int, HBRUSH>::iterator it = BrushMap.begin(); it != BrushMap.end(); ++it)
        if (it->second)
            DeleteObject(it->second);
}

void TDlg::MakeBrush(CDC *pdc, CDC &memdc, int id)
{
    CWnd *item = GetDlgItem(id);

    CRect rc;
    item->GetClientRect(&rc);
    item->MapWindowPoints(this, &rc);

    CBitmap bmp;
    bmp.CreateCompatibleBitmap(&memdc, rc.Width(), rc.Height());
    memdc.SelectObject(bmp);
    memdc.BitBlt(0, 0, rc.Width(), rc.Height(), pdc, rc.left, rc.top, SRCCOPY);
    BrushMap[id] = CreatePatternBrush(bmp);
}

BOOL TDlg::OnEraseBkgnd(CDC* pDC)
{
    BITMAP bm;
    Bitmap.GetBitmap(&bm);

    CDC memdc;
    memdc.CreateCompatibleDC(pDC);
    CBitmap* pOldbitmap = memdc.SelectObject(&Bitmap);
    pDC->BitBlt(0, 0, bm.bmWidth, bm.bmHeight, &memdc, 0, 0, SRCCOPY);

    //BrushMap should be intialized once
    if (!BrushMap.size())
        for (CWnd *p = GetWindow(GW_CHILD); p; p = p->GetNextWindow(GW_HWNDNEXT))
            if (p->GetDlgCtrlID() > 0)
                MakeBrush(pDC, memdc, p->GetDlgCtrlID());

    memdc.SelectObject(pOldbitmap);

    return TRUE;
}

HBRUSH TDlg::OnCtlColor(CDC* pDC, CWnd* wnd, UINT nCtlColor)
{
    HBRUSH br = CDialogEx::OnCtlColor(pDC, wnd, nCtlColor);

    pDC->SetTextColor(RGB(255, 0, 0));
    pDC->SetBkMode(TRANSPARENT);

    int id = wnd->GetDlgCtrlID();
    if (id > 0 && BrushMap[id])
        return BrushMap[id];

    if (nCtlColor == CTLCOLOR_STATIC)
        return (HBRUSH)GetStockObject(NULL_BRUSH);

    return br;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-03-05
    • 1970-01-01
    • 1970-01-01
    • 2014-01-25
    • 1970-01-01
    • 2019-01-21
    • 2013-03-09
    • 1970-01-01
    相关资源
    最近更新 更多