BMPs anzeigen durch OnPaint()

BlackD0G

Grünschnabel
Hallo zusammen!

Ich lade eine Bitmap aus einer Datei und möchte sie in einem StaticFeld auf meinem Dialog anzeigen lassen.
Das Problem ist, die geladene Bitmap wird für einen Sekundenbruchteil angezeigt, dann sehe ich wieder den grauen Dialoghintergrund.
Also das laden scheint zu funktionieren, nur stimmt irgend etwas mit der OnPaint() Routine nicht.
Ich bin mit dem Debugger durchgegangen und habe die Stelle, die für das Verschwinden der Bitmap verantwortlich ist ausfindig machen können. Leider weiß ich nicht wie ich das beheben soll.
Hier mal der Code zum Laden und zum Anzeigen aus der OnPaint():
Code:
void CDlgTestDlg::OnBtLoadImg() 
{
	CFileDialog dlg(TRUE,"bmp", "*.bmp");
	if(dlg.DoModal()==IDOK){
		m_pBMP.DeleteObject();
		hBitmap =	(HBITMAP) ::LoadImage(AfxGetInstanceHandle(),
		dlg.GetFileName().GetBuffer(1), IMAGE_BITMAP, 0, 0,
		LR_LOADFROMFILE | LR_CREATEDIBSECTION);
		m_bImgLoaded = true;
		// Bitmap erstellen
		m_pBMP.Attach(hBitmap);
                m_pBMP.GetBitmap(&bm);
		AllocUserMem(bm.bmWidth,bm.bmHeight,bm.bmBitsPixel/8);
	  m_pBMP.GetBitmapBits(bm.bmWidth*bm.bmHeight*bm.bmBitsPixel/8,m_pBuffer);	// Bilddaten laden
	}	
	Invalidate();
}
Damit wird das Bild geladen
Jetzt Code zum anzeigen ( Ausschnitt aus OnPaint())

Code:
	if(m_bImgLoaded){
			CClientDC cdc(&m_Display);
			CRect rect;
			CDC m_pdcMem;
					
		if (!m_pdcMem.CreateCompatibleDC(&cdc))
				return;
			// Bild zeichnen
			m_pdcMem.SelectObject(&m_pBMP);
			
			m_Display.GetClientRect(&rect);
			m_pBMP.GetBitmap(&bm);
			
			SetStretchBltMode(cdc,COLORONCOLOR); // Anzeigemodus zur korrekten Anzeige des Bildes
			cdc.StretchBlt(0, 0, rect.Width(), rect.Height(), 
				&m_pdcMem, 0, 0, bm.bmWidth, bm.bmHeight, 
				SRCCOPY);	
		}
		CDialog::OnPaint();  // <------- FEHLER
	}
}

An der mit "FEHLER" markierten Stelle wird das Bild dann wieder gelöscht. Wenn ich diese Zeile auskommentiere bleibt das Bild zwar da, allerdings verschwinden dann Buttons im Dialog.

Wo liegt mein Fehler, oder hab ich die ganze Sache ganz falsch angefasst?
Bin noch nicht so erfahren mit MFC.

Danke schonmal!
Gruß Doggy
 
Wenn du das Bild selber zeichnen willst, musst du das in der OnPaint()-Routine des Static-Controls und nicht des Dialoges ausführen. Das bedeutet, du müsstest eine eigene Klasse vom Static-Control ableiten und dort OnPaint() überschreiben.

Ansonsten, warum machst du dir soviel Mühe? CStatic bring von Haus aus eine Methode SetBitmap() mit.

Gruß
MCoder
 
Ich bin mir da nicht ganz sicher, aber es kann sein, daß Du das Rechteck mit Deiner Bitmap nach dem Zeichnen und vor dem Aufruf der Basisklassen-OnPaint mit ValidateRect validieren mußt.
Probier's mal aus.
 
Kann es sein, dass du die OnPaint() der Basisklasse nicht aufrufen solltest?


::OnPaint() soll zum Zeichnen von Meldungen nicht aufgerufen werden.
 
@ titanic:
wenn du diese Zeile meinst
Code:
CDialog::OnPaint();  // <------- FEHLER
Die wurde schon vom Wizard hinzugefügt, ich hab da nichts verändert.

@MCoder

wenn ich m_Display.SetBitmaps(HBitmap); aufrufe passiert nichts. m_Display ist die ControlVar. für das CStatic.
Aber das war mir ehrlich gesagt auch neu, dass es diese Fkt. gibt. Bin MFC Rookie.
Aber vielleicht kannst du mir sagen, was man da noch machen muss, damit diese SetBitmap() fkt funktioniert, weil das hört sich ja schon recht praktisch an.

Ich habe es gestern dann so gelöst, dass ich die Zeile mit Invalidate() nach der "Bild laden " - Fkt. in
Code:
m_Display.Invalidate(); OnPaint();
geändert habe.

Jetzt geht es.

Bin mal gespannt, ob es auch noch funktioniert, wenn ich eine Zeile mit OnMouseMove über das Bild zeichne, um die Zeile für das Zeilenprofil zu markieren.
Aber danke schonmal!
 
Hallo BlackDOG,

für SetBitmap() muss das Static-Control den Style SS_BITMAP haben und außerdem wird das Bitmap dann immer automatisch in Originalgröße angezeigt. Ist also für deinen Zweck nicht so prakatisch und mein gestriger Kommentar dazu eher weniger hilfreich.

Gruß
MCoder
 
Ok danke schon mal.

Hab noch eine Frage, die gehört eigentlich nicht ganz hier rein, aber soll ich jetzt extra nen neuen Thread aufmachen...?

Also ich habe eine Dialogbasierende Anwendung, zu der ich aber ein Menu hinzugefügt habe.

Wenn ich auf einen bestimmten Eintrag klicke, dann soll da ein Hächen gesetzt werden und bei erneutem klicken wieder entfernt werden.
Eigentlich sollte folgendes ja funktionieren:
Code:
void CDlgTestDlg::OnMenuZeilenprofil() 
{
	if(m_isZeilenprofil)
		m_isZeilenprofil = false;
	else{
		m_isZeilenprofil = true;
		OnMouseMove(1,m_LinePoint);
	}	
}

void CDlgTestDlg::OnUpdateMenuZeilenprofil(CCmdUI* pCmdUI) 
{
	if(m_isZeilenprofil)
		pCmdUI->SetCheck(1);
        else
		pCmdUI->SetCheck(0);	
}

Hab ich nen Denkfehler, kommt mir so vor. Auf der anderen Seite hab ich es so ähnlich schonmal gemacht, allerdings hatte ich damals eine SDI mit View-Doc-Struktur. Und habe damals diese Änderungen im View vorgenommen.
Danke & mfG
Doggy
 
Die ON_UPDATE_COMMAND_UI-Geschichte funktioniert bei Dialogen nicht so ohne weiteres. Ich habe vor Jahren mal eine Anleitung dazu gefunden, allerdings noch nie selber ausprobiert. Ich weiss also nicht, ob's funktioniert:
C++:
// 1. Im Dialog Header (.h) folgende Handler-Methode ergänzen:
afx_msg LRESULT OnKickIdle(WPARAM, LPARAM);

// 2. In der Dialog Source (.cpp) diesen Header ergänzen:
#include <afxpriv.h>

// 3. In der Message Map der Dialog Source diesen Eintrag ergänzen
ON_MESSAGE(WM_KICKIDLE, OnKickIdle)

// 4. Und die implementation des Handlers in der Dialog Source
LRESULT CMyDialog::OnKickIdle(WPARAM wp, LPARAM lCount)
{
    UpdateDialogControls(this, TRUE);
    return 0;
}
Gruß
MCoder
 
Zuletzt bearbeitet von einem Moderator:
Hi MCoder,

habe die Anleitung befolgt, aber was dann, sollte es dann schon funktionieren?
Muss ich den Handle direkt aufrufen, oder wird er dann über automatisch über die den UI Handle aufgerufen?

Zumindest läuft das Programm weiter ohne irgend welche Fehler.
Aber Häckchen gibt es noch keine.
Wie gesagt, weil ich nicht weiß was ich mit diesem Handle anfangen soll. Im übrigen wusste ich mit den WParam und LParam noch nie etwas anzufangen.

Wenn du noch Tips hast, wäre ich dir sehr dankbar ;)
 
Sollte dann eigentlich schon funktionieren, aber wie gesagt, hab's noch nie probiert.
Beim Versuch, die Quelle ausfindig zu machen, bin ich aber auf folgenden MSDN-Artikel gestoßen.
Vielleicht hilft's Dir weiter

Gruß
MCoder
 
Zurück