我想重载CEdit,实现自定义绘制。
从CEdit继承了CColorEdit,在对话框上为重载的EditBox定义控件变量m_ColorEdit,然后再修改变量类型为CColorEdit m_ColorEdit。
通过另一个EditBox输入文字,赋值给重载的m_ColorEdit,在CColorEdit::OnPaint()里实现自定义绘制,没有问题。
但是单击了这个重载的EditBox之后,显示的又变成原来的CEdit的内容了,不知还要重载CEdit的哪个消息?
用SPY++跟踪了一下,没有头绪,恳请帮忙。

解决方案 »

  1.   

    楼主能贴出一些代码吗?
    要不就再处理OnActivate好了。
      

  2.   


    这里有一个button的处理。
    void CMyButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) 
    {
    CDC* pDC   = CDC::FromHandle(lpDrawItemStruct->hDC);
    CRect rect = lpDrawItemStruct->rcItem;
    UINT state = lpDrawItemStruct->itemState; CString strText;
    GetWindowText(strText);    // draw the control edges (DrawFrameControl is handy!)
    if (state & ODS_SELECTED)
            pDC->DrawFrameControl(rect, DFC_BUTTON, DFCS_BUTTONPUSH | DFCS_PUSHED);
        else
            pDC->DrawFrameControl(rect, DFC_BUTTON, DFCS_BUTTONPUSH);    // Fill the interior color if necessary
        rect.DeflateRect( CSize(GetSystemMetrics(SM_CXEDGE), GetSystemMetrics(SM_CYEDGE)));
        if (m_bOverControl)
            pDC->FillSolidRect(rect, RGB(255, 255, 0)); // yellow    // Draw the text
        if (!strText.IsEmpty())
        {
            CSize Extent = pDC->GetTextExtent(strText);
    CPoint pt( rect.CenterPoint().x - Extent.cx/2, rect.CenterPoint().y - Extent.cy/2 ); if (state & ODS_SELECTED) 
                pt.Offset(1,1); int nMode = pDC->SetBkMode(TRANSPARENT); if (state & ODS_DISABLED)
    pDC->DrawState(pt, Extent, strText, DSS_DISABLED, TRUE, 0, (HBRUSH)NULL);
    else
    pDC->TextOut(pt.x, pt.y, strText);        pDC->SetBkMode(nMode);
        }
    }
    void CMyButton::PreSubclassWindow() 
    {
    CButton::PreSubclassWindow(); ModifyStyle(0, BS_OWNERDRAW); // make the button owner drawn
    }
      

  3.   

    如果不行,可以在OnActivate中用Invalidate();
      

  4.   

    要实现自绘制控件不是响应WM_PAINT消息就可以的, 首先要设置该控件的自绘制属性, 然后重写DrawItem函数, 在这个函数中绘制控件的外观才行呀.具体代码类似 enoloo(行者无僵)给出的代码, 我就不再重复了.稍微解释一下 ModifyStyle(0, BS_OWNERDRAW);  //这个就是设置控件的属性为自绘制控件, 这是必须的然后该控件的具体的显示工作就放在了 DrawItem 函数中了.关于自绘制的问题你也可以起参考一本书<<MFC Windows程序设计>>
      

  5.   

    Button支持自绘制,当然没问题。EditBox不同的。
    代码麽,没什么用,要看也可。// ColorEdit.cpp : 实现文件
    //#include "stdafx.h"
    #include "CoDPlayerNameEditor.h"
    #include ".\coloredit.h"
    // CColorEditIMPLEMENT_DYNAMIC(CColorEdit, CEdit)
    CColorEdit::CColorEdit()
    : m_Color(NULL)//从主对话框传递COLORREF数组指针
    {
    }CColorEdit::~CColorEdit()
    {
    }
    BEGIN_MESSAGE_MAP(CColorEdit, CEdit)
    ON_WM_PAINT()
    ON_WM_ERASEBKGND()
    ON_WM_DRAWITEM()
    ON_CONTROL_REFLECT(EN_SETFOCUS, OnEnSetfocus)
    ON_WM_SETFOCUS()
    ON_WM_ACTIVATE()
    END_MESSAGE_MAP()// CColorEdit 消息处理程序
    void CColorEdit::OnPaint()
    {
    CPaintDC dc(this); // device context for painting
    // TODO: 在此处添加消息处理程序代码
    // 不为绘图消息调用 CEdit::OnPaint()
    //HKEY_LOCAL_MACHINE\SOFTWARE\Activision\Call of Duty
    //InstallPath
    //\main\config_mp.cfg
    /*
    1 - 红色
    2 - 绿色
    3 - 黄色
    4 - 蓝色
    5 - 青色
    6 - 粉色
    7 - 白色
    8 - 黑色
    9 - 红色
    */
    //COLORREF m_Color[10];
    const char ControlChar = '^';
    const char ZeroChar = '0';
    const char NineChar = '9';
    char ColorChar;
    int ColorKey = 0; CDC *pdc = GetDC();
    CString ColorName;
    GetWindowText(ColorName);
    CRect ClientRect;
    GetClientRect(ClientRect);
    pdc->FillSolidRect(ClientRect, RGB(200, 200, 200));
    int iLength = ColorName.GetLength();
    int iPos = ColorName.Find(ControlChar, 0);
    int iPosNext = 0;
    int x = ClientRect.left;
    CString strSub;
    while (iLength && iPosNext != -1)
    {
    if (iPos == -1)
    pdc->SetTextColor(m_Color[0]);
    else
    {
    iPos ++;
    ColorChar = ColorName.GetAt(iPos);
    if (ColorChar >= ZeroChar && ColorChar <= NineChar)
    {
    ColorKey = ColorChar - ZeroChar;
    pdc->SetTextColor(m_Color[ColorKey]);
    iPos++;
    }
    }
    iPosNext = ColorName.Find(ControlChar, iPos);
    if (iPosNext != -1)
    strSub = ColorName.Mid(iPos, iPosNext - iPos);
    else
    strSub = ColorName.Right(iLength - iPos);
    pdc->TextOut(x, ClientRect.top, strSub);
    x += pdc->GetTextExtent(strSub).cx;
    iPos = iPosNext;
    }
    ReleaseDC(pdc);
    }BOOL CColorEdit::OnEraseBkgnd(CDC* pDC)
    {
    // TODO: 在此添加消息处理程序代码和/或调用默认值
    return FALSE; return CEdit::OnEraseBkgnd(pDC);
    }void CColorEdit::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct)
    {
    // TODO: 在此添加消息处理程序代码和/或调用默认值
    //if (nIDCtl == IDC_COLOR_EDIT)
    //{
    ////HKEY_LOCAL_MACHINE\SOFTWARE\Activision\Call of Duty
    ////InstallPath
    ////\main\config_mp.cfg
    // /*
    // 1 - 红色
    // 2 - 绿色
    // 3 - 黄色
    // 4 - 蓝色
    // 5 - 青色 LG
    // 6 - 粉色 Pink
    // 7 - 白色
    // 8 - 黑色
    // 9 - 红色
    // */
    // COLORREF m_Color[10];
    // m_Color[0] = RGB(255, 255, 255);
    // m_Color[1] = RGB(255, 0, 0);
    // m_Color[2] = RGB(0, 255, 0);
    // m_Color[3] = RGB(255, 255, 0);
    // m_Color[4] = RGB(0, 0, 255);
    // m_Color[5] = RGB(0, 255, 255);
    // m_Color[6] = RGB(255, 0, 255);
    // m_Color[7] = RGB(255, 255, 255);
    // m_Color[8] = RGB(0, 0, 0);
    // m_Color[9] = RGB(255, 0, 0);
    // const char ControlChar = '^';
    // const char ZeroChar = '0';
    // const char NineChar = '9';
    // char ColorChar;
    // int ColorKey = 0; // CDC *pdc = CDC::FromHandle(lpDrawItemStruct->hDC);
    // CString ColorName;
    // GetWindowText(ColorName);
    // CRect ClientRect(lpDrawItemStruct->rcItem);
    // pdc->FillSolidRect(ClientRect, RGB(200, 200, 200));
    // int iLength = ColorName.GetLength();
    // int iPos = ColorName.Find(ControlChar, 0);
    // int iPosNext = 0;
    // int x = ClientRect.left;
    // CString strSub;
    // while (iLength && iPosNext != -1)
    // {
    // if (iPos == -1)
    // pdc->SetTextColor(m_Color[0]);
    // else
    // {
    // iPos ++;
    // ColorChar = ColorName.GetAt(iPos);
    // if (ColorChar >= ZeroChar && ColorChar <= NineChar)
    // {
    // ColorKey = ColorChar - ZeroChar;
    // pdc->SetTextColor(m_Color[ColorKey]);
    // iPos++;
    // }
    // }
    // iPosNext = ColorName.Find(ControlChar, iPos);
    // if (iPosNext != -1)
    // strSub = ColorName.Mid(iPos, iPosNext - iPos);
    // else
    // strSub = ColorName.Right(iLength - iPos);
    // pdc->TextOut(x, ClientRect.top, strSub);
    // x += pdc->GetTextExtent(strSub).cx;
    // iPos = iPosNext;
    // }
    // return;
    ////} //CEdit::OnDrawItem(nIDCtl, lpDrawItemStruct);
    }void CColorEdit::OnEnSetfocus()
    {
    // TODO: 在此添加控件通知处理程序代码
    Invalidate();
    }void CColorEdit::OnSetFocus(CWnd* pOldWnd)
    {
    CEdit::OnSetFocus(pOldWnd);
    Invalidate();
    //this->ShowCaret();
    //this->SetCaretPos(CPoint(10, 2)); // TODO: 在此处添加消息处理程序代码
    }void CColorEdit::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized)
    {
    CEdit::OnActivate(nState, pWndOther, bMinimized); // TODO: 在此处添加消息处理程序代码
    Invalidate();
    }这里,在OnEnSetfocus()和OnSetfocus()里的Invalidate()有个用处,就是第一次单击鼠标激活控件的时候,控件保持我的绘制内容;再点击一次,就又恢复原来的内容了。而且,二者只要一个响应就可以了。
    OnActivate()里的Invalidate()没有用处。
      

  6.   

    恩,在OnSetFocus里面
    if(GetSafeHwnd() != NULL)
    Invalidate();  //这样比较好。
      

  7.   

    BS_OWNERDRAW是Button控件的属性。
    不是简单的自绘啦,否则200分那么容易得的?
      

  8.   

    BS_OWNERDRAW是Button控件的属性。
    不是简单的自绘啦,否则200分那么容易得的?
    //我也没有说他又自绘属性呀,不过还是要感谢你的建议。
    //在类中加一个刷子br.并创建solidbrush.
    HBRUSH CMyEdit::CtlColor(CDC* pDC, UINT nCtlColor) 
    {
    // TODO: Change any attributes of the DC here

    // TODO: Return a non-NULL brush if the parent's handler should not be called
    pDC->SetTextColor(RGB(255,0,0));
    pDC->SetBkColor(RGB(0,200,0));
    pDC->SetBkMode(TRANSPARENT);
    return HBRUSH(br);
    }
      

  9.   

    将OnPaint中的东西放到CtlColor中试试。
      

  10.   

    发现一篇好文,楼主不妨看看。
    http://www.codeproject.com/editctrl/ceditbkcolor.asp?msg=35828
      

  11.   

    用SetWindowText..不要用TextOut.
    而且要在CtlColor中,否则改变不了颜色。HBRUSH CMyEdit::CtlColor(CDC* pDC, UINT nCtlColor) 
    {
    // TODO: Change any attributes of the DC here

    // TODO: Return a non-NULL brush if the parent's handler should not be called
    pDC->SetTextColor(RGB(255,0,0));
    pDC->SetBkColor(RGB(0,200,0));
    pDC->SetBkMode(TRANSPARENT);
    CRect rect;
    GetClientRect(&rect);
    // pDC->DrawText("abcdefg...",&rect,DT_CENTER);
    SetWindowText("abcdefg...");
    return (HBRUSH)br;
    }
      

  12.   

    如果有人看了我的代码,应该明白我的目的不是简单地改变背景色和字体颜色。
    我要根据自定义的颜色控制码显示彩色的(多种颜色)文字。
    另外,关于WM_CTLCOLOR,论坛上也有很多人来问,我建议看看MSDN的一篇文章,专门讲EditBox的:Knowledge Base  HOWTO: Change the Background Color of an MFC Edit Control
      

  13.   

    sgnaw(李逍遥) ( ) 信誉:117  2004-04-18 16:12:00  得分:0 
     
     
      发现一篇好文,楼主不妨看看。
    http://www.codeproject.com/editctrl/ceditbkcolor.asp?msg=35828
      
    谢谢,我去看看,不过要折磨我的英文了。
      

  14.   

    这里,在OnEnSetfocus()和OnSetfocus()里的Invalidate()有个用处,就是第一次单击鼠标激活控件的时候,控件保持我的绘制内容;再点击一次,就又恢复原来的内容了。而且,二者只要一个响应就可以了。//用SetWindowText,不要用TextOut.
      

  15.   

    oh, my god.
    我说过了,我要绘制多种色彩的文字。查找了CodeGuru和CodeProject关于EditControl的文章,没有这样的例子。相似的是彩色语法显示,但是那些要么是继承CView的,要么是从CWnd重新构建的,还真没有继承CEdit的。看来,还真没有人比我在这个问题上认识更深入的吗?
      

  16.   

    啊,刚巧偶也碰到这个问题,被搞得一头雾水中- -我想问题应该是在自己重载的代码绘制了之后,又被其他部分的代码调用了基类的默认绘制代码重新画过了才变成了原样。我想问题的关键应该是要先弄清楚控件是在哪个消息里被“擅自”重画的,初步的想法是在基类 CEdit 所有画图相关的消息映射里设断,被断下来之后查看调用堆栈再做进一步分析。不过偶还米动手试过,明天偶先试试看。
      

  17.   

    从CEdit继承好像不行, 我有一个从CStatic继承的例子,有兴趣的话
    把邮箱告诉我,我发给你!
      

  18.   

    我的观点是从CEdit出发,搞多种色彩文字显示的编辑控件是不合适的,这也从CodeGuru和CodeProject中没有这样的例子得到了佐证。而且CEdit也不支持自画。
      

  19.   

    不就是为了省事,能用Edit Control丰富的功能。
      

  20.   

    我觉得CEDIT只提供了最基本的编辑功能,这些功能的实现难度比起你绕过CEDIT,自己输出彩色字体来要小得多。
      

  21.   

    为什么我的EDIT控件不能响应CTRL + C和CTRL + V???
    http://expert.csdn.net/Expert/topic/2993/2993385.xml?temp=.9396479
    哪位帮忙看看
    谢谢。
      

  22.   

    上面发错了,是这个地址
    http://expert.csdn.net/Expert/topic/2989/2989649.xml?temp=.9427912
      

  23.   

    可以在内存DC上完成绘画!
    然后在OnPaint中BitBlt过去!
    不过这种方法我试过!
    我是在允许EDIT可编辑的状态下做的,效果不好!
    不知道把EDIT变成DISABLE怎么样!
      

  24.   

    -----通过另一个EditBox输入文字,赋值给重载的m_ColorEdit,在CColorEdit::OnPaint()里实现自定义绘制,没有问题。
    但是单击了这个重载的EditBox之后,显示的又变成原来的CEdit的内容了,不知还要重载CEdit的哪个消息?我没有做过,不过我想这个问题肯定不会重载OnPaint这么简单了。想想单击后控件获得输入焦点光标就会闪烁,这个时候肯定有个类似定时器的消息,而CEdit本身对这个消息的处理的绘制过程中应该并不只是通过OnPaint来重画。我想你可以自己加入对这个消息的处理,使它尽量按自己的意愿重绘。拙见~
      

  25.   

    -----这里,在OnEnSetfocus()和OnSetfocus()里的Invalidate()有个用处,就是第一次单击鼠标激活控件的时候,控件保持我的绘制内容;再点击一次,就又恢复原来的内容了。而且,二者只要一个响应就可以了你说的这个现象让我很纳闷,于是用spy++观察了一下(它的消息监视真不好用,cpu占用率太高又让我死机一次),结果倒是挺吻合的。你可以看到,“第一次单击鼠标激活控件的时候”,会产生WM_SETFOCUS消息(于是会Invalidate()产生WM_PAINT,而保持你的绘制内容);再点击却不会有WM_SETFOCUS了,而估计CEdit本身在有WM_LBUTTONDOWN等消息时用了其他的方法绘制(猜测,你可以看到根本不会有WM_PAINT消息)。而且绘制光标时应该是对一个值为0x0118的消息处理完成的,也不会调用到OnPaint.
      

  26.   

    你说的很正确,我也看了Spy++,好在没死机:)不过确实分析不出来。
      

  27.   

    没办法了,只好从CWnd重新继承,自己设计ColorEdit类。CEditView也试过了,一样。
      

  28.   

    xp风格编辑框只是简单绘制外框,没用的
    我认为还是应该以EDIT为基础,自已从CWnd重新写很烦琐
    不过不要只重载OnPaint(),还是重载WindowProc,
    然后对其消息进行跟踪、排除性分析,找到有用的。
    我想这方面知识有够充足的话,是可以做到的。
    我没做过EDIT的子类化,只是个人看法
      

  29.   

    如果直接用 raw api 的话说不定还轻松点...
    偶对 mfc 的实现的架构也不是很清楚,应该是用了大量的宏做消息映射,导致宏展开太多太深了,跟都跟不完,我晕~
    也许应该把喉结那本深入浅出翻出来啃一下-_-用 raw api 的话可以很简单地挂上控件的 winproc,那天我写个自定义的 Tab(还是 static?忘了,汗)就这么搞的,程序不是很大,我就直接用 api 了,MFC 实在让偶呕吐- -
      

  30.   

    #include "stdafx.h"
    #include "c_toolkit.h"
    #include "TimeEdit.h"#ifdef _DEBUG
    #define new DEBUG_NEW
    #undef THIS_FILE
    static char THIS_FILE[] = __FILE__;
    #endif/////////////////////////////////////////////////////////////////////////////
    // CTimeEditCTimeEdit::CTimeEdit()
    {
    }CTimeEdit::~CTimeEdit()
    {
    }
    BEGIN_MESSAGE_MAP(CTimeEdit, CEdit)
    //{{AFX_MSG_MAP(CTimeEdit)
    ON_WM_CREATE()
    ON_WM_TIMER()
    ON_WM_PAINT()
    //}}AFX_MSG_MAP
    END_MESSAGE_MAP()/////////////////////////////////////////////////////////////////////////////
    // CTimeEdit message handlersint CTimeEdit::OnCreate(LPCREATESTRUCT lpCreateStruct) 
    {
    if (CEdit::OnCreate(lpCreateStruct) == -1)
    return -1;
    EnableWindow(false);
    OnTimer(0);
    SetTimer(100,1000,NULL);
    // TODO: Add your specialized creation code here

    return 0;
    }void CTimeEdit::OnTimer(UINT nIDEvent) 
    {
    COleDateTime time = COleDateTime::GetCurrentTime(); CString str;
    str.Format("%d-%02d-%02d(%s)  %02d:%02d:%02d",time.GetYear(),time.GetMonth(),time.GetDay(),GetWeek(time.GetDayOfWeek())
    ,time.GetHour(),time.GetMinute(),time.GetSecond());
    SetWindowText(str);
    // TODO: Add your message handler code here and/or call default

    // CEdit::OnTimer(nIDEvent);
    }CString CTimeEdit::GetWeek(int day)
    { switch(day) 
    {
    case 1:
    return "星期日";
    case 2:
    return "星期一";
    case 3:
    return "星期二";
    case 4:
    return "星期三";
    case 5:
    return "星期四";
    case 6:
    return "星期五";
    case 7:
    return "星期六";
    default:
    break;
    }
    return "";
    }void CTimeEdit::OnPaint() 
    {
    CPaintDC dc(this); // device context for painting
    CRect rect;
    GetClientRect(rect);
    CXTMemDC dcm(&dc,rect);

    dcm.SetTextColor(RGB(255,0,0));
    dcm.SetBkColor(RGB(0,0,0));
    CString str;
    GetWindowText(str);
    dcm.SelectObject(&xtAfxData.font);
    dcm.DrawText(str,rect,DT_SINGLELINE|DT_VCENTER|DT_CENTER);
    }
    这是一个只显示时间的CEdit
      

  31.   

    楼主为什么不用  richedit 喃。他的功能不是更强吗,还可以加入图片。
      

  32.   

    1.有了CPaintDC dc(this); 就不要 CDC *pdc = GetDC();了吧。2.既然是单击时不行,就在OnLButtonDown里Invalidate();没有必要放在OnSetfocus()里。单击是好解决的,选择文字等时不太好解决。要实现自定义的复杂功能,可能从EDIT类继承不太合适。
      

  33.   

    建议楼主看看gvim 这个soft ,开源的。他的处理机制有点意思。
    楼主,我建议全部自己写,而不要继承 edit,那样更麻烦。
      

  34.   

    俺正在写这个类似文字功能.写的差不多了.有什么问题请和我联系.
    Msn:[email protected]
    Eml:[email protected]
      

  35.   

    回复人: hnyyy(前进) ( ) 信誉:116  2004-05-04 15:56:00  得分:0 
     
    1.有了CPaintDC dc(this); 就不要 CDC *pdc = GetDC();了吧。
    〉〉这个是这样的:我这段代码本来放在别的地方,下面的pDC->不想改了,其实我用CDC *pDC = &dc;也一样,不是关键。2.既然是单击时不行,就在OnLButtonDown里Invalidate();没有必要放在OnSetfocus()里。
    〉〉试过了,也不行。单击是好解决的,选择文字等时不太好解决。要实现自定义的复杂功能,可能从EDIT类继承不太合适。谢谢。 
      

  36.   

    关键是找出EDIT的哪个消息使之"变成原来的CEdit的内容了"