Ruckelfreie Laufschrift

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 21 Antworten in diesem Thema. Der letzte Beitrag () ist von horvat.

    Ruckelfreie Laufschrift

    Hallo

    ich bin gerade dabei ein Programm zu schreiben welches eine Laufschrift erzeugt.
    Ich verwende hierfür Visual Studio 2015 mit Visual Basic Windows Forms-Anwendung.
    Das Programm funktioniert grundsätzlich, leider ruckelt die Schrift in leichten unregelmäßigen Abständen.
    Ich habe es auf zwei Varianten versucht[*]Ein Label wird mit New Point(lblText.Location.X - 1, lblText.Location.Y) von einem 10ms Timer laufend verschoben.
    [*]Der Text wird mit DrawString von einem 10ms Timer laufend neu gezeichnet.
    [/list]Hier in dem Forum gibt es bereits einige Threads für Laufschriften die so gelöst wurden, scheinbar hat das ruckeln dort niemanden gestört, für meine Anwendung ist es leider unbrauchbar, die Schrift soll später auf einen großen Monitor angezeigt werden.

    Vermutlich könnte es auch die Schuld des Timers sein, da dieser vom 10ms Intervall dauernd abweicht.
    Was ich auch schon versucht habe ist die Differenzzeit der Timerdurchläufe zu messen und je nach vergangener Zeit die Pixelsprünge zu rechnen (1ms entspricht 0,1 Pixel), was aber auch ruckelt :( .

    Weiß jemand von euch einen Weg wie ich dieses ruckeln entfernen kann? Vielleicht mit einer Variante in der ich Visual Basic benutzen kann?
    ich denke, das leistungsfähigste in Winforms wird was mit OwnerDrawing sein.

    ansonsten ist WinForms halt prinzipiell für Animationen schlecht geeignet.

    Ich kann mal an mein OwnerDrawing eine Laufschrift-Projekt dranmachen.

    achso - bei deine Ruckel-Versuche: Hast du da mal die Prozessor-Last überprüft?
    Habe mal ein Beispiel getestet bei mir. Es schaut relativ ruckelfrei aus und hat kaum CPU Auslastung:

    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public Partial Class Form1
    2. Inherits Form
    3. Public Sub New()
    4. InitializeComponent()
    5. End Sub
    6. Private direction As Integer
    7. Private drawString As [String]
    8. Private rs As RectangleF
    9. Private drawFont As New Font("Arial", 60)
    10. Private drawBrush As New SolidBrush(Color.Black)
    11. Private Sub timer1_Tick(sender As Object, e As EventArgs)
    12. Dim invRect As New RectangleF(If((direction = 1), rs.X, rs.X - 1), rs.Y, If((direction = 1), rs.Width + 1, rs.Width), rs.Height)
    13. rs.X += 1 * direction
    14. If rs.X + rs.Width >= Me.Width Then
    15. direction = -1
    16. End If
    17. If rs.X = 0 Then
    18. direction = 1
    19. End If
    20. Me.Invalidate(New System.Drawing.Region(invRect))
    21. End Sub
    22. Private Sub Form1_Load(sender As Object, e As EventArgs)
    23. drawString = "test"
    24. Me.DoubleBuffered = True
    25. direction = 1
    26. rs = New RectangleF()
    27. timer1.Interval = 10
    28. timer1.Start()
    29. End Sub
    30. Private Sub Form1_Paint(sender As Object, e As PaintEventArgs)
    31. rs.Size = e.Graphics.MeasureString(drawString, drawFont)
    32. e.Graphics.DrawString(drawString, drawFont, drawBrush, rs)
    33. End Sub
    34. Private Sub textBox1_TextChanged(sender As Object, e As EventArgs)
    35. drawString = textBox1.Text
    36. End Sub
    37. End Class



    Ist nicht fertig nur zum Testen. Ist eine leere Form mit einem Timer und einer Textbox.

    LG
    Das ist meine Signatur und sie wird wunderbar sein!
    Vielen Dank für die schnellen Antworten.
    @ErfinderDesRades
    Was würdest du anstelle von WinForms verwenden, ideal für mich wäre wenn es weiterhin in VB programmierbar ist.

    @Mono:
    Ich habe dein Beispiel probiert, wenn es langsam fährt ruckelt es fast nicht, wie bei meiner Anwendung, wenn man aber die Geschwindigkeit erhöht(rs.Width + 3) beginnt es doch zu ruckeln.
    Ich bin leider nicht so der Visual Studio Experte
    Wenn ich WPF benutze gibt es dann andere Möglichkeiten eine Laufschrift zu erzeugen oder wird hier wieder der selbe Code verwendet?
    Kommt dabei dann ein besseres Ergebnis raus?
    Hat noch jemand dieses tolle WPF-Testprogramm, bei dem allerlei Zeugs passiert? Also im Hintergrund ist ein Text mit Gauss'schem Weichzeichner und horizontal fliegt ein vektorbasiertes Trollface über das Fenster, das auch auf und ab wippt.
    Ich finde, das zeigt ziemlich gut, was WPF kann. Bis dahin muss diese kleine Testprogramm reichen. Einfach ein neues WPF-Projekt erstellen und den XAML-Code ins Window-Element einfügen:

    XML-Quellcode

    1. <Grid>
    2. <Grid.RowDefinitions>
    3. <RowDefinition Height="Auto"/>
    4. <RowDefinition Height="*"/>
    5. </Grid.RowDefinitions>
    6. <Button x:Name="StartButton" Grid.Row="0" Padding="30">
    7. Klick mich
    8. <Button.Triggers>
    9. <EventTrigger RoutedEvent="Button.Click">
    10. <BeginStoryboard>
    11. <Storyboard>
    12. <DoubleAnimation
    13. Storyboard.TargetName="LabelTranslateTransform"
    14. Storyboard.TargetProperty="X"
    15. From="0.0"
    16. To="400.0"
    17. Duration="0:0:5"
    18. AutoReverse="False"
    19. RepeatBehavior="Forever"
    20. />
    21. </Storyboard>
    22. </BeginStoryboard>
    23. </EventTrigger>
    24. </Button.Triggers>
    25. </Button>
    26. <Label Grid.Row="1" HorizontalAlignment="Left" VerticalAlignment="Top">
    27. Hallo Welt
    28. <Label.RenderTransform>
    29. <TranslateTransform x:Name="LabelTranslateTransform" X="0" Y="0"/>
    30. </Label.RenderTransform>
    31. </Label>
    32. </Grid>

    Also es sollte nachher von der Struktur her so aussehen:

    XML-Quellcode

    1. <Window
    2. (Hier einige Attribute)
    3. >
    4. <Grid>
    5. <Grid.RowDefinitions>
    6. ...
    7. </Grid.RowDefinitions>
    8. ...
    9. </Grid>
    10. </Window>

    C#- bzw VB-Code wird keiner benötigt. Einfach Debuggen und den Button klicken.
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils
    @ErfinderDesRades
    Dein WinForms-Projekt läuft bei mir nicht ganz gleichmäßig. Liegt einfach daran, dass der WinForms-Timer nicht sehr genau ist.
    Dein WPF-Projekt läuft bei mir absolut Ruckelfrei. Das kann jetzt viele Gründe haben, warum es bei Dir ruckelt. Eventuell eine gaaanz alte Grafikkarte im Rechner? ;)

    @horvat
    Kommt drauf an, was Du machen willst. Ich würde empfehlen, Eigenschaften des Animation-Objektes an Eigenschaften im ViewModel zu binden und diese dann nach Bedarf zu verändern. Hier ist MVVM das Stichwort.
    Wenn Dir das zu kompliziert ist bzw. wenn Du WPF nicht wirklich lernen möchtes (solltest Du aber :P ), dann kannst Du dem Element ein x:Name="Irgendwas" geben. Dann kannst Du im Code des Fensters auf dieses Element zugreifen.
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils
    Hallo Niko

    ich habe nun von Microsoft ein super Beispiel für Animation gefunden,
    Hier wird ein Rechteck ein und ausgeblendet über die Eigenschaft Rectangle.OpacityProperty.
    Jetzt bin ich auf der Suche nach der Eigenschaft da das Projekt bewegt, MarginProperty funktioniert leider nicht.

    VB.NET-Quellcode

    1. Imports System.Windows.Media.Animation
    2. Class MainWindow
    3. Private myStoryboard As Storyboard
    4. Public Sub New()
    5. InitializeComponent()
    6. Dim myPanel As New StackPanel()
    7. myPanel.Margin = New Thickness(10)
    8. Dim myRectangle As New Rectangle()
    9. myRectangle.Name = "myRectangle"
    10. Me.RegisterName(myRectangle.Name, myRectangle)
    11. myRectangle.Width = 100
    12. myRectangle.Height = 100
    13. myRectangle.Fill = Brushes.Blue
    14. Dim myDoubleAnimation As New DoubleAnimation()
    15. myDoubleAnimation.From = 1.0
    16. myDoubleAnimation.To = 0.0
    17. myDoubleAnimation.Duration = New Duration(TimeSpan.FromSeconds(5))
    18. myDoubleAnimation.AutoReverse = True
    19. myDoubleAnimation.RepeatBehavior = RepeatBehavior.Forever
    20. myStoryboard = New Storyboard()
    21. myStoryboard.Children.Add(myDoubleAnimation)
    22. Storyboard.SetTargetName(myDoubleAnimation, myRectangle.Name)
    23. Storyboard.SetTargetProperty(myDoubleAnimation, New PropertyPath(Rectangle.MarginProperty..))
    24.  
    25. ' Use the Loaded event to start the Storyboard.
    26. AddHandler myRectangle.Loaded, AddressOf myRectangleLoaded
    27. myPanel.Children.Add(myRectangle)
    28. Me.Content = myPanel
    29. End Sub
    30. Private Sub myRectangleLoaded(ByVal sender As Object, ByVal e As RoutedEventArgs)
    31. myStoryboard.Begin(Me)
    32. End Sub
    33. End Class
    Verstehst du eigentlich, was du da machst? Also was Animationen sind, was Storyboards sind, was ein StackPanel ist usw. Das solltest du zuerst mal in Erfahrung bringen.

    C#-Quellcode

    1. RootGrid.BeginAnimation(Grid.MarginProperty,
    2. new ThicknessAnimation(new Thickness(0), new Thickness(400, 0, -400, 0), TimeSpan.FromSeconds(5))
    3. {
    4. RepeatBehavior = RepeatBehavior.Forever,
    5. AutoReverse = false
    6. });

    Ich weiß, dass du etwas für VB willst und dass das oben C# ist, aber es bringt dir nichts, wenn du einfach den Code kopierst. Versuch, ihn zu verstehen, dann sollte es in VB kein Problem sein. So kompliziert, wie Microsoft das macht, brauchst du es nicht tun. Ich habe auch keine Ahnung, was die Vorteile von @Niko Ortner sind, er Animiert die X Koordinate von dem RenderTransform, sollte aber auch kein Problem sind, ich animiere immer die Margin :)
    Mfg
    Vincent

    Hallo VincentTB,
    leider kenne ich mich noch nicht so gut in WPF aus, doch diese Animation sind genau was ich für meine Laufschrift brauchen.

    Ich habe den Code jetzt etwas vereinfacht um ein Label über einen Buttonklick auszublenden.

    VB.NET-Quellcode

    1. Dim myDoubleAnimation As New DoubleAnimation()
    2. myDoubleAnimation.From = 1.0
    3. myDoubleAnimation.To = 0.0
    4. myDoubleAnimation.Duration = New Duration(TimeSpan.FromSeconds(5))
    5. lblText.BeginAnimation(Label.OpacityProperty, myDoubleAnimation)


    Meine Problem ist nun das ich die Eigenschaft nicht finden kann um das Textfeld zu bewegen. Mir ist schon klar das die Werte .From und .To verstellt werden müssen.

    Bei meinem Beispiel wird der Text mit BeginAnimation ausgeblendet. Wenn Autoreverse auf False ist und RepeatBehavior nicht gesetzt wurde, kann ich dann davon ausgehen das die Animation beendet ist und nicht mehr irgendwo im Hintergrund weiterläuft?
    Es gibt zwei Möglichkeiten, das Textfeld zu bewegen: Einmal über die Margin-Eigenschaft (wie in meinem Beispiel) oder über den RenderTransform (wie in dem Beispiel von @Niko Ortner). Du darfst es dir aussuchen. Wenn AutoReverse false ist und das RepeatBehavior auf None ist, wird die Animation einmal ausgeführt, also ja, dann ist es vorbei.
    Mfg
    Vincent

    Tut mir leid aber ich bekomm es mit den Eigenschaften MarginProperty und RenderTransformProperty nicht hin.
    Muss man nicht noch irgendwo x oder y angeben damit er in die richtige Richtung fährt?



    VB.NET-Quellcode

    1. Dim myDoubleAnimation As New DoubleAnimation()
    2. myDoubleAnimation.From = 200.0
    3. myDoubleAnimation.To = 0.0
    4. myDoubleAnimation.Duration = New Duration(TimeSpan.FromSeconds(5))
    5. lblText.BeginAnimation(Label.MarginProperty, myDoubleAnimation)
    ich denke, du musst ganz weit zurückgehen in die Grundlagen.
    Vermutlich ist dir das Konzept "Datentyp" noch nicht wirklich klar.
    Denn du versuchst, mit einer DoubleAnimation eine Thickness zu animieren - was ja Quatsch ist (wenn man in Datentypen denkt), denn ein Double ist keine Thickness.

    Wie gesagt, ganz weit zurückgehen, und erstmal überhaupt VisualBasic korrekt einrichten: Visual Studio - Empfohlene Einstellungen

    Das wird dir das Sprach-Prinzip "Datentyp" näher bringen.
    Hallo

    ich hab mich da etwas verrannt. Ich wollte eigentlich die Eigenschaft Rendertransform X oder Y für die Simulation verwenden. Das müsste doch mit Double Animation funktionieren oder?
    In dem XAML Beispiel von Nico wurde doch auch Double Animation verwendet.
    <DoubleAnimation
    Storyboard.TargetName="LabelTranslateTransform"
    Storyboard.TargetProperty="X"
    From="0.0"
    To="400.0"
    Duration="0:0:5"
    AutoReverse="False"
    RepeatBehavior="Forever"