Autor Wątek: [WinAPI] Podwójne buforowanie  (Przeczytany 15056 razy)

Offline Bimbol

  • Użytkownik

  • +1
# Styczeń 14, 2014, 19:52:08
Witam, uczę się aktualnie WinAPI. Dokładnie to z tego kursu: http://cpp0x.pl/kursy/Kurs-WinAPI-C++/167
Jednak utknąłem na lekcji Animacja. Program, który ułożyłem zgodnie ze wskazówkami tego poradniki uruchamia się, ale nie uzyskuje pożądanego efektu.

To jest cały kod programu (tak wiem, jest tam syf, ale chodzi mi tylko o to by działało poprawnie):

Kod: (c++) [Zaznacz]
#include <windows.h>
#include <commctrl.h>

LPSTR NazwaKlasy = "Klasa Okienka";
MSG Komunikat;
HWND g_hwnd;
const WORD ID_TIMER = 1;
HBITMAP hbmMaska;

SHORT SpeedX = 2, SpeedY = 2;
RECT rcOkno, rcTemp;
HBITMAP hbmKulka;
BITMAP bmKulka;
RECT rcKulka;

HDC hdcMem;

HDC hdcBufor, hdcBuf2;
HBITMAP hbmBuf, hbmOldBuf, hbmOld;

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
void RysujKulke();
HBITMAP CreateBitmapMask(HBITMAP hbmColour, COLORREF crTransparent);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
InitCommonControls();
// WYPEŁNIANIE STRUKTURY
WNDCLASSEX wc;

wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = NazwaKlasy;
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

// REJESTROWANIE KLASY OKNA
if (!RegisterClassEx(&wc))
{
MessageBox(NULL, "Wysoka Komisja odmawia rejestracji tego okna!", "Niestety...",
MB_ICONEXCLAMATION | MB_OK);
return 1;
}

// TWORZENIE OKNA
HWND hwnd;

hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, NazwaKlasy, "Oto okienko", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, NULL, NULL, hInstance, NULL);

if (hwnd == NULL)
{
MessageBox(NULL, "Okno odmówiło przyjścia na świat!", "Ale kicha...", MB_ICONEXCLAMATION);
return 1;
}

g_hwnd = hwnd;

GetClientRect(g_hwnd, &rcOkno);

ShowWindow(hwnd, nCmdShow); // Pokaż okienko...
UpdateWindow(hwnd);

hbmKulka = (HBITMAP)LoadImage(NULL, "C:\\IMG\\IMAGES\\BUILDING\\ARAB BARRACKS.BMP", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
hbmMaska = CreateBitmapMask(hbmKulka, RGB(0, 255, 0));

GetObject(hbmKulka, sizeof(bmKulka), &bmKulka);

SetRect(&rcKulka, 5, 5, 5 + bmKulka.bmWidth, 5 + bmKulka.bmHeight);

HDC hdc = GetDC(g_hwnd);

hdcMem = CreateCompatibleDC(hdc);
hbmOld = (HBITMAP)SelectObject(hdcMem, hbmKulka);

hdcBufor = CreateCompatibleDC(hdc);
hbmBuf = CreateCompatibleBitmap(hdcBufor, rcOkno.right, rcOkno.bottom);
hbmOldBuf = (HBITMAP)SelectObject(hdcBufor, hbmBuf);
FillRect(hdcBufor, &rcOkno, (HBRUSH)GetStockObject(LTGRAY_BRUSH));

ReleaseDC(g_hwnd, hdc);

if (SetTimer(hwnd, ID_TIMER, 100, NULL) == 0)
MessageBox(hwnd, "Nie można utworzyć timera!", "Kurde", MB_ICONSTOP);

// Pętla komunikatów
while (GetMessage(&Komunikat, NULL, 0, 0))
{
TranslateMessage(&Komunikat);
DispatchMessage(&Komunikat);
}
return Komunikat.wParam;
}

// OBSŁUGA ZDARZEŃ
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_CLOSE:
DestroyWindow(hwnd);
break;

case WM_DESTROY:
KillTimer(hwnd, ID_TIMER);
SelectObject(hdcBufor, hbmOldBuf);
DeleteDC(hdcBufor);
DeleteDC(hdcBuf2);
DeleteDC(hdcMem);
DeleteObject(hbmKulka);
DeleteObject(hbmMaska);
DeleteObject(hbmBuf);
DeleteObject(hbmOld);
PostQuitMessage(0);
break;


case WM_TIMER:
RysujKulke();
break;

default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}

return 0;
}

void RysujKulke()
{

// pobierz HDC okna
HDC hdc = GetDC(g_hwnd);
//zamaż "starą" kulkę
//FillRect(hdc, &rcTemp, (HBRUSH)GetStockObject(LTGRAY_BRUSH)); // Stare
FillRect(hdcBufor, &rcOkno, (HBRUSH)GetStockObject(LTGRAY_BRUSH));
// wylicz nowe parametry kulki
if (rcKulka.left <= 0 || rcKulka.right >= rcOkno.right) SpeedX = -SpeedX;

if (rcKulka.top <= 0 || rcKulka.bottom >= rcOkno.bottom) SpeedY = -SpeedY;

OffsetRect(&rcKulka, SpeedX, SpeedY);
//OffsetRect(&rcTemp, SpeedX, SpeedY); // Stare

//narysuj na nowej pozycji
SelectObject(hdcMem, hbmMaska);
BitBlt(hdcBufor, rcKulka.left, rcKulka.top, rcKulka.right - rcKulka.left,
rcKulka.bottom - rcKulka.top, hdcMem, 0, 0, SRCAND);
SelectObject(hdcMem, hbmKulka);
BitBlt(hdcBufor, rcKulka.left, rcKulka.top, rcKulka.right - rcKulka.left,
rcKulka.bottom - rcKulka.top, hdcMem, 0, 0, SRCINVERT);

BitBlt(hdc, 0, 0, rcOkno.right, rcOkno.bottom, hdcBufor, 0, 0, SRCCOPY);
ReleaseDC(g_hwnd, hdc);
}

HBITMAP CreateBitmapMask(HBITMAP hbmColour, COLORREF crTransparent)
{
HDC hdcMem, hdcMem2;
HBITMAP hbmMask, hbmOld, hbmOld2;
BITMAP bm;

GetObject(hbmColour, sizeof(BITMAP), &bm);
hbmMask = CreateBitmap(bm.bmWidth, bm.bmHeight, 1, 1, NULL);

hdcMem = CreateCompatibleDC(NULL);
hdcMem2 = CreateCompatibleDC(NULL);

hbmOld = (HBITMAP)SelectObject(hdcMem, hbmColour);
hbmOld2 = (HBITMAP)SelectObject(hdcMem2, hbmMask);

SetBkColor(hdcMem, crTransparent);

BitBlt(hdcMem2, 0, 0, bm.bmWidth, bm.bmHeight, hdcMem, 0, 0, SRCCOPY);
BitBlt(hdcMem, 0, 0, bm.bmWidth, bm.bmHeight, hdcMem2, 0, 0, SRCINVERT);

SelectObject(hdcMem, hbmOld);
SelectObject(hdcMem2, hbmOld2);
DeleteDC(hdcMem);
DeleteDC(hdcMem2);

return hbmMask;
}

A tutaj screen: http://img.pl/Hlrf.png
Na szarym tle, powinna przemieszczać się kolorowa bitmapa.

Szukałem na google rozwiązania, ale nie znalazłem. Próbowałem rozwiązać sam, ale skutek jest taki jaki widać na screenie.

Pozdrawiam.

Offline Mr. Spam

  • Miłośnik przetworów mięsnych

Offline Rokuzo

  • Użytkownik
    • Masz na sprzedaż klucze do cs go?

  • +3
# Styczeń 14, 2014, 21:27:55
Litości. Zapomnij o rysowaniu bezpośrednio poprzez WinApi i chwyć za coś bardziej ludzkiego. (np. SDL2)
Uważam, że WinApi nie jest dobre na początek, serio, więcej zachodu niż korzyści. Owszem nie raz może się bezpośrednie WinApi przydać ale po co? Zwłaszcza, że jak widzę to początki przygody z C++ :)

Offline kubera

  • Użytkownik
    • Prywatna strona

# Styczeń 14, 2014, 22:08:00
Ja nie neguję pisania pod Windows SDK, ale zaproponowałbym Direct2D...
W zasadzie może być już dostępne pod Vistą.

API, które tu występuje widziałem już w Windows 3.10 spory czas temu.

Offline Krzysiek K.

  • Redaktor
    • DevKK.net

# Styczeń 14, 2014, 22:19:32
Cytuj
Ja nie neguję pisania pod Windows SDK, ale zaproponowałbym Direct2D...
W zasadzie może być już dostępne pod Vistą.
Lepiej Direct3D, jeżeli już jakieś Microsoftowe API. Działa od XP albo i wcześniej i gwarantuje akcelerację sprzętową.

Cytuj
API, które tu występuje widziałem już w Windows 3.10 spory czas temu.
Co nie zmienia faktu, że żeby odpalić Direct3D 11 nadal trzeba wywołać CreateWindow dostępne od owego Windowsa 3.10. ;)

Offline Bimbol

  • Użytkownik

# Styczeń 14, 2014, 22:48:19
Litości. Zapomnij o rysowaniu bezpośrednio poprzez WinApi i chwyć za coś bardziej ludzkiego. (np. SDL2)
Uważam, że WinApi nie jest dobre na początek, serio, więcej zachodu niż korzyści. Owszem nie raz może się bezpośrednie WinApi przydać ale po co? Zwłaszcza, że jak widzę to początki przygody z C++ :)
Ja nie neguję pisania pod Windows SDK, ale zaproponowałbym Direct2D...
W zasadzie może być już dostępne pod Vistą.

API, które tu występuje widziałem już w Windows 3.10 spory czas temu.

Lepiej Direct3D, jeżeli już jakieś Microsoftowe API. Działa od XP albo i wcześniej i gwarantuje akcelerację sprzętową.
Co nie zmienia faktu, że żeby odpalić Direct3D 11 nadal trzeba wywołać CreateWindow dostępne od owego Windowsa 3.10. ;)

Dla sprostowania sprawy, nie zamierzam używać WinAPI do tworzenia czegokolwiek graficznego.
Kod nie jest mój, pochodzi prosto z tutoriala, jedynie ja jestem odpowiedzialny za bałagan w nim (różne próby w celu dążenia do poprawności kodu).
Po prostu chcę wiedzieć, co tutaj jest źle. A to, że autor kursu wspomniał o podwójnym buforowaniu, to nie chcę tego pominąć. Z WinAPI zamierzam korzystać tylko do aplikacji okienkowych.

Tak więc, jakieś rady? Bo, póki co nie zamierzam brnąć dalej. Najpierw chce opanować to, mimo, że pewnie nie będę z tego korzystał.

Offline Xender

  • Użytkownik

  • +1
# Styczeń 14, 2014, 23:01:46
Jedna rada - użyj biblioteki do GUI wyższego poziomu, jak wxWidgets, GTK czy Qt.
W WinAPI idzie się prędzej zachlastać, niż napisać jakieś skomplikowane GUI (a i proste sporo zajmuje).

Używając jednej z tych bibliotek zyskujesz także wieloplatformowość - dopóki nie robisz czegoś system-specific, albo API/funkcjonalność konkretnego systemu nie ułatwia Ci znacząco roboty, to nie ma powodu, żeby wiązać aplikację z jednym systemem. W dodatku tak niezbyt udanym, jak Windows.

Disclaimer - używałem z nich tylko Qt i jest ok, chociaż potrzebuje własnego preprocesora ze względu na modyfikacje, które wprowadza do języka (głównie mezhanizm slotów i sygnałów) - natomiast nie wymaga ani specjalnego IDE, ani kompilatora - wystarczy dać jako element builda przepuszczenie kodu, który korzysta z Q_OBJECT przez MOC (ten preprocesor) i działa z różnymi kompilatorami.
wxWidgets odpalałem raz. W GTK nie pisałem nic.

Offline Bimbol

  • Użytkownik

# Styczeń 14, 2014, 23:15:07
Jedna rada - użyj biblioteki do GUI wyższego poziomu, jak wxWidgets, GTK czy Qt.
W WinAPI idzie się prędzej zachlastać, niż napisać jakieś skomplikowane GUI (a i proste sporo zajmuje).

Używając jednej z tych bibliotek zyskujesz także wieloplatformowość - dopóki nie robisz czegoś system-specific, albo API/funkcjonalność konkretnego systemu nie ułatwia Ci znacząco roboty, to nie ma powodu, żeby wiązać aplikację z jednym systemem. W dodatku tak niezbyt udanym, jak Windows.

Disclaimer - używałem z nich tylko Qt i jest ok, chociaż potrzebuje własnego preprocesora ze względu na modyfikacje, które wprowadza do języka (głównie mezhanizm slotów i sygnałów) - natomiast nie wymaga ani specjalnego IDE, ani kompilatora - wystarczy dać jako element builda przepuszczenie kodu, który korzysta z Q_OBJECT przez MOC (ten preprocesor) i działa z różnymi kompilatorami.
wxWidgets odpalałem raz. W GTK nie pisałem nic.

Kiedyś rozglądałem się właśnie za biblioteką GUI. Trafiłem na Qt i miałem zamiar korzystać, jednak zafascynował mnie OpenGL i tak w nim siedzę, ale pomyślałem, że znajomość biblioteki GUI również mi się przyda.

Czyli mam rozumieć, że najlepszym wyjściem w tej sytuacji jest porzucenie dalszego kursu i zabranie się za Qt? Tylko pytanie jak to jest z licencją Qt?

Offline Lobsang Rampa

  • Użytkownik
    • Global Epidemic

# Styczeń 14, 2014, 23:26:37
Z wymienionych przez Xendera bibliotek polecam wxWidgets, Można w nim osadzić OpenGL (w pozostałych pewnie też), działa na Windows i Linux, jest całkowicie free do wszelkich zastosować, ma czytelne API i jak dla mnie jest bezproblemowa, GTK i Qt nie testowałem, ale jak podejmowałem jakiś czas temu decyzję o wyborze biblioteki to jak dla mnie wxWidgets miał wtedy "teoretycznie" najwięcej plusów.

Jest tez książka wprowadzająca w podstawy wxWidgets i Qt, możesz sobie na jej podstawie wyrobić sam opinie:
http://helion.pl/ksiazki/c-wykorzystaj-potege-aplikacji-graficznych-janusz-ganczarski-mariusz-owczarek,cppwyk.htm
« Ostatnia zmiana: Styczeń 14, 2014, 23:28:42 wysłana przez Lobsang Rampa »

Offline Xender

  • Użytkownik

  • +2
# Styczeń 15, 2014, 00:03:04
^ Autor wykorzystuje Dev-C++ (pierwsza rzecz w przykładowym rozdziale na podlinkowanej stronie to screenshoty z tworzenia nowego projektu). Coś mi mówi, że lepiej trzymać się od tej książki z daleka.

Offline Bimbol

  • Użytkownik

# Styczeń 15, 2014, 00:28:09
Zbyt dużo jest tutoriali do Qt bym kupował książkę :)
Także, dzięki za informacje i naprostowanie.

Temat można zamknąć.

Offline Lobsang Rampa

  • Użytkownik
    • Global Epidemic

# Styczeń 15, 2014, 01:15:58
^ Autor wykorzystuje Dev-C++ (pierwsza rzecz w przykładowym rozdziale na podlinkowanej stronie to screenshoty z tworzenia nowego projektu). Coś mi mówi, że lepiej trzymać się od tej książki z daleka.
Mam tą książkę i mogę powiedzieć, ze jako wprowadzenie po polsku do wxWidgets i Qt może być (opisano przystępnie np. zdarzenia). Więcej natomiast można znaleźć w oficjalnym podręczniku do wWidgets, ale to już po angielsku (choć prosto napisane). Co do DevCpp, to ta książka była wydana w 2008.

Offline Xender

  • Użytkownik

# Styczeń 15, 2014, 12:42:06
Co do DevCpp, to ta książka była wydana w 2008.
Nie wiem, czy już wtedy nie śmierdział trupem, natomiast dobrym IDE nie był nigdy, nawet w czasach swojej "świetności".

Offline Lobsang Rampa

  • Użytkownik
    • Global Epidemic

  • +2
# Styczeń 15, 2014, 13:24:29
Nie wiem, czy już wtedy nie śmierdział trupem, natomiast dobrym IDE nie był nigdy, nawet w czasach swojej "świetności".
Wiele lat temu pracowałem przez jakiś czas na nim i nie miałem nigdy specjalnych z nim problemów, środowisko jak środowisko (przed nim korzystałem z Visual Studio, obecnie z CodeBlocks).

Offline Xender

  • Użytkownik

# Styczeń 15, 2014, 17:04:51
Dla mnie dobre środowisko (niekoniecznie zintegrowane) to przede wszystkim dobry edytor, a potem dobre podpowiadanie. Dev nie miał żadnego z nich.

Dobry edytor to poziom, który reprezentuje Vim, Emacs czy Sublime (akurat ten ostatni nie jest tak potężny, jak pierwsze dwa, ale i nie wymaga takiej nauki). Przede wszystkim chodzi tu o możliwości manipulacji tekstem, ale także kolorowanie (i dobry color theme).

Przy okazji - feature'em, który wydaje mi się być nieproporcjonalnie mało popularny w stosunku do jego przydatności, jest wielokursor.

Podstawowe pytanie - skoro Dev nie stwarza problemów, to czemu teraz korzystasz z C::B?

Offline Krzysiek K.

  • Redaktor
    • DevKK.net

# Styczeń 15, 2014, 17:47:54
Dla mnie dobre środowisko (niekoniecznie zintegrowane) to przede wszystkim dobry edytor, a potem dobre podpowiadanie. Dev nie miał żadnego z nich.
Do tego dołączył bym dobry debugger z podglądaniem wartości zmiennych po najechaniu kursorem i ładnym zarządzaniem breakpointami. Edit & continue też nie gardzę.