JProgressBar für Verbindungsaufbau

Moltar

Mitglied
Hallo!

Ich möchte gerne eine JProgressBar anzeigen lassen, während sich mein Client mit dem Server verbindet.

Es wird ein JFrame mit LoginFormular angezeigt.
In meiner Login-Funktion soll nun das LoginPanel gegen mein ProgressPanel ausgetauscht werden.
Dann wird über den Client der Login ausgeführt und am Ende wird das Hauptmenü angezeigt.

Das sieht bei mir so aus (gekürzt):
Code:
public void login(String username, char[] password) {
		if(username == null) {
			MyMessage.showError("Benutzername nicht angegeben!");
			return;
		}
		if(password == null) {
			MyMessage.showError("Passwort nicht angegeben!");
			return;
		}
		
		// ProgressPanel anzeigen
		panels.put("Progress", new ProgressPanel());
		new Thread() {
			public void run() {
				showPanel("Progress");
				SwingUtilities.invokeLater(new Runnable() {
					public void run() {
						// nichts weiter tun
					}
				});
			}
		}.start();
		//MyMessage.showInfo("Test");
		
		showPanel("Progress");
		try {
			client.init();
			client.login(username, password);
		} catch(ClientException e) {
			MyMessage.showError(e.getMessage());
			return;
		}
		showPanel("MainMenu");
	}

Code:
import java.awt.BorderLayout;

import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JProgressBar;

public class ProgressPanel extends JPanel {
	private static final long serialVersionUID = 1L;
	private JProgressBar progBar;
	private JLabel lblText;
	
	public ProgressPanel() {
		super();
		init();
		progBar.setIndeterminate(true);
	}
	
	public ProgressPanel(int max) {
		super();
		init();
		progBar.setIndeterminate(false);
		progBar.setMaximum(max);
		
	}
	
	private void init() {
		setLayout(new BorderLayout());
		progBar = new JProgressBar();
		lblText = new JLabel();
		
		JPanel rootPanel = new JPanel();
		rootPanel.setLayout(new BorderLayout());
		rootPanel.add(progBar, BorderLayout.CENTER);
		rootPanel.add(lblText, BorderLayout.PAGE_END);		
		add(rootPanel, BorderLayout.CENTER);
	}
	
	public void setText(String text) {
		lblText.setText(text);
	}
	
	public void increase(int amount) {
		progBar.setValue(progBar.getValue() + amount);
	}
}

Das Ganze funktioniert aber nur, wenn die Zeile
Code:
// MyMessage.showInfo("Test");
aktiv ist.

Die Funktion showPanel(JPanel) wechsel das aktuelle Panel auf dem getContentPane() aus und aktualisiert den JFrame.

MyMessage ist einfach nur eine Erweiterung zu JOptionPane.show...

Warum funktioniert das nur, wenn ich das Dialogfeld anzeigen lasse, obwohl ich doch den Panelwechsel in einen eigenen Thread gepackt habe?

Grüße

Moltar
 
An welcher Stelle rufst Du denn die "increase" Methode auf? Theoretisch sollte das in dem Thread geschehen, dessen Fortschritt die JProgressBar anzeigen soll. Dein Thread tut allerdings nichts soweit ich das sehe. Außer showPanel() aufzurufen, aber das passiert sowieso zwei Zeilen tiefer nach MyMessage.showInfo().

Warum funktioniert das nur, wenn ich das Dialogfeld anzeigen lasse, obwohl ich doch den Panelwechsel in einen eigenen Thread gepackt habe?

Was funktioniert? Dass die ProgressBar läuft oder dass sie überhaupt erstmal angezeigt wird? Dass sie läuft würde mich wundern, wenn Du nicht irgendwo "increase" aufrufst (s.o.).

Mehr Info bitte :)

Du musst jedenfalls Deinen Login-Vorgang in einem eigenen Thread aufrufen und da an geeigneter Stelle "increase" aufrufen.
 
Hallo inter,

Brauche ich ein increase, wenn ich
Code:
progBar.setIndeterminate(true);
verwende? Ich habe derzeit keine entsprechende Methode verwendet.

Wenn ich das Dialogfeld anzeigen lasse, wird auch die ProgressBar angezeigt und der Ladebalken pendelt hin und her (so wie er soll).

Wenn ich das Dialogfeld nicht anzeigen lasse, wird die ProgressBar nicht angezeigt.

Ich hatte mir das so gedacht, dass er einen zweiten Thread anlegt, in dem das ProgressPanel angezeigt wird und im Hauptthread läuft der Login ab. Wenn der Login fertig ist, zeigt der Hauptthread das Hauptmenü an.

Eigentlich ist das ganze ja sogar ein linearer Vorgang, also theoretisch in einem Thread möglich, aber ich habe die Anzeige des ProgressPanels in einen eigenen Thread gepackt, in der Hoffnung, dann würde der Ladebalken aktualisiert. Aber es wird ja nicht mal das Panel angezeigt.

Grüße
Moltar
 
Hallo,

ich habe das Problem jetzt gelöst, indem ich die Threads getauscht habe:
- der Hauptthread zeigt das ProgressPanel an
- ein zweiter Thread führt die übrigen Aktionen aus

Nun hätte ich gerne noch die Möglichkeit, aus dem zweiten Thread Rückgabewerte an den Hauptthread zu geben.
Wenn beispielsweise der Login fehlschlägt, soll ein false zurückgegeben werden.

Hier erstmal mein aktuelle Code:
Code:
public boolean login(final String username, final char[] password) {
		if(username == null) {
			MyMessage.showError("Benutzername nicht angegeben!");
			return false;
		}
		if(password == null) {
			MyMessage.showError("Passwort nicht angegeben!");
			return false;
		}
		
		panels.put("Progress", new ProgressPanel());
		showPanel("Progress");
		
		new Thread() {
			public void run() {
				if(!client.init() || !client.login(username, password)) {
					showPanel("Login");
					//return false;
				}
			
				menuBar = new MyMenuBar(client.getPermissions(), client.getGermanNames());
				editBar = new EditBar();
				signBar = new SignBar();
				finishBar = new FinishBar();
				
				if(!createPanels() || !showPanel("MainMenu")) {
					showPanel("Login");
					//return false;
				}
			}
		}.start();
		return true;
	}

Das auskommentierte "return false;" im zweiten Thread funktioniert logischerweise nicht, weil run den Rückgabetyp void hat. Wie kann ich es trotzdem realisieren, dass meine Login-Methode den Erfolg der Methoden aus dem zweiten Thread zurückgibt?

Grüße
Moltar
 
So wie ich das sehe, brauchst Du eigentlich keine Threads. Eben weil Du nur einen seriellen Ablauf hast. Die ProgressBar im indeterminate-Mode ist ja nur eine graphisches Gimik. Threads brauchst Du erst wenn Du parallel noch etwas anderes machen willst. Und sei es nur den User den Login-Vorgang manuell abbrechen zu lassen. Aber da die ProgressBar anders nicht animiert wird...

Du kannst aus einem Thread ganz normal auf Variablen zugreifen. Also schreib doch einfach die Ergebnisse Deiner Funktionsaufrufe in globale Variablen oder ruf eine Methode auf, die Dir das Ergebnis in Deiner Benutzeroberfläche anzeigt (oder was auch immer Du damit vor hast). Du kannst natürlich auch Deinem Thread-Objekt eine Referenz auf eine Variable (Objekt) übergeben, die es dann manipulieren kann. Wäre sauberer aber auch aufwändiger.

Behalte aber im Hinterkopf, dass Du nie weißt wann der Login-Thread diese Variablen belegt. Es muss ausgeschlossen werden, das der Main-Thread Deines Programmes davor auf sie zugreift. Sollte in diesem Fall aber eigentlich kein Problem darstellen, da Dein Hauptprogramm ja sowieso "hinter" der ProgressBar verschwindet und der User nichts tun kann bis der Login-Thread sich wieder beendet hat.

Grüße
Inter
 
Hallo inter,

danke für deine Hilfe und Antworten :)

Habe die Rückgabewerte entfernt, da in der aufrufenden Funktion sowieso nichts weiter gemacht wird und ich daher den Rückgabewert eigentlich auch nicht brauche.

Grüße
Moltar
 
Zurück