HBITMAP-Objekt auf MFC-Form anzeigen (ohne Flackern)?



  • Oh, die memdc.h hab ich schon in meinem Projekt. 🙂
    Aber das Beispiel dort hat mir irgendwie nicht weiter geholfen. Es wird nicht erklärt, wie man das mit den Bitmaps macht, weshalb ich jetzt auch hier nach Hilfe suche. 😞

    Ich weiß ja bisher nicht mal, wie man das *mit* Flackern hinkriegt. 😉



  • Ich habe etwas ähnliches und wollte es auch zuerst über eine Art double buffering machen.
    Dann hab ich es aber so gemacht:
    http://www.codeguru.com/cpp/controls/controls/article.php/c2297/

    Funktioniert einwandfrei.



  • Sorry, ich verstehe nicht, wie man das benutzt...

    Muss ich für das Bitmap dann ein "Picture Control" benutzen oder zeichne ich das direkt auf die Form?
    (Eine "OnEraseBkgnd"-Methode hat mein Dialog nämlich aktuell nicht.)

    Edit: Naja, per Picture Control funktioniert es schon mal: m_BMP.SetBitmap(myBitmap); ... jedoch flackert es total und verschwindet nach einem kurzen Augenblick auch wieder, also relativ nutzlos. 👎😞

    Hilfe! 😞


  • Mod

    1. Jedes Control hat ein OnEraseBkgnd, wenn es keinen Handler hat, musst Du den Default-Handler überschreiben! Das solltest Du doch aus der Beschreibung von CMemDC entnehmen können. Das ist überhaupt bei deiser Sache das wichtigste.
    Wenn Du sowieso den ganzen Bereich Blt'test dann kannst Du Dir sogar CMemdc sparen!
    2. Wenn es ein Child-Control ist musst Du dieses subclassen und dort auch WM_ERASEBKGND ersetzen. WM_ERASEBKGND ist die eigentliche Ursache für Flackern bei der Ausgabe!



  • Danke. Ich bin jetzt so weit:

    void CMyDlg::OnPaint()
    {
    	if (IsIconic())
    	{
    		//(hier steht nur das standardzeug von mfc)
    	}
    	else
    	{
    		CPaintDC dc(this);
    		HDC bitmap_dc = CreateCompatibleDC(dc);
    		HBITMAP old_bitmap=(HBITMAP)SelectObject(bitmap_dc, myBitmap);
    		BitBlt(dc, 18, 24, 320+18, 240+24, bitmap_dc, 0,0, SRCCOPY);
    		SelectObject(bitmap_dc, old_bitmap);
    		DeleteObject(bitmap_dc);
    
    		CDialog::OnPaint();
    	}
    }
    

    und

    BOOL CMyDlg::OnEraseBkgnd(CDC* pDC)
    {
    	return FALSE;
    }
    

    Wenn ich myBitmap (globale HBITMAP-Variable) gefüttert habe, mache ich "Invalidate();".
    Aber es flackert immer noch. Was ist falsch? 😕



  • Weiß denn niemand, wie das funktioniert? 😞
    Hab den ganzen Morgen wieder MSDN gewälzt, aber hilft nicht.

    Habe gestern noch ein bisschen Code in meinen vorherigen Post reineditiert, vielleicht kann jemand anhand dessen sagen, was da nicht stimmt?

    Danke schonmal.



  • Kannst du einen möglichst kleinen und compilierbaren Beispielcode posten?
    Mit dem zu zeichnenden Bild (so, dass man nur compileren und starten muss um den Effekt zu sehen)?

    Ich habe das so gemacht:
    - Custom Control
    --- von CWnd abgeleitet
    --- zeichnet in Paint das Bitmap
    --- OnEraseBkgnd tut nichts (return FALSE)
    - Custom Control sitzt auf einer Form (CDialog)
    - in OnEraseBkgnd der Form wird verhindert, dass der Bereich des
    Cutom Controls gelöscht wird (siehe codeguru)

    Mehr hab ich nicht. Keine zusätzlichen Klassen oder ähnliches.
    Das Bild wird alle ~120ms aktualisiert und flackert nicht.


  • Mod

    1. Wenn Du schon selber zeichnest, dann bitte nicht mehr CDialog::OnPaint aufrufen!
    2. Verwende mal nach Invalidate direkt ein UpdateWindow, oder gleich RedrawWindow!



  • Habe ein kompilierbares (VC++ 😎 Beispiel gemacht:
    http://uploaded.to/?id=ithij2

    Das Bild muss für dieses Beispiel in c:\bild1.bmp liegen.
    Der Code ist jedenfalls bestimmt großer Mist. ⚠


  • Mod

    Der Code ist wirklich blödsinnig, warum lädst Du die Bitmap immer neu.
    Ich habe kein Flackern, wenn ich es so mache:

    if (hBitmap) 
    		{
    			CPaintDC dc(this);
    			HDC bitmap_dc = CreateCompatibleDC(dc);
    			HBITMAP old_bitmap=(HBITMAP)SelectObject(bitmap_dc, hBitmap);
    			BitBlt(dc, 18, 24, 320+18, 240+24, bitmap_dc, 0,0, SRCCOPY);
    			SelectObject(bitmap_dc, old_bitmap);
    			DeleteObject(bitmap_dc);
    		}
    		else
    			CDialog::OnPaint();
    	}
    }
    
    // Die System ruft diese Funktion auf, um den Cursor abzufragen, der angezeigt wird, während der Benutzer
    //  das minimierte Fenster mit der Maus zieht.
    HCURSOR CflackernDlg::OnQueryDragIcon()
    {
    	return static_cast<HCURSOR>(m_hIcon);
    }
    
    BOOL CflackernDlg::OnEraseBkgnd(CDC* pDC) 
    {
        return TRUE;
    }
    
    void CflackernDlg::OnBnClickedButton1()
    {
    	CString pfad = ("bild1.bmp");
    
    	HINSTANCE hInstance = AfxGetInstanceHandle();
    	hBitmap = (HBITMAP)LoadImage(hInstance, pfad, IMAGE_BITMAP, 320, 240, LR_LOADFROMFILE);
    
    	for (int i=0; i<1000; i++) {
    		RedrawWindow(NULL,NULL,RDW_INVALIDATE|RDW_UPDATENOW);
    	}
    }
    


  • Herzlichen Dank! Dein Tipp hat das Flackern behoben!! 👍

    Gibt es jetzt noch irgendwie die Möglichkeit, dass das letzte Bitmap nicht verschwindet, wenn man das Fenster kurz minimiert?


  • Mod

    hbitmap natürlich auf NULL setzen (freigeben nicht vergessen) und einfach ein Invalidate()!



  • Martin Richter schrieb:

    hbitmap natürlich auf NULL setzen (freigeben nicht vergessen) und einfach ein Invalidate()!

    Klingt nach einem Missverständnis. Es soll NICHT verschwinden. Wenn ich deinen Anweisungen folge, verschwindet es nicht erst nach dem Minimieren sondern sofort. Oder irre ich mich?

    Edit: Hmm, im flacker-Demo-Programm verschwindet das Bild nicht durch Minimieren. Dann ist in meinem wirklichen Programm noch was falsch. Vergiess es, es hat sich erledigt! 😉

    Danke schön nochmal! Auf euch ist Verlass! 👍


Anmelden zum Antworten