Canvas-Problem



  • Guten Tag!

    Ich programmiere nun seit einigen Jahren C++ beruflich, hatte jedoch bislang noch nicht mit graphischer Ausgabe zu schaffen. Da eine graphische Ausgabe beim aktuellen Projekt unentbehrlich ist musste ich mein Wissen in diesem Gebiet erweitern.
    Ich programmiere in der Borland Developer Studio Umgebung (C++ Builder).

    Derzeit Zeichne ich auf einer dynamischen unsichtbaren TImage-Componente [Puffer] (direkt auf den Canvas) Striche und Punkte einer komplexen Berechnung.
    Bei einem Mouseover-Event einer sichtbaren TImage-Componente, welche für die reale Graphische Ausgabe zuständig ist, wird zuerst mit CopyRect der Inhalt der oben genannten dynamischen Componente in eine neue Dynamische Componente kopiert, die jeweilie Berechnung an der Stelle ausgeführt und darauf gezeichnet und das ganze Ergebnis dann per CopyRect auf die sichtbare TImage-Componente übertragen.

    Mein Problem ist folgendes:
    Nach einiger Zeit, in der dieses Prinzip wunderbar funktioniert hat, gleich ob man über das Bild gefahren ist oder nicht, aber nicht in festem Zeitabschnitt, passiert folgendes: 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.

    Ich bitte Sie mir zu sagen, wo eventuell das Problem liegt, mache ich einen generellen Fehler?
    Vielen Dank schon einmal im voraus für die Hilfe. Ich bitte Sie jedoch um Gnade, da mein Wissen im Bereich der graphischen Ausgabe noch sehr beschränkt ist 😉

    Mit freundlichen Grüßen
    Michael C.



  • Das ist eher was für " VCL/CLX (Borland C++ Builder)". 😉



  • 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