Du verwendest einen veralteten Browser. Es ist möglich, dass diese oder andere Websites nicht korrekt angezeigt werden. Du solltest ein Upgrade durchführen oder ein alternativer Browser verwenden.
Ich hab ein problem mit meiner ProgressBar, die nicht schrittweise angezeigt wird.
ich habs schon mit newRunnable gemacht aber irgendwie springt er sofort auf 100%. was könnte hier das problem sein?
Code:
jProgressBar1.setStringPainted(true);
static public void increaseProgressBarValue() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
jProgressBar1.setValue(jProgressBar1.getValue()+1);
}
});
}
Wie wird denn deine JPrograssBar initialisiert? Ist es möglich, dass das max nur 1 ist und deshalb gleich 100% angezeigt wird, wenn du den um 1 erhöhst? Oder rufst du increaseProgressBarValue() vielleicht innerhalb einer Schleife auf und sie geht zwar schrittweise von 0 nach 100%, aber trozdem so schnell, dass es gar nicht sichtbar ist?
Nebenbei ist es eher seltsam, dass increaseProgressBarValue static ist. Vielleicht wäre es eine Überlegung werd, das ganze etwas mehr Objekt-orientiert zu designen.
increaseProgressBarValue wird von schleifen und aber auch außerhalb von schleifen aufgerufen. das es einfach nicht sichtbar ist, weil while schleife zu schnell ist, könnte nicht möglich sein ist aber nicht auszuschließen.
ich lese zeilen und schreibe eine datei mit dem gelesenen und geänderten textinhalt ca. vier mal. die datei hat ca. 200 zeilen.
also vier mal lesen und ändern einer datei welche ca. 200 zeilen hat. die methode die liest und schreibt (wird erst nach click eines buttons ausgeführt, der wiederum einen neuen panel anzeigen lässt). der panel wird durch cordlayout angezeigt, wenn der user auf panel 4 auf weiter klickt dann wird panel 5 angezeigt und die methode der schreib und leseoperationen ausgeführt. Ich hab den wechsel von panel 4 auf panel 5 sogar vor den leseoperationen gestellt.
ich hab jetzt auch die aufrufe minimiert und er bleibt bei 49% stehen.
nein maximal value von progressbar ist 100 und wird viele schritte vor der eigentlichen datei-auslesung und beschreibung initialisiert.
Was denn jetzt, ja oder nein? Setzt halt mal ein sleep in deine while Schleifen hinein:
[Java]
try {
Thread.sleep(100); // Warte eine Zehntel Sekunde
} catch (Exception e) { e.printStackTrace(); }
[/Java]
Ist es sonst möglich, dass deine while-Schleife im Event dispatching thread (EDT) abläuft? Dann würde nämmlich deine JPrograssBar nie neu gezeichnet, bis die while-Schleife zu Ende ist. Und erst dann würden alle 100 Runnables, die du in die Event-Queue gesteckt, ablaufen und den Wert sofort auf 100 setzen.
Füge mal folgendes vor deiner while-Schleife ein:
[Java]
System.out.println("Ausführender Thread: "+Thread.currentThread().getName());
[/code]
Wenn dann steht: "Ausführender Thread: AWT-EventQueue-0", dann ist es tatsächlich der EDT.
Ansonsten kann ich dir ohne Source Code auch nicht weiterhelfen. Woher soll ich wissen, was deine Panel 4 und 5 in ihrere Freizeit so machen?
es wird eine ausgabe erzeugt und zwar mehrmals mit demselben namen: (und zwar weil ich es in die methode increaseProgressBarValue gesetzt hab, welche innerhalb der lese und schreib methode von einer anderen klasse aufgerufen wird).
Ausgabe in system.out.println: "Ausführender Thread: AWT-EventQueue-0"
ich habe eine pause mal hinzugefügt. aber naja nicht mein gewünschter erfolg. denn dann tut er nur einmal ne pause machen.
also das mit den EDT's habe ich schon mal gelesen, dass er die progressbar nur dann repainted wenn er bei 100% ist (also schon fertig ist).
achso ja: in der freizeit tun panel4 und panel5 eier schaukeln :lol:
ernsthaft: also das wäre jetzt zu viel code. ist ja eigentlich egal was die machen. aber wichtig: wenn ich ein sleep hineinsetze wird panel5 angezeigt und dann die progressbar sichtbar später erhöht. das zeigt, dass die lese und schreib methoden hier uninteressant sind.
Ok, ich weiss, was das Problem ist: Deine while-Methode wird vom EDT abgearbeitet und so wird jedes Zeichnen geblock, bis diese while-Schleife zu Ende ist.
Zuerst die Theorie:
Der EDT ist verantwortlich für alles, was auf den GUIs gezeichnet wird. Er und nur er zeichnet jede Komponente. Wenn der EDT irgendwo beschäftigt ist, z.B. in einer Schleife ond einer Thread.sleep, dann ist die gesamte GUI eingefroren. Das Swing Konzept funktioniert folgendermassen: Es existiert eine Event-Queue, in die "Aufträge" gespeichert werden. Der EDT macht nun nichts anderes als diese Liste systematisch abzuarbeiten. Solche Aufträge sind z.B. das Zeichnen einer JPanel oder eines JButtons oder auch nur das teilweise Neuzeichnen einer JProgressBar, wenn sich der Wert geändert hat. Ausserdem werden alle möglichen "Events" in diese Liste gespeichert. z.B. wenn du auf einen Button klickst, der einen ActionListener angehängt hat, dann wird ein ActionEvent in die Liste aufgenommen und vom EDT ausgeführt, sobald er zu diesem Element gekommen ist.
Es gibt übrigens nur einen EDT, nicht "die EDTs"
So ist es in Moment:
Ich gehe davon aus, dass deine while Schleife startet, sobald du den Button geklickt hast. Wahrscheinlich hast du dem Button einen ActionListener angehängt. Es wird also ein ActionEvent in die Event-Queue gespeichert und irgendwann kommt der EDT und führt die actionPerformed-Methode aus. Und da drin steht sicher deine while-Schleife. D.h. der EDT ist jetzt in dieser Schleife und kann nichts mehr neuzeichnen, insbesondere nicht deine JProgressBar. Unterdessen werden aber mit SwingUtilities.invokeLater viele neue Events in die Queue aufgenommen. Wenn der EDT dann endlich fertig ist mit der while-Schleife nimmt er sich die nächsten Elemente aus der Liste, nämlich alle deine Kommandos, den Wert der JProgressBar zu erhöhen und wenn er alle durch hat, dann erst zeichnet er die JProgressBar endlich neu. Und dann ist der Wert natürlich 100. Er zeichnet die ProgressBar deshalb erst zum Schluss, weil durch das erhöhen des Wertes in der JProgressBar ein repaint() aufgerufen wird, das ganz einfach auch einen "Zeichen-Auftrag" zu hinterst in die Queue legt, also hinter all den Wert-Erhöhungen.
Jetzt musst du es folgendermassen ändern:
Geh in den ActionListener, den du dem Button angehängt hast und betrachte die actionPerformed() Methode. Anstatt hier in die while-Schleife einzutreten, startest du einen neuen Thread, der das macht. Mit folgendem Code:
Java:
public void actionPerformed(ActionEvent event) {
new Thread() {
public void run() {
// deine while-Schleife und alles andere, das dazugehört
}
}.start();
}
Nun läuft deine while-Schleife in einem separatem Thread und der EDT hat Zeit, deine JProgressBar ständig anzupassen und neu zu zeichnen
Hoffe, du nimmst es mir nicht übel, dass ich den EDT so vermenschlicht hab
gelöst. scheint mal! denn jetzt meine ich das die while schleife sehr schnell abgearbeitet wird. und man sieht die progressBar ab 60% bis 100% hoch gehen, weil der wechsel von panel4 zu panel5 wohl länger dauert.
ich hab da so ein paar variable sleep timer rein gesetzt damit das nach was aussieht.
wer hätte gedacht das so komplizierte schreib und lese arbeiten von einem dualcore prozessor so schnell abgearbeitet werden...
noch eine frage: man nehme an: mehrere verschachtelte hierarchisch aufgebaute funktionen-->
oberste Ebene (1) Funktion 1
zweite Ebene (1.1) Funktion 1.1
zweite Ebene (1.2) Funktion 1.2
dritte Ebene (1.2.1) Funktion 1.2.1
wenn ich jetzt einen neuen Thread auf Ebene 1 Lege sind dann die Funktionen darunter auch auf demselben Thread?
Denn bei mir liegt so ein fall vor! sollte ich dann jede funktion in einen neuen Thread liegen, um die progressbar zum zeichnen zu bringen und nicht auf endgültige endwerte (i.s.v. value) zu warten?
Du hast es super erklärt und nix auseinander gerissen! :toll:
Freut mich, dass es klappt. Naja, nur damit es "nach etwas aussieht", müsstest du das ganze ja nicht verlangsamen
Zu deiner Frage:
Wenn du von einer Funktion eins() aus eine weitere Funktion zwei() aufrufst, also eine Ebene eintauchst, dann wird kein neuer Thread gestartet, sondern das läuft im selben weiter. Threads laufen ja alle parallel, würde bei einem Funktionsaufruf zwei() ein neuer Thread starten, würde der alte Thread mit der Funktion eins() weiter machen, obwohl zwei() noch gar nicht abgarbeitet wurde. Das würde natürlich nicht funktionieren.
Neue Threads entstehen nur, wenn das explizit geschrieben wird, z.B. so wie ich es oben geschrieben habe.
In einem Programm laufen nicht so viele Threads. Mal sicher einer, der mit der main-Methode beginnt und dann je nachdem noch weitere. Wenn du Swing verwendest, werden etwa 5 weitere Threads gestartet, wobei du kaum einen anderen, als den EDT berücksichtigen musst. Die JVM selber braucht auch noch einige Threads, bei mir sind das 9, auf anderen Plattformen, könnte das anders sein.
Ich hab mal schnell eine kleine Demo gemacht, die veranschaulicht, wovon javimka redet.
Er hat's zwar sehr gut erklärt aber was zum Ankucken ist immer toll, und mir war grad langweilig xD
Den Code kannst du einfach kopieren und starten.
Java:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class EDTDemo extends JFrame {
public static void main(String[] args) {
new EDTDemo().setVisible(true);
}
private Color c;
public EDTDemo() {
final JPanel p = new JPanel() {
protected void paintComponent(java.awt.Graphics g) {
super.paintComponent(g);
g.setColor(c);
g.fillRect(0, 0, getWidth(), getHeight());
};
};
p.setPreferredSize(new Dimension(300, 300));
final Random r = new Random();
new Thread() {
public void run() {
// endlosschleife...
while (true) {
c = new Color(r.nextInt(255), r.nextInt(255), r
.nextInt(255));
// repaint() schickt ein Event zum EDT, dass das Panel
// neu gezeichnet werden soll.
p.repaint();
try {
Thread.sleep(50);
} catch (InterruptedException e) {
}
}
}
}.start();
JButton calcs = new JButton("process 5 secs on EDT");
calcs.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// Dieser Code wird vom EDT aufgerufen
// Hier könnten komplexe Berechnungen stehen, die 5 Sekunden
// dauern.
try {
Thread.sleep(5000);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
}
});
add(p, BorderLayout.CENTER);
add(calcs, BorderLayout.NORTH);
pack();
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
}