Hallo liebe Community!
Ich programmiere schreibe zur Zeit an einem Projekt, für das ich etwas Grafik benötige.
Deshalb hab ich angefangen, mich in die WinAPI einzuarbeiten, und bin auf folgendes Problem gestoßen:
Wenn ich viel Grafik in meinem Fenster hab, und es öfters aktualisiere, beginnt es zu flackern.
Höchst wahrscheinlich liegt das daran, dass ich den Hintergrund immerwieder lösche und neu zeichnen lasse:
Wenn ich das allerdings nicht mache, gibt es Probleme, beim verschieben von Objekten (wie zB. Text), da dann deren "Schleifspur" auf dem Hintergrund sichtbar bleiben, oder anders gesagt: Es wird zwar gezeichnet aber nicht wieder gelöscht, und deshalb brauche ich "RDW_ERASE", das wiederum das Flackern auslöst.
Um dieses Problem zu beheben gibt es bereits eine Lösung: Double Buffering.
Alles was ich zeichnen will, zeichne ich dann nicht direkt auf den Bildschirm, sondern in ein Bitmap und bringe das dann irgendwie (wohl mit BitBlt(...)) auf den Bildschirm.
Ich habe schon viel danach auf Google gesucht aber leider nichts gefunden, was funktioniert hat, und verstehe selbst langsam nicht mehr, was ich falsch mache, und deshalbstelle ich euch eine einfache Frage:
Was muss ich vor, und was nach die Zeichenfunktionen (zB. TextOut(...)) schreiben, um nicht auf den Bildschirm, sondern in einen Backbuffer zu zeichnen, und den dann wiederum auf den Bildschirm zu bringen?
Hier der gesamte Quellcode, in dem ich nur Text über den Bildschirm bewege, um das Flackern heraufzubeschwören:
main.cpp:
header.h:
Ich hoffe, dass jemand eine einfache Lösung dazu findet, und danke euch schonmal im Vorraus für eure Mühe.
MfG
LFP
Ich programmiere schreibe zur Zeit an einem Projekt, für das ich etwas Grafik benötige.
Deshalb hab ich angefangen, mich in die WinAPI einzuarbeiten, und bin auf folgendes Problem gestoßen:
Wenn ich viel Grafik in meinem Fenster hab, und es öfters aktualisiere, beginnt es zu flackern.
Höchst wahrscheinlich liegt das daran, dass ich den Hintergrund immerwieder lösche und neu zeichnen lasse:
Code:
GetClientRect(hWnd,lprect);
::RedrawWindow(hWnd,lprect,NULL,RDW_ERASE|RDW_UPDATENOW|RDW_INVALIDATE);
Wenn ich das allerdings nicht mache, gibt es Probleme, beim verschieben von Objekten (wie zB. Text), da dann deren "Schleifspur" auf dem Hintergrund sichtbar bleiben, oder anders gesagt: Es wird zwar gezeichnet aber nicht wieder gelöscht, und deshalb brauche ich "RDW_ERASE", das wiederum das Flackern auslöst.
Um dieses Problem zu beheben gibt es bereits eine Lösung: Double Buffering.
Alles was ich zeichnen will, zeichne ich dann nicht direkt auf den Bildschirm, sondern in ein Bitmap und bringe das dann irgendwie (wohl mit BitBlt(...)) auf den Bildschirm.
Ich habe schon viel danach auf Google gesucht aber leider nichts gefunden, was funktioniert hat, und verstehe selbst langsam nicht mehr, was ich falsch mache, und deshalbstelle ich euch eine einfache Frage:
Was muss ich vor, und was nach die Zeichenfunktionen (zB. TextOut(...)) schreiben, um nicht auf den Bildschirm, sondern in einen Backbuffer zu zeichnen, und den dann wiederum auf den Bildschirm zu bringen?
Hier der gesamte Quellcode, in dem ich nur Text über den Bildschirm bewege, um das Flackern heraufzubeschwören:
main.cpp:
Code:
// MAIN.CPP //
#include "header.h"
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM); // Funktion, die Messages verarbeitet
HWND hWnd; // Handle zum Hauptfenster
HINSTANCE hInstance; // Instanz des Programmes
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR szCmdLine, int iCmdShow) { // Hauptfunktion
hInstance = hInst; // Instanz des Programmes
const char szClassname[] = "hWnd"; // Klassenname der Fensterklaase
MSG msg; // Nachrichten, die von Windows an das Programm geschickt werden
WNDCLASS wc; // Fensterklasse
wc.cbClsExtra = NULL;
wc.cbWndExtra = NULL;
wc.hbrBackground = (HBRUSH) (4+1); // Fenster-Hintergrundfarbe
wc.hCursor = LoadCursor(NULL, IDC_ARROW); // Mauszeiger
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); // Icon
wc.hInstance = hInst; // Instanz des Fensters
wc.lpfnWndProc = WndProc; // Funktion, die Benutzereingaben und Childfenster verwaltet
wc.lpszClassName = szClassname; // Klassenname
wc.lpszMenuName = NULL; // Menü laden
wc.style = NULL; // Besondere Fensterstyles
if (!RegisterClass(&wc)) { // Registrierung der Klasse
MessageBox(NULL, "Die Klasse konnte nicht registriert werden ", "Fehler", MB_OK | MB_ICONERROR); // Falls die Klasse nicht registriert werden konnte: Fehlermeldung ...
return 1; // ... und Beendigung des Programms
}
hWnd = CreateWindow(szClassname /*Klassenname*/, "Titel" /*Titel des Fensters*/, WS_POPUP /*Art des Fensters*/, 100 /*X-Koordinate des Fensters*/, 100 /*Y-Koordinate des Fensters*/, 800 /*Breite des Fensters (ist egal, da das Fenster ja später maximiert wird)*/, 600 /*Höhe des Fensters (ist egal, da das Fenster ja später maximiert wird)*/, NULL /*Elternfenster (Da es ja das einzige Fenster ist wird hier NULL eingesetzt)*/, NULL /*Menuname (wichtig für Buttons!, da hier aber keine erwünscht sind -> NULL)*/, hInst /*Instanz des Fensters*/, NULL); // Erstellung des Hauptfernsters
if (!hWnd) { // Wenn das Fenster nicht erstellt werden konnte
MessageBox(NULL, "Das Fenster konnte nicht erstellt werden", "Fehler", MB_OK | MB_ICONERROR);
return 1;
}
ShowWindow(hWnd, SW_MAXIMIZE); // Fenster maximieren und anzeigen
UpdateWindow(hWnd); // Und WM_PAINT ausführen
hFont = CreateFont(25,10,0,0,FW_DONTCARE,FALSE,false,FALSE,DEFAULT_CHARSET,OUT_OUTLINE_PRECIS,
CLIP_DEFAULT_PRECIS,ANTIALIASED_QUALITY, VARIABLE_PITCH,TEXT("Arial"));
// Messageverwaltung
PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
while(msg.message != WM_QUIT){
dwTime1 = timeGetTime(); //Zeit vor dem Rendern messen und in dwTime1 speichern
GetClientRect(hWnd,lprect);
::RedrawWindow(hWnd,lprect,NULL,RDW_ERASE|RDW_UPDATENOW|RDW_INVALIDATE); //Hintergrund löschen und alles neu zeichnen (hier entsteht wohl das Flackern)
while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { // Während Messages von Windows ankommen
TranslateMessage(&msg); // Messages übersetzen
DispatchMessage(&msg); // Und an msg verschicken
}
Sleep(3); //PC etwas entlasten :)
dwTime2 = timeGetTime(); //Zeit nach dem Rendern messen und in dwTime2 speichern
fTime = (float)(dwTime2 - dwTime1) / 1000.0f; //Durch die Differenz die zum Rendern benötigte Zeit in fTime speichern, die später zum verschieben benötigt wird
x += fTime*100; // Den Text so weit verschieben, wie er in der Zeit, die zum Rendern verbraten wurde, eig. hätte wandern müssen (Vorallem in aufwendigeren animationen wichtig um auf allen PC die gleiche Geschwindigkeit des Textes herzustellen)
if(x > screenX){ //Sollte der Text den Bildschirmrand verlassen
x = -50; //Setze ihn wieder an den Anfang
}
}
return 0; // Funktion beenden, wenn keine Messages mehr ankommen
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { // Funktion, die Messages verarbeitet
switch (msg) {
case WM_CREATE:
screenX = GetSystemMetrics(SM_CXSCREEN); //Bildschirmbreite (in Pixeln)
screenY = GetSystemMetrics(SM_CYSCREEN); //Bildschirmhöhe (in Pixeln)
return 0;
case WM_PAINT:
hDC = BeginPaint(hWnd, &ps);
TextOut(hDC,x,200,"Text1",arraylaenge("Text1"));
TextOut(hDC,x,300,"Text2",arraylaenge("Text2"));
TextOut(hDC,x,400,"Text3",arraylaenge("Text3"));
TextOut(hDC,x,500,"Text4",arraylaenge("Text4"));
TextOut(hDC,x,600,"Text5",arraylaenge("Text5"));
TextOut(hDC,x,700,"Text6",arraylaenge("Text6"));
TextOut(hDC,x,800,"Text7",arraylaenge("Text7"));
TextOut(hDC,x,900,"Text8",arraylaenge("Text8"));
EndPaint(hWnd, &ps);
break;
case WM_DESTROY: // Wenn das Fenster geschlossen werden soll ...
PostQuitMessage(0); // ... melden, dass keine Messages mehr empfangen werden soll
break;
case WM_LBUTTONDOWN:
SetFocus(hWnd);
break;
case WM_KEYDOWN:
switch(wParam){
case VK_ESCAPE:
PostQuitMessage(0);
break;
case VK_RETURN :
SetFocus(hWnd);
return 0;
}
default: // Wenn keine der vorherigen Messages zutrifft ...
return DefWindowProc(hWnd, msg, wParam, lParam);
break;
}
}
int arraylaenge (char name[]){
int laenge = 0;
while(name[laenge]!='\0'){
laenge++;
}
return laenge;
}
header.h:
Code:
#include <Windows.h> // Bibliothek, die unbedingt zur Erstellung eines Fensters nötig ist
#include <iostream>
#include <conio.h>
#pragma comment(lib,"Winmm.lib")
HDC hDC;
HFONT hFont;
PAINTSTRUCT ps;
int screenX;
int screenY;
int nCharacters;
LPRECT lprect;
DWORD dwTime1, dwTime2;
float fTime = 0.002f;
float x = -50; //x-Koordinate des zu animierenden Text
int arraylaenge (char name[]);
Ich hoffe, dass jemand eine einfache Lösung dazu findet, und danke euch schonmal im Vorraus für eure Mühe.
MfG
LFP
Zuletzt bearbeitet: