(erledigt) Laden einer bitmap.bmp



  • Die Bitmap befindet sich in meinem Projektordner und heißt test.bmp.
    In meiner main.cpp siehts folgendermaßen aus:

    case WM_CREATE:
    {
       // Hintergrund (Bitmap)
       testbitmap = NULL;
       HBITMAP testbitmap = (HBITMAP)::LoadImage(NULL, "test.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
       MessageBox(hwnd, "Could load Bitmap!", "Tasty", MB_OK | MB_ICONEXCLAMATION);
    
      if(testbitmap == NULL)
      {
         MessageBox(hwnd, "Could not load Bitmap!", "Error", MB_OK | MB_ICONEXCLAMATION);
      }
    
    [.....]
    
          case WM_PAINT:
          {
             // Bitmap "painten"
             BITMAP bm;
             PAINTSTRUCT ps;
             HDC hdc = BeginPaint(hwnd, &ps);
             HDC hdcMem = CreateCompatibleDC(hdc);
             HBITMAP hbmOld = (HBITMAP) SelectObject(hdcMem, testbitmap);
             GetObject(testbitmap, sizeof(bm), &bm);
             BitBlt(hdc, 0, 0, bm.bmWidth, bm.bmHeight, hdcMem, 0, 0, SRCCOPY);
             SelectObject(hdcMem, hbmOld);
             DeleteDC(hdcMem);
             EndPaint(hwnd, &ps);
    

    Ich bekomme definitiv eine Bitmap, das weiß ich dank meiner "Could load Bitmap" Abfrage. Diese ist aber komplett weiß. Mein nächster Ansatz ist, herauszufinden wie gross die bitmap ist, mit Hilfe von bm.bmWidth und Height, aber dazu bin ich im Moment zu müde ...Wenn wer ne Idee hat, wie ich noch rangehen könnte wäre des toll, Gute Nacht soweit


  • Mod

    Nein Deine Bitmap ist nicht weiß.
    Du hast eine loake Variable testBitmap deifniert mit

    HBITMAP testbitmap = (HBITMAP)::LoadImage(NULL, "test.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
    

    Dadruch "verdeckst" Du Variable auf dem globalen Scope. Diese ist natürlich NULL!

    Evtl. solltest Du etwas mehr an C++ Grundlagen arbeiten...



  • Keks @ Martin,
    habe nun folgendermaßen abgeändert:

    testbitmap = (HBITMAP)::LoadImage(NULL, szFileName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
    

    O.K., soweit ich verstanden habe, muss ich anstelle von "test.bmp" doch das szFileName verwenden. Ich habe allerdings noch nicht verstanden, wo in meinem Code ich dann den Pfad meiner Bitmap an die Variable (ist doch eine?) szFileName übergeben kann. Wird szFilename hier deklariert?

    /*  Make the class name into a global variable  */
    char szClassName[ ] = "WindowsApp";
    char szFileName[] = "BitmapCollection";
    

    Btw, C und C++ erst seit letztem Sonntag, seid gnädig ...



  • cyberleon schrieb:

    Btw, C und C++ erst seit letztem Sonntag, seid gnädig ...

    Und warum lernst Du dann schon WinApi?
    Von dem Code da oben verstehst Du wahrscheinlich nicht eine Zeile richtig, oder?

    So wird das nichts. Bleibt vorerst in der Console bis die Sprache sitzt.



  • Habe mir nun Code geschrieben, der mir Breite und Höhe meiner Bitmap ausgibt, was meiner Bitmap allerdings nicht im geringsten entspricht ...

    bm.bmHeight ist 26
    mehr Sorgen macht mir
    bm.bmWidth mit bescheidenen 1920798048

    // Achtung, Testsequenzen, geben Bitmapgrösse aus, können später entfernt werden.
             int Bitmaphoehe;
             Bitmaphoehe = bm.bmHeight;
             char buffer[5];
             itoa(Bitmaphoehe, buffer, 10);
             //printf("%s\n", buffer);
                     textBox9 = CreateWindow(TEXT("edit"), TEXT(buffer),
                      WS_VISIBLE | WS_CHILD | WS_BORDER | ES_AUTOHSCROLL,
                     300, 285, 50, 20,
                      hwnd, (HMENU) 1, NULL, NULL
                      );  
             int Bitmapbreite;
             Bitmapbreite = bm.bmWidth;
             char buffer2[5];
             itoa(Bitmapbreite, buffer2, 10);
             //printf("%s\n", buffer2);      // printf erfordert #include <stdio.h>
                     textBox10 = CreateWindow(TEXT("edit"), TEXT(buffer2),
                      WS_VISIBLE | WS_CHILD | WS_BORDER | ES_AUTOHSCROLL,
                     400, 285, 50, 20,
                      hwnd, (HMENU) 1, NULL, NULL
                      );           
             // Testsequenzen BIS HIER
    

    @ Unregistrierter:
    Ich lerne die Sprache mit Sicherheit NICHT, indem ich sie nicht verwende. Die Bitmap-Funktion ist neu für mich, NATÜRLICH kann ich da noch nicht alles dran verstehen. Grundlagen lernen schön und gut, aber egal wie viele arcuscotangensfunktionen ich mir auch in C zusammenreime, davon lerne ich NICHTS für den Umgang mit Bitmaps in C++/WinAPI - schon alleine deshalb weil ich dort aufgrund der Aufgabenstellungen nie auf Bitmaps stoßen werde.



  • So lernst du aber nichts über:
    Funktionen, Zeiger oder Referenzen z.b.

    Ich hab gerade noch was in einem Ordner von mir gefunden, vielleicht hilft dir das weiter:

    #include <iostream>
    #include <conio>
    #include <windows.h>
    using namespace std;
    
    int del_img();
    
    int main()
    {
    
    {
    int a;
    
      HBITMAP hBitmap = (HBITMAP)LoadImage(NULL,"bitmap.bmp",
                         IMAGE_BITMAP,0,0,LR_LOADFROMFILE);
    
      BITMAP bmp;
      GetObject(hBitmap,sizeof(bmp),&bmp);
    
      HWND hwnd = FindWindow("ConsoleWindowClass",NULL);
      HDC hDC = GetDC(hwnd);
    
      HDC hBitmapDC = CreateCompatibleDC(hDC);
      SelectObject(hBitmapDC,hBitmap);
    
      BitBlt(hDC,20,20,bmp.bmHeight,bmp.bmWidth,hBitmapDC,0,0,SRCCOPY);
    
      DeleteObject(hBitmap);
      ReleaseDC(hwnd,hBitmapDC);
      ReleaseDC(hwnd,hDC) ;
    
    cin>>a;
    
            if (a==1)
            {
            del_img();
            }
    
    system("PAUSE");
    }
            int del_img()
            {
                RECT rc;
               GetClientRect(0, &rc);
               InvalidateRect(0, &rc, true);
            }
    


  • Stück Torte @ Unreg!

    na, damit konnte ich doch arbeiten 🙂

    Zwei Probleme und eine Frage habe ich noch:

    1. Mit der Bitmap wird noch nicht mein ganzes Fenster gefüllt, sondern sie ist einsam und allein oben links in der Ecke. Irgendwie muss ich eine Wiederholungssequenz für sie aktivieren können. Falls nicht, muss ich wohl das

    BitBlt(hDC,0,0,bmp.bmHeight,bmp.bmWidth,hBitmapDC,0,0,SRCCOPY);
    

    zusammen mit der momentanen hwnd Fenstergrösse verrechnen und die bitmap ebenso oft laden?

    2. Die Bitmap wird über meine Buttons geklebt, wenn ich die Buttons benutze, oder die Fenstergröße stark verkleinere und wieder vergrößere. Ich nehme an, das das daran liegt, das meine Funktion in case WM_PAINT nicht ganz richtig aufgehoben ist?

    case WM_PAINT:
          {
             if(hwnd)                // wenn Fenster gefunden, dann hwnd != NULL
             {    
                 hwnd = FindWindow(NULL, "Wurstwassersäufer");  
                 HBITMAP hBitmap = (HBITMAP)LoadImage(NULL, "test.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
                 BITMAP bmp;
                 GetObject(hBitmap,sizeof(bmp),&bmp); 
    
                 HDC hDC = GetDC(hwnd); 
                 HDC hBitmapDC = CreateCompatibleDC(hDC); 
                 SelectObject(hBitmapDC,hBitmap); 
    
                 BitBlt(hDC,0,0,bmp.bmHeight,bmp.bmWidth,hBitmapDC,0,0,SRCCOPY); 
    
                 DeleteObject(hBitmap); 
                 ReleaseDC(hwnd,hBitmapDC); 
                 ReleaseDC(hwnd,hDC) ; 
    
                 Bitmaphoehe = bmp.bmHeight;
                 Bitmapbreite = bmp.bmWidth;
    
                 break; 
             }
             return 0;
          }
    

    3. Meine Frage: Ich habe zum Entfernen der Bitmap aus dem Speicher die Funktion

    int del_img() 
    { 
       RECT rc; 
       GetClientRect(0, &rc); 
       InvalidateRect(0, &rc, true); 
    }
    

    ganz an den Anfang des Programms gesetzt, noch über die int main, und das Anwenden der Funktion in den Case Window destroy

    case WM_DESTROY:
          {
             del_img();
    

    gesetzt - bin ich da richtig vorgegangen? (Es funktioniert jedenfalls) Im vorigen Beispiel wurde sie ja über die Variable a aufgerufen.



  • cyberleon schrieb:

    1. Mit der Bitmap wird noch nicht mein ganzes Fenster gefüllt, sondern sie ist einsam und allein oben links in der Ecke.

    --> google.de --> msdn Name der WinAPI Funktion
    msdn LoadImage --> http://msdn.microsoft.com/en-us/library/windows/desktop/ms648045(v=vs.85).aspx

    cxDesired [in]
    
    Type: int
    
    The width, in pixels, of the icon or cursor. If this parameter is zero and the fuLoad parameter is LR_DEFAULTSIZE, the function uses the SM_CXICON or SM_CXCURSOR system metric value to set the width. If this parameter is zero and LR_DEFAULTSIZE is not used, the function uses the actual resource width.
    cyDesired [in]
    
    Type: int
    
    The height, in pixels, of the icon or cursor. If this parameter is zero and the fuLoad parameter is LR_DEFAULTSIZE, the function uses the SM_CYICON or SM_CYCURSOR system metric value to set the height. If this parameter is zero and LR_DEFAULTSIZE is not used, the function uses the actual resource height.
    

    http://msdn.microsoft.com/en-us/library/dd183370(v=vs.85).aspx
    Für BitBlt kann man Koordinaten angeben.



  • Keks @ Unreg!

    Ich hatte nur in der BitBld gesucht, nicht in LoadImage() - aber genau dort sind die Angaben für Breite und Höhe, mit der die Bitmap übertragen wird, d.h. dort kann ich festlegen auf welches Verhältnis die Bitmap gestreckt werden soll - Vielen Dank für den Tip 😃

    Mein zweites Problem, also das beim wiederholten Aufrufen von WM_PAINT meine Buttons von meiner Background Bitmap übermalt werden, besteht noch.
    Als Grund könnte ich mir vorstellen ... ehrlich gesagt, ich habe keine Ahnung.
    WM_CREATE, worin sich meine buttons befinden, wird vor WM_PAINT ausgeführt, also müsste auch beim Programmstart meine Knöpfe übermalt werden, werden Sie aber nicht. Ich habe diesbezüglich auch die Funktion CAPTUREBLT in BitBlt() zu verwenden versucht, bekam aber den Fehler "CAPTUREBLT undeclared, first use in this function", was mich doch etwas verwirrt, da SRCCOPY ja funktioniert ... liegt das eventuell an meinem compiler (DevC++ 4.9.9.2), bzw daran das die Datenbank darin veraltet ist? (Ich habe Visual Studio 2010 nicht benutzt, weil es mir das Verwenden/ Bearbeiten von rexource.rc Dateien verbietet ...)

    Dinge, die ich herausgefunden habe:

    case WM_PAINT:
    wird offenbar nur beim Vergrößern, nicht beim Verkleinern der Fenstergröße aktiviert (Was logisch ist). Bein Vergrößern offenbar bei jeder Pixelreihe, die neu hinzukommt.

    WM_PAINT
    wird bei Programmstart (mindestens) 2 mal ausgeführt. Ich habe die Häufigkeit des Zeichnens meiner Bitmap mit einer If-Abfrage limitiert. Als ich meine Bitmap nur einmal laden ließ, war sie im Programm nicht sichtbar, erst ab 2 mal:

    case WM_PAINT:
          {
             if(hwnd)                         // wenn Fenster gefunden, dann hwnd != NULL
             {    
                hwnd = FindWindow(NULL, "Wurstwassersäufer");        // suche Fenster mit Titel Wurstwassersäufer
    
                if( wurstbrot <= 2)
                {
                    wurstbrot = wurstbrot + 1;
                    HBITMAP hBitmap = (HBITMAP)LoadImage(NULL, "test.bmp", IMAGE_BITMAP, 400, 400, LR_LOADFROMFILE);
                    BITMAP bmp;
                    GetObject(hBitmap,sizeof(bmp),&bmp); 
                    HDC hDC = GetDC(hwnd); 
                    HDC hBitmapDC = CreateCompatibleDC(hDC); 
                    SelectObject(hBitmapDC,hBitmap); 
              //      GetClientRect(hwnd, LPRECT);        // AUFGABE: Fenstergrösse herausfinden
                    BitBlt(hDC,0,0,bmp.bmHeight,bmp.bmWidth,hBitmapDC,0,0,SRCCOPY); // (hDC, Anfangsposix, AnfangsposiY
    
                    DeleteObject(hBitmap); 
                    ReleaseDC(hwnd,hBitmapDC); 
                    ReleaseDC(hwnd,hDC); 
    [.....]
    


  • Wenn Buttons drüberliegen dann ist das nicht der Fensterinhalt (der in WM_PAINT gemalt wird) sondern der Fenster-Hintergrund (der in WM_ERASEBKGND gemalt wird).
    Du behandelst also die falsche Nachricht.

    Davon abgesehen...
    * Was soll das FindWindow() im WM_PAINT Handler? Das Window-Handle hast du doch eh schon.
    * Wo sind die in WM_PAINT "verpflichtenden" BeginPaint()/EndPaint() Aufrufe?



  • Also, so wie ich des sehe wird WM_ERASEBKGND eben nicht zum Malen eines Hintergrund sondern zum Löschen des Hintergrunds verwendet, steht zumindest so hier: http://msdn.microsoft.com/en-us/library/windows/desktop/ms648055(v=vs.85).aspx

    das FindWindow() brauche ich glaub ich hier tatsächlich nicht, vielen Dank für den Tip!

    Die BeginPaint()/EndPaint() Aufrufe hatte ich weiter unten in WM_PAINT, weil ich noch ein paar Kreise und Vierecke dazwischen gemalt habe. aber die haben doch soweit ich weiss nichts mit der Funktion WM_PAINT zu tun, sondern dienen dazu, dass man im aktuellen hwnd herumkrizeln kann, oder nicht? Ein test mit folgender Abwandlung meines case ergab jedenfalls kein anderes Resultat als vorher. Seltsamerweise werden die Kreise und Vierecke, die ich male, NICHT erneut geladen und ÜBER meine buttons / Textfelder gelegt, sondern bleiben immer brav darunter, wie es sich für Hintergrund gehört - obwohl auch sie beim "resizen" des Fensters erneut geladen werden. Hier der Code:

    case WM_PAINT:
       {
          hdc = BeginPaint( hwnd, &ps );                   // draw the following stuff:
        //GetClientRect(hwnd, LPRECT);        // AUFGABE FÜR SPÄTER: Fenstergrösse herausfinden, um in LoadImage einzufügen
          HBITMAP hBitmap = (HBITMAP)LoadImage(NULL, "test.bmp", IMAGE_BITMAP, 400, 400, LR_LOADFROMFILE);
          BITMAP bmp;
          GetObject(hBitmap,sizeof(bmp),&bmp); 
          HDC hDC = GetDC(hwnd); 
          HDC hBitmapDC = CreateCompatibleDC(hDC); 
          SelectObject(hBitmapDC,hBitmap); 
          BitBlt(hDC,0,0,bmp.bmHeight,bmp.bmWidth,hBitmapDC,0,0,SRCCOPY); // (hDC, Anfangsposix, AnfangsposiY
    
          DeleteObject(hBitmap); 
          ReleaseDC(hwnd,hBitmapDC); 
          ReleaseDC(hwnd,hDC); 
    
          Bitmaphoehe = bmp.bmHeight;
          Bitmapbreite = bmp.bmWidth;
          if(hBitmap == NULL)
          {
             MessageBox(hwnd, "Could not load Bitmap!", "Error", MB_OK | MB_ICONEXCLAMATION);
          }
    
          // ALTE POSITION VON hdc = BeginPaint( hwnd, &ps ); , habe ich nun zum Test nach oben kopiert
          Ellipse( hdc, 300, 100, 330, 130 );               // Ellipse: ( hdc, Anfangspunktx, Anfangspunkty, Endpunktx, Endpunkty)
          Ellipse( hdc, 160, 100, 190, 130 );               // Ellipse: ( hdc, Anfangspunktx, Anfangspunkty, Endpunktx, Endpunkty)
          Rectangle( hdc, 20, 90, 330, 100 );              // Rectangle: ( hdc, Anfangspunktx, Anfangspunkty, Endpunktx, Endpunkty)
          Rectangle( hdc, 220, 70, 300, 90 );              // Rectangle: ( hdc, Anfangspunktx, Anfangspunkty, Endpunktx, Endpunkty)
          EndPaint( hwnd, &ps );   
          break;
          return 0;   // kA, brauche ich das hier? (iss schon spät heute ...)
    }
    

  • Mod

    WM_ERASEBKGND ist für das Zeichnen des Hintergrundes verantwortlich. Das kann man auch als Löschen bezeichnen.

    Überflüssig ist das ganze natürlich wenn in WM_PAINT sowieso alles gezeichnet wird. Das Konzept ist aber so, dass durch WM_ERASEBKGND der Hintergrund vorbereitet wird und durch WM_PAINT darauf nur gezeichnet wird was notwedig ist.

    Alles was Du zeichnen willst musst zwischen Deinen BeginPaint/EndPaint reinpacken! Grundsätzlich!

    Wenn Child COntrols in Deinen Fenster liegen, dann liegen dir immer über Deinem Fenster! Was meinst Du mit Laden in diesem Zusammenhang?

    Grundsätzlich hat eben jede´s Fenster seine eigene Ausgabefläche. Dabei liegen Childfenster über dem Elternfenster und werden danach gezeichnet.

    Wenn Child COntrols sich überlappen kann es zum Chaos kommen. Helfen kann WS_CLIPSIBLINGS und auch kann eine WM_PAINT Funktion Bereiche eines Kinds übermalen. Verhindert wird das mit WS_CLIPCHILDREN.



  • R O F L
    ich hab den Fehler -.-.-

    statt hDC musste ich natürlich hdc in BitBld nehmen, also

    BitBlt(hdc,0,0,bmp.bmHeight,bmp.bmWidth,hBitmapDC,0,0,SRCCOPY); // (hDC, Anfangsposix, AnfangsposiY
    

    statt

    BitBlt(hDC,0,0,bmp.bmHeight,bmp.bmWidth,hBitmapDC,0,0,SRCCOPY); // (hDC, Anfangsposix, AnfangsposiY
    

    Hier der komplette Code, falls mal jemand für seinen Hintergrund zuerst eine Bitmap laden und dann darauf malen möchte:

    case WM_PAINT:
          {
                    hdc = BeginPaint( hwnd, &ps );                   // draw the following stuff:
            //      GetClientRect(hwnd, LPRECT);        // AUFGABE FÜR SPÄTER: Fenstergrösse herausfinden, um in LoadImage einzufügen
    
                    HBITMAP hBitmap = (HBITMAP)LoadImage(NULL, "test.bmp", IMAGE_BITMAP, 400, 400, LR_LOADFROMFILE);
                    BITMAP bmp;
                    GetObject(hBitmap,sizeof(bmp),&bmp); 
                    HDC hDC = GetDC(hwnd); 
                    HDC hBitmapDC = CreateCompatibleDC(hDC); 
                    SelectObject(hBitmapDC,hBitmap); 
                    BitBlt(hdc,0,0,bmp.bmHeight,bmp.bmWidth,hBitmapDC,0,0,SRCCOPY); // (hDC, Anfangsposix, AnfangsposiY
    
                    DeleteObject(hBitmap); 
                    ReleaseDC(hwnd,hBitmapDC); 
                    ReleaseDC(hwnd,hDC); 
    
                    Bitmaphoehe = bmp.bmHeight;
                    Bitmapbreite = bmp.bmWidth;
                    if(hBitmap == NULL)
                    {
                       MessageBox(hwnd, "Could not load Bitmap!", "Error", MB_OK | MB_ICONEXCLAMATION);
                    }
    
                    // ALTE POSITION VON hdc = BeginPaint( hwnd, &ps ); , habe ich nun zum Test nach oben kopiert
                    Ellipse( hdc, 300, 100, 330, 130 );               // Ellipse: ( hdc, Anfangspunktx, Anfangspunkty, Endpunktx, Endpunkty)
                    Ellipse( hdc, 160, 100, 190, 130 );               // Ellipse: ( hdc, Anfangspunktx, Anfangspunkty, Endpunktx, Endpunkty)
                    Rectangle( hdc, 20, 90, 330, 100 );              // Rectangle: ( hdc, Anfangspunktx, Anfangspunkty, Endpunktx, Endpunkty)
                    Rectangle( hdc, 220, 70, 300, 90 );              // Rectangle: ( hdc, Anfangspunktx, Anfangspunkty, Endpunktx, Endpunkty)
                    EndPaint( hwnd, &ps );   
    
                   break;
          }
    

    Herausgefunden habe ich das durch den vorhergehenden Kommentar "BeginPaint() und EndPaint() sind zwingend" - Vielen Dank nochmal an dieser Stelle! Mein Problem war, das ich von zwei Personen Code hatte, die natürlich Ihre Variablen anders genannt hatten - da die Variablen aber so ähnlich waren (hdc und hDC) wars mir einfach nicht aufgefallen 🙂

    Mein nächstes Thema wird nun sein, die Größe des Fensters herauszufinden, in dem ich male - mit Hilfe der Funktion

    GetClientRect(hwnd, LPRECT);
    

    Aber ich denke dafür lohnt sich ein neuer Thread - falls ich es nicht selbst hinbekomme 🙂



  • BitBlt(hdc,0,0,bmp.bmWidth,bmp.bmHeight,hBitmapDC,0,0,SRCCOPY);
    


  • :)p


Anmelden zum Antworten