Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Multimedia (https://www.delphipraxis.net/16-multimedia/)
-   -   Delphi Flickernder Newsticker - ich hab bald alle Techniken durch (https://www.delphipraxis.net/65747-flickernder-newsticker-ich-hab-bald-alle-techniken-durch.html)

berens 20. Mär 2006 20:24


Flickernder Newsticker - ich hab bald alle Techniken durch
 
Hallo Leute.

Ich sitz hier jetzt schon etliche Wochen an so einer besch...eidenen Newstickerfunktion, und irgendwie will es mir nicht gelingen.

Aufgabe: einen String in Schriftgröße 72 vor rechts nach links durchscrollen lassen, nach möglichkeit Pixel für Pixel und die gleichmäßig, ohne Ruckeln, Flickern oder Sprünge. Der gesamte Zeichenbereich hat in etwa die Dimensionen von 1400 x 150 px. Es bleibt anzumerken dass der Newsticker nur ein Teilprogramm ist, und das restliche Programm auch ein bisschen Rechenleistung braucht.

Damit ihr nicht denken müsst, ich frag hier einfach uns lass Euch die Arbeit schaffen, meine Verzeifelten versuche bisher:

Begriffserklärung:
Sprüge: Newsticker bewegt sich normalerweise um 1 px weiter, weil aber gerade etwas gerechnet wurde überspring der Newsticker mehrere Pixel oder wird alternativ langsamer.
Flackern: Stellt Euch ein O oder eine Null vor, deren Oberseite nicht mehr an die Unterseite passt (versuche das mal zu illustrieren:)

aus:
###
#--#
###

wird:
###
-#--#
-###

Ruckeln: naja, wird bei "Sprünge" miterklärt (halt das Gegenteil davon), einfach ein unregelmäßiges Ablaufen)


1:
http://www.delphipraxis.net/internal...light=flickern
Paintbox hilft nicht, und GD32 ist ab einer gewissen Größe auch recht langsam.

2:
Bitmap mit Textout, BitBlt auf Backbuffer und dann BitBlt auf Form.Canvas, flackert auch

3:
DirectX bzw. DirectDraw jeweils getestet mit (http://turbo.gamedev.net/) DelphiX, UnDelphiX, DGLEngine, Asphyre

4:
Einbinden eines TWebbrowsers mit einer Flash (SWF) Animation, die einen Newsticker darstellt - flackert auch

5:
Testen einer Website, die mit DHTML und Javascript einen Text darstellt - flackert auch

6:
Siehe 2, allerdings am Anfang den ganzen Text auf ein großes Bitmap, und dass dann immer um ein px verschoben mit BitBlt anzeigen lassen - ruckelt (<-- immernoch die beste Lösung bisher)

Alle Methoden arbeiten mit Threads, da "Zeichen" wurde sowohl ohne, als auch mit Synchronize ausprobiert.

Das Hauptproblem, weshalb Punkt 6 wohl auch am vielversprechensten aussieht, ist wohl dass die Schriften (Vektorgraphik!) jedesmal beim Textout-Zeichnen auf ein Bitmap neu skaliert und berechnet werden müssen (?).

Hoffe das Problem selbst wird damit erstmal deutlich.

Damit Ihr ein "bisschen" Anreiz habt mitzurätseln, stetze ich hiermit EINEN KASTEN BIER als BELOHNUNG aus (oder etwas vergleichbares nach eigener Wahl), wer maßgeblich zur Lösung dieses Problemes beiträgt!

Vielen Dank schonmal im Vorraus, ich bin auf eure Antworten angewiesen.

DGL-luke 20. Mär 2006 20:42

Re: Flickernder Newsticker - ich hab bald alle Techniken dur
 
also wenn dir das so wichtig ist, dass der da nicht springt, dann würde ich den gesamten berechnungskram in einen thread verlagern, den du alle sekunden anhältst, deinen ticker verschiebst, und dann wieder laufen lässt.

berens 20. Mär 2006 20:47

Re: Flickernder Newsticker - ich hab bald alle Techniken dur
 
Es existiert schon ein Thread für das Verschieben (ein Integer wird um 1 vermindet = X-Wert für Textout etc.). In einem anderen Thread wird die Draw-Routine (entweder die für DirectX oder die mit dem BitBlt) aufgerufen (während des Zeichnens ist der andere Thread suspended).

DGL-luke 20. Mär 2006 20:55

Re: Flickernder Newsticker - ich hab bald alle Techniken dur
 
ok, wie wärs mit timebased movement (also verschiebeung in abhängigkeit von tatsächlich vergangener zeit)? dann kanns zwar immer noch ruckeln, aber es sollte wenigstens nicht mehr irgendwie springen, zumindest je nach fps-zahl...

Dann kannst du dir auch den integer-verschiebe-thread sparen, da du nur on demand berechnest.

(verschiebung in pixel = vergangene zeit in sek * verschiebung in pixel pro sek)

Wenn du diesem thread, der also die verschiebung berechnet und zeichnet, eine höhere prio gibst, dann hilft das vielleicht....

Den thread am besten einmal starten und dann immer n sleep(100-500) reinhauen, damit er nicht dauernd zeichnet.

jfheins 20. Mär 2006 21:06

Re: Flickernder Newsticker - ich hab bald alle Techniken dur
 
Also der Code geht bei mir relativ gut, auch bei 100% cpu - dann natürlich sehr langsam ;)

Delphi-Quellcode:
var
  ende, x: Cardinal;
begin
  ende := GetTickCount + 3000;
  x := 800;

  while GetTickCount < ende do
  begin
    PaintBox321.Buffer.Clear (clWhite32);
    PaintBox321.Buffer.Textout(x, 20, 'Hallo');
    PaintBox321.Flush;
    sleep (0);
    if x <= 10 then x := 800
    else dec (x);
  end;
Mit GR32 ...

@Luke: Gerade dann wird es springen, wenn eine lange Zeit zwischen den Frames vergeht ;)

berens 20. Mär 2006 23:17

Re: Flickernder Newsticker - ich hab bald alle Techniken dur
 
@jfheins: Das sieht generell schonmal ganz gut aus, (das obligatorische:) aaaber, mit steigender Schriftgröße (z.B. 150) und einem längeren Text (s.u.) wird der Ticker immer langsamer. Dann bleibt einem nur noch, die Schrittweite auf 2 oder Höher zu stellen, (dec(x, 2)) damit der Betrachter beim Lesen nicht einschläft. Und sobald die Schrittweite 2 beträgt, haben wir wieder diesen "Verzerrungseffekt" bzw. Flackern (hoffe Ihr könnt das nachvollziehen).

Meine aktuelle Version:
Delphi-Quellcode:
var
  ende, x: Integer;
begin
  ende := GetTickCount + 30000;
  x := 800;

  while GetTickCount < ende do
  begin
    PaintBox321.Buffer.Clear (clWhite32);
    PaintBox321.Buffer.Font.Size := 72;
    PaintBox321.Buffer.Textout(x, 0, 'Funktioniert das denn auch mit etwas längeren Texten noch flüssig und wenn die Schriftgröße 150 beträgt?');
    PaintBox321.Flush;
    //    sleep (0);
    Application.ProcessMessages;
    if x <= -50 then x := 800
    else dec (x, 2);
  end;
end;

Luckie 20. Mär 2006 23:42

Re: Flickernder Newsticker - ich hab bald alle Techniken dur
 
Zeichne nicht direkt auf dem Canvas der Painbox, sondern auf ein Bitmap im Speicher, welches du dann mit BitBlt auf den Canvas kopierst. Zeichenroutinen sind unter Windows generell langsam.

berens 21. Mär 2006 08:51

Re: Flickernder Newsticker - ich hab bald alle Techniken dur
 
Nun gut, habe das ganze nun mit einen TBitmap32 als Hintergrundpuffer versucht, aber großartig (merkbar?) besser wird es auch nicht. Das Problem ist nach wie vor, dass es mit 1 Pixel je Takt echt ewig langsam ist und eine CPU Auslastung von 100% auf Dauer ist auch nicht wirklich ok. *seufz* Ich meine es gibt mittlerweile photorealistische super-3d computerspiele, das ist das Problem mit so einem blöden Text der einfach nur von rechts nach links durchlaufen soll (vor mir aus langen da 16 Farben die er darstellen kann).

Naja, aktueller Code, wobei ich denke dass wir vielleicht dennoch bei DirectX o.ä. besser aufgehoben wären:

Danke nochmal an alle, die sich bisher an der Diskussion beteiligen, ich hoffe auf viele weitere Beiträge.

Delphi-Quellcode:
var
  ende, x: Integer;
begin
  ende := GetTickCount + 30000;
  x := 800;

  while GetTickCount < ende do
  begin
    backbuffer.Clear(clWhite32);
    backbuffer.Font.Size := 72;
    backbuffer.Textout(x, 0, 'Funktioniert das denn auch mit etwas längeren Texten noch flüssig und wenn die Schriftgröße 150 beträgt?');
    BitBlt(PaintBox321.Canvas.Handle, 0, 0, width, 150, backbuffer.Canvas.Handle, 0, 0, SRCCOPY);
//    PaintBox321.Buffer.Clear (clWhite32);
//    PaintBox321.Buffer.Font.Size := 72;
//    PaintBox321.Buffer.Textout(x, 0, 'Funktioniert das denn auch mit etwas längeren Texten noch flüssig und wenn die Schriftgröße 150 beträgt?');
//    PaintBox321.Flush;
//    sleep (0);
//    Application.ProcessMessages;
    if x <= -50 then x := 800
    else dec (x);
  end;
end;

Gollum 21. Mär 2006 09:03

Re: Flickernder Newsticker - ich hab bald alle Techniken dur
 
Hallo,

schau Dir einmal die Windows-Funktion MSDN-Library durchsuchenScrollDC und MSDN-Library durchsuchenScrollWindow an.
Vielleicht hilft es...

berens 21. Mär 2006 09:49

Re: Flickernder Newsticker - ich hab bald alle Techniken dur
 
Hab bei dem Suchbegiff ScrollDC noch das folgende Thema ausgegraben http://www.delphipraxis.net/internal...ect.php?t=2322 , leider ist das auch zu langsam im Scrollen und (zumindest mit kleiner Schrift) flimmert auch.

Ich komm mit dem ScrollDC nicht so ganz klar. Wie geht das richtig?

Delphi-Quellcode:
var
  ende, x: Integer;
  r: TRect;
begin
  ende := GetTickCount + 30000;
  x := 800;

  while GetTickCount < ende do
  begin
    // Auf dem Canvas ist nun schon die aktuelle Schrift zu sehen
    r := Rect(0, 0, width, 150);
    ScrollDC(PaintBox321.Canvas.Handle, -1, 0, r, r, PaintBox321.Handle, NIL); // verschieben
    if x <= -50 then x := 800
    else dec (x);
  end;

Edit: Ich hab mit ScrollWindow eben ne kleine Demo geschrieben, und die sieht sau gut aus (mit nem Label). Die Sache ist, dass ja der Bereich, der vorher noch nicht sichtbar ist nun immer mit der letzten Pixelspalte des Labels gezeichnet wird (Labels scrollt links raus und hinterlässt eine Spur). Das muss man irgendwie mit dem ClipRect oder so machen. Wie genau Funktioniert das (* gleich mal "the fucking searchfunction"-benutzt* :D), für CodeBeispiele wäre ich ganz dankbar, ansonsten zeichne ich das vielleicht mit einem Bitmap und dann immer die letzte Pixelspalte, obwohl mit Label oder so schon lieber wäre.

Delphi-Quellcode:
  repeat
    ScrollWindow(Self.Handle, -1, 0, NIL, NIl);
    sleep(10);
    Application.ProcessMessages;
  until 1=2;

Khabarakh 21. Mär 2006 10:23

Re: Flickernder Newsticker - ich hab bald alle Techniken dur
 
Zitat:

Zitat von berens
Delphi-Quellcode:
var
  ende, x: Integer;
begin
  ende := GetTickCount + 30000;
  x := 800;

  while GetTickCount < ende do
  begin
    PaintBox321.Buffer.Clear (clWhite32);
    PaintBox321.Buffer.Font.Size := 72;
    PaintBox321.Buffer.Textout(x, 0, 'Funktioniert das denn auch mit etwas längeren Texten noch flüssig und wenn die Schriftgröße 150 beträgt?');
    PaintBox321.Flush;
    //    sleep (0);
    Application.ProcessMessages;
    if x <= -50 then x := 800
    else dec (x, 2);
  end;
end;

So wird das sicher nichts. Da der Text statisch ist, solltest du ihn in einem eigenen Bitmap sichern und dieses dann versetzt auf den Paintboxbuffer zeichnen. Damit sollten >100 FPS kein Problem sein.

berens 21. Mär 2006 10:27

Re: Flickernder Newsticker - ich hab bald alle Techniken dur
 
Das ist zwar eine gute Idee (siehe mein Punkt 6), allerdings das du dann ein Problem, wenn du einen längeren Text bekommmst (sagen wir 10000 Zeichen, also widestring). Stell dir das mal als farbiges Bitmap vor mit 150px Höhe und ~10.000*50px = 500.000 px (!) Breite, das macht kein Arbeitsspeicher mit...

Irgendwer ein Beispiel für ScrollDC?

Khabarakh 21. Mär 2006 10:39

Re: Flickernder Newsticker - ich hab bald alle Techniken dur
 
War Punkt 6 schon immer da oben :stupid: ? Bei langen Texten pufferst du einfach die doppelte (oder dreifache, ...) Bildbreite, das Neuberechnen verschiebst du optimalerweise in einen eigenen Thread.

berens 21. Mär 2006 11:54

Re: Flickernder Newsticker - ich hab bald alle Techniken dur
 
Hat noch keine mitr ScrollDC gearbeitet? Wie siehst mit ScrollWindow aus?

Edit: Mein aktuelle Code:

Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var
  ende, x: Integer;
  ScrollRect, ClipRect, UpdateRect: TRect;
begin
  ende := GetTickCount + 30000;
  x := 0;

  while (GetTickCount < ende) and not cl do
  begin
    inc(x, 2);
//    backbuffer.Clear(clWhite32);
//    backbuffer.Font.Size := 72;
//    backbuffer.Textout(0, 0, 'Funktioniert das denn auch mit etwas längeren Texten noch flüssig und wenn die Schriftgröße 150 beträgt?');
//    BitBlt(PaintBox321.Canvas.Handle, 0, 0, width, 150, backbuffer.Canvas.Handle, 0, 0, SRCCOPY);
    ScrollRect := PaintBox321.BoundsRect;
    ClipRect := PaintBox321.BoundsRect;

    ScrollDC(PaintBox321.Canvas.Handle, -2, 0, ScrollRect, ClipRect, 0, @UpdateRect);
    InvalidateRect(PaintBox321.Canvas.Handle,@updaterect,True);
    BitBlt(PaintBox321.Canvas.Handle, width-10, 0, 2, PaintBox321.Height, backbuffer.Canvas.Handle, x, 0, SRCCOPY);
    //    ReleaseDC(Handle, PaintBox321.Canvas.Handle);

//    PaintBox321.Buffer.Clear (clWhite32);

//    PaintBox321.Buffer.Font.Size := 72;
//    PaintBox321.Buffer.Textout(x, 0, 'Funktioniert das denn auch mit etwas längeren Texten noch flüssig und wenn die Schriftgröße 150 beträgt?');
//    PaintBox321.Flush;
    sleep (2);
    Application.ProcessMessages;
//    if x <= -50 then x := 800
//    else dec (x, 2);
  end;
end;

Gandalfus 22. Mär 2006 11:39

Re: Flickernder Newsticker - ich hab bald alle Techniken dur
 
Delphi-Quellcode:
[quote="berens"]@jfheins: Das sieht generell schonmal ganz gut aus, (das obligatorische:) aaaber, mit steigender Schriftgröße (z.B. 150) und einem längeren Text (s.u.) wird der Ticker immer langsamer.
Der text wird nicht langsamer es dauer nur länger bis ein Buchstabe durchgescrollt ist weil er breiter ist. Es scheint also nur so als ob es langsamer wäre.
Die Geschwindigkeit muss also von der Schriftgrösse abhängig sein.
Und das dann noch um "timebased movement" erweitern.

Dann braucht man nur noch einen timer/Thread der 25 mal pro Sekunde aufgerufen wird. (Für die menschliche Wahrnehmung genügen ungefähr 25 Bilder pro Sekunde, um eine "ruckelfreie" Illusion der Kontinuität zu erzeugen" Wikipedia)


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

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