BMP verschwunden



  • Hallo,
    in meiner StatusBar zeichne ich ein Bitmap aus einer TImageList.

    ImageList1->Draw(StatusBar1->Canvas, x, y, BMP_1, true);
    

    Der Hintergrund des Bitmaps ist transparent.
    Wenn ich das Fenster aus dem Bildschirm schiebe oder z.B. minimiere und anschließend maximiere, ist das Icon verschwunden.
    Scheinbar zeichnet das Fenster in solchen Situationen das Icon nicht mehr neu.

    Wie kann ich das verhindern? 😕

    Ps: Wenn ich das BMP einem TImage zuordne und dann zeichne, passiert das nicht, aber die Transparenz ist dann leider verschwunden.



  • In welcher Methode zeichnest du denn die Bitmap?
    OnDrawPanel müßte das richtige Ereignis dafür sein.



  • Danke @Th69 für Deinen Hinweis. Habe mir schon gedacht, dass ich den Event OnDrawPanel einsetzen muß.
    Das Zeichnen des Bitmaps erfolgt wie in der folgenden Funktion dargestellt.
    Vielleicht gibt es doch noch eine andere Möglichkeit, das Zeichnen des Bitmaps in meiner Funktion zu erzwingen?

    enum StatusTask {noTask, Task1, Task2 /*usw*/};
    
    void TForm1::StatusBarInfo(StatusTask t) { //ändert die Anzeige der Statusbar je nach Aufgabe
    	switch (t) {
    	case noTask:
    		StatusBar1->Panels->Items[0]->Text = L"";
    		ImageList1->Draw(StatusBar1->Canvas, StatusBar1->Panels->Items[0]->Width + 4, 4, BMP_noTask, true);
    		break;                                             
    	case Task1:
    		StatusBar1->Panels->Items[0]->Text = L" Infotext zu Aufgabe1"; 
            ImageList1->Draw(StatusBar1->Canvas, StatusBar1->Panels->Items[0]->Width + 4, 4, BMP_Task1, true);
    		break;
    	case Task2:
            //usw.
    	default: ;
    	};
    }
    

    Wenn ich das Bitmap über ein TImage mit der folgenden Konstruktion anzeige, klappt das mit dem Neuzeichnen. Leider verlieren dabei die Bitmaps ihre Transparenz. Gibt's hierzu vielleicht eine Idee das zu vermeiden?

    DrawImage(ImageList1, StatusBarImage, BMP_Task4);
    
    //---------------------------------------------------------------------------
    TImage* StatusBarImage;     //new =>Konstruktor, bzw delete =>Destruktor
    
    void TForm1::DrawImage(TImageList* ImageList, TImage* OutImage, int Index) {
    	Graphics::TBitmap* BMP = new Graphics::TBitmap();
    	ImageList->GetBitmap(Index, BMP);
    	OutImage->Picture->Assign(BMP);
    	delete BMP;
    }
    


  • Hi,
    in Listing 2 einfügen

    BMP->TransparentColor = clRed;
    

    mfg
    kpeter



  • Hallo @kpeter, Danke für Deine Antwort.

    @kpeter schrieb:

    BMP->TransparentColor = clRed;

    Das klappt leider auch nicht.

    Mein Versuch Bitmaps mit Transparenz aus einer TImageList zu laden und einem TImage zuzuweisen, damit sie automatisch gezeichnet werden, ist gescheitert. 😞
    Entweder behalten die Bitmaps ihre Transparenz, werden dann aber nicht neugezeichnet oder aber sie werden neu gezeichnet, verlieren dann ihre Transparenz.

    Sowie es aussieht muß ich doch den Weg gehen, den @Th69 mit dem Event OnDrawPanel vorgeschlagen hat. Das ist natürlich unschön, weil dort alle Zeichenoperationen nochmal wiederholt werden müssen, die ich bereits unter der Funktion

    void TForm1::StatusBarInfo(StatusTask t) { //ändert die Anzeige der Statusbar je nach Aufgabe
    

    schon einmal ausführen lasse.

    Überzeugt bin ich nicht, dass das die einzige Lösungs-Möglichkeit sein soll.



  • Als das Windows-API entstand, war Speicherplatz knapp, und daher war es effizienter, daß die Bildschirminhalte der Anwendungen nicht vom System zwischengespeichert, sondern bei Bedarf einfach von der Anwendung neu gezeichnet wurden. Entsprechend solltest du ausschließlich in OnPaint-Eventhandlern und verwandten Methoden auf das Canvas der Komponente zeichnen, also dann, wenn Windows es anfordert.



  • Danke @Linnea, Dein Tipp mit cd32Bit hat mir geholfen. 👍
    Für alle, die es interessiert:

    DrawImage(ImageList1, StatusBarImage, BMP_Task4);
    
    //----------------------------------------------------------------
    TImage* StatusBarImage; //new=>Konstruktor, bzw delete=>Destruktor
    
    void TForm1::DrawImage(TImageList* ImageList, TImage* OutImage, int Index) {
    	Graphics::TBitmap* BMP = new Graphics::TBitmap();
    	ImageList->GetBitmap(Index, BMP);       
    	OutImage->Transparent = true; 
    	OutImage->Picture->Assign(BMP);
    	delete BMP;
    }
    

    Bitmaps in TImageList1: 16x16, weißer Hintergrund
    Im OI:
    AllocBy: 4
    BkColor: clWhite (das mußte noch umgestellt werden)
    BlendColor: clNone
    ColorDepth: cd32Bit (wie von @Linnea vorgeschlagen, besten Dank nochmal)
    DrawingStyle: dsNormal
    Height: 16
    ImageType: itImage
    Masked: True
    Name: ImageList1
    ShareImages: False
    Tag: 0
    Width: 16

    Hallo @audacia,
    Deine Antwort klingt ein bißchen nach Schulbuch, aber sehr interessant 😃 ;). So kann ich aber leider noch nichts damit anfangen. 😕
    Laß uns doch Deinen guten Tipp etwas mehr in die Praxis rücken!

    Das Problem habe ich oben bereits, wie ich hoffe, veständlich dargestellt.

    1. Ich habe eine Funktion,

    void TForm1::StatusBarInfo(t)
    

    die an den unterschiedlichsten Stellen im Programm aufgerufen wird.

    2. In dieser Funktion werden verschiedene Zeichenaktionen ausgeführt, die dummerweise dann nicht ausgeführt werden, wenn das Fenster z.B vekleinert u anschließend vegrößert wird.
    Um dies zu verhindern gibt es (jetzt) die oben genannte Lösung, oder ich stelle die Zeichenaktionen in die Funktion OnDrawPanel, wie von Dir postuliert.
    Das ist aber äußerst unschön, da alle Zeichenaktionen aus StatusBarInfo(t) auch dort nochmals eingebaut werden müssen.

    3. Das Problem wäre zu lösen, wenn ich an den Stellen, an denen die Funktion StatusBarInfo(t) steht, das OnDrawPanel-Event auslösen könnte. Dann könnte ich alle Aktionen nach OnDrawPanel verschieben und dort ausführen lassen.

    Hast Du dazu einen Lösungsansatz für die PRAXIS?



  • Hallo thunderbol,

    du brauchst doch einfach nur in OnDrawPanel deine eigene Methode 'StatusBarInfo' aufzurufen. Das einzige was du dir dann noch in einer Membervariable merken mußt, ist der aktuelle 'StatusTask', den du dann als Parameter übergibst.

    P.S: Um dann das Neuzeichnen des Controls zu erzwingen einfach Control->Refresh() aufrufen, d.h.

    void TForm1::SetStatusTask(StatusTask t)
    {
      m_statustask = t; // <- oben erwähnte Membervariable
      StatusBar1->Refresh();
    }
    


  • Großes Lob und vielen Dank. Hab's genauso gemacht.
    Das mit

    Control->Refresh();
    

    war das Tüpfelchen auf dem I. Es funktioniert jetzt perfekt.

    Vielen Dank @Th69.
    Zuletzt ist es doch noch eine Klasse Lösung geworden. 🙂


Anmelden zum Antworten