[Swing] Flüssig animierter Fortschrittsbalken?

mccae

Senfdazugeber
Hallo,

Ich hoffe ihr könnt mir bei meinem kleinen Problem helfen:

Es geht darum dass ich eine Progressbar brauche, die durchgehend animiert ist.
Der Balken, der von 0 bis 100 prozent läuft, soll dies in einer einstellbaren Zeitspanne tun. (Wie zum Beispiel von 0 bis 100 in 15 sekunden und wieder von vorn beginnen).

Auch ein Pausieren des Balkens und manipulieren der aktuellen Value während der Laufzeit soll möglich sein.

Das einfachste war meiner Meinung nach einfach das Erstellen einer eigenen Progressbar welche von JProgressbar erbt.

Doch leider malt die JProgressbar auch bei korrekter Nutzung des EDT sehr ruckelnd/flackernd, und nicht flüssig.

Da alle Swingkomponenten doublebuffered sind, wird's eben daran nicht liegen.
Eher die interne Errechnung der Werte in setValue(int value) anhand von minimum und maximum wird das Problem sein.

Was könnte man tun?

Einfach ein eigenes Component schreiben, welches eine eigene Zeichenmethode implementiert?

Ich brauche nämlich nur die Möglichkeit der flüssigen Animation - Die Progressbar muss nicht so aussehen wie aus dem L&F, sondern kann auch ein einfarbiger Balken mit Border sein.

Kann man mir Denkanstöße geben was das betrifft? (Aufbau - Threading - Berechnungen).

Vielen Dank,
Martin C. C.
 
Hallo,

Ich hatte mal ein ähnliches Problem, welches ich dann mit der Auslagerung des ProgressBar-Prozesses (Berechnung und Setzen des Wertes) in einen Thread gelöst habe.

Probier das doch mal aus.

Gruß,
Martin
 
Hallo,

Ich hatte mal ein ähnliches Problem, welches ich dann mit der Auslagerung des ProgressBar-Prozesses (Berechnung und Setzen des Wertes) in einen Thread gelöst habe.

Probier das doch mal aus.

Gruß,
Martin

Huhu,

Genau das hab' ich ja gemacht.

Nach einigem Herumexperimentieren habe ich die Lösung für das Problem gefunden!

Nachdem man auf dem EDT setValue aufruft, folgt bei mir jetzt ein Aufruf von repaint().

Dies sorgt dafür, dass die Progressbar sofort (und nicht später) neu gezeichnet wird, und somit flüssig animiert ist.

Gruß,
Martin C.C.
 
Hallo,

Ich habe dieses Thema wieder aufgemacht, da ich auf ein kleines Problem gestoßen bin.

Wie kann ich herausfinden, ob das Fenster oder der Dialog in dem meine JProgressBar eingebettet ist sichtbar ist, oder nicht?

Denn dies ist wichtig um den Thread der die Animation ausführt korrekt zu steuern.

Der Daemon-Thread der die Animation ausführt, tut dies nur, wenn die ProgressBar displayable, visible und showing ist.

Wird der Parentframe disposed, so ist das Objekt nicht mehr displayable, und der Thread stoppt.

Jedoch weiß ich nicht, wie ich auf ein "HIDE" des Fensters oder Dialogs reagieren kann.
Denn wenn das Parentfenster versteckt wird, liefert das isVisible() der ProgressBar immer noch true, isDisplayable() auch, jedoch isShowing() nicht mehr.

Leider konnte ich keine Methode - auch nicht in den Parentklassen von JProgressBar finden, die bei einem Verstecken des Parentframes aufgerufen werden.

Vielleicht wäre es interessant zu wissen, ob man als erbende Klasse auf Methoden zugreifen kann, die den Wert, den isShowing() liefert verändern.
Ein Überschreiben einer solchen Methode würde mich ans Ziel führen.

Kennt sich jemand aus?

Muss man dafür ganz tief in der Trickkiste wühlen?

Gruß,
Filip
 
Howdie.

"Hidden" heißt, dass sich der Container hinter einer anderen Komponente befindet und daher nicht gerendert wird, seh ich das richtig?
Die Antwort auf die Frage, ob dieser Container sichtbar ist oder nicht, wäre eigentlich das von dir bereits genannte isShowing(), daher verstehe ich sie nicht ganz. Zitat aus der API-Beschreibung:
Determines whether this component is showing on screen. This means that the component must be visible, and it must be in a container that is visible and showing.

Falls du meinst, dass du nicht dauernd zyklisch auf den isShowing()-Status pollen möchtest:
Wie wäre es mit einem WindowStateListener? Mit dem könntest du evtl. das Event ComponentEvent.COMPONENT_HIDDEN abfangen. Die Verwendung von Listenern auf Komponenten außerhalb des betroffenen Moduls finde ich persönlich immer etwas unschön, da die Kapselung größtenteils flöten geht... Aber ich weiß nicht, wie man diese Events sonst abfangen sollte.

Gruß
miffi
 
Hallo,

Falls du meinst, dass du nicht dauernd zyklisch auf den isShowing()-Status pollen möchtest:
Wie wäre es mit einem WindowStateListener?

Das regelmäßige Überprüfen von isShowing() macht keinen sinn, da ich ja Threads einsparen will, und keinen neuen zum Animator-Thread erstellen möchte.

Ein WindowStateListener am Parentfenster ist leider auch keine Option.
Meine von JProgressBar erbende Klasse muss die Aufgabe übernehmen, da sich diese sonst nicht universell einsetzen lässt.

Gibt es denn keine Möglichkeit auf sich in den Ablauf, der den Wert der Variable setzt, den isShowing() liefert, zu hooken?

Gruß,
Filip
 
Sowas dachte ich mir schon, du willst das ganze auf jeden Fall gekapselt haben. Ist ja auch gut so.
Was ist denn überhaupt das konkrete Problem? Mir erschließt sich noch nicht, warum die Komponente sich anders verhalten soll, wenn sie hidden ist. Macht das Performance-technisch so einen großen Unterschied?

Noch eine Anmerkung zu "JProgressBar muss die Aufgabe übernehmen":
Falls alle Stricke reißen und du die entsprechende Methode nicht gehookt kriegst, gäbs noch eine weitere Möglichkeit. Da du ja eigentlich immer einen Container hast, der deine Oberfläche beinhaltet, könntest du deiner Klasse beispielsweise eine Methode registerContainer(java.awt.Container) hinzufügen oder den Container an den Konstrukor übergeben. Dann könntest du innerhalb deines Progress-Moduls einen StateListener hinzufügen und auch die Events abfangen. Ich weiß, dass deine Klasse dann nicht mehr einfach als universelle Swing-Komponente einsetzbar und es auch nicht unbedingt die schönste Lösung ist, aber manchmal gehts halt nicht anders.

Falls du was findest, lass es mich wissen. Muss mich auch öfter mit so nem Mist rumschlagen...

Gruß
miffi
 
Huhu,

Performancetechnisch wird das ständige Überprüfen von isShowing() im Vergleich zum Auslassen eines solchen extra Threads schon einen Unterschied machen.

Ich habe mir die Sources des JDKs angesehen, und musste leider feststellen, dass alle Komponenten auf einem Fenster bei einem Statuswechsel nicht informiert werden.

Was die Methode isShowing() tut, ist die isShowing() Methode des Parents aufzurufen.
Dies geschieht rekursiv - so lange bis ein Element erreicht wurde, welches nicht sichtbar ist.
Das letzte Element in dieser Aufrufkette ist dann das Fenster, welches natürlich über seinen eigenen Status bescheid weiß.

Leider bleibt mir eben nichts anderes übrig, als den Thread auch bei verstecktem Fenster laufen zu lassen - jedoch einfach keine Renderoperationen anzuweisen.
So legt sich der Thread einfach alle 25ms schlafen und schläft weiter, falls isShowing() immer noch false ist.

mfg
Filip
 
Zurück