Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Multimedia (https://www.delphipraxis.net/16-multimedia/)
-   -   Delphi Flimmern bei bewegten Bitmaps für eine Prozessvisualisierung (https://www.delphipraxis.net/43561-flimmern-bei-bewegten-bitmaps-fuer-eine-prozessvisualisierung.html)

Andreas_R 5. Apr 2005 20:46


Flimmern bei bewegten Bitmaps für eine Prozessvisualisierung
 
Hallo,

ich möchte für die grafische Darstellung (Prozessvisualisierung) einer industriellen Automation eine Bitmap auf der Canvas einer Form hin- und herbewegen.
Dazu frage ich die EW bzw. MW einer Siemens S5 in einem bestimmten Takt über RS232 und mit einem "Timer.Interval := 1" ab, liegt also im Millisekunden-Bereich, je nach Rechnerpower und Konsistenz der SPS.
Die Y-Position der Bitmap ist konstant, jedoch ändert sich ständig der X-Wert. Diesen liefert mir die SPS.

Nach einer Positionsänderung der Bitmap lasse ich die Canvas über die Methode Paint des Formulars neu zeichnen, und zwar in einem begrenzten Bereich. Hierbei kommt es unweigerlich zum Flimmern der Animation.

Hat jemand vielleicht eine Idee, wie ich das abstellen kann ?

Hier der Code:
Delphi-Quellcode:
procedure TForm1.FormPaint(Sender: TObject);
var x: integer;
begin
     x:= xOffset + xMove;
     Canvas.PolyLine( [Point(10, 10), Point(720, 10), Point(720, 350),
                      Point(10, 350), Point(10, 10)]);
     Canvas.FillRect(Rect(11, 11, 719, 349));
     Canvas.Draw(x, yOffset, Bmp);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
     Bmp.LoadFromFile('Grafik2.bmp');
     Timer1.Enabled:= true;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
     Bmp.LoadFromFile('Grafik.bmp');
     Timer1.Enabled:= false;
     Timer2.Enabled:= false;
     Paint;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
     xMove:= xMove + 10;
     if xMove >= 500 then
     begin
          Bmp.LoadFromFile('Grafik3.bmp');
          Timer1.Enabled:= false;
          Timer2.Enabled:= true;
     end;
     Paint;
end;

procedure TForm1.Timer2Timer(Sender: TObject);
begin
     xMove:= xMove - 10;
     if xMove <= 0 then
     begin
          Bmp.LoadFromFile('Grafik2.bmp');
          Timer2.Enabled:= false;
          Timer1.Enabled:= true;
     end;
     Paint;
end;

procedure TForm1.TrackBar1Change(Sender: TObject);
begin
     Timer1.Interval:= TrackBar1.Position;
     Timer2.Interval:= TrackBar1.Position;
     Edit1.Text:= IntToStr(TrackBar1.Position);
end;
Und noch zwei Screenshots:

http://www.tsm-factory.de/Delphi/Prozess_01.png

http://www.tsm-factory.de/Delphi/Prozess_02.png

Danke für eure Vorschläge.

Gruß,
Andreas

toms 5. Apr 2005 20:48

Re: Flimmern bei bewegten Bitmaps für eine Prozessvisualisie
 
Hallo!


Setze die DoubleBuffered Eigenschaft der Form auf True.

Sanchez 5. Apr 2005 20:51

Re: Flimmern bei bewegten Bitmaps für eine Prozessvisualisie
 
Hallo Andreas,

Hast du schon die Eigenschaft DoubleBuffered vom Formular auf true gesetzt? Das sollte das flimmern unterdrücken.

grüße, daniel

Andreas_R 6. Apr 2005 19:48

Re: Flimmern bei bewegten Bitmaps für eine Prozessvisualisie
 
Hi toms, hi Sanchez,

der Tipp mit dem DoubleBuffered := true bewirkt leider nichts.
Ich zeichne die Bitmap direkt auf die Canvas der Form.
Soweit ich weiß, hat DoubleBuffered nur einen positiven Nutzen bei Nachfahren von TWinControl.
TForm gehört zwar dazu, aber es bewirkt nichts.

Könnte es sein, dass die Methode Canvas.FillRect einen etwas höheren Zeit- und Rechenaufwand benötigt
und von daher das Flimmern kommt ?
Wenn ich die Bitmap in ein TImage lade und dieses dann bewege, erhalte ich übrigens den gleichen Effekt.

Mir stellt sich die Frage, ob ich mal versuchsweise die Grafik selbst zeichnen sollte ?
Was natürlich mit einem ungeheuren Programmieraufwand verbunden ist, dazu habe ich eigentlich keine Lust und
auch keine Zeit.
Oder sollte ich die Malerarbeiten lieber der GPU überlassen, sofern die Nutzung von DirectX in Delphi überhaupt
möglich ist ?

Gruß,
Andreas

Khabarakh 6. Apr 2005 19:57

Re: Flimmern bei bewegten Bitmaps für eine Prozessvisualisie
 
Du solltest jegliche Grafikoperationen auf einem TBitmap durchführen und dann (z.B. mittels Draw) auf die Form kopieren. Außerdem würde ich Bild3 nicht jedes Mal neu laden, sondern in einem seperaten Bitmap speichern. Zusammen mit DoubleBuffered sollte es kein Flimmern mehr geben.

PS: Ein Timer wird niemals ein Intervall von einer Millisekunde schaffen, mit XP sind es höchstens circa 14 ms. Nimm am besten eine Endlosschleife und ProcessMessages.

Andreas_R 7. Apr 2005 19:57

Re: Flimmern bei bewegten Bitmaps für eine Prozessvisualisie
 
Hallo,

eure Tipps haben leider alle keine Verbesserungen in der Darstellung bewirkt.
Weder das DoubleBuffering noch die Kopie aller Bitmaps in je eine eigene Instanz.

Ich habe das Projekt mal in eine ZIP gepackt (Simulation, ohne serielle Connection zur S5 !!!).
Wäre schön, wenn jemand meinen vermeintlichen Fehler beseitigen könnte.
Damit könnt ihr euch selbst am besten ein flimmerndes Bild davon machen. :wink:

Download: hier

Danke für weitere Hinweise. :-D

Gruß,
Andreas

Nicodius 7. Apr 2005 21:12

Re: Flimmern bei bewegten Bitmaps für eine Prozessvisualisie
 
nur mal so directX ist möglich in Delphi (such mal hier DelphiX etc)


weiß aber nicht ob es directX schon für Delphi 2005 gibt

Gandalfus 7. Apr 2005 21:22

Re: Flimmern bei bewegten Bitmaps für eine Prozessvisualisie
 
Tipp von mir
Wenn man, z.B. eine Grafik mit einem Timer verschiebt, treten störende Flickereffekte auf. Kann ich das irgendwie abstellen?

Ja das ist Möglich.
1. Die einfachste Möglichkeit ist es DoubleBuffered des Parents auf True setzen:

Dazu ein kleines Beispiel:

Delphi-Quellcode:
var Form1: TForm1;
vx: Integer = 1;implementation
{$R *.DFM}
procedure TForm1.BitBtn1Click(Sender: TObject);
begin
  Form1.DoubleBuffered:=True;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  Image1.Left:=Image1.Left +vx;
  if Image1.Left>ClientWidth - Image1.Width-1 then   vx:=vx*-1;
  if Image1.Left<1 then   vx:=vx*-1;
end;
btw.: TImage auf diese Wiese zuverwenden ist nicht gut.

2. Man benutzt ein offscreen Bitmap. Also alles zeichnen erfolgt auf einem Hintergrundbild und wenn alles gezeichnet wurde wird das gesamte Bild auf den "Bildschirm" kopiert.

Delphi-Quellcode:
var Form1: TForm1;
vx: Integer = 1;implementation
Backpuffer: TBitmap;
Bild: TBitmap;
bildleft,bildtop: integer;
{$R *.DFM}
procedure TForm1.BitBtn1Click(Sender: TObject);
begin  
  //Ein Bild erstellen mit der gleichen Grösse wie das Formular
  Backpuffer:= TBitmap.create;
  Backpuffer.width := self.width;
  Backpuffer.height:= self.height;
  Bild:= TBitmap.create;
  Bild.loadfromfile("c:\blabla.bmp");
  Timer1.enable := true;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  Backpuffer.canvas.brush.color := clwhite;
  Backpuffer.canvas.rectangle(0,0,Backpuffer.width,Backpuffer.height)
 
  bildleft:=bildleft+vx;
  if bildleft>ClientWidth - bild.Width-1 then   vx:=vx*-1;
  if bildleft<1 then   vx:=vx*-1;
  BitBlt(Backpuffer.Canvas.Handle, bildleft, bildtop, Bild.Width, Bild.Height, Bild.canvas.handle, 0, 0, SRCCOPY);//Bild auf Backpuffer kopieren
BitBlt(self.Canvas.Handle, 0, 0, Backpuffer.Width, Backpuffer.Height, Backpuffer.canvas.handle, 0, 0, SRCCOPY);//Backpuffer auf das Formular kopieren
end;
Wie man sieht ist diese Methode etwas aufwendiger allerding verbraucht ein TBItmap weniger Ressorcen als ein TImage und somit ist diese Methode schneller.

3. Verhindern das der Hintergrund gelöscht wird.
Delphi-Quellcode:
type
  TForm1 = class(TForm)
    procedure StopFlicker(var Msg: TWMEraseBkgnd); message WM_ERASEBKGND;
end;

Procedure TForm1.StopFlicker(var Msg: TWMEraseBkgnd);
begin
  Msg.Result := 1;
end;
Das Funktioniert aber nur bei TWinControl bei TGraphiccontrol kann man es mit ControlStyle := [csOpaque] versuchen.

Man kann sich das aber auf sparen indem man nicht die Methoden repaint, invalidate oder vergleichbare benutzt sondern die Methode in der gezeichnet wird direkt aufruft.

HeinerGrimm 7. Apr 2005 22:54

Re: Flimmern bei bewegten Bitmaps für eine Prozessvisualisie
 
Hallo Andreas,

ich hatte mal ein ähnliches Problem und ähnliche Antworten erhalten. Auch bei mir hat DoubleBuffered nicht das Geringste geholfen. Sehr gut ging aber Folgendes:

Als Basiskomponente eine TPaintBox verwenden.
Darauf ein TBitmap legen (nicht sicher, ob das notwendig ist).
Das neue Bild in ein TBitmap zeichnen und dieses per BitBlockTransfer in die (sichtbare) Bitmap auf der PaintBox kopieren. Das flimmert bei mir überhaupt nicht.

Grüße Heiner



http://www.wissenschaft-technik-ethik.de

dizzy 7. Apr 2005 23:04

Re: Flimmern bei bewegten Bitmaps für eine Prozessvisualisie
 
Und genau so sollte man es auch machen ;). Ich hatte bei dieser Variante auch noch keinerlei Probleme mit Flickern.

\\edit: Eine PaintBox sollte nichtmal nötig sein - man kann ja auch direkt auf's Formular kopieren. Ob und welche Vor/Nachteile eine PB mit sich bringt weiss ich nicht.

\\edit2: Mit der Graphics32-Library ( www.g32.org ) sollte es auch sehr gut gehen. TImage32 aufs Formular, einen Layer darin für das zu bewegende Bild, und dann die Position des Layers verändern. Allerding bedarf grad die Einarbeitung in das ordentliche Verwenden von Layern etwas Zeit... aber dann läuft's schnell! :)


Alle Zeitangaben in WEZ +1. Es ist jetzt 16:23 Uhr.
Seite 1 von 2  1 2      

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