从CButton派生出自绘按钮类CBtmpbutton在单文档视类窗口中Create后,编译运行时显示了该按钮的程序窗口一闪即过?
经过试了直接在视类窗口中使用SDK的“button"类创建按钮运行正常,不重载DrawItem()函数则视类窗口也显示正常,所以估计是重载DrawItem()函数有问题但是一直不知道问题具体所在,因为运行时视类窗口显示了按钮控件一闪而过,也不提示任何运行时错误,所以下断点运行,程序一直在DrawItem()函数内循环,故也不知道该怎么找出这样的问题,下面贴出手动添加的代码的部分,请大家帮指导指导!:
// Btmpbutton.h : header file(以下为定义CBtmpbutton类的头文件Btmpbutton.h)
//
#include <bitset>
using std::bitset;
class CBtmpbutton : public CButton
{
// Construction
public:
CBtmpbutton();// Attributes
public:// Operations
public:// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CBtmpbutton)
public:
virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
protected:
virtual void PreSubclassWindow();
//}}AFX_VIRTUAL// Implementation
public:
static UINT m_testfocusid;
CString m_titlestr;
CRect m_rect;
CDC* m_pDC;
void DrawTestFocusButton();
void DrawPendButton();
void DrawPassButton();
bitset<18> m_bitset;
CBitmap m_bitmap1;
virtual ~CBtmpbutton(); // Generated message map functions
protected:
//{{AFX_MSG(CBtmpbutton)
//}}AFX_MSG DECLARE_MESSAGE_MAP()
};
以下为:Btmpbutton.cpp中的手动增加代码了的函数:
1
UINT CBtmpbutton::m_testfocusid = 1;//手动增加代码的地方1:这里初始化了CBtmpbutton类的静态变量。
CBtmpbutton::CBtmpbutton()
{}
2
void CBtmpbutton::PreSubclassWindow() 
{
// TODO: Add your specialized code here and/or call the base class

CButton::PreSubclassWindow();
ModifyStyle(0, BS_OWNERDRAW);//手动增加代码的地方2:这里增加BS_OWNERDRAW风格。
}3
void CBtmpbutton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) 
{
// TODO: Add your code to draw the specified item
m_rect =  lpDrawItemStruct->rcItem;
UINT buttonid =  lpDrawItemStruct->CtlID;
m_pDC=CDC::FromHandle(lpDrawItemStruct->hDC);
int nSaveDC=m_pDC->SaveDC();
GetWindowText(m_titlestr);
switch(buttonid)
{
case 1:
if(m_bitset.test(0))
DrawPassButton();
else
{
if(1 == (m_testfocusid))
DrawTestFocusButton();
else
DrawPendButton();
}
break;
case 2:
if(m_bitset.test(1))
DrawPassButton();
else
{
if(2 == (m_testfocusid))
DrawTestFocusButton();
else
DrawPendButton();
}
break;
         case 3:
               ......

       }
m_pDC->RestoreDC(nSaveDC);
}

解决方案 »

  1.   

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

    CButton::PreSubclassWindow();
    ModifyStyle(0, BS_OWNERDRAW);
    }void CBtmpbutton::DrawPassButton()
    {
    m_pDC->SetBkMode(TRANSPARENT);
    CBrush greenbr;
    greenbr.CreateSolidBrush(RGB(0,255,0));
    m_pDC->FillRect(m_rect,&greenbr);
    SetWindowText(m_titlestr);
    greenbr.DeleteObject();
    }void CBtmpbutton::DrawPendButton()
    {
    m_pDC->SetBkMode(TRANSPARENT);
    CBrush yellowbr;
    yellowbr.CreateSolidBrush(RGB(255,255,0));
    m_pDC->FillRect(m_rect,&yellowbr);
    SetWindowText(m_titlestr);
    yellowbr.DeleteObject();}void CBtmpbutton::DrawTestFocusButton()
    {
    m_pDC->SetBkMode(TRANSPARENT);
    CBrush bluebr;
    bluebr.CreateSolidBrush(RGB(145,120,0));
    m_pDC->FillRect(m_rect,&bluebr);
    SetWindowText(m_titlestr);
    bluebr.DeleteObject();
    }
    以下为在CAbutnView视类中增加的对WM_CREATE的消息处理int CAbutnView::OnCreate(LPCREATESTRUCT lpCreateStruct) 
    {
    if (CView::OnCreate(lpCreateStruct) == -1)
    return -1;

    // TODO: Add your specialized creation code here
    ::CreateWindowEx(WS_EX_WINDOWEDGE,"button","aaa",WS_CHILD | WS_VISIBLE,120,120,75,35,this->m_hWnd,(HMENU)1,::GetModuleHandle(NULL),NULL); //仅创建这个按钮时,程序显示正常
    m_pbmpbtn.Create("aaa",WS_CHILD | WS_VISIBLE,CRect(185,100,255,135),this,1);//创建这个按钮后运行,程序显示按钮的视类中看到了这个按钮,但是程序一闪而过,跟踪确认只要增加重载DrawItem函数这部分功能的代码,程序就会一闪而过,否则视类显示正常。请大家帮指导知道这个DrawItem函数重载是的要领,我这个程序哪里出了问题?
    return 0;
    }
      

  2.   

    FromHandle得到的是临时对象,不能保存起来备用。如果需要全局起作用的CDC, 可以自己创建一个 CDC::CreateCompatibleDC。
      

  3.   

    查看FromHandle的说明,写的很清楚,是用过即作废的临时对象。 保存起来用肯定对出错的。
      

  4.   

    先SaveDC,然后RestoreDC?你想做什么呢
      

  5.   

    我照着网上下载下来运行的很好的XPButtonDemo这个例子改的它上面是:
    void CXPButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
    {
    //从lpDrawItemStruct获取控件的相关信息
    CRect rect =  lpDrawItemStruct->rcItem;
    CDC *pDC=CDC::FromHandle(lpDrawItemStruct->hDC);
    int nSaveDC=pDC->SaveDC();
    UINT state = lpDrawItemStruct->itemState;
    POINT pt ;
    TCHAR strText[MAX_PATH + 1];
    ::GetWindowText(m_hWnd, strText, MAX_PATH);

    //画按钮的外边框,它是一个半径为5的圆角矩形
    pt.x = 5;
    pt.y = 5;
    CPen* hOldPen = pDC->SelectObject(&m_BoundryPen);
    pDC->RoundRect(&rect, pt);
    我上面的也只是把这个pDC指针保存到了成员变量指针m_pDC中了,现在我完全照着XPButtonDemo上的做把成员变量指针m_pDC删除,将之以 CDC *pDC替代,然后编译连接后运行效果一样的一闪而过,事实上这两种形式其实都是一样的,都是保存CDC的指针,你说从CDC::FromHandle(lpDrawItemStruct->hDC);得到的是临时对象的指针,是啊,但是,系统每次调用DrawItem函数时不都是会重新对CDC *pDC赋上当次的正确的DC指针了嘛,我想应该不是这个问题吧
    另因为我测试这个自绘按钮类的时候只创建了一个按钮,其按钮的ID标号为1,并且将m_testfocusid 初始化为1了,所以程序调用DrawItem函数时应该只会运行case 1: 中DrawTestFocusButton(); 下了断点后跟踪发现,它运行这一个函数DrawTestFocusButton();根本就不运行pDC->RestoreDC(nSaveDC);这一句,就又循环进了DrawItem函数又从CRect rect =  lpDrawItemStruct->rcItem;这句运行到DrawTestFocusButton();函数,如此循环,好象也循环无止尽!
      

  6.   

    哦,刚照着cnzdgs说的把SetWindowText注释掉,按钮显示就正常了。
      

  7.   

    SetWindowText会引起窗口(控件)重绘,从而形成递归,所以会出问题。
    还有其它问题吗?