如何将静态控件背景设置为对话框背景?

时间:2015-06-18 15:41:28

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

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

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

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

enter image description here

我不知道为什么在每一步都没有关闭静态窗口以避免这种问题。 我添加了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, "");

我会感激任何帮助。

2 个答案:

答案 0 :(得分:3)

最简单的解决方案是:

  1. 不要将文字背景模式设置为透明。
  2. 将文本背景颜色(使用SetBkColor)设置为对话框的颜色。
  3. 唯一的技巧是将对话框的颜色变为COLORREF。如果您正在使用标准内容,则可以使用其中一种库存颜色常量调用GetSysColor。

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

    1. Add WS_EX_TRANSPARENT到静态控件的扩展窗口样式。
    2. 继续使用透明文字模式。然后,您的文本将被绘制在对话位的新副本上。
    3. WS_EX_TRANSPARENT样式应该使静态控件下面的对话框部分在静态控件之前被绘制。那应该&#34;擦除&#34;上一个文本,然后静态控件将绘制新文本。

      请注意,WS_EX_TRANSPARENT也会生成控件transparent to hit testing(例如,鼠标点击)。由于它是一个静态控制,这不重要。但这就是为什么这不是其他类型控件的通用解决方案。

答案 1 :(得分:3)

绘制不透明:

使用m_Brush初始化CreateSolidBrush并使用SetBkMode(OPAQUE)代替TRANSPARENT

绘图透明:

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

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

应该这样做。

另一个选项,此代码将其他控件与背景图像(编辑控件,单选按钮和复选框)混合使用Dialog可以有WS_CLIPCHILDREN标志,但如果要重绘,静态控件将需要一个正ID( IDC_STATIC通常设置为-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;
}