写了个CEdit的继承类,美化效果不理想,全部代码如下。
我想实现一个下划线、背景透明的编辑框,刚运行的时候效果有了,但在上面输入文字时,文字背景就变成白色了,帮忙看看代码哪有问题,头文件就不贴了。HBRUSH COwnEdit::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
HBRUSH hbr = CEdit::OnCtlColor(pDC, pWnd, nCtlColor); // TODO:  在此更改 DC 的任何特性 // TODO:  如果默认的不是所需画笔,则返回另一个画笔
//pDC->SetBkColor(GetSysColor(COLOR_3DFACE));
pDC->SetBkMode(TRANSPARENT);
    return (HBRUSH)GetStockObject(HOLLOW_BRUSH);
//return hbr;
}
void COwnEdit::OnPaint()
{
CPaintDC dc(this); // device context for painting
// TODO: 在此处添加消息处理程序代码
// 不为绘图消息调用 CEdit::OnPaint()
CRect rect;
    this->GetRect(&rect);
    CDC* pDC=GetDC();
int nStyle = GetStyle() & ES_MULTILINE;
dc.MoveTo(rect.left,rect.bottom);
dc.LineTo(rect.right,rect.bottom);
    CString str;
    this->GetWindowText(str);      CFont* pFont=this->GetFont();
    CFont oldFont;
    dc.SelectObject(pFont);

    dc.DrawText(str,&rect,DT_LEFT | DT_TOP);
dc.SetBkMode(TRANSPARENT);
//pDC->SetBkColor(GetSysColor(COLOR_3DFACE));
//pDC->SetBkMode(TRANSPARENT);
}
HBRUSH COwnEdit::CtlColor(CDC* pDC, UINT /*nCtlColor*/)
{
// TODO:  在此更改 DC 的任何特性 // TODO:  如果不应调用父级的处理程序,则返回非 null 画笔
//pDC->SetBkColor(GetSysColor(COLOR_3DFACE));
pDC->SetBkMode(TRANSPARENT);
    return (HBRUSH)GetStockObject(HOLLOW_BRUSH);
//return NULL;
}
BOOL COwnEdit::OnChildNotify(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pLResult)
{
// TODO: 在此添加专用代码和/或调用基类 //return CEdit::OnChildNotify(message, wParam, lParam, pLResult);
 // We only want to handle WM_CTLCOLOREDIT messages - 32 bit only
    if (message != WM_CTLCOLOREDIT) 
    {
        return CEdit::OnChildNotify(message, wParam, lParam, pLResult);
    }
    HDC hdcChild = (HDC)wParam;
    // Text is black – you can modify this by adding
    // another variable for text color
   // SetTextColor(hdcChild, RGB(0,0,0));
    //SetBkColor(hdcChild, m_BackColor);
SetBkMode(hdcChild, TRANSPARENT);
//hdcChild->SetBkMode(TRANSPARENT);    return TRUE;
}
void COwnEdit::OnSetFocus(CWnd* pOldWnd)
{
CEdit::OnSetFocus(pOldWnd);    m_BackColor = RGB(255,255,0);
CDC* pDC = GetDC();
    Invalidate(FALSE);
// TODO: 在此处添加消息处理程序代码
pDC->SetBkMode(TRANSPARENT);
}
void COwnEdit::OnKillFocus(CWnd* pNewWnd)
{
CEdit::OnKillFocus(pNewWnd);
// I am setting normal back color to white
    // – you can modify this as you see fit
    m_BackColor = RGB(255,255,255);
    // Force a repaint
CDC* pDC = GetDC();
    Invalidate(FALSE);
//pDC->SetBkMode(TRANSPARENT);
}void COwnEdit::SetBkGrndColor()
{
    // Delete the old brush
    m_Brush.DeleteObject();
    // Create a new brush in the specified color
    m_Brush.CreateSolidBrush(m_BackColor);
    CDC* pDC = GetDC();
    pDC->SetBkMode(TRANSPARENT);
    //pDC->SetBkColor(m_BackColor);
    // Select the brush into this window’s device context
    pDC->SelectObject(&m_Brush);
    CRect rc;
    // Get the client area of the edit control
    GetClientRect(&rc);
    ScreenToClient(&rc);
    // Apply the device context to the client area of the edit control
    //pDC->Rectangle(0, 0, rc.Width(), rc.Height());
    // Rewrite the text since the backcolor paint
    // overwrote the existing text
    pDC->SetTextColor(RGB(0,0,0));
    pDC->TextOut(2, 2, m_Text.GetBuffer(m_Text.GetLength()));
}

解决方案 »

  1.   

    HBRUSH COwnEdit::CtlColor(CDC* pDC, UINT /*nCtlColor*/)是REFLECT消息BOOL COwnEdit::OnChildNotify(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pLResult)干什么的?HBRUSH COwnEdit::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)又是干什么的?
      

  2.   

    响应OnEraseBkgnd绘制背景。事件OnEnChange刷新控件。这个你缺少了,所以输入后出问题。
      

  3.   

    需要把edit的背景制作为一个Brush,在OnEraseBkgnd(CDC* pDC)中用这个Brush刷背景。
      

  4.   


    CBrush* CDrawEditDlg::CreateBackgroundBrush(CDC* pDC,int ctrlId)
    {
    CDC dcMem;
    dcMem.CreateCompatibleDC(pDC);//DeleteDC needed
    CBitmap* pOldBitmap = dcMem.SelectObject(&m_bitmap);
    // Retrieve the size of our bitmap...
    BITMAP bmp;
    m_bitmap.GetObject(sizeof(bmp),&bmp);
    // and the size of our dlg's client area
    CRect rect;
    GetClientRect(&rect);
    //
    CRgn  rgnClip;
    CRect rc;
    GetDlgItem(ctrlId)->GetWindowRect(&rc);
    rgnClip.CreateRectRgnIndirect(rc);//DeleteObject needed
    CDC* pDCex=GetDCEx(&rgnClip,DCX_PARENTCLIP);//ReleaseDC needed
    // Fill the client area of dlg,include the ctrl with our bitmap
    pDCex->StretchBlt(rect.left, rect.top,rect.Width(), rect.Height(),
    &dcMem,0, 0, bmp.bmWidth, bmp.bmHeight,SRCCOPY);
    // we create the background brush of SelEdit
    CDC dcMemCtrl;
    dcMemCtrl.CreateCompatibleDC(pDCex);//DeleteDC needed
    CBitmap CtrlBmp;//DeleteObject needed
    CtrlBmp.CreateCompatibleBitmap(pDCex,rc.Width(),rc.Height());
    pOldBitmap = dcMemCtrl.SelectObject(&CtrlBmp);
    ScreenToClient(&rc);
    MapWindowPoints(this,rc);
    // afxDump << rc << " xx\n";
    dcMemCtrl.BitBlt(0, 0, rc.Width(), rc.Height(), pDCex, rc.left, rc.top, SRCCOPY);
    CBitmap  *nowBMP=dcMemCtrl.SelectObject(pOldBitmap); 
    // copy to CB for checking
    #ifdef TEST
    OpenClipboard();
    EmptyClipboard(); 
    SetClipboardData(CF_BITMAP,nowBMP->GetSafeHandle());
    CloseClipboard();
    #endif
    CBrush *pBackBr=new CBrush;
    pBackBr->CreatePatternBrush(nowBMP);
    //
    DeleteObject(rgnClip);
    DeleteObject(CtrlBmp);
    ReleaseDC(pDCex);
    dcMemCtrl.DeleteDC();
    //
    return pBackBr;
    }
    //
    #define ONE_DC#ifdef ONE_DC // edit not hided !
    BOOL CDrawEditDlg::OnEraseBkgnd(CDC* pDC) 
    {
    // TODO: Add your message handler code here and/or call default
    if(!m_bInitEditBr)
    {// add  edit rect
    m_bInitEditBr=TRUE;
    m_pbrEd=CreateBackgroundBrush(pDC, IDC_SEL_EDIT);
    }
      

  5.   

    BOOL CSelEdit::OnEraseBkgnd(CDC* pDC) 
    {
    CDrawEditDlg *pdlg=(CDrawEditDlg*)GetParent();
    CRect rc;
    GetWindowRect(&rc);
    ScreenToClient(&rc);
    // afxDump << rc << "\n";
    pDC->FillRect(rc,pdlg->m_pbrEd);//PatternBrush return TRUE;
    // return CEdit::OnEraseBkgnd(pDC);
    }
      

  6.   


    我理解是,先把控件所在位置的窗口背景存到Brush里,然后每次更新界面都用这个Brush来画背景,是这样吗?但你的代码没成功,帮忙再看看,好吗?我是在OnCtlColor里返回这个Brush的,不知道用法是否有误?还有,是否可以实现在自绘的Edit类里实现获取主窗口的背景?
      

  7.   

    “我理解是,先把控件所在位置的窗口背景存到Brush里,然后每次更新界面都用这个Brush来画背景”
    对。
    这是vc6上多次使用的代码,没问题的。“是否可以实现在自绘的Edit类里实现获取主窗口的背景”可以,但有个问题是‘自绘的Edit类’里如何区分不同的实例。(不同的实例有不同的背景,因位置不同)
      

  8.   


    我是在vs2010里使用这个代码,没效果,不知道有无使用错误。在自绘Edit类里我实现了这个方法,先获取父窗口上控件所在位置大小(就可通过这个来区分不同实例)的背景保存在CImage里,再绘在控件上,效果很好,没有不和谐的地方,但有一个比较严重的问题,在窗口上多几个Edit控件的话,打开程序时,明显感到控件一个一个慢慢的加载上来,太慢了。我是用GetPixel和SetPixel来获取父窗口背景和保存的,而且慢的原因就在这里,去掉这些代码就没慢的问题了。如果按照我这个思路的话,请问是否有快速获取父窗口背景的方法?
      

  9.   

    下面是 Slider 的做法:
    1.先得到Id:void CYourSlider::PreSubclassWindow() 
    {
    // TODO: Add your specialized code here and/or call the base class
    #ifdef SELF_GET
    UINT id=::GetDlgCtrlID(this->m_hWnd);
    //afxDump << id << "\n";
    m_aInfo[m_CtrlCount].CtrlId=id;
    m_CtrlCount++;
    #endif
    //
    CSliderCtrl::PreSubclassWindow();
    }
    2。获取对应Id的控件背景:BOOL CYourSlider::OnEraseBkgnd(CDC* pDC) 
    {
    // TODO: Add your message handler code here and/or call default
    //
    #ifdef SELF_GET UINT id=::GetDlgCtrlID(this->m_hWnd);
    afxDump << id << "\n";
    for(int jj=0;jj <= m_CtrlCount;jj++)
    {
    if((m_aInfo[jj].CtrlId > 0) && (m_aInfo[jj].CtrlId==id) && (m_aInfo[jj].pBkdBrush==0))
    {// brush
    CDC *pDCdlg=GetParent()->GetDC();
    CRect rc;
    GetWindowRect(&rc);
    ScreenToClient(&rc);
    afxDump << rc << "\n";
    CDC dcMemCtrl;
    dcMemCtrl.CreateCompatibleDC(pDC);//DeleteDC needed
    CBitmap CtrlBmp;//DeleteObject needed
    CtrlBmp.CreateCompatibleBitmap(pDC,rc.Width(),rc.Height());
    CBitmap *pOldBitmap = dcMemCtrl.SelectObject(&CtrlBmp);
    dcMemCtrl.BitBlt(0, 0, rc.Width(), rc.Height(), pDC,rc.left, rc.top,SRCCOPY);
    CBitmap  *nowBMP=dcMemCtrl.SelectObject(pOldBitmap);// 
    // copy to CB for checking
    #ifdef TEST
    OpenClipboard();
    EmptyClipboard(); 
    SetClipboardData(CF_BITMAP,nowBMP->GetSafeHandle());
    CloseClipboard();
    #endif
    CBrush *pBackBr=new CBrush;
    pBackBr->CreatePatternBrush(nowBMP);
    m_aInfo[jj].pBkdBrush=pBackBr;
    //
    DeleteObject(CtrlBmp);
    dcMemCtrl.DeleteDC();
    ReleaseDC(pDCdlg);
    return TRUE;
    }
    }
    #endif
    return TRUE;
    }3。
    typedef struct _ctrlInfo
    {
    CBrush  *pBkdBrush;
    UINT     CtrlId;
    } CTRL_INFO,*LPCTRL_INFO;
    4。
    protected:
    CTRL_INFO m_aInfo[MAX_CTRL];// 10
    int m_CtrlCount;关键:
    pBackBr->CreatePatternBrush(nowBMP);
      

  10.   

    补一个:
    void CYourSlider::OnPaint() 
    {
    CPaintDC dc(this); // device context for painting

    CRect rc;
    GetWindowRect(&rc);
    ScreenToClient(&rc);
    // use 2 buffer , because a bit flicking
    CDC memDC;
    memDC.CreateCompatibleDC(&dc);
    CBitmap MemBitmap;
    MemBitmap.CreateCompatibleBitmap (&dc, rc.Width(), rc.Height());
    HBITMAP OldBitmap = (HBITMAP) memDC.SelectObject (MemBitmap);
    // back ground
    UINT id=::GetDlgCtrlID(this->m_hWnd);
    CBrush *pBkgBrush=0;
    for(int jj=0;jj<MAX_CTRL;jj++)
    {
    if(m_aInfo[jj].CtrlId==id)
    {
    pBkgBrush=m_aInfo[jj].pBkdBrush;
    break;
    }
    }
    if(pBkgBrush)
    {
    // afxDump << rc << "\n";
    memDC.FillRect(rc,pBkgBrush);//PatternBrush
    }
      

  11.   

    被无视的感觉真无奈!
    http://topic.csdn.net/u/20121023/16/ed3c04e5-bdd6-45f5-b7ff-283b7b3a1e2c.html
      

  12.   

    自绘CEdit是一个难点, 简单的自绘, 可以看我很早以前的博文.http://blog.csdn.net/psbeond/article/details/386223文章只讲了如何背景贴图(透明的原理就是先把父窗口背景贴到edit上,再贴edit背景).但完美自绘Edit,还有很多路要走. 比如设置输入位置左上角偏移等等.
    ------------------------------------------------------------------------
      

  13.   


    您提供的CreatePatternBrush代码我没运行成功,我按照我自己的思路已经实现了,谢谢你!我是通过获取父窗口的背景,然后直接作为控件的背景画上去,效果不错。获取父窗口背景是一个一个像素拷贝的,应该有更好的方法,但原理肯定是一样的,有一个问题需要注意,如果直接从父窗口的CDC拷贝图像数据的话,会很慢,而且通过GetCurrentBitmap得到的只是临时对象,在xp下可能可能会出现内存不能读/写的错误,我的做法是先把父窗口背景图片数据整个先拷贝下来,再处理。方法感觉方法有点笨,看到效果没影响就没继续找好方法了。
      

  14.   


    LibUIDK是你们公司的吗?还要收费的啊?现在的网络环境,只得望而却步了,呵呵完美自绘Edit确实要走的路很多,不同事件都会影响到背景的绘制。