Bitmaps

Wie Sie Bitmaps aus Dateien laden und darstellen, das haben Sie schon im Kapitel GDI erfahren. Bitmaps lassen sich aber auch als Ressource zum Programm hinzufügen. Der Vorteil dabei ist, dass Sie bei der Weitergabe Ihres Programms die Bitmap-Datei selbst nicht mehr weitergeben müssen, sondern die Bitmap ist mit ins Programm eingebunden. Sehen wir uns an, wie Bitmaps als Ressourcen eingebunden werden.

Falls Sie das Beispiel SBmpUser aus der vorherigen Lektion nicht mehr geöffnet haben, so öffnen Sie dieses zunächst.

Im Verzeichnis 99Templates befinden sich zwei Bitmap-Dateien die wir nun einbinden. Öffnen Sie dazu die Ressourcen-Ansicht und klicken Sie mit der rechten Maustaste den Eintrag SBmpUser Ressourcen an. Wählen Sie aus dem eingeblendeten Kontext-Menü den Eintrag Importieren... aus und fügen dann nacheinander die Dateien OFF.BMP und ON.BMP zur Ressource hinzu. Geben Sie den neu hinzugefügten Bitmap-Ressourcen die IDs IDB_OFF und IDB_ON. Das war's dann auch schon. Selbstverständlich können Sie, wenn Sie grafisch begabt sind, eigene Bitmaps erstellen. Klicken Sie dazu den Ressource-Typ Bitmap mit der rechten Maustaste an und wählen aus dem Kontext-Menü den Eintrag Bitmap einfügen aus. Standardmäßig wird dann eine Bitmap mit der Auflösung 48x48 und 16 Farben erstellt. Wollen Sie eine andere Auflösung oder Farbtiefe, führen Sie einen Doppelklick innerhalb des Editorfensters durch. Daraufhin wird folgender Dialog eingeblendet:

Bitmap-Ressource Parameter

Hier können Sie dann die ID, die Auflösung, die Farbtiefe und, durch Auswahl des Tabulators Palette, die Farben einstellen.

IDs von Bitmap-Ressourcen sollten mit dem Präfix IDB_xxx beginnen. Und obwohl wir externe Bitmap-Dateien in die Ressource eingebunden haben, werden die Bitmaps nachher beim Übersetzen und Linken mit zum Programm dazugebunden

Um eine Bitmap-Ressource zu laden, steht die CBitmap Methode LoadBitmap(...) zur Verfügung. Sie erhält als Parameter die ID der zu ladenden Bitmap. Damit Sie die geladene Bitmap auch ausgeben können, müssen Sie zunächst, wie in der Lektion Bitmaps und Speicher-DC im Kapitel GDI besprochen, einen Speicher-DC erstellen und dann das Bitmap-Objekt darin selektieren. Anschließend können Sie mit Hilfe der CDC Methode BitBlt(...) die Bitmap ausgeben.

Beginnen wir diesen Übungsteil mit dem Laden der Bitmaps und dem Erstellen des für die Ausgabe notwendigen Speicher-DC. Da diese Schritte nur einmal durchgeführt werden müssen, bringen wir sie sinnvollerweise wieder in der Methode OnInitialUpdate(...) unter. Fügen Sie aber der Klasse CSBmpUserView zuerst folgenden privat Daten hinzu:
CDC    *m_pMemDCOff;
CDC    *m_pMemDCOn;
CBitmap m_CBmpOff;
CBitmap m_CBmpOn;
bool    m_bIsOn;

Anschließend fügen Sie der Klasse die OnInitialUpdate(...) Methode hinzu und erweitern deren Code wie folgt:

void CSBmpUserView::OnInitialUpdate()
{
    CView::OnInitialUpdate();
   
    // TODO: Speziellen Code hier einfügen und/oder Basisklasse aufrufen
    // Beide Bitmap aus Ressource laden
    m_CBmpOff.LoadBitmap(IDB_OFF);
    m_CBmpOn.LoadBitmap(IDB_ON);
    // 2 Speicher-DC erstellen
    CDC *pDC = GetDC();
    m_pMemDCOff = new CDC;
    m_pMemDCOff->CreateCompatibleDC(pDC);
    m_pMemDCOn = new CDC;
    m_pMemDCOn->CreateCompatibleDC(pDC);
    // Beide Bitmaps darin selektieren
    m_pMemDCOff->SelectObject(&m_CBmpOff);
    m_pMemDCOn->SelectObject(&m_CBmpOn);
    // Flag fuer Bitmap-Darstellung initialisieren
    m_bIsOn = false;
    // Geliehenen DC auch wieder freigeben
    ReleaseDC(pDC);
}

Sodann kann die Methode OnDraw(...) angepasst werden. Je nach Zustand der Membervariable m_bIsOn soll entweder die Bitmap IDB_ON (Speicher-DC ist m_pMemDCOn) oder IDB_OFF (Speicher-DC ist m_pMemDCOff) dargestellt werden:

void CSBmpUserView::OnDraw(CDC* pDC)
{
    CSBmpUserDoc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);
    // ZU ERLEDIGEN: Hier Code zum Zeichnen der ursprünglichen Daten hinzufügen
    // Struktur fuer Bitmap-Kenndaten
    BITMAP BmpParam;
    // Falls On-Bitmap gezeichnet werden soll
    if (m_bIsOn)
    {
        m_CBmpOn.GetBitmap(&BmpParam);
        pDC->BitBlt(10,10,BmpParam.bmWidth,BmpParam.bmHeight,
                    m_pMemDCOn,0,0,SRCCOPY);
    }
    else
    {
        m_CBmpOff.GetBitmap(&BmpParam);
        pDC->BitBlt(10,10,BmpParam.bmWidth,BmpParam.bmHeight,
                    m_pMemDCOff,0,0,SRCCOPY);
    }
}

Das Toggeln der Membervariable m_bIsOn führen wir in der Methode OnLButtonDown(...) durch. Wird auf die dargestellte Bitmap geklickt, so soll diese wechseln. Erweitern Sie hierzu die OnLButtonDown(...) Methode wie folgt:

void CSBmpUserView::OnLButtonDown(UINT nFlags, CPoint point)
{
    // TODO: Code für die Behandlungsroutine für Nachrichten hier einfügen und/oder Standard aufrufen

    // Hintergrundfarbe des Fensters auslesen
    CDC *pDC = GetDC();
    COLORREF BackColor = pDC->GetBkColor();
    // Falls Cursor auf Bitmap zeigt
    // (akt. Farbe ungleich Hintergrundfarbe)
    if (pDC->GetPixel(point.x,point.y) != BackColor)
    {
        // darzustellende Bitmap wechseln
        m_bIsOn = !m_bIsOn;
        Invalidate();
        return;
    }
    ReleaseDC(pDC);
   
    // String-Objekte erstellen
    ....
}

Übersetzen und starten Sie das Beispiel nun.

Wenn Sie mit der linken Maustaste die Bitmap anklicken, so sollte diese wechseln. Ob eine Bitmap oder der Fensterhintergrund angeklickt wurde, wird durch auswerten des Farbwertes unterhalb des Cursors festgestellt. Dieses Verfahren funktioniert natürlich nur dann, wenn innerhalb der Bitmap keine Farben vorkommen die mit dem Fensterhintergrund identisch sind.

Aber haben Sie sich beim Beenden des Programms auch einmal die Ausgabe in Debuggerfenster angesehen? Dort werden zwei memory leaks gemeldet, d.h. irgendwo haben Sie Speicher reserviert und dann aber vergessen, diesen auch wieder freizugeben.

Versuchen Sie selber einmal diesen 'kleinen' Fehler zu beheben.

Lösung zur Ausgabe von Bitmaps

In der Methode OnInitialUpdate(...) haben wir zum einen zwei Speicher-DCs reserviert und zum anderen auch noch Bitmaps geladen. All dies sollte beim Beenden der Anwendung auch wieder freigegeben werden. In der Regel können Sie in der Methode OnInitialUpdate(...) reservierte Ressourcen in der Methode OnDestroy(...) wieder freigeben. Fügen Sie diese Methode noch der Klasse CSBmpUserView wie folgt hinzu:

void CSBmpUserView::OnDestroy()
{
    CView::OnDestroy();
   
    // TODO: Code für die Behandlungsroutine für Nachrichten hier einfügen
    // Speicher-DCs freigeben
    delete m_pMemDCOff;
    delete m_pMemDCOn;
    // Bitmaps freigeben
    m_CBmpOff.DeleteObject();
    m_CBmpOn.DeleteObject();
}

Ende der Lösung

Übersetzen und starten Sie das Programm. Jetzt sollte alles fehlerfrei funktionieren.

Das fertige Beispiel zu dieser und der vorherigen Lektion finden Sie auch unter 07Ressourcen\SBmpUser.

Und damit beenden wir das Thema Bitmap-Ressource und kommen in der nächsten Lektion zu einer der wichtigsten Ressource, dem Menü.



Copyright © 2004

Senden Sie Emails mit Fragen oder Kommentaren zu dieser Website an: mailto:info@cpp-tutor.de
 Wolfgang Schröder, Lerchenweg 23, D-72805 Lichtenstein. Tel: +49 7129 6470