С++ gdi рисует эллипс

хорошо, я могу нарисовать эллипс, проблема в том, что я пытаюсь нарисовать один эллипс, но изменить его значение x на другое. вот так я рисую один эллипс, и значение x равно 1 через десять секунд, я хочу, чтобы значение x было равно 10, но кажется, что я создаю новый эллипс со значением x 10. вот мой код

while(sd==1)//sd equal 1 
{
    sf++;//sf equals 1
    onPaint(hdc);
    InvalidateRect(hWnd,0,true);
}
//on paint function
VOID onPaint(HDC hdc)
{
   Graphics graphics(hdc);
   Pen      pen(Color(255, 0, 0, 255));
   graphics.DrawEllipse(&pen,sf , 0, 50, 50);
}

ну, я думал, что недействительный прямоугольник очистит все, что было нарисовано, и перекрасит его, но это не сработало.


person Ramilol    schedule 09.08.2010    source источник


Ответы (3)


Если вы хотите сделать анимацию, вам лучше установить таймер.

Использование InvalidateRect в качестве способа генерации WM_PAINT кажется излишним, он сделает гораздо больше. Вместо этого вы можете рисовать непосредственно в вызове OnTimer, так как он находится вне WM_PAINT, вам нужно будет получить контекст устройства с помощью GetDC.

Например, если у вас может быть функция DrawFrame(HDC hDC). OnTimer обновит текущую позицию и вызовет DrawFrame, OnPaint вызовет DrawFrame, но не обновит позицию (таким образом, если вы хотите остановить анимацию, у вас будет отрисовка последнего кадра).

DrawFrame очистит фон (возможно, с помощью FillRect) и нарисует круг в новой позиции. Если у вас большая область, это будет мерцать, чтобы избежать этого, как предложил Том, вы можете использовать DC памяти и HBITMAP для двойного буфера.

person Ismael    schedule 09.08.2010
comment
Хорошо, спасибо за подробности, но не могли бы вы привести пример использования getDC и какую функцию следует использовать для обновления? - person Ramilol; 10.08.2010
comment
Это очень просто HDC hDC = GetDC(hWnd) проверить msdn.microsoft.com/en -us/library/dd144871(VS.85).aspx. Вы должны обновляться при запуске OnTimer, чтобы у вас была плавная анимация. - person Ismael; 11.08.2010

Вы не должны пытаться нарисовать несколько кадров анимации за один раз.

Сохраните переменную sf где-нибудь, а в OnPaint() увеличьте sf, нарисуйте один эллипс и вызовите Invalidate()

Invalidate вызовет повторный вызов OnPaint().

Это должно работать, но будет очень мерцать :) Вы можете исправить мерцание двойной буферизацией.

person Tom Sirgedas    schedule 09.08.2010
comment
ну, это рисует больше, чем один, и sf - это golabe varabile - person Ramilol; 10.08.2010

InvalidateRect помечает окно как «недопустимое», но это не приводит к немедленному стиранию и перерисовке. Стирание и рисование происходит только тогда, когда работает ваш насос сообщений (например, цикл с GetMessage и DispatchMessage). Когда очередь сообщений иссякнет, GetMessage синтезирует сообщения WM_ERASEBKGND и WM_PAINT для недопустимых окон. Когда эти сообщения отправляются оконной процедуре, окно получает возможность рисовать.

Ваша функция onPaint только рисует, а не стирает. И поскольку ваш цикл никогда не завершается, помпа сообщений никогда не запускается.

Для простых анимаций решение SetTimer. В вашем обработчике сообщений WM_TIMER обновите свои переменные для одного кадра, вызовите InvalidateRect и верните (что позволит продолжить работу насоса сообщений). Появится сообщение о стирании и рисовании, затем снова сработает таймер, и вы получите следующий кадр.

person Adrian McCarthy    schedule 11.08.2010
comment
Кто-нибудь может объяснить, почему за этот пост проголосовали? Это объясняет, почему InvalidateRect не работает так, как ожидал спрашивающий. - person Adrian McCarthy; 30.08.2010