Я пытаюсь динамически изменить текст CStatic
контроль. Моя переменная-член называется mStatic
типа CStatic
, Я изменил идентификатор на IDC_MYSTATIC
вместо IDC_STATIC
,
я звоню mStatic.SetWindowText("asdfasdf")
когда я хочу изменить текст элемента управления. Я делаю это периодически в таймере.
Теперь у меня проблема в том, что предыдущий текст не стирается после того, как я SetWindowText()
, Это только продолжает накапливаться, пока я не получу беспорядок на экране.
Родительское окно имеет многоуровневое свойство с растровым фоном. Я также установил свойство color_key, чтобы определенный цвет растрового изображения рассматривался как прозрачный (т.е. он не будет прорисован и пропустит сообщения мыши). Элемент управления mStatic рисуется на непрозрачных частях, имеющих фоновый рисунок.
Почему окно не становится недействительным?
Была такая же проблема. Следующие код починил это:
mStatic.SetWindowText("New text");
CRect rect;
mStatic.GetWindowRect(&rect);
ScreenToClient(&rect);
InvalidateRect(&rect);
UpdateWindow();
Возможно, для вашего статического текстового элемента управления включен стиль SS_SIMPLE. Вы можете проверить флаги стиля в файле ресурсов или с помощью GetStyle ().
Статическое управление в стиле SS_SIMPLE отображает текст быстрее, но также — как MSDN описывает —
«Статические элементы управления SS_SIMPLE не очищают область отображения элемента управления при отображении текста. Если отображается более короткая строка, отображается часть исходной строки, которая длиннее новой более короткой строки».
Удалите SS_SIMPLE из флагов стиля, и CStatic будет вести себя «нормально».
это статья поддержки базы знаний описывает ту же проблему, когда SetWindowText()
звонок сделан из другого потока. Это то, что делает твой таймер?
Если это так, решение может быть просто:
mStatic.SetWindowText("asdfasdf");
CRect clientRect;
mStatic.GetClientRect(clientRect);
mStatic.InvalidateRect(clientRect);
Как уже упоминалось другими, статический элемент управления не обязательно стирает фон перед рисованием текста.
Я считаю, что это гораздо лучшее решение подкласс статического контроля и заставить недействительный контроль оттуда. Это позволяет легко реализовать его на всех статических текстах с прозрачным фоном, без необходимости делать дополнительные вызовы, чтобы лишить законной силы элемент управления из его родительского класса.
Один из способов поймать изменение текста элемента управления внутри самого элемента управления — это реагировать на WM_SETTEXT
сообщение и принудительно сделайте недействительным оттуда:
int CStaticT::OnSetText(LPCTSTR text)
{
LRESULT res = Default();
Invalidate();
UpdateWindow();
return res;
}
Вот краткий пример, извлеченный из одного из моих классов, о том, как может выглядеть такой подклассный элемент управления:
//////////////////////////////////////////////////////////////////////////
// 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;
}