Bitte helft mir: HDC
-
Moin!!
Ich habe ein großes Problem: Ich bin dabei ein MapEditor zu schreiben...
So weit, so gut. Nur mit der Darstellung der Karte hab ich Probleme:
Je öfter sie neugezeichnet wird, desto mehr Speicherplatz wird belegt!!!
Ich weiß nicht woran es liegt - alle Objecte werden wieder abgebautvoid CHdcMap :: fNeuZeichnen (HWND hwnd, int x, int y, short *iGrafik, int xPos, int yPos) { DeleteObject (hBitmap); DeleteDC (hdcMem); hdcMem = CreateCompatibleDC (GetDC (hwnd)); hBitmap = CreateCompatibleBitmap (GetDC (hwnd), x*40, y*40); SelectObject (hdcMem, hBitmap); hdcFeldMem = CreateCompatibleDC (GetDC (hwnd)); for (a = 0; a < x; a++) { for (b = 0; b < y; b++) { if (iGrafik[((xPos + a) * iKoY )+(yPos + b)] == 0) { SelectObject (hdcFeldMem, hFeldBitmap); BitBlt (hdcMem, a * 40, b * 40, 40, 40, hdcFeldMem, 0, 0, SRCCOPY); } } } DeleteDC (hdcFeldMem); }
Hat es damit zu tun, daß die alte Bitmap gehalten werden muss, oder so..??
BITTE HELFT MIR
Lenin
[ Dieser Beitrag wurde am 10.05.2003 um 18:30 Uhr von Lenin2001 editiert. ]
-
Ich hab es nur überflogen und folgene Punkte gefunden:
1. Warum werden hBitmap und hdcMem nicht im gleichen Funktionaufruf (am Ende), sondern erst im nächsten Aufruf gelöscht?
2. Zweimal GetDC ohne ReleaseDC
3. Die Bitmaps werden nicht mehr aus den DCs geholt, Rückgabewert von SelectObject merken und Bitmap durch zweiten Aufruf von SelectObject mit dem gemerken Rückgabewert wieder befreien!
4. SelectObject *vor* beide Schleifen setzen
-
zu 2. es sind 3 GetDC Aufrufe
und um deine Frage noch zu beantworten, ja es liegt an 2. und 3.Ich hab deine Speicherlöscher mal beseitigt. Ich glaube, ich verstehe nun Punkt 1 von oben. Es war wohl so gedacht: Das Bitmap wird angelegt, die Map gezeichnet, das Bitmap in einer anderen Funktion verarbeitet und im nächsten Funktionsaufruf von fNeuZeichnen gelöscht, wieder neugezeichnet usw.
Aber wieso sparst du dir das nicht? Stattdessen legst du das Bitmap einmal im Konstruktor von CHdcMap an, zeichnest es bei Bedarf durch fNeuZeichnen, machst dann noch andere schöne Dinge mit ihm und löschst es erst im Destruktor von CHdcMap wieder?void CHdcMap :: fNeuZeichnen (HWND hwnd, int x, int y, short *iGrafik, int xPos, int yPos) { HDC hdcWnd = GetDC(wnd); hdcMem = CreateCompatibleDC (hdcWnd); hdcFeldMem = CreateCompatibleDC (hdcWnd); //hBitmap = CreateCompatibleBitmap (hdcWnd, x*40, y*40); // --- Sollte in den Konstruktor HBITMAP hBitmapOld = (HBITMAP)SelectObject (hdcMem, hBitmap); HBITMAP hFeldBitmapOld = (HBITMAP)SelectObject (hdcFeldMem, hFeldBitmap); for (a = 0; a < x; a++) { for (b = 0; b < y; b++) { if (iGrafik[((xPos + a) * iKoY )+(yPos + b)] == 0) { BitBlt (hdcMem, a * 40, b * 40, 40, 40, hdcFeldMem, 0, 0, SRCCOPY); } } } SelectObject (hdcFeldMem, hFeldBitmapOld); SelectObject (hdcMem, hBitmapOld); // altes Bitmap wieder rein, dann ist hBitmap wieder frei und kann gelöscht o.ä. werden //DeleteObject (hBitmap); // --- Sollte in den Destruktor DeleteDC (hdcMem); DeleteDC (hdcFeldMem); ReleaseDC(hwnd, hdcWnd); }
-
Danke erst mal....
Ich weiß nicht, ob deine Funktion funktioniert, da ich es so
nicht testen kann.Hier sind nochmal genauere Erleuterungen:
Ich habe drei Klassen geschrieben:
CHdcMap, CHdcMouse, CHdcRaster
In CHdcMap wird die Map gemalt, in CHdcMouse die Maus und
in HdcRaster das Raster der Map.
Beim Darstellen auf dem Bildschirm werden die drei HDC über-
einander gelegt:hdc = BeginPaint (hwnd, &ps); BitBlt (hdc, 0, 0, hw.xko-20, hw.yko-20, obMap.fHolen(), 0, 0, SRCCOPY); if (hw.bRasterChecked) BitBlt (hdc, 0, 0, hw.xko-20, hw.yko-20, obRaster.fHolen(), 0, 0, SRCAND); if (m.mx+1 >= (m.h.iKoX)) m.mx = m.h.iKoX -1; if (m.my+1 >= (m.h.iKoY)) m.my = m.h.iKoY -1; BitBlt (hdc, m.mx*40, m.my*40, 40, 40, obMouse.fHolen (), 0, 0, SRCCOPY); EndPaint (hwnd, &ps);
Ich habe es so gewählt, dass nicht alle drei Klassen jedes mal
neu gezeichnet werden, wenn sich die Maus bewegt! Das würde
doch sonst jede Menge CPU verschlucken.... oder??Die Funktion CHdcMap::fNeuZeichnen wird nur aufgerufen,
wenn sich die Map verschiebt (scrolling) oder sich ein Feld ändert.
Ansonsten soll die hdcMem im Speicher bleiben.
Darum darf auch DeleteDC (hdcMem) erst aufgerufen werden, wenn
die Map neu gezeichnet werden soll.
So ähnlich gilt es auch für die anderen beiden Klassen.Vielleicht gehe ich ja damit falsch um! Ich dachte mir, daß man
schön drei Bilder zeichnet und die immer wieder verwendet..Ich hoffe ihr habt jetzt ein bissel mehr Überblick!!
Vielleicht annst du mir noch mal die Funktion umschreiben, so dass sie jetzt funktioniert??
Lenin
-
Also ich würde dir das am ehesten so empfehlen, dass du Map und Raster (werden doch wohl eh immer in einem Zuge aktualisiert, oder?) in einen Backbuffer (auch schon damit es flimmer-frei ist) zeichnest und dann in WM_PAINT, oder wo auch immer, diesen auf den Fenster-DC blittest und anschließend den Maus-DC drüberlegst. Oder hab ich dich da jetzt falsch verstanden?
-
Ich weiß auch nicht, ob das oben funktioniert, hab es nicht getestet, da ich keine Klasse habe.
Original von Lenin2001:
Ansonsten soll die hdcMem im Speicher bleiben.
Einen DC brauchst Du nur zum Zeichnen. Nach Gebrauch solltest du ihn in seinen ursprünglichen Zustand bringen, d.h. Bitmap wieder raus und ihn dann löschen/freigeben. DC sind Systemobjekte, die begrenzt(!) sind und deshalb immer gleich nach Gebrauch zurückgegeben werden sollten.
Darum darf auch DeleteDC (hdcMem) erst aufgerufen werden, wenn
die Map neu gezeichnet werden soll.Deine Arbeit ist im Bitmap, nicht im DC. Das Bitmap enthält die Bilddaten, es sollte die gesamte Laufzeit über bestehen bleiben. Natürlich kannst du auch immer ein neues anlegen und das alte freigeben. Das Bitmap kann aber im Gegensatz zum DC ohne Probleme bestehen bleiben.
Vielleicht gehe ich ja damit falsch um! Ich dachte mir, daß man
schön drei Bilder zeichnet und die immer wieder verwendet..ja, Bild == Bitmap != DC. Deshalb würde ich das Bitmap einmal im Konstruktor erzeugen, mit Hilfe des DC zeichnen, den immer gleich wieder freigeben und das Bitmap erst im Destruktor wieder löschen. Dann brauchst Du es ja nicht mehr.