Canvas->Draw() erzeugt Exception?



  • Hi Leute
    Ich habe versucht in ein ListView mit Draw ein Bild aus einem TImage in eine Zeile
    zu zeichnen. Doch leider füllt sich der Arbeitsspeicher immer mehr und erzeugt
    eine Exception :

    ---------------------------
    Benachrichtigung über Debugger-Exception
    ---------------------------
    Im Projekt FileHandler.exe ist eine Exception der Klasse EInvalidOperation mit der Meldung 'Leinwand/Bild erlaubt kein Zeichnen' aufgetreten.
    ---------------------------
    Anhalten   Fortsetzen   Hilfe   
    ---------------------------
    

    und danach eine andere mit Stack-overflow:

    ---------------------------
    Benachrichtigung über Debugger-Exception
    ---------------------------
    Im Projekt FileHandler.exe ist eine Exception der Klasse EStackOverflow mit der Meldung 'Stack-Überlauf' aufgetreten.
    ---------------------------
    Anhalten   Fortsetzen   Hilfe   
    ---------------------------
    

    nur leider weiß ich nicht wieso.
    Ich hoffe es kann mir jemand helfen.



  • Dann debugge doch mal deinen Code oder wenn du nicht weiterkommst, poste ihn hier.



  • Sry ich hab vergessen das zu erwähnen: Ich zeichne das Bild pro Zeile
    in ein ListView(OwnerDraw). Das Draw-Event wird beim verschieben usw aus-
    gelöst. Der Code Funktioniert ja aber wenn ich es oft verschiebe steigt der Ram-
    Bedarf von 2 auf ca 4MB und das Programm meldet die oben genannten Exceptions.

    Lg XBert



  • Hallo

    Dann erzeugst du irgendwo memory Leaks. Schau ob du irgendwo Speicher mit new reservierst aber nicht mehr mit delete löschst.

    bis bald
    akari



  • hab ich schon ich habe 2 bitmaps mit new erzeugt und ein paar TRect
    und habe alles mit delete wieder gelöscht

    XBert



  • Hallo

    Der Speicherverbrauch und die Exception kommen aber nicht von ListView selber, sondern von deinem Code. Vielleicht solltest du mal einzelne Teile des fraglichen Quellcodes ausklammern um zu sehen wann das fehlerhafte Verhalten verschwindet.
    So oder so können wir hier ohne Einsicht in deinen Quellcode nur raten.

    bis bald
    akari



  • Ok dann Poste ich hier den Code:

    void __fastcall TForm1::ListView1DrawItem(TCustomListView *Sender,
          TListItem *Item, TRect &Rect, TOwnerDrawState State)
    {
    
         Graphics::TBitmap *prog= new Graphics::TBitmap();
         Graphics::TBitmap *prog1= new Graphics::TBitmap();
    
         TRect mainRect,Progress,addInf,temp,Abort,showDialog;
    
         mainRect.Left=Rect.Left;
         mainRect.Top=Rect.Top+1;
         mainRect.Right=Rect.Left+ListView1->Columns->operator [](0)->Width-2;
         mainRect.Bottom=Rect.Bottom;
    
         Progress.Left=Rect.Left+ListView1->Columns->operator [](0)->Width;
         Progress.Top=Rect.Top;
         Progress.Right=Progress.Left+ListView1->Columns->operator [](1)->Width-2;
         Progress.Bottom=Rect.Bottom;
    
         addInf.Left=Progress.Right+2;
         addInf.Top=Rect.Top+1;
         addInf.Right=addInf.Left+ListView1->Columns->operator [](2)->Width-1;
         addInf.Bottom=Rect.Bottom;
    
         showDialog.Left=addInf.Right+2;
         showDialog.Top=Rect.Top;
         showDialog.Right=showDialog.Left+ListView1->Columns->operator [](3)->Width-1;
         showDialog.Bottom=Rect.Bottom;
    
         Abort.Left=showDialog.Right+2;
         Abort.Top=Rect.Top;
         Abort.Right=Abort.Left+ListView1->Columns->operator [](4)->Width-1;
         Abort.Bottom=Rect.Bottom;
    
         // Aktions-Namen-Balken
    
         ListView1->Canvas->TextRect(mainRect,mainRect.Left+20,mainRect.Top+2,Item->Caption );
    
         //Icons
    
         int k = 16;
         TIcon *myIcon=new TIcon();
    
         if(Item->Caption=="Kopieren")k=0;
         else if(Item->Caption=="Ausschneiden")k=1;
         else if(Item->Caption=="Löschen")k=2;
         else if(Item->Caption=="Freigabe(n) aufheben")k=3;
         else if(Item->Caption=="Vergleichen")k=4;
         else if(Item->Caption=="Verschlüsseln")k=5;
         else if(Item->Caption=="Neue(n) Ordner erstellen")k=6;
         else if(Item->Caption=="Neue(n) Registry-Schlüssel erstellen")k=7;
         else if(Item->Caption=="Verpacken")k=8;
         else if(Item->Caption=="Umbenennen")k=9;
         else if(Item->Caption=="Freigeben")k=10;
         else if(Item->Caption=="Shreddern")k=11;
         else if(Item->Caption=="Teilen")k=12;
         else if(Item->Caption=="Synchronisieren")k=13;
         else if(Item->Caption=="Entschlüsseln")k=14;
         else if(Item->Caption=="Entpacken")k=15;
    
         icons->GetIcon(k,myIcon);
    
         ListView1->Canvas->Draw(mainRect.Left+2, mainRect.Top+2,myIcon);
         DestroyIcon(myIcon);
    
         // Fortschritts-Balken
    
         ImageList1->GetBitmap(0,prog);
         ImageList1->GetBitmap(1,prog1);
         double proz=StrToFloat(Item->SubItems->operator [](0));
         int pixel;
         pixel=(proz/100)*(Progress.Right-Progress.Left);
    
         for(int i=0;i< pixel;i++){
            ListView1->Canvas->Draw(Progress.Left+i,Progress.Top,prog );
         }
         for(int i=pixel;i<(Progress.Right-Progress.Left);i++){
            ListView1->Canvas->Draw(i+Progress.Left,Progress.Top,prog1 );
         }
    
      /*
         //Prozentanzeige --vv-- (funktioniert nicht)
    
         int textLeft=(ListView1->Columns->operator [](1)->Width - ListView1->Canvas->TextWidth(Item->SubItems->operator [](0)))/2 + mainRect.Width() ;
         int textTop= (mainRect.Height() - ListView1->Canvas->TextHeight(Item->SubItems->operator [](0)))/2 ;
         temp.Left=textLeft;
         temp.Top=textTop;
         temp.Right=textLeft+ListView1->Canvas->TextWidth(Item->SubItems->operator [](0));
         temp.Bottom=textTop+ListView1->Canvas->TextHeight(Item->SubItems->operator [](0));
         ListView1->Canvas->Font->Color=clBlack;
         ListView1->Canvas->TextRect(temp,temp.Left,temp.Top,(Item->SubItems->operator [](0)) );
        */
    
        //Zusätzliche Informationen 
    
        ListView1->Canvas->TextRect(addInf,addInf.Left,addInf.Top,Item->SubItems->operator [](1) );
        //Dialog/Abbrechen - Buttons
    
        ListView1->Canvas->Draw(showDialog.Left,showDialog.Top,Image1->Picture->Graphic);
        ListView1->Canvas->Draw(Abort.Left,Abort.Top,Image2->Picture->Graphic);
    
        //Speicher freigeben
         delete prog1,mainRect,addInf,prog,temp,Abort,showDialog;
    
    }
    

    Ich hoffe,dass das weiterhilft.

    LG XBert



  • Hallo

    Ohne jetzt alles genau überprüft zu haben kann ich schon,al sagen das diese Zeile hier nicht das macht was du erwartest :

    delete prog1,mainRect,addInf,prog,temp,Abort,showDialog;
    

    Der Kommaoperator ist nämlich hier falsch, es wird nur das letzte Argument verwendet. Alle anderen werden nur "angefasst" aber nicht verarbeitet.

    Du must schon jedes Objekt einzeln löschen

    delete prog1;
    delete mainRect;
    ...
    delete showDialog;
    

    bis bald
    akari



  • Danke das wusste ich nicht.
    Aber ich nehme an, dass ich die ganzen TRect als pointer definieren muss
    um sie Löschen zu können oder sollte das auch so funktionieren (ohne Löschen der TRect)?

    LG XBert



  • Hallo

    Nein Löschen must du nur, was du mit new auch anlegst. Wenn du etwas ohne new auf dem Stack anlegst wird die Instanz automatisch gelöscht. Und wenn du etwas auf dem Stack anlegen kannst wie die TRects dann solltest du das auch machen. Bei TBitmap geht das leider nicht also must du dort mit new und delete arbeiten.

    In diesem speziellen Fall beschränkt sich das Löschen auf die TBitmaps.

    bis bald
    akari



  • Ok danke das hab ich nie gelernt.
    Aber ich hab noch ein memoryleak gefunden weil ich dachte das TIcon mit DestroyIcon()
    gelöscht wird. Aber man muss es danach auch noch mit delete "zerstören".

    Aber eine Frage hab ich noch:
    Was macht

    int j=17;
    delete &j;
    

    LG XBert



  • Hallo

    XBert schrieb:

    Ok danke das hab ich nie gelernt.
    Aber ich hab noch ein memoryleak gefunden weil ich dachte das TIcon mit DestroyIcon()
    gelöscht wird. Aber man muss es danach auch noch mit delete "zerstören".

    Das delete dürfte ausreichen, das DeleteIcon brauchst du nicht.

    Aber eine Frage hab ich noch:
    Was macht

    int j=17;
    delete &j;
    

    Ärger. Denn das ist nicht erlaubt. Da j eine Stack-Variable ist und nicht auf dem Heap angelegt wurde, wird es auch automatisch beim Verlassen des Gültigkeitsbereiches gelöscht. Wenn du nun trotzdem delete auf die Instanz anwendest wird das Löschen zweimal ausgeführt, was in der Regel zu einem Speicherzugriffsfehler führt.

    bis bald
    akari



  • der Compiler nimmt es aber an und es wird keine Exception ausgelöst

    LG XBert



  • Hallo

    Dann hast du Glück (oder Pech?). Denn es ist ungültig. Und da kann alles mögliche passieren.

    bis bald
    akari


Anmelden zum Antworten