AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

TimeSetEvent / Canvas / Thread?

Ein Thema von HJay · begonnen am 1. Feb 2011 · letzter Beitrag vom 3. Nov 2011
Antwort Antwort
Seite 1 von 3  1 23      
HJay

Registriert seit: 7. Dez 2009
172 Beiträge
 
Delphi XE7 Enterprise
 
#1

TimeSetEvent / Canvas / Thread?

  Alt 1. Feb 2011, 23:26
Ich möchte eine wissenschaftliche Grafik kontinuierlich flüssig animieren und die restliche Benutzeroberfläche soll interaktiv bleiben und die Animation nicht hakeln lassen. Als Trivialversion habe ich daher erst einmal eine primitive "NewsTicker-Laufschrift" testen wollen, die echte Grafik sollte dann später leicht auszutauschen sein. Aber mir gelingt nicht einmal ansatzweise eine flüssige, pixelbasierte Animation. Wer hat Tipps, wie man da herangeht?

Ich dachte, dass ich das mit einem MultiMedia-Timer realisieren könnte.

Die Schrift springt aber um geschätzte 10 px je sichtbarer Änderung und jede Mausbewegung auf der Form lässt alles stehen. Liegt das daran, dass das ganze nicht threadsicher ist? Was mache ich so grundsätzlich falsch und wie kann man das Problem beheben? (D6 unter W7)

Code:
type
  TNewsTicker = class(TObject)
  private
    mmResult : Integer;
    Canvas  : TCanvas;
    X       : Integer;
  public
    constructor Create(ACanvas: TCanvas);
    destructor Destroy; override;
  end;

implementation

procedure TimeCallBack(TimerID, Msg: Uint; dwUser, dw1, dw2: DWORD); pascal;
  var ANewsTicker : TNewsTicker;
begin
  ANewsTicker := TNewsTicker(dwUser);
  ANewsTicker.Canvas.TextOut(ANewsTicker.X, 100, 'Test');
  Inc(ANewsTicker.X);
end;

{ TNewsTicker }

constructor TNewsTicker.Create(ACanvas: TCanvas);
begin
  inherited Create;
  Canvas  := ACanvas;
  X       := 0;
  mmResult := TimeSetEvent(50, 10, @TimeCallBack, DWORD(Self), TIME_PERIODIC);
end;

destructor TNewsTicker.Destroy;
begin
  TimeKillEvent(mmResult);
  inherited Destroy;
end;
und aufgerufen einfach durch die Form der Anwendung:

Code:
procedure TFormMain.Button1Click(Sender: TObject);
begin
  MainNewsTicker := TNewsTicker.Create(Canvas);
end;
  Mit Zitat antworten Zitat
Aremo

Registriert seit: 24. Nov 2009
Ort: Aachen
9 Beiträge
 
Delphi 10.1 Berlin Professional
 
#2

AW: TimeSetEvent / Canvas / Thread?

  Alt 2. Nov 2011, 11:42
Zunächst könntest Du die Gemauigkeit auf 0 ( = höchste Genauigkeit ) setzen und die Aufrufhäufigkeit auf 10 mSec

also von
mmResult := TimeSetEvent(50, 10, @TimeCallBack, DWORD(Self), TIME_PERIODIC);
auf
mmResult := TimeSetEvent(10, 0, @TimeCallBack, DWORD(Self), TIME_PERIODIC);

herabsetzen. Wenn Du die Routine nur alle 50 mSec ausführen möchtest, kannst Du intern einen Zähler von 1 bis 5 installieren und nur bei Zähler = 5 ausführen.

Dies löst aber wahrscheinlich nocht nicht das Problem, dass der Timer bei Mausbewegungen pausiert.
Dieses Pausieren habe ich bei Disk I/O auch schon feststellen müssen uns suche nach einer entsprechenden Lösung.
Gottfried Arens - Soft-dynamics.de
  Mit Zitat antworten Zitat
Medium

Registriert seit: 23. Jan 2008
3.686 Beiträge
 
Delphi 2007 Enterprise
 
#3

AW: TimeSetEvent / Canvas / Thread?

  Alt 2. Nov 2011, 11:58
Du sprichst von Threadsicher im Zusammenhang mit einem Timer. Der Timer ist aber kein Thread! Dein Vorhaben würde ich nämlich tatsächlich mit einem (echten) Thread angehen. Mal eine Pseudoklasse:
Delphi-Quellcode:
type
  TMyAnimation = class(TThread)
  private
    FBitmap: TBitmap;
    FTargetCanvas: TCanvas;
    procedure DrawFrame;
  protected
    procedure Execute; override;
  public
    constructor Create(aCanvas: TCanvas);
    destructor Destroy; override;
  end;

implementation

constructor TMyAnimation.Create(aCanvas: TCanvas);
begin
  inherited Create(false);
  FTargetCanvas := aCanvas;
  FBitmap := TBitmap.Create;
end;

destructor TMyAnimation.Destroy;
begin
  FBitmap.Free;
end;

procedure TMyAnimation.DrawFrame;
begin
  FTargetCanvas.Draw(FBitmap.Canvas, ... ...);
end;

procedure TMyAnimation.Execute;
var
  loopBeginTickCount: Int64;
const
  MS_PER_FRAME = 50;
begin
  repeat
    loopBeginTickCount := GetTickCount;
    // FBitmap mit neuem Frame bestücken, was auch immer das ist
    Synchronize(DrawFrame);
    Sleep(Max(MS_PER_FRAME - (GetTickCount-loopBeginTickCount), 1));
  until Terminated;
end;
"When one person suffers from a delusion, it is called insanity. When a million people suffer from a delusion, it is called religion." (Richard Dawkins)

Geändert von Medium ( 2. Nov 2011 um 12:00 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.184 Beiträge
 
Delphi 12 Athens
 
#4

AW: TimeSetEvent / Canvas / Thread?

  Alt 2. Nov 2011, 11:58
Nicht die Pixel an dem ungenauen Timer-Interval richten, denn Timer-Events haben eine geringe Priorität ... also nahezu alle anderen Messages werden bevorzugt verarbeitet und ist mal der Rechner und/oder dein VCL-Thread ausgelastet, dann hängt es halt.

Ein Intervall von 50 (bis zu 20 Bilder die Sekunde) sollte ausreichen, aber dabei nicht das X um 1 hochzählen, sondern die tatsächliche Zeit, zwischen den Aufrufen oder von Beginn an, messen und davon abhängig die Position "berechnen".


[add]
Ich würde garkeine Thread verwenden.
Einfach den Timer und immer wenn Zeit ist, wird gezeichnet ... der Thread kann da auch nix machen, wenn keine Zeit vorhanden ist, da er sich ja eh synchronisieren muß.
$2B or not $2B

Geändert von himitsu ( 2. Nov 2011 um 12:01 Uhr)
  Mit Zitat antworten Zitat
Medium

Registriert seit: 23. Jan 2008
3.686 Beiträge
 
Delphi 2007 Enterprise
 
#5

AW: TimeSetEvent / Canvas / Thread?

  Alt 2. Nov 2011, 12:05
Ein ausgelastetes System ist ein ausgelastetes System. Klar. Aber ein Thread knallt doch regelmäßiger dazwischen als ein Timer, vor allem wenn man ihm noch ein wenig höhere Prio verpasst - falls die Animation diese Wichtigkeit hat. Streng genommen müsste man daher sogar 2 Thread nehmen: Einen, der die Frames berechnet, und einen der nur zeichnet. Da ich in obigem Beispiel aber die zum berechnen benötigte Zeit im Sleep() berücksichtige, geht das so auch schon ganz gut. (Ich hab's ziemlich genau so auch mehrfach im Einsatz. Das geht schon ganz gut, glaub mir )
"When one person suffers from a delusion, it is called insanity. When a million people suffer from a delusion, it is called religion." (Richard Dawkins)
  Mit Zitat antworten Zitat
Benutzerbild von Bummi
Bummi

Registriert seit: 15. Jun 2010
Ort: Augsburg Bayern Süddeutschland
3.470 Beiträge
 
Delphi XE3 Enterprise
 
#6

AW: TimeSetEvent / Canvas / Thread?

  Alt 2. Nov 2011, 12:18
Application.OnIdle ???
Thomas Wassermann H₂♂
Das Problem steckt meistens zwischen den Ohren
DRY DRY KISS
H₂ (wenn bei meinen Snipplets nichts anderes angegeben ist Lizenz: WTFPL)
  Mit Zitat antworten Zitat
Medium

Registriert seit: 23. Jan 2008
3.686 Beiträge
 
Delphi 2007 Enterprise
 
#7

AW: TimeSetEvent / Canvas / Thread?

  Alt 2. Nov 2011, 12:43
Feuert auf manchen Systemen nur, wenn man die Maus über einem der Fenster bewegt, oder man im OnIdle von Hand invalidiert, was wiederum zu Hakeln in der Bedienung führen kann. Vor allem, wenn das Erstellen der Bilder etwas mehr als eine halbe Hand voll Zyklen kostet.
"When one person suffers from a delusion, it is called insanity. When a million people suffer from a delusion, it is called religion." (Richard Dawkins)
  Mit Zitat antworten Zitat
Benutzerbild von Bummi
Bummi

Registriert seit: 15. Jun 2010
Ort: Augsburg Bayern Süddeutschland
3.470 Beiträge
 
Delphi XE3 Enterprise
 
#8

AW: TimeSetEvent / Canvas / Thread?

  Alt 2. Nov 2011, 12:52
nuja, wenn man Done auf false setzt nicht ....
Thomas Wassermann H₂♂
Das Problem steckt meistens zwischen den Ohren
DRY DRY KISS
H₂ (wenn bei meinen Snipplets nichts anderes angegeben ist Lizenz: WTFPL)
  Mit Zitat antworten Zitat
Medium

Registriert seit: 23. Jan 2008
3.686 Beiträge
 
Delphi 2007 Enterprise
 
#9

AW: TimeSetEvent / Canvas / Thread?

  Alt 2. Nov 2011, 12:58
Okay, ja stimmt, das war damals als ich diverse Methoden probiert habe mein Fehler, Mist =) Dennoch finde ich es hübscher, möglichst wenig im Thread der GUI rennen zu lassen. Ich mag Threads mittlerweile sooo gerne, weil sie oft schon von sich aus zu schlankem und stark entkoppeltem Design zwingen. Und gerade bei so schnellen zyklischen Dingen wäre ich heilfroh das weitestgehend aus meinem GUI Kontext raus zu haben. Hat mir einfach jetzt schon zu oft das Leben leichter gemacht, als dass ich es nicht nachdrücklich empfehlen wollen würde
"When one person suffers from a delusion, it is called insanity. When a million people suffer from a delusion, it is called religion." (Richard Dawkins)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.184 Beiträge
 
Delphi 12 Athens
 
#10

AW: TimeSetEvent / Canvas / Thread?

  Alt 2. Nov 2011, 13:18
OnIdle wird, so wie es auch in der OH erwähnt wird, nur einmal ausgeführt, wenn alle anderen nstehenden Messages abgearbeitewt wurden.

Bewegt man die Maus ein Stückchen, dann kommen neue Messages rein (z.B. WM_MOUSEMOVE) und wurden diese wieder abgearbeitet, wird OnIdle jedes Mal erneut ausgeführt.




Wie gesagt, um in Delphi auf die VCL-Forms zu zeichnen, muß/sollte man sich im VCL-Thread befinden ... also solange man nicht zusätzliche (längere) Berechnungen im Thread hat, kommt man mit einem Timer IMHO besser.
$2B or not $2B

Geändert von himitsu ( 2. Nov 2011 um 13:24 Uhr)
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 3  1 23      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 16:53 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