Bitmaps anzeigen....



  • Hallo!
    Ich will ein beliebiges Bitmap dynamisch laden und anzeigen lassen. Ich hab auch schon in der FAQ geschaut und dort nur den Verweis auf das Buch "C++ in 21 Tagen" gefunden.
    Also hab ich mich mit all dem rumgeplagt, komm aber einfach nicht zum Ziel.
    Hier der Quellcode bisher:

    CBitmap bmp;
    
        HBITMAP hBitmap = (HBITMAP)::LoadImage(AfxGetInstanceHandle(),
    "C:\Programme\Eigene Programme\Doppelkopf\karten\Bitmap\karte1.bmp", IMAGE_BITMAP, 0, 0,
    LR_LOADFROMFILE | LR_CREATEDIBSECTION);
        bmp.Attach(hBitmap);
    
        BITMAP bm;
        bmp.GetObject(sizeof(bm), &bm);
    
        CDC dcMem;
        CDC dc;
    
        dcMem.CreateCompatibleDC(&dc);
        dcMem.SelectObject(&bmp);
        dc.BitBlt(10,10,bm.bmWidth,bm.bmHeight,&dcMem,0,0,SRCCOPY);
    

    Es kommt immer der Fehler "Debug Assertion failed".

    Weiß da jemand Rat?

    Später will ich uach noch dass die Bitmaps auf Klick Ereignisse und ähnliches reagieren können, bzw. sie auch wieder zu entladen sind. Geh ich hierfür den richtigen Weg oder bin ich komplett falsch? Kann mir jemand helfen wie ich das verwirklichen kann?
    Ich such wirklich schon ewig, aber hab bisher nichts brauchbares gefunden.

    Danke im Voraus,
    Flux

    [ Dieser Beitrag wurde am 27.10.2002 um 17:12 Uhr von Flux editiert. ]



  • 1.)
    CDC dc;// noch nicht initialisiert
    dcMem.CreateCompatibleDC(&dc);

    Das sollte zumindest hinhauen:

    CDC* dc = GetDC();
    dcMem.CreateCompatibleDC(&dc);

    2.)

    CBitmap bmp; -> lieber CBitmap* bmp = new CBitmap;

    3.)

    BITMAP bm;
    bmp.GetObject(sizeof(bm), &bm);

    sollte zwar auch gehen, aber:

    bmp->GetBitmap( &bm );

    würde ich der Faulheit wegen bevorzugen...



  • Vielen Dank erstmal!

    Hab alle 3 Punkte verbessert, aber es kommt immer noch der selbe Fehler...
    Liegt das vielleicht an dem falschen Pfad oder so? Er bringt halt immer Warnungen dass er die Escape Zeichen nicht erkennt (was ja auch logisch ist...). Muss man den Pfad irgendwie anders angeben? Oder ist sonst noch etwas falsch?

    Grüße,
    Flux



  • Uuups, das hab ich ja glatt übersehen:

    "C:\\Programme\\Eigene Programme\\Doppelkopf\\karten\\Bitmap\\karte1.bmp",

    Bei Pfadangaben immer \\ statt \ verwenden, da z.B. \n bei formatieretem Text als Zeichenumbruch verstanden wird.



  • Ok, super!!! Jetzt kommt kein Fehler mehr! Danke!!

    Nur es wird trotzdem nichts angezeigt? Also das Bild wird noch nicht angezeigt. was mach ich noch falsch?!

    Grüße,
    Flux



  • Sorry, aber das ist nur aus irgendeinem Project rauskopiert (außerdem bin ich gerade erst nach Hause gekommen:))

    HINSTANCE hinst = AfxGetInstanceHandle();
                HANDLE hndl = LoadImage(hinst, m_strBitmap,IMAGE_BITMAP,0,0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
                DWORD Error = GetLastError();       
                if (hndl)
                {
                    CBitmap * new_Bitmap = new CBitmap;
                    if (new_Bitmap->Detach())
                    {   
                        new_Bitmap->DeleteObject();
                    }
                //Aktuell geladenes Bitmap mit Bitmap-Objekt verbinden
                    else 
                        new_Bitmap->Attach(hndl);
                    new_Bitmap->GetBitmap(&bm);
                    if(m_bmpBitmap)
                    {
                        delete m_bmpBitmap;
                        m_bmpBitmap = 0;
                    }
                    m_bmpBitmap = new_Bitmap;
    

    So, jetzt sollte ein korrektes CBitmap in m_bmpBitmap sein, nun zur Anzeige:

    CDC *pDC = GetDC();
        CDC dcMem;// Gerätekontext erzeugen, in den Bitmap geladen wird
        dcMem.CreateCompatibleDC(pDC);// Bitmap in den kompatiblen Gerätekontext selektieren
        dcMem.SelectObject(aBitmap);
        CRect lRect;// Anzeigebereich verfügbar machen
        GetClientRect(lRect);// Bitmap in Dialogfeld kopieren und in Größe anpassen
        pDC->StretchBlt( lRect.top - ShowPoint.y, lRect.left - ShowPoint.x, (int)(bm.bmWidth * m_fOptZoom), (int)(bm.bmHeight * m_fOptZoom), &dcMem, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);
    

    am Schluß natürlich nicht vergessen alles schön sauber zu machen:

    ReleaseDC(pDC);

    wenn du die kompletten Funktionen brauchst, sag bescheid. Saven willst du ja bestimmt irgendwann auch noch ;). Die Komentare im Quelcode bitte nicht so ernst nehmen, die sind schon seeeeeehr alt....



  • Wow, danke erstmal!!!!

    Hab den Code übernommen, aber es geht immer noch nicht...
    Und zwar kommt bei der "delete m_bmpBitmap;" Anweisung ein "Fehler in Anwendung" weil den Vorgang Read nicht ausführen konnte. Kommentiere ich die Codezeilen aus kommt zwar kein Fehler mehr, aber es passiert immer noch nichts (keine Anzeige).

    Hier mein gesamter Code der Funktion:

    BOOL Spiel::OnInitDialog() 
    {
        CDialog::OnInitDialog();
    
        BITMAP bm;
    
        HINSTANCE hinst = AfxGetInstanceHandle();
        HANDLE hndl = LoadImage(hinst, "C:\\Programme\\Eigene Programme\\Doppelkopf\\karten\\Bitmap\\karte1.bmp",IMAGE_BITMAP,0,0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
    
        if (hndl)
        {
            CBitmap* new_Bitmap = new CBitmap;
            if (new_Bitmap->Detach())
                {   
                    new_Bitmap->DeleteObject();
                }
            else 
                new_Bitmap->Attach(hndl);
    
            new_Bitmap->GetBitmap(&bm);
            if(m_bmpBitmap)
                {
                    delete m_bmpBitmap;
                    m_bmpBitmap = 0;
                }
            m_bmpBitmap = new_Bitmap;
    
            CDC *pDC = GetDC();
            CDC dcMem;// Gerätekontext erzeugen, in den Bitmap geladen wird
            dcMem.CreateCompatibleDC(pDC);// Bitmap in den kompatiblen Gerätekontext selektieren
            dcMem.SelectObject(m_bmpBitmap);
            CRect lRect;// Anzeigebereich verfügbar machen
            GetClientRect(lRect);// Bitmap in Dialogfeld kopieren und in Größe anpassen
            pDC->BitBlt(lRect.top, lRect.left, bm.bmWidth, bm.bmHeight, &dcMem, 0, 0,SRCCOPY);
    
            ReleaseDC(pDC);
            ReleaseDC(&dcMem);
        }
    
        return TRUE;  // return TRUE unless you set the focus to a control
                      // EXCEPTION: OCX-Eigenschaftenseiten sollten FALSE zurückgeben
    }
    

    wobei m_bmpBitmap ein protected CBitmap Zeiger der Klasse Spiel ist:

    protected:
        CBitmap *m_bmpBitmap;
    

    Es tut mir echt leid wenn ich mich mega blöd anstelle, aber ich habe einfach wenig Erfahrung mit VC++ und vor allem der Benutzung von Bitmaps mit diesem. Und im Internet finde ich nichts wirklich brauchbares.

    Was aber wirklich super wäre, wäre wenn du mir die erwähnten Funktionen an webmaster@vb-programming.de schicken könntest!!

    Vielen Dank nochmal für alles!
    Flux



  • Yop, ganz einfach: wo wird denn m_bmpBitmap initialisiert ?
    Im Konstruktor deiner Klasse sollte dann stehen :

    m_bmpBitmap = NULL;

    Die folgenden Zeilen geben dann den Speicher wieder frei, wenn vorher bereits was geladen war in m_bmpBitmap:

    if(m_bmpBitmap)//Wenn nicht initialisiert....
    {
    delete m_bmpBitmap;//kracht es hier natürlich.....
    m_bmpBitmap = 0;
    }

    Da die Frage aber öfter mal kommt mal hier den kompletten Code zum Laden:

    HINSTANCE hinst = AfxGetInstanceHandle();
                HANDLE hndl = LoadImage(hinst, m_strBitmap,IMAGE_BITMAP,0,0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
                DWORD Error = GetLastError();       
                if (hndl)
                {
                    CBitmap * new_Bitmap = new CBitmap;
                    if (new_Bitmap->Detach())
                    {   
                        new_Bitmap->DeleteObject();
                    }
                //Aktuell geladenes Bitmap mit Bitmap-Objekt verbinden
                    else 
                        new_Bitmap->Attach(hndl);
    

    ShowBitmap(new_Bitmap);//Fkt siehe unten

    zum anzeigen in einem CWnd folgende Funktion:

    void CPictviewView::ShowBitmap(CBitmap *aBitmap)
    {
        CDC *pDC = this->GetDC();
        CDC dcMem;// Gerätekontext erzeugen, in den Bitmap geladen wird
        dcMem.CreateCompatibleDC(pDC);// Bitmap in den kompatiblen Gerätekontext selektieren
        dcMem.SelectObject(aBitmap);
        CRect lRect;
        GetClientRect(lRect);
        pDC->StretchBlt( lRect.top, lRect.left, bm.bmWidth, bm.bmHeight, &dcMem, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);
        ReleaseDC(pDC);
    }
    


  • @TheBigW

    Bitte überdenk mal Deinen Code!! Da ist mehr als 1 Fehler drin !!

    if (hndl)
    {
      CBitmap * new_Bitmap = new CBitmap;
      if (new_Bitmap->Detach())   // da kann gar nix drin sein
      {   
        new_Bitmap->DeleteObject();  // wenn nix drin, dann auch DeleteObject ohne Funktion
      }
      //Aktuell geladenes Bitmap mit Bitmap-Objekt verbinden
      else 
        new_Bitmap->Attach(hndl);
    

    zum anzeigen in einem CWnd folgende Funktion: (Weitere Fehler und Änderung)

    void CPictviewView::ShowBitmap(CBitmap *aBitmap)
    {
      CClientDC dc(this);
      CDC dcMem;
      // Gerätekontext erzeugen, in den Bitmap geladen wird
      dcMem.CreateCompatibleDC( &dc);
      // Bitmap in den kompatiblen Gerätekontext selektieren
      CBitmap* pOldBitmap = dcMem.SelectObject( aBitmap);
      CRect lRect;
      GetClientRect(lRect);
      dc.StretchBlt( lRect.top, lRect.left, bm.bmWidth, bm.bmHeight, &dcMem, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);
      dcMem.SelectObject( pOldBitmap); // !!!
    }
    


  • Das war ja auch keine Komplettlösung sonern ein Anastz aus einem kleinen Bitmapviewer der auch noch aus grauer Prog-Vorzeit stammt. Damals wußte ich es halt auch nicht besser. Aber du hast auf alle Fälle recht, man sollte lieber gar nichts posten als fehlerhaften Code.

    Gleich mal noch zwei Fragen:

    1.) Warum ausgerecnhet CClientDC dc(this); ?

    CDC* pDC = GetDC(); und am Ende ReleaseDC(pDC);

    macht doch im Prinzip das Gleiche oder?

    2.) CBitmap* pOldBitmap = dcMem.SelectObject( aBitmap);

    sollte wennschon, dann nicht eher

    CGdiObject* oldGdiObj = dcMem.SelectObject( aBitmap);

    stehen?

    Deine Kritik ist auf alle Fälle berechtigt, auch wenn der vorher gepostete Abschitt (bis auf das im Nichts verschwindende GDI - Objekt :)) sicher auch funktioniert.



  • Zu 1.
    Ja, das ist das gleiche, aber mit CClientDC weiss ich, dass es sich um den Clientbereich handelt, und es ist nur 1 Zeile Code 😉
    Warum also nicht nutzen, wenn die MFC-Leute das schon zur Verfügung stellen?

    Zu 2.
    Was machst Du, wenn Du Font, Pen und Bitmap selektieren willst?

    CGdiObject* oldGdiObj1 = dcMem.SelectObject( aBitmap);
    CGdiObject* oldGdiObj2 = dcMem.SelectObject( aFont);
    CGdiObject* oldGdiObj3 = dcMem.SelectObject( aPen);

    Da nehm ich lieber:
    CBitmap* oldBmp = dcMem.SelectObject( aBitmap);
    CFont* oldFont = dcMem.SelectObject( aFont);
    CPen* oldPen = dcMem.SelectObject( aPen); // übersichtlicherer Code

    Aber funktionieren tut beides!



  • Also, erstmal ein riesen, riesen Dankeschön an euch beide!!
    Es geht jetzt, aber es lag an folgendem Problem (zumindestens unter anderem):
    Von der Init Dialog aus wird irgendwie nichts angezeigt, wenn ich den selben Code für das Klickereigniss eines Buttons benutze wird das Bild zum Glück genau richtig auf dem Formular dargestellt! Danke danke danke!!!
    Aber irgendwie ist das trotzdem noch voll problematisch, denn sobald ich das Programm wegklick, also einfach inaktiv mach und mir was anderes anschau, und dann wieder in der Statusbar aktivier ist das Bild verschwunden.
    Hmm, das ist irgendwie nicht so gut! Auch komisch und nachteilig find ich dass man es nicht über die InitDialog anzeigen lassen kann...

    Ist es jetzt eigentlich noch möglich dass man auf ein Klick Ereignis auf das Bild reagieren kann? Falls nicht ist das nicht so schlimm, dann geh ich halt mit dem ganz normalen KlickEreignis des Formulars um und überprüf eben in welchem Bereich geklickt wurde!

    Trotzdem nochmals big thx!!

    Flux

    [ Dieser Beitrag wurde am 29.10.2002 um 14:47 Uhr von Flux editiert. ]



  • Ahh ok, ich hab schon ne Lösung:
    Wenn man das Ganze bei OnPaint macht gehts problemlos!! Sowohl das Zeichnen als auch dass es nicht mehr verschwindet!
    Super!!

    Thx!

    Flux


Anmelden zum Antworten