CStatic does not invalidate every time its text is changed

4.3k Views Asked by At

I am trying to dynamically change the text of a CStatic control. My member variable is called mStatic of the type CStatic. I have changed the ID to IDC_MYSTATIC instead of IDC_STATIC.

I am calling mStatic.SetWindowText("asdfasdf") when I want to change the text of the control. I do this periodically in a timer.

Now I have the problem that the previous text is not erased after I call the SetWindowText(). It just keeps piling up until I get a mess on the screen.

The parent window has the layered property with a bitmap background. I have also set the color_key property so a certain color of the bitmap is viewed as transparent (I.e. It will not be drawn and will let mouse messages through). The mStatic control is drawn on the parts not transparent, that have a bitmap background.

Why isn't the window invalidating?

4

There are 4 best solutions below

1
On

This knowledge base support article describes the same problem when the SetWindowText() call is made from another thread. Is that what your timer is doing?

If so the solution could simply be to:

  mStatic.SetWindowText("asdfasdf");
  CRect clientRect;
  mStatic.GetClientRect(clientRect);
  mStatic.InvalidateRect(clientRect);
0
On

As mentioned by others already, a static control doesn't necessarily erase its background prior to drawing the text.

I find it a much better solution to subclass the static control and force the invalidation of the control from there. This enables one to easily implement it on all static texts with transparent background, without having to do extra calls to invalidate the control from its parent class.

One way to catch a change of the control's text from within the control itself is to react to the WM_SETTEXT message and force the invalidation from there:

int CStaticT::OnSetText(LPCTSTR text)
{
    LRESULT res = Default();
    Invalidate();
    UpdateWindow();
    return res;
}

Here is a brief example, extracted from one of my classes, of how such a subclassed control could look like:

//////////////////////////////////////////////////////////////////////////
// Header
//////////////////////////////////////////////////////////////////////////
class CStaticT : public CStatic
{
    DECLARE_DYNAMIC(CStaticT)

public:
    CStaticT();
    virtual ~CStaticT();

protected:
    afx_msg int OnSetText(LPCTSTR text);
    DECLARE_MESSAGE_MAP()

private:
    BOOL m_InitialSet;
};

//////////////////////////////////////////////////////////////////////////
// Implementation
//////////////////////////////////////////////////////////////////////////
IMPLEMENT_DYNAMIC(CStaticT, CStatic)
CStaticT::CStaticT()
{
    m_InitialSet = FALSE;
}

CStaticT::~CStaticT()
{
}

BEGIN_MESSAGE_MAP(CStaticT, CStatic)
    ON_WM_SETTEXT()
END_MESSAGE_MAP()

int CStaticT::OnSetText(LPCTSTR text)
{
    LRESULT res = Default();

    // I've noticed issues when this forces the invalidation
    // of the static control before the parent's background
    // is painted completely.
    // This is a cheap workaround, skipping the initial setting
    // of the text by the subclassing call.
    // You have to test if this works out for your environment.
    if (!m_InitialSet)
    {
        m_InitialSet = TRUE;
        return res;
    }

    // Force of the invalidation
    Invalidate();
    UpdateWindow();

    return res;
}
1
On

Perhaps your static text control have a SS_SIMPLE style enabled. You can check style flags on resource file or using GetStyle().

Static control with SS_SIMPLE style displays text faster, but also - as MSDN describes - "SS_SIMPLE static controls do not clear the control's display area when displaying text. If a shorter string is displayed, the part of the original string that is longer than the new shorter string is displayed."

Clear SS_SIMPLE from style flags and CStatic will behave 'normally'.

0
On

Had the same issue. The following code fixed it:

mStatic.SetWindowText("New text");
CRect rect;
mStatic.GetWindowRect(&rect);
ScreenToClient(&rect);
InvalidateRect(&rect);
UpdateWindow();