Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Delphi Oberfläche wird nicht vollständig aktualisiert (https://www.delphipraxis.net/153789-oberflaeche-wird-nicht-vollstaendig-aktualisiert.html)

knaeuel 16. Aug 2010 12:29

Oberfläche wird nicht vollständig aktualisiert
 
Hallo liebes Forum,

folgendes Problem:
ich habe eine eigene Komponente TMyImage erstellt, abgeleitet von TImage. Wenn ich nun meine neue Komponente benutze, dann werden nicht mehr alle Objekte der Oberfläche aktualisiert.
TLabeledEdit, TButton, ... die hängen alle fest. Soweit ich das gerade sehe, wird die Oberfläche nur noch vollständig aktualisiert, wenn ich das Fenster verschiebe oder die Größe des Fensters ändere. Die Felder werden außerdem noch aktualisiert, wenn ich direkt drauf-/reinklicke.

Minimieren, Maximieren, Wertänderungen bei den Editfeldern haben keinen Effekt.

TMyImage hat eine eigene Paint-Methode, deklariert als published procedure Paint(); override;
In der Implementierung rufe ich zunächst inherited; auf, anschließend werden aus einem Array zu zeichnende Objekte gelesen und gezeichnet.
Die Klasse TMyImage stellt außerdem die beiden Events MouseDown und MouseMove zur Verfügung.
Beide Procedures sind als reiner Aufruf von inherited; implementiert.

Kann mir jemand verraten, womit ich die Aktualisierung der Oberfläche platt gemacht habe?

Daniela.S 16. Aug 2010 12:54

AW: Oberfläche wird nicht vollständig aktualisiert
 
Ein bisschen Source aus der Paint Procedure wäre hilfreich. Ansonsten bleibt nur raten... irgendwo beim Zeichnen falsches Handle erwischt?

knaeuel 16. Aug 2010 13:07

AW: Oberfläche wird nicht vollständig aktualisiert
 
hier die Paint-Methode. Leider ist sie etwas länger. Kurz zusammengefasst malt sie die Akteure auf einem großem gedachten Kreis und zeichnet anschließend Verbindungslinien, wenn welche definiert wurden.

Code:
procedure TSozioImage.Paint();
var ai:integer;
    a,b,c:real;
    act_color:TColor;
    bi,wert:integer;
    ckurz,akurz,bkurz,steigung,xziel,yziel:real;
begin
  //zuerst:
  inherited;
  //alle Akteure einzeichnen
  Picture.Bitmap.Canvas.Pen.Color:=initial_pen_color;
  Picture.Bitmap.Canvas.Brush.Color:=clWhite;//initial_brush_color;
  for ai := 0 to anzahl_akteure-1 do
  begin
    act_color:=akteur[ai].color;
    Picture.Bitmap.Canvas.Pen.Color:=act_color;
    KreisZeichnen(akteur[ai].x,akteur[ai].y,akteur[ai].radius,true,act_color);
    Picture.Bitmap.Canvas.Font.Color:=act_color;
    Picture.Bitmap.Canvas.TextOut(wc.vx2x(akteur[ai].bx),wc.vy2y(akteur[ai].by),akteur[ai].akteur);
  end;
  //alle Verbindungen einzeichnen
  for ai:=0 to length(akteur)-1 do
  begin
    Picture.Bitmap.Canvas.Pen.Color:=akteur[ai].color;
    for bi:=0 to length(akteur[ai].output)-1 do
    begin
      if ai<>bi then //Beziehung zu sich selbst überspringen
      begin
        //eine Beziehung einlesen
        wert:=StrToInt(akteur[ai].output[bi]);
        //zeichnen
        if wert>0 then
        begin
          Picture.Bitmap.Canvas.MoveTo(wc.vx2x(akteur[ai].x),wc.vy2y(akteur[ai].y));
          //Endpunkt der Linie berechnen:
          //die Linie soll bereits bei Erreichen des Kreises des Ziels enden
          //und eine Pfeilspitze erhalten
        //1. Länge der Verbindungsgeraden bestimmen (Hypotenuse c)
          a:=(akteur[bi].x-akteur[ai].x);
          b:=(akteur[bi].y-akteur[ai].y);
          c:=sqrt(a*a+b*b);
          //c um den Radius des Ziel"kreises" verkürzen
          ckurz:=c-akteur[bi].radius;
        //2. neues verkürztes Steigungsdreieck berechnen
          //Steigung der Hypotenuse ist konstant
          steigung:=b/a;
          //neues a: a²+(a*steigung)²=c²
          akurz:=sqrt(ckurz*ckurz/(steigung*steigung+1));
          //neues b: a²+b²=c²
          bkurz:=sqrt(ckurz*ckurz-akurz*akurz);
        //3. Koordinaten bestimmen
          //a>=0: nach oben zeichnen
          //a<0: nach unten zeichnen
          if a>=0 then
            xziel:=akteur[ai].x+akurz
          else
            xziel:=akteur[ai].x-akurz;
          //b>=0: nach rechts zeichnen
          //b<0: nach links zeichnen
          if b>=0 then
            yziel:=akteur[ai].y+bkurz
          else
            yziel:=akteur[ai].y-bkurz;
          Picture.Bitmap.Canvas.LineTo(wc.vx2x(xziel),wc.vy2y(yziel));
        end;
      end;
    end;
  end;
  //am Ende
//  inherited;
end;

Daniela.S 16. Aug 2010 13:43

AW: Oberfläche wird nicht vollständig aktualisiert
 
Also ich würde mal Paint in den protected Bereich verschieben.

Delphi-Quellcode:
  protected
    { Protected-Deklarationen }
    procedure Paint; override;
Inherited ist eigentlich nicht notwendig, da du, wenn du den Hintergrund löscht, nichts aus der Originalroutine benötigst.
Besser wäre es in eine temporäre Bitmap zu zeichnen und dann mit BitBlt auf einmal zu veröffentlichen. Das minimiert auch lästiges Flackern.

Delphi-Quellcode:
procedure TMyImage.Paint();
var
  bmp  : TBitmap;
begin
  // temporäres Bitmap erstellen
  bmp := TBitmap.Create;
  try
    // Größe festlegen
    bmp.Width := Self.Width;
    bmp.Height := Self.Height;
   
    // Hintergrund weiss färben
    with bmp.Canvas do begin
      Brush.Color := clWhite;
      Brush.Style := bsSolid;
      FillRect( Rect( 0, 0, bmp.Width, bmp.Height ) );
      end;
    // jetzt alles in bmp.Canvas zeichnen

    // zum Abschluss auf den richtigen Canvas zeichnen
    BitBlt( Self.Canvas.Handle, 0, 0, Self.Width, Self.Height,
            bmp.Canvas.Handle, 0, 0, SRCCOPY );

  finally
    FreeAndNil( bmp );
    end;
end;

knaeuel 16. Aug 2010 14:06

AW: Oberfläche wird nicht vollständig aktualisiert
 
wenn ich den inherited-Aufruf entferne, wird die Grafik gar nicht mehr gezeichnet. Die restliche Oberfläche wird allerdings aktualisiert.

Den Befehl BitBlp gibt es bei Delphi 2006 scheinbar nicht. Ich suche gerade nach Alternativen. Es sieht wohl nach CopyRect oder so ähnlich aus.

Ergebnis kommt in Kürze

fkerber 16. Aug 2010 14:10

AW: Oberfläche wird nicht vollständig aktualisiert
 
Hi!

Delphi-Referenz durchsuchenBitBlt mit t am Ende ;)


Liebe Grüße,
Frederic

knaeuel 16. Aug 2010 14:27

AW: Oberfläche wird nicht vollständig aktualisiert
 
ah danke, ja, ich hab das jetzt genau so umgesetzt.

Ohne inherited-Aufruf wird tatsächlich nichts von der Grafik angezeigt.
Was mir bisher gar nicht aufgefallen war: sobald die Paint-Methode Daten zum Anzeigen findet, braucht das Programm eine CPU komplett für sich. Daher dann wohl auch die fehlenden Aktualisierungen. Die Frage ist also jetzt, warum hört das Programm nicht auf, die Paint-Methode aufzurufen.

und siehe da, da hatte ich noch in der Procedure KreisZeichnen einen direkten Zugriff auf Canvas. Den noch entfernt und das temporäre Bitmap in KreisZeichnen rübergereicht und mitbenutzt. Jetzt ist die CPU-Last wech, die Paint-Methode wird nur noch aufgerufen, wenns wirklich nötig ist.

OK, also ich bin schon überrascht, dass ich das Canvas-Objekt nicht einfach nach Gusto benutzen darf.

Herzlichen Dank für die Hilfe und die gleich mitgereichte Implementierung des Double Buffers :-)

Bummi 16. Aug 2010 14:31

AW: Oberfläche wird nicht vollständig aktualisiert
 
leite doch von TGraphiccontrol ab ....

SirThornberry 16. Aug 2010 16:28

AW: Oberfläche wird nicht vollständig aktualisiert
 
Das Problem ist recht einfach beschrieben. So bald Picture von TImage geändert wird, wird dafür gesorgt das dies auch sichtbar wird. Und dies geschieht über einige Zwischenaufrufe durch den Aufruf von Paint. Im Paint änderst du jedoch wieder den Inhalt von dem was TImage anzeigen soll und somit wird erneut das Paint aufgerufen. Und das setzt sich immer so fort.

@knaeuel: Verwende zukünftig bitte die delphi-Tags anstelle der Code-Tags wenn du Delphi-Code postest.


Alle Zeitangaben in WEZ +1. Es ist jetzt 11:30 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz