UI Refresh Problem

Also, ich habe eine swing GUI, die dies und jenes macht, mein Problem betrifft aber folgendes:

da ist ein Label für eine Statusnachricht
und ein Button (Start) der ein Script ausführt, dieses wird mit einem ProcessBuilder.waitFor() ausgeführt, so dass die GUI schön wartet bis das Script fertig ist, bevor der Benutzer wieder rumklicken kann.
Soweit so gut funktioniert alles wie es soll, bis auf die Sache mit der Statusmeldung.

Ursprungszustand: label ist leer
Nach erstem Ausführen vom Script: label.setText(“ausgeführt”)
wenn ich jetzt aber wieder auf Start klicke, soll der Statustext wieder leer sein, was nicht passiert.

Folgender code: Button “Start” actionPerformed

        statuslabel.setText("");

	jPanelPatient.revalidate();

	tabellenzeile = jtFormate.getSelectedRow();

	anzahlscans++;
	aufloesung = jtFormate.getValueAt(tabellenzeile, 1).toString();
	x = aufloesung.substring(0, 3);
	y = aufloesung.substring(4, 7);

	dateiname = txtDateiname.getText();
	f = new File(speicherort);

	startScript();

	statuslabel.setText("script ausgeführt");

und startScan

    private void startScan(String jardir, String device, String patnu, String praxis, String x, String y,
	    String speicherort, String dateiname, String bildbetrachter, String mode) {
	String script = jardir + "/start_sane.sh";
	String[] shellcom = {script, device, patnu, praxis, x, y, speicherort, dateiname, mode};
	System.out.println("start Scan: " + script + " " + device + " " + patnu + " " + praxis + " "
		+ x + " " + y + " " + speicherort + " " + dateiname + " " + bildbetrachter + " " + mode);
	try {
	    new ProcessBuilder(shellcom).start().waitFor();
	    System.out.println("scannen fertig");
	} catch (IOException | InterruptedException ex) {
	    javax.swing.JOptionPane.showMessageDialog(null, ex, "Exception", 0);
	    Logger.getLogger(Fct_SCAN.class.getName()).log(Level.SEVERE, null, ex);
	}
    }

Wenn ich das .waitFor() aus Zeile 7 der startScan() Methode rausnehme, aktualisiert die GUI wie erwünscht, auch ohne das revalidate().

Die Frage ist, was muss ich tun, damit die GUI aktualisiert wird, bevor startScan ausgeführt wird.

Den Prozess im EDT auszuführen und diesen (somit auch die GUI) mittels waitFor zu blockieren ist für den Anwender nicht gerade schön (Anwendung wirkt auf Anwender eingefroren, GUI wird nicht korrekt dargestellt…).
Und in Deinem Fall blockierst Du Dich auch noch selbst. Überlege Dir lieber einen Mechanismus, der vor dem Ausführen des Prozesses z.B. Buttons disabled und führe den Prozess in einem separaten Thread aus. Dann klappt es auch mit der Aktualisierung des Textes in der Statuszeile.

Benötigt dein Skript eventuell noch ein Enter nachdem es durchgelaufen ist und auf das das waitFor vergeblich wartet?

@ bERt0r nein, wie gesagt funktioniert ja alles wie es soll, die GUI ist nur so lange “gesperrt” bis das Script fertig ist, dann kann man problemlos weiter rumklicken (und wieder ausführen)

@ Michael tja das mit dem Sperren ist aber Kundenwunsch, ich könnte zwar jetzt auch einfach alle Komponenten deaktivieren, nur ist es leider nicht nur der Start-Button, das .waitFor() erschien mir da sehr einfach und schnell :). Ich kann zwar über die Panel Container alles recht sauber und schnell abschalten und beim Script auf einen Erfolgsreturn warten und dann wieder alels aktivieren, aber das waitFor() erscheint mir da echt ersteinmal eleganter. Gibt es sonst nichts? (Wenn ich auch nur Ansatzweise eine Idee hätte wie ich es sonst angehen könnte, hätte ich es gesagt)

Kundenwunsch “sperren” ist ja etwas anderes, als die GUI der Anwendung zu blockieren. Weiß nicht, ob der Kunde es toll findet wenn er bei längeren Prozessen nur noch ein graues Fenster sieht.

Prinzipiell könnte alle Komponenten die zeitweise deaktiviert und wieder aktiviert werden sollen in einer Liste halten dann muss man vor und nach dem Process nur über die Liste iterieren.

Eine einfache Alternative, wäre eine GlassPane (evtl. teiltransparent, so dass der Anwender auch optisch erkennen kann, das die GUI gesperrt ist) über den Frame zu legen und alle MouseEvents abzufangen.

In dem Fall sagt meine Glaskugel dass deine startScan Methode auf dem EDT läuft (z.B in einem ActionListener) und ihn dadurch blockiert. Du musst die in einen eigenen Thread packen.

@ Michael man kann immernoch das Fenster verschieben und schließen, es ist icht grau oder so, nur sind die ganzen Steuerelemente “gesperrt” was ja sein soll (aber statt ausgegraut wie per setEnabled(false), nur nicht anklickbar). Das mit der Liste funktioniert auch nicht.

@ bERt0r Ok, hoffte das mit dem neuen Thread umgehen kann, wurde wohl Nichts. Die Steuerelemente musste ich zwar nu zu Fuß deaktivieren und sie anschließend wieder aktivieren, war ja aber nicht gerade aufwendig, funktioniert also alles wie gewünscht.

class Scan implements Runnable {
     public Scan() {
		
     }

     public void run() {
           Fct_SCAN clsFS = new Fct_SCAN();
           clsFS.startScan(scanjardir, scannerdevice, patnu, praxis, x, y, speicherort, dateiname, 
                      bildbetrachter, mode, frmMain);
     }
}
Thread t = new Thread(new Scan());
t.start();

“Scan” ist eine innere Klasse im ActionEvent des JButtons, kann man es so lassen, oder doch lieber eine eigene “äußere” Klasse?

Warum sollte das mit der Liste nicht funktionieren? Das Deaktivieren muss natürlich im EDT und nicht im ProcessBuilder Thread passieren.
Sofern die Scan Klasse für “aussenstehende” nicht interessant ist kann sie durchaus eine innere Klasse bleiben.

Es geht (ging) nicht als es nur den EDT gab, jetzt wo ich den ProcessBuilder in einen anderen Thread ausgelagert habe, geht es ja. Da würde wohl auch das mit der Liste gehen, ist aber überflüssig (habe einfach die Mutter aller Panele disabled ^^).