CWnd::OnPaint
является ответом на сообщение WM_PAINT
и не должен вызываться напрямую.
WM_PAINT
вызывает CWnd::OnPaint
, что вызывает CPaintDC dc(this)
, что в свою очередь вызывает BeginPaint
/ EndPaint
API. Эта последовательность сообщения + ответа должна быть оставлена как есть.
Поэтому CPaintDC dc(this)
должен появиться один раз - и только один раз - внутри OnPaint
, а не где-либо еще. Переопределите OnPaint
следующим образом:
void CMyDialog::OnPaint()
{
CDialogEx::OnPaint(); //this will call CPaintDC dc(this);
//optional:
CClientDC dc(this); //CClientDC can be used anywhere in a valid window
//use dc for drawing
}
//or
void CMyDialog::OnPaint()
{
CPaintDC dc(this);
//use dc for drawing
}
Вам также не нужно устаревшее if (IsIconic()) {...}
условие.
Чтобы заставить окно перерисоваться, вызовите Invalidate()
(тоже самое, что и InvalidateRect(NULL, TRUE)
)
InvalidateRect(NULL, TRUE)
- запрос перекрасить окно. Система посмотрит на этот запрос и отправит сообщение WM_PAINT
в это окно, когда будет такая возможность. Поэтому вызов InvalidateRect
может не обработать то, как вы ожидаете, что он будет работать в последовательной программе. Например, второй последовательный вызов InvalidateRect
не будет иметь никакого эффекта. Окно уже помечено для обновления.
for(int i(9); i >= 0; --i)
{
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
m_fDiagramData.push_back((float)rand() / RAND_MAX);
InvalidateRect(NULL, TRUE);
OnPaint();
}
OnPaint()
следует удалить из приведенного выше кода. Тем не менее, анимация невозможна в одном потоке (по крайней мере, не таким образом). Программа занята прохождением цикла, она не может обрабатывать WM_PAINT
и другие сообщения.
Итак, вам нужен дополнительный поток или просто используйте SetTimer
, и ответьте на ON_WM_TIMER()
/ OnTimer
для анимации. Пример:
int counter = 0;
BEGIN_MESSAGE_MAP(CMyDialog, CDialogEx)
ON_WM_PAINT()
ON_WM_TIMER()
...
END_MESSAGE_MAP()
void CMyDialog::OnPaint()
{
CPaintDC dc(this);
CString s;
s.Format(L"%02d", counter);
dc.TextOut(0, 0, s);
}
void CMyDialog::animate()
{
counter = 0;
SetTimer(1, 1000, NULL);
}
void CMyDialog::OnTimer(UINT_PTR n)
{
if(n == 1)
{
Invalidate(); //force repaint
counter++;
if(counter == 10)
KillTimer(1);
}
}