将静态控件子类化到对话框窗口

时间:2015-07-01 08:53:00

标签: c++ visual-c++ mfc subclass static-content

让我先从目标开始:我将静态控件的背景设置为对话框,而静态控件内容不是固定字符串,并且在切换案例语句之后更改。换句话说,我将把带有动态内容的静态控件的背景设置为带有静态bimap图像的对话窗口。

为了达到这个目标,三个句柄消息定义如下: OnEraseBkgnd(),OnDestroy(),OnCtlColor()

为了显示文本,在每个Switch case语句之后我设置了一个SetWindowText函数:

::SetWindowText(GetDlgItem(IDC_STATIC_FORM)->m_hWnd, ArrayName);

这里唯一的问题是overlapping。预览事件或案例中的所有文本都保留在SetWindowText。要在每个SetWindowText定义一个InvalidateRect(Null)之后解决这个问题,这个问题也解决了,但是在程序中我收到了一个总是闪烁的对话框,如果我在技术上说,闪烁。我认为问题只是因为Invalidate应用于整个对话框而不仅仅是静态控件。对于对话而不是控件,OnCtlColor被覆盖。因为我只想让控件无效,所以我必须继承CStatic控件,只覆盖它的OnCtlColor(不是对话框),而只调用它的Invalidate。

我的问题:

假设我在主代码中为静态控件声明了一个变量,并在构造函数中初始化它,我定义了一个名为CSTATICCTRL的类,其基类为CDialogEX,那么消息处理程序如下:

变量成员定义为:

CSTATICCTRL m_STATIC_FORM;

BOOL CSTATICCTRL::OnEraseBkgnd(CDC* pDC)
{
    // TODO: Add your message handler code here and/or call default
    CDC dcMemory;
    dcMemory.CreateCompatibleDC(pDC);
    CBitmap* pOldbitmap = dcMemory.SelectObject(&Background);
    CRect rcClient;

    const CSize& sbitmap = bitmapSize;
    pDC->BitBlt(0, 0, sbitmap.cx, sbitmap.cy, &dcMemory, 0, 0, SRCCOPY);
    /*The BitBlt function performs a bit-block transfer of the color data corresponding to a rectangle of pixels
    from the specified source device context into a destination device context.*/
    dcMemory.SelectObject(pOldbitmap);

    return 1;
    //return CDialogEx::OnEraseBkgnd(pDC);
}

HBRUSH CSTATICCTRL::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
    //HBRUSH hbr = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor);

    if (pWnd->GetDlgCtrlID() == IDC_STATIC_FORM)
    {
        pDC->SetBkMode(TRANSPARENT);
        pDC->SetTextColor(RGB(255, 255, 255));
        Invalidate();

    }
    return (HBRUSH)GetStockObject(NULL_BRUSH);

}
void CSTATICCTRL::OnDestroy()  //free the resources created for the bitmap,
{
    CDialog::OnDestroy();
    Background.DeleteObject(); // Delete Background bitmap
    BrushHol.DeleteObject();
    // Delete Brush
}

我也将这些消息留在了主代码上。然后我尝试以这种方式在每个开关案例之后使静态控件无效:

 m_STATIC_FORM.Invalidate();

此外,在新类的末尾添加了一个PreSubclassWindow()句柄,如下所示。

void CSTATICCTRL::PreSubclassWindow()
{
    // TODO: Add your specialized code here and/or call the base class

    CDialogEx::PreSubclassWindow();
    ModifyStyle(0, BS_OWNERDRAW);   // make the button owner drawn

} 

什么都没发生!我不知道我的代码有什么问题!!以这种新的方式,静态控制内容发生了变化,但它不透明,重叠仍然存在。

更新

实际上刚才我意识到新的Class在评论一些行后对静态控件和对话框没有任何影响!!我想首先我应该激活CSTATICCTRL然后我可以处理它的句柄消息。

对于对话框代码,使用了这三个句柄消息:

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(&Background);
    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;
    //return CDialog::OnEraseBkgnd(pDC);
}




void CMainDlg::OnDestroy()  //free the resources created for the bitmap,
{
    CDialog::OnDestroy();

    // Delete Brush
}

HBRUSH CMainDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{

    // TODO:  Change any attributes of the DC here

    return (HBRUSH)GetStockObject(NULL_BRUSH);
}

1 个答案:

答案 0 :(得分:2)

我没试过这个,但我认为它会起作用。

在对话框中覆盖OnCtlColor。当它检测到正在绘制静态控件时,返回空刷。这样可以防止背景被擦除,这是导致闪烁的原因。

在静态控件上设置WS_EX_TRANSPARENT样式。这将导致控件下方的对话框部分在绘制控件之前重新绘制,从而删除旧文本。

编辑:根据an article by Raymond Chen WS_EX_TRANSPARENT样式在这种情况下无效,因为对话框不是静态控件的兄弟,它是父对象。您可以使用RedrawWindow重新绘制静态控件下方的部分。

您不应该需要自己的课程,CStatic可以正常使用这些修改。如果你决定你需要你自己的类,你不应该从CDialogEx派生它,那应该保留给对话窗口。

pStatic->SetWindowText(str);
CRect rcChild;
pStatic->GetClientRect(&rcChild);
pStatic->MapWindowPoints(this, &rcChild);
RedrawWindow(rcChild, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
pStatic->InvalidateRect(NULL);