BitBlt Bitmap на CClientDC
{
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 у ли дело. Выясняется что нет.)
Перед заданием вопроса упорно гуглил, но нашел лишь подобные примеры. Объясните пожалуйста что я не так делаю. Заранее благодарен!
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);
}
{
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, однако там ничего не рисуется. Подскажите пожалуйста как избавиться от проблемы связанной с перерисовкой.
При любом перемещении все мое изображение начинает мерцать, перерисовываться. Однако, если посмотреть на стандартные игры windows(всякий там сапер, карты, и т.д.) то при перетаскивании окна никакой перерисовки не происходит. Каким образом это реализовано там? Я пытался рисовать изображение в обработчиках других событий и конструкторе CMFC6View, однако там ничего не рисуется. Подскажите пожалуйста как избавиться от проблемы связанной с перерисовкой.
Эта проблема уже сложнее. Дело в том, что при обработчике OnPaint вы перерисовываете каждый раз всю клиентскую часть окна полностью. За одно перемещение окна WM_PAINT отсылается окну несколько раз, поэтому и полная перерисовка происходит столько же раз. Вообщем для себя я так и не нашел нормального способа рисования с помощью GDI ни в MSVC ни в средах Borland. "Моргание" всегда присутствует. Уж не знаю как там писались стандартные игры от microsoft, но обычно при разработке даже настольных игр зачастую используют OpenGL или DirectX. Хотя в случае с сапером в Borland'е я обходился использованием стандартных компонентов и написанием собственных и достигал вполне приемлегого результата.
В данной же ситуации могу лишь предложить небольшое решение для оптимизации вашего кода. Все дело в том, что сообщение WM_PAINT не обязательно означет, что перерисовка требуется всему окну. Скорее наоборот, обычно перерисовать необходимо лишь небольшую его часть (т.н. Invalid). Узнать какая именно часть клиентской области требует перерисовки можно с помощью члена m_ps класса CPaintDC. Это указатель на структуру PAINTSTRUCT в которой содержится член rcPaint. Значение rcPaint - это и есть координаты области, который нужно перерисовать.
[QUOTE=nikitozz]небольшое решение для оптимизации вашего кода.[/QUOTE]
Все верно, да только винда и так отсекает все функции производящие вывод за границами невалидного региона при WM_PAINT-е и за его границами рисовать не получится, а также оптимизирует те что пересекают регион частично, поэтому оптимизация будет лишь по скорости, и то в том случае если невалидный прямоугольник достаточно мал, а код прорисовки достаточно сложен и медленен (например вычисление сложного графика)..
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);