Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

BitBlt Bitmap на CClientDC

1.6K
21 августа 2008 года
Shtirlitz
145 / / 31.07.2006
Доброго времени суток!
Код:
void CMainFrame::OnPaint()
{
    CClientDC myDC(this);
    MyBitMap=new CBitmap();
    MyBitMap->CreateCompatibleBitmap(&myDC,70,70);
    //MyBitMap->LoadBitmapW(IDB_BITMAP1);
    MyCDC=new CDC();
    MyCDC->CreateCompatibleDC(&myDC);
    //MyCDC->SelectObject(MyBitMap);
    MyCDC->Rectangle(0,0,40,40);
    myDC.BitBlt(0,0,70,70,MyCDC,0,0,SRCCOPY);
}


В данном коде есть 2 проблемы(возможно больше ;)):

1:При совместном использовании функций CreateCompatibleBitmap и LoadBitmapW(LoadBitmap) происходит ошибка времени выполнения. Хотя по отдельности никаких проблем нет все компилируется и запускается.

2:Данный код не выводит ничего на дисплей. В чем здесь дело? Чего не хватает? (Rectangle вставил как раз чтобы проверить не в Bitmap у ли дело. Выясняется что нет.)

Перед заданием вопроса упорно гуглил, но нашел лишь подобные примеры. Объясните пожалуйста что я не так делаю. Заранее благодарен!
288
21 августа 2008 года
nikitozz
1.2K / / 09.03.2007
Возможно ошибаюсь, но по-моему проблема в том, что в обработчике OnPaint необходимо использовать только CPaintDC, а не CClinetDC. И еще, если это Single Document проект, то рисовать необходимо в обработчике сообщения WM_PAINT в классе представления, т.е. CChildView::OnPaint. Вот работающий пример из MSDN
Код:
CPaintDC dc(this); // device context for painting
    CBitmap bmp;
   
    if (bmp.LoadBitmap(IDB_BITMAP1))
    {
        // Get the size of the bitmap
        BITMAP bmpInfo;
        bmp.GetBitmap(&bmpInfo);

        // Create an in-memory DC compatible with the
        // display DC we're using to paint
        CDC dcMemory;
        dcMemory.CreateCompatibleDC(&dc);

        // Select the bitmap into the in-memory DC
        CBitmap* pOldBitmap = dcMemory.SelectObject(&bmp);

        // Find a centerpoint for the bitmap in the client area
        CRect rect;
        GetClientRect(&rect);
        int nX = rect.left + (rect.Width() - bmpInfo.bmWidth) / 2;
        int nY = rect.top + (rect.Height() - bmpInfo.bmHeight) / 2;

        // Copy the bits from the in-memory DC into the on-
        // screen DC to actually do the painting. Use the centerpoint
        // we computed for the target offset.
        dc.BitBlt(nX, nY, bmpInfo.bmWidth, bmpInfo.bmHeight, &dcMemory,
            0, 0, SRCCOPY);

        dcMemory.SelectObject(pOldBitmap);
    }
1.6K
21 августа 2008 года
Shtirlitz
145 / / 31.07.2006
Спасибо большое за помощь! Но вот возник еще один вопрос.Я пробую делать так:
Код:
void CMFC6View::OnPaint()
{  
    int x_offset=100;
    int y_offset=40;
    CDC sourceDC,sourceDC2;
    CPaintDC targetDC(this);

    CBitmap bitmap_w,bitmap_b;
    CBitmap bitmap;

    bitmap_b.LoadBitmap(IDB_BITMAP10);
    bitmap_w.LoadBitmap(IDB_BITMAP11);

    sourceDC.CreateCompatibleDC(&targetDC);
   

    targetDC.Rectangle(x_offset-1,39,70*8+x_offset+1,70*8+1+y_offset);
    for(int i=0;i<8;i++)
        for(int j=0;j<8;j++)
        {
            if((i+j)%2==0)
                sourceDC.SelectObject(&bitmap_w);
            else
                sourceDC.SelectObject(&bitmap_b);
           
            targetDC.BitBlt(x_offset+i*70,y_offset+j*70,70,70,&sourceDC,0,0,SRCCOPY);
        }


}


При любом перемещении все мое изображение начинает мерцать, перерисовываться. Однако, если посмотреть на стандартные игры windows(всякий там сапер, карты, и т.д.) то при перетаскивании окна никакой перерисовки не происходит. Каким образом это реализовано там? Я пытался рисовать изображение в обработчиках других событий и конструкторе CMFC6View, однако там ничего не рисуется. Подскажите пожалуйста как избавиться от проблемы связанной с перерисовкой.
288
22 августа 2008 года
nikitozz
1.2K / / 09.03.2007
Цитата: Shtirlitz

При любом перемещении все мое изображение начинает мерцать, перерисовываться. Однако, если посмотреть на стандартные игры windows(всякий там сапер, карты, и т.д.) то при перетаскивании окна никакой перерисовки не происходит. Каким образом это реализовано там? Я пытался рисовать изображение в обработчиках других событий и конструкторе CMFC6View, однако там ничего не рисуется. Подскажите пожалуйста как избавиться от проблемы связанной с перерисовкой.



Эта проблема уже сложнее. Дело в том, что при обработчике OnPaint вы перерисовываете каждый раз всю клиентскую часть окна полностью. За одно перемещение окна WM_PAINT отсылается окну несколько раз, поэтому и полная перерисовка происходит столько же раз. Вообщем для себя я так и не нашел нормального способа рисования с помощью GDI ни в MSVC ни в средах Borland. "Моргание" всегда присутствует. Уж не знаю как там писались стандартные игры от microsoft, но обычно при разработке даже настольных игр зачастую используют OpenGL или DirectX. Хотя в случае с сапером в Borland'е я обходился использованием стандартных компонентов и написанием собственных и достигал вполне приемлегого результата.
В данной же ситуации могу лишь предложить небольшое решение для оптимизации вашего кода. Все дело в том, что сообщение WM_PAINT не обязательно означет, что перерисовка требуется всему окну. Скорее наоборот, обычно перерисовать необходимо лишь небольшую его часть (т.н. Invalid). Узнать какая именно часть клиентской области требует перерисовки можно с помощью члена m_ps класса CPaintDC. Это указатель на структуру PAINTSTRUCT в которой содержится член rcPaint. Значение rcPaint - это и есть координаты области, который нужно перерисовать.

14
22 августа 2008 года
Phodopus
3.3K / / 19.06.2008
Если код рисования в WM_PAINT покрывает ВСЮ клиентскую область окна, то можно проигнорировать WM_ERASEBKGND (не отдавать его стандартной процедуре обработки) и мерцания станет куда меньше, если не исчезнет совсем.
[QUOTE=nikitozz]небольшое решение для оптимизации вашего кода.[/QUOTE]
Все верно, да только винда и так отсекает все функции производящие вывод за границами невалидного региона при WM_PAINT-е и за его границами рисовать не получится, а также оптимизирует те что пересекают регион частично, поэтому оптимизация будет лишь по скорости, и то в том случае если невалидный прямоугольник достаточно мал, а код прорисовки достаточно сложен и медленен (например вычисление сложного графика)..
1.7K
22 августа 2008 года
Denis_R
63 / / 15.02.2004
Для того чтобы не мерцала надо делать так
CPaintDC dc(this);
CDC memDC;
CBitmap bitmap;
CRect clientRect;
GetClientRect(&clientRect);
CBitmap *pOldMemDCBitmap = NULL;
memDC.CreateCompatibleDC(&dc);
bitmap.CreateCompatibleBitmap( &dc, clientRect.Width(), clientRect.Height() );
CBitmap *pOldmemDCBitmap = (CBitmap*)memDC.SelectObject(&bitmap);
//стесь рисуем в memDC
//и в конце это все добро отоброжаем
dc.BitBlt(0, 0, clientRect.Width(), clientRect.Height(), &memDC, 0, 0, SRCCOPY);
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог