看到别人写的一个类XNStatic,该类继承于CStatic类,新增了一些功能,比如关联静态文本框后,可以动态更改静态文本框的文字内容,文字的颜色,文字的背景色,文字的字体大小等功能。
该类的结构简单,通俗易懂。用起来也比较方便,但是本人在用到一个功能时,发现了一个问题:
比如,我新建一个单文档应用程序,在对话框上增加一个IDC_STATIC1,并将该IDC_STATIC控件关联到XNStatic,然后再添加两个BUTTON,分别在BUTTON1和BUTTON2的ONCLICK事件调用XNStatic的SetTextCaption设置IDC_STATIC1的显示内容。比如:在BUTTON1单击事件中我们计划显示:“12345”;在BUTTON2单击事件中我们计划显示:“6789”;
问题出现了:当我们单击BUTTON1时,IDC_STATIC1显示了:12345;然后我们再单击BUTTON2,这时,6789就直截重叠在12345上面。这是我们不愿意看到的,我想作者的原意应该是在12345擦除后再显示6789。结果作者没有实现这个目的,我试图更正这个错误,但改了很久也没能实现。希望有高手能帮忙改改,当然,最好不要在改动接口的情况下完成。(顺便提一下:如果我们在每个BUTTON单击事件里面加一个Invalidate()语句,是可以去掉重叠的,但是这种操作会使整个窗口闪动太大。这种方式是我们所不愿意接受的,所以我们希望是直接改进XNStatic类)
现在把该类代码贴出来:考备后分别保存.cpp和.h就可以了
头文件:
////----------保存成:XNStatic.h------------------/////
#if !defined(AFX_XNSTATIC_H__8DD5B5B1_0A02_43EF_B873_4B7B4F12F228__INCLUDED_)
#define AFX_XNSTATIC_H__8DD5B5B1_0A02_43EF_B873_4B7B4F12F228__INCLUDED_#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// XNStatic.h : header file
///////////////////////////////////////////////////////////////////////////////
// CXNStatic windowclass CXNStatic : public CStatic
{
// Construction
public:
CXNStatic();// Attributes
public:// Operations
public:// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CXNStatic)
//}}AFX_VIRTUAL// Implementation
public:
BOOL m_FtStyle;
void SetFontStyle(int FontSize,CString FontStyle,BOOL FtStyle=true);
BOOL m_BkTrue;
void SetTextCaption(CString TextCapion);
void SetTextColor(COLORREF TextColor);
void SetBackColor(COLORREF BackColor,BOOL BkTrue=true);
CString m_TextCaption;
COLORREF m_TextColor;
COLORREF m_BackColor;
virtual ~CXNStatic(); // Generated message map functions
protected:
//{{AFX_MSG(CXNStatic)
afx_msg void OnPaint();
//}}AFX_MSG DECLARE_MESSAGE_MAP()
private:
CFont m_Font;
};///////////////////////////////////////////////////////////////////////////////{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.#endif // !defined(AFX_XNSTATIC_H__8DD5B5B1_0A02_43EF_B873_4B7B4F12F228__INCLUDED_)
源文件:
////-----------保存成:XNStatic.cpp-----------------////
// XNStatic.cpp : implementation file
//#include "stdafx.h"
#include "XNStatic.h"#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif/////////////////////////////////////////////////////////////////////////////
// CXNStaticCXNStatic::CXNStatic()
{
m_TextColor=RGB(0,0,0);
m_BkTrue=FALSE;
m_FtStyle=FALSE;
//m_TextCaption="StaticText 静态文本框";
m_TextCaption="";
//m_Font.CreatePointFont(9,"宋体");
}CXNStatic::~CXNStatic()
{
}
BEGIN_MESSAGE_MAP(CXNStatic, CStatic)
//{{AFX_MSG_MAP(CXNStatic)
ON_WM_PAINT()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()/////////////////////////////////////////////////////////////////////////////
// CXNStatic message handlersvoid CXNStatic::SetBackColor(COLORREF BackColor,BOOL BkTrue)
{
m_BackColor=BackColor;
m_BkTrue=BkTrue;//为真时,才能设置文字背景色,默认为假
}void CXNStatic::SetTextColor(COLORREF TextColor)
{
m_TextColor=TextColor;
Invalidate();
}void CXNStatic::SetTextCaption(CString TextCapion)
{
m_TextCaption=TextCapion;
Invalidate();
//UpdateWindow();
}void CXNStatic::SetFontStyle(int FontSize,CString FontStyle,BOOL FtStyle)
{
m_Font.CreatePointFont(FontSize,FontStyle);
m_FtStyle=FtStyle;
}void CXNStatic::OnPaint() 
{
CPaintDC dc(this); // device context for painting // TODO: Add your message handler code here
CRect rect;
GetClientRect(&rect);

dc.SetBkColor(m_BackColor);//设置文字背景色
if(!m_BkTrue)//只有在不设置文字背景色时
{
dc.SetBkMode(TRANSPARENT);//设置文字背景色透明
} CFont *pFont;
if(!m_FtStyle)
{
pFont=GetParent()->GetFont();
}else
{
pFont=&m_Font;
}
CFont *pOldFont=dc.SelectObject(pFont); dc.SetTextColor(m_TextColor);//字体颜色
dc.DrawText(m_TextCaption,&rect,DT_CENTER); dc.SelectObject(pOldFont);
// Do not call CStatic::OnPaint() for painting messages
}希望有高手指点迷经,问题解答完马上散分。
可以把代码按上面的方法贴出来或是发到我邮箱里:[email protected]
再次感谢!

解决方案 »

  1.   

    这个类看起来不会造成你说的现象,可能你的代码中有设置静态控件背景透明的功能,也就是响应了WM_CTLCOLOR消息。
    另外代码中绘制的地方有些不合理,我改一下试试,没有测试:
    void CXNStatic::OnPaint()  

        CPaintDC dc(this); // device context for painting     // TODO: Add your message handler code here 
        CRect rect; 
        GetClientRect(&rect);     if(!m_BkTrue)//只有在不设置文字背景色时 
        { 
            dc.SetBkMode(TRANSPARENT);//设置文字背景色透明 
        }
        else
        {
            dc.SetBkColor(m_BackColor);//设置文字背景色 
            dc.FillSolidRect(rect, m_BkTrue); // 要求你调用设置文字的功能之前先调用SetBackColor()设置背景色
        }    CFont *pFont; 
        if(!m_FtStyle) 
        { 
            pFont=GetParent()->GetFont(); 
        }else 
        { 
            pFont=&m_Font; 
        } 
        CFont *pOldFont=dc.SelectObject(pFont);     dc.SetTextColor(m_TextColor);//字体颜色 
        dc.DrawText(m_TextCaption,&rect,DT_CENTER);     dc.SelectObject(pOldFont); 
        // Do not call CStatic::OnPaint() for painting messages 
      

  2.   

    关键是加了这句
    dc.FillSolidRect(rect, m_BkTrue); // 要求你调用设置文字的功能之前先调用SetBackColor()设置背景色
      

  3.   

    在绘制字体前刷新背景先  int saveDC = dc.SaveDC(); //保存设备  CRect rect; GetClientRect(&rect); //获取客户区
      CBrush brush(dc.GetBkColor()); //使用背景色画刷
      dc.FillRect(&rect,&brush);//使用背景色填充背景  //处理窗体风格
      DWORD wnd_Style = GetWindowLong(this->GetSafeHwnd(),GWL_STYLE);
      if(wnd_Style & )
      {
      }  //处理扩展风格
      DWORD exwnd_Style = GetWindowLong(this->GetSafeHwnd(),GWL_EXSTYLE);
      if(exwnd_Style &)
      {
      }  //处理显示
      /*
      */  dc.RestoreDC(saveDC); //恢复设备 
      

  4.   

    如果你使用透明背景,应该用InvalidateRect刷新static后面控件。
      

  5.   

    响应这个类的WM_ERASEBKGND事件,绘制底色。
      

  6.   

    Mackz :
    我试了你改进的方法,文字显示时同样还是参生重叠。同时,再指出一下:我前面提到的操作都是要求文字显示为透明状态,没有设置背景色!
    如果你有时间,期待你能把代码运行测试调试一下,能马上发现我所描述的问题!cnzdgs :
    我在程序里用了Invalidate(),Invalidate()重绘的范围应该比你提到的InvalidateRect()范围更广吧。当然,我也把InvalidateRect加入代码中试过了,同样没有用,但是我不明白你说:“应该用InvalidateRect刷新static后面控件”什么意思?什么后面控件?你所指的InvalidateRect是何时何地调用呢?期待高手们能继续关注此问题!谢谢!
      

  7.   

    你调用Invalidate刷新的是static控件,我的意思是刷新其背后的控件,如果static控件的父控件是对话框就刷新对话框,用InvalidateRect的用意是缩小要刷新的范围,因为实际要刷新的只有static控件的区域,如果整个刷新就太慢了,也浪费CPU资源。
      

  8.   

    说实话,仅仅为了显示一个字符串,还不如直接在对话框的OnPaint()中绘制。我上面的修改也说了,针对设置背景色的情况。看来你就是不设置背景色而且还要求背景透明的。再这样试试:
    void CXNStatic::SetTextCaption(CString TextCapion) 
    {
        CRect rc;
        GetWindowRect(&rc);
        GetParent()->ScreenToClient(&rc);
        GetParent()->Invalidate(&rc);
        m_TextCaption = TextCapion; 
        Invalidate(); 
      

  9.   

    调用SetTextCaption函数之前,你应该刷新这个控件所占的区域,而不是用Invalidate来刷新所有的区域: CRect   rc; 
    GetDlgItem(IDC_STATIC1)->GetWindowRect(&rc); 
    ScreenToClient(&rc); 
    InvalidateRect(rc); // 仅仅刷新IDC_STATIC1的区域即可 
    // 接着调用SetTextCaption函数
      

  10.   

    或者是修改SetTextCaption函数,可以这样: void CXNStatic::SetTextCaption(CString TextCapion)   

    HWnd hWndParent = ::GetParent(m_hWnd); RECT rc; 
    ::GetWindowRect(m_hWnd, &rc); 
    ::ScreenToClient(hWndParent, &rc); 
    InvalidateRect(hWndParent, rc); m_TextCaption=TextCapion;   
    }
      

  11.   

    谢谢大家,谢谢大家!
    感谢laiyiling 在两个版面中都回答了我!