Canvas-Problem



  • Da haben Sie wohl recht. Eventuell ist ein Administrator zugegen, der den Beitrag verschieben könnte?



  • Hallo

    Derzeit Zeichne ich auf einer dynamischen unsichtbaren TImage-Componente [Puffer]

    Dazu benutzt man aber TBitmap, nicht TImage.

    Es werden keinerlei aktualisierungen mehr automatisch auf die sichtbare TImage-Componente übertragen, jedoch die Berechneten Werte ausgegeben, wenn ich darüber fahre, aber sie vermischen sich mit den vorigen, sodass nur noch ein gemisch aus den, seit dem der Fehler aufgetreten ist, gezeichneten Canvas zu sehen ist, so als würde er sie nicht löschen.

    Entweder wird der Puffer selber nicht richtig gelöscht/überzeichnet, oder bei CopyRect wird ein Modus verwendet, der statt einen kompletten Übertragen eine Addition von Quelle und Ziel macht (TCanvas::CopyMode)
    Auch bei der Verwendung von Threads kann es bei schlechter Synchronisation zu solchen Fehlern kommen.
    Aber ohne genauen und relevanten Code können wir da kaum weiterhelfen.

    Und der Thread gehört wirklich ins BCB-Forum.

    bis bald
    akari



  • Ich bezweifle, dass es am CopyMode liegt, da es ja immer anfangs funktioniert! Erst nach einigen Minuten (öfters gar Stunden) beginnt das Problem uns lässt sich nicht mehr rückgängig machen, außer durch eben einen unbefriedigenden Neustart des Programmes.

    Ich werde hier ausschnitte des relevanten Codes präsentieren:
    Vielleicht ist es auch noch hilfreich zu erwähnen, dass DrawLastResults durch einen Thread aufgerufen wird!

    Header der MainGUI:

    ...
    private:	
    TImage* outputBuffer;
    TImage* resultsBuffer;
    ...
    

    FormCreate von MainGUI:

    ...
    	outputBuffer = new TImage(this);
    	outputBuffer->Width = outputGraphic->Width;
    	outputBuffer->Height = outputGraphic->Height;
    
    	resultsBuffer = new TImage(this);
    	resultsBuffer->Width = outputGraphic->Width;
    	resultsBuffer->Height = outputGraphic->Height;
    ...
    

    Die Routine DrawLastResults:

    ...
    	resultsBuffer->Canvas->Brush->Color = clWhite;
    	resultsBuffer->Canvas->Pen->Color = clBlack;
    	resultsBuffer->Canvas->Rectangle(0, 0, resultsBuffer->Width, resultsBuffer->Height);
    
    ...
    	(Viele tausende aufrufe von MoveTo, LineTo, Pixels[x][y], TextOutA, Pen->Color, Brush->Color, Rectangle, Circle... auf dem Canvas von resultsBuffer)
    ...
    
    	outputGraphic->Canvas->CopyRect(gRect, resultsBuffer->Canvas, gRect);
    ...
    

    Die Routine OnMouseMove für das Ausgabe"Image":

    ...
    	outputBuffer->Canvas->CopyRect(gRect, resultsBuffer->Canvas, gRect);
    
    	outputBuffer->Canvas->Pen->Color = clLtGray;
    	outputBuffer->Canvas->Font->Color = clGray;
    	outputBuffer->Canvas->MoveTo(irgendeinXwert, irgendeinYwert);
    	outputBuffer->Canvas->LineTo(irgendeinXwert, irgendeinYwert2);
    	outputBuffer->Canvas->TextOut(einandererXwert, nocheinYwert, "istJaAuchEgal");
    	outputBuffer->Canvas->TextOut(einandererXwert2, nocheinYwert2, "istJaAuchEgal2");
    
    	outputGraphic->Canvas->CopyRect(gRect, outputBuffer->Canvas, gRect);
    ...
    


  • Dieser Thread wurde von Moderator/in HumeSikkins aus dem Forum C++ in das Forum VCL/CLX (Borland C++ Builder) verschoben.

    Im Zweifelsfall bitte auch folgende Hinweise beachten:
    C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?

    Dieses Posting wurde automatisch erzeugt.



  • Wenn du mit Threads arbeitest, so mußt du natürlich sicherstellen, daß sich die beiden Routinen DrawLastResults und OnMouseMove nicht gegenseitig beinflussen.

    Wenn CopyRect aufgerufen wird, während der andere Thread sich noch in DrawLastResults befindet, so kriegst du natürlich nur unvollkommene Images.

    Am besten, du lockst die Threads (evtl. reicht auch eine einfache boolsche Variable).



  • Hallo

    Die Konfliktvermeidung gerade ebi Ausgabeoperationen wird dabei von bei korrekter Verwendung von TThread::Synchronize übernommen.

    bis bald
    akari



  • DIe Überschneidung beider Routinen habe ich schon auf mehrere Arten und Weisen unmöglich gemacht, was aber zu keinerlei Veränderung geführt hat, was das "abtürzen" der Grafik betrifft.

    Das mit Synchronize ist ein guter Denkanstoß, den ich vorerst mal weiter verfolgen werde.
    Leider ist das Problem zwar reproduzierbar, jedoch nicht mit geringem Zeitaufwand.

    Vielen Dank bis hierhin!



  • Fehlanzeige.

    Synchronize bringt zwar in vielen Fällen die gwünschte Wirkung, jedoch steht auch hierzu in der BCB Hilfe, dass graphische Objekte ThreadSicher sind und auch außerhalb der Synchronize Methode angesprochenwerden können, sofern Lock und Unlock richtig angewandt wurden (habe ich nachgetragen, hat nichts geholfen).
    Weitere Ideen?



  • Hallo,
    ich weiß nicht genau, aber ich würde mir mal TCanvas::CopyMode ansehen.?

    Gruß



  • Hallo Michael,

    DrawLastResult zeichnet alles in resultBuffer. Anschließend wird das alles noch in outputGraphic (ist wohl das real im Formular vorhandene TImage Objekt ?) kopiert. Dies ist mir allerdings nicht ganz klar.
    Schließlich wird in OnMouseMove dieser Kopiervorgang in outputGraphic ebenfalls durchgeführt, nur mit ein paar zusätzlichen Zeichenvorgängen vorher und den Umweg über outputBuffer.
    Ist somit nicht die Anweisung

    outputGraphic->Canvas->CopyRect(gRect, resultsBuffer->Canvas, gRect);
    

    in DrawLastResult überfällig?

    Denn falls outputGraphics das reale TImage Objekt ist, dann würden ja sowohl DrawLastResult als auch OnMouseMove eine Darstellung durchführen. Generell sollte aber in einer Anwendung die finale Präsentation der Grafik nur in einer Funktion statt finden und meist ist das in OnPaint() von der übergeordneten Komponente (meist das Formular) der Fall.

    Gruß
    Markus



  • Nunja.
    Es wird innhalb von DrawLastResults eine sehr große und auch ein bis zwei sekunden dauernde Berechnung durchgeführt, welche das visuelle Ergebnis dann in resultsBuffer speichert, sodass die Berechnung nicht bei jedem OnMouseMove neu ausgeführt werden muss.
    Am Ende der Berechnung möchte ich das Ergebnis aber auch anzeigen lassen. Beim OnMouseMove werden zusätzlich zu der aktuellen Mausposition zusätzliche Informationen zu dem Diagramm angezeigt. Deswegen müssen beide Funktionen eine Ausgabe auf die Hauptoberfläche tätigen.
    Ich habe das ganze jetzt mit Lock() und Unlock() synchronisiert, dadurch sollten keine Überschneidungen mehr stattfinden.

    Vielen Dank für Ihre Hilfe. Ich werde mich jetzt anderen im Programm befindlichen Problemen widmen. Auftraggeber hat die graphische Ausgabe erst einmal in den Hintergrund geschoben. Ich melde mich, falls das Problem weiterhin auftauchen wird.


Anmelden zum Antworten