Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Visual C++/MFC/WTL > рисование без мерцания


Автор: drazah 3.11.2010, 23:50
Мне нужно сделать примитивную анимацию - миниатюрный танк   "ползет" по формочке.
Я делаю так. Создаю таймер. В его обработчике пишу:


Код

void CMainWnd::OnTimer(UINT)
{
     xCurrent += 5; // увеличили текущую координату по иксу
     Invalidate(); // вызов метода OnPaint ?? 
}


Отрисовка окна такая:

Код

void CMainWnd::OnPaint()
{
      CPaintDC dc(this);
      drawTank(dc); //функции отрисовки танка
}


На выходе все рисуется, но мерцает =(  Подтолкните на путь истинный! В частности сам подход c этим Invalidate вообще верный или надо как-то по другому все организовывать?

P.S. Нашел похожую тему. http://forum.vingrad.ru/forum/topic-52762/unread-1.html 
взял код от туда, а именно

Код

void CMainWnd::OnPaint()
{
        CDC * pDCDest=GetDC();    
        CDC dcMem;    
        dcMem.CreateCompatibleDC(pDCDest);    
        CBitmap *pPrevBmpMem=dcMem.GetCurrentBitmap();    
        CRect rCl;    
        GetClientRect(rCl);    
        CBitmap BmpNewMem;    
        BmpNewMem.CreateCompatibleBitmap(pDCDest, rCl.Width(), rCl.Height());    
        dcMem.SelectObject(&BmpNewMem);    
        dcMem.FillSolidRect(rCl, RGB(255,255,255));    
        CDC *pDCTemp=pDCDest;    
        pDCDest=&dcMem;    


        CDC memDC;    
     
        my_tank.drawTank(pDCDest);   


        pDCDest=pDCTemp;    
        pDCDest->BitBlt(rCl.left, rCl.top, rCl.Width(), rCl.Height(), &dcMem,rCl.left, rCl.top, SRCCOPY);    
        dcMem.SelectObject(pPrevBmpMem);
}


Танк вообще не двигается. 

Автор: Cheloveck 3.11.2010, 23:59
Цитата(drazah @  3.11.2010,  23:50 Найти цитируемый пост)
Подтолкните на путь истинный! 

Для отрисовки анимации средствами GDI делают так:
  • Создают новый контекст рисования совместимый с тем, на котором нужно рисовать (CreateCompatibleDC);
  • Создают новый битмап, опять же, совместимый (CreateCompatibleBitmap);
  • Устанавливают новый битмап в новый контекст (SelectObject);
  • Рисуют на новом контексте;
  • Копируют новый контекст в тот, на который нужно рисовать (BitBlt).
Сие называется двойная буфиризация.

Автор: drazah 4.11.2010, 10:43
Спасибо, Cheloveck.
Как я понимаю, это все писать в фунции отрисовки. Делал  так:
Код

void CMainWnd::OnPaint() 
{
    CPaintDC dc (this);

    // Создание совместимого контекста устройства 
    CDC dcMem;
    
    // Создаю битмап
    CBitmap bitmap;
        
    // Определение размеров клиентской области окна
    RECT rect;
    this->GetClientRect(&rect);


    dcMem.CreateCompatibleDC(&dc);
    bitmap.CreateCompatibleBitmap( &dcMem, rect. right, rect.bottom ) ;
    dcMem.SelectObject( &bitmap );
    //рисую на новом контексте
    dcMem.LineTo(11,400); //- вызов функции рисования 

    // Копирование содержимого одного контекста в другой 
    dc.BitBlt( 0, 0, rect.right, rect.bottom, &dcMem, 0, 0, 0) ; 

    // Удаление совместимого контекста устройства
    dcMem.DeleteDC(); 
}

В функции таймера не менял ничего. На выходе - черное мерцающее окно) 
Можете подправить где что не так?

Автор: voov 23.11.2010, 14:55
drazah, разбираться нету времени. Вот кусок рабочего кода, разберись сам.

Код

void CBarChildWnd::OnPaint()
{
    CPaintDC dc(this); // device context for painting
    // Do not call CWnd::OnPaint() for painting messages

    // Двойная буфферизация
    CRect rectBuf;                    // Это нам для координат
    GetClientRect(&rectBuf);        // Получим координаты
    CDC mem;                        // Вспомогательный контест
    mem.CreateCompatibleDC(&dc);    // Создаем его в памяти
    CBitmap btmp;                    // "Пустой вспомогательный растр"
    btmp.CreateCompatibleBitmap(&dc, rectBuf.Width(), rectBuf.Height());    //Создаем и его в памяти
    CBitmap* oldBitmap = mem.SelectObject(&btmp);        // Выбираем этот растр, тем самым создав "невидимое полотно"
    mem.SetBkMode(TRANSPARENT);
    //Начинаем рисовать на "невидимом полотне". Рисуем все что угодно. Даже можем передовать туда растр и т.д.

....
    // получаем размер окна и заливаем фон
    CRect rect;
    GetClientRect(&rect);

    // если установлено выделение - рисуем фокус
    if (m_selected) {
        mem.DrawFocusRect(&rect);
        rect.DeflateRect(SELECTED_OFFSET, SELECTED_OFFSET);
    }

....
    // Теперь все , что нарисовали в один прием передаем на "видимое полотно"
    dc.BitBlt(0, 0, rectBuf.Width(), rectBuf.Height(), &mem, 0, 0, SRCCOPY);

    mem.SelectObject(oldBitmap);
}

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)