Gui blockiert / friert ein

Jens81

Gesperrter Benutzer
Hallo zusammen,

ich lade größere Datenmengen aus einer Datenbank. Diese Daten bzw. diverse Statistiken werden in der Anwendung angezeigt.

Nun soll der Benutzer die Möglichkeit haben, die geladenen Daten zu aktualisieren. Jetzt das Problem: Realisiere ich das Neu-laden der Daten im Thread, friert die GUI manchmal bzw. öfters ein. Es wird keine Exception geworfen. Hat der GC vielleicht etwas damit zu tun? Oder woran könnte es noch liegen?

Implementiere ich die Funktion ohne Thread, läuft sie immer durch.

Allerdings soll diese Funktion als Thread implementiert werden, damit die restliche GUI nicht blockiert wird.

Da keine Exception geworfen wird, bin ich ziemlich ratlos???:L

Gruß,
Jens
 

Jens81

Gesperrter Benutzer
Insgesamt sind es schon sehr viele Zeilen Code, aber der Aufruf läuft so (Thread auskommentiert):

Java:
	private void ladeModellNeu() {/*
		Thread ladeModellNeuThread = new Thread() {
			@Override
			public void run() {*/
				fenster.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
				DisabledGlassPane glass = new DisabledGlassPane();
				JRootPane rootPane = SwingUtilities.getRootPane(fenster);
				rootPane.setGlassPane(glass);
				glass.activate("Bitte warten...");
				
				ladevorgang = true;
				modell.removeAllItems();
				
				ladeDaten(null);
				
				setContentReiter1();
				setContentReiter2();
				setContentReiter3();
				setContentReiter4();
				setContentReiter5();
				setContentReiter6(true);

				ladevorgang = false;

				glass.deactivate();
				fenster.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));/*
			}
		};
		ladeModellNeuThread.start();*/
	}

PS: Wie gesagt, so auskommentiert läuft alles durch, nur wenn ich den Thread reinnehme geht es öfters nicht...

Mein Verdacht war ursprünglich der Garbage Collector, da ich während des Ladevogangs schon viel Speicher benötige... allerdings kann ich mir den Unterschied zwischen den Versionen mit und ohne Thread nicht erklären
 
Zuletzt bearbeitet:
S

SlaterB

Gast
wenn sowieso ein GlassPane die GUI extra sperrt, wie kannst du dann feststellen, ob sie blockiert oder nicht? ;)

> Wie gesagt, so auskommentiert läuft alles durch, nur wenn ich den Thread reinnehme geht es öfters nicht...

geht was genau nicht?
 

Michael...

Top Contributor
Java:
					fenster.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
				DisabledGlassPane glass = new DisabledGlassPane();
				JRootPane rootPane = SwingUtilities.getRootPane(fenster);
				rootPane.setGlassPane(glass);
				glass.activate("Bitte warten...");
				...
Die Änderungen an der GUI müssen hier raus. In den Thread sollten nur die Änderungen der Daten vorgenommen werden.
 

Jens81

Gesperrter Benutzer
Die GlassPane dient nur dazu, den User vom Drücken irgendwelcher Knöpfe während eines Ladevorgangs abzuhalten.

Mit "die GUI friert ein" meine ich, dass nicht nur das akutelle, sondern alle Fenster nicht mehr bedienbar sind. Öffne ich beispielsweise via Firefox Google und minimiere den Browser, zeigt die Anwendung nicht mehr ihre Oberfläche, sondern den "Rest" vom Browser (bzw. jeder anderen Anwednung die "darüber" liegt)... Ich hoffe es ist klar geworden was ich meine (?)
 

Jens81

Gesperrter Benutzer
@Michael... Ich habe mehrere ähnliche Funktionen mit kleineren Berechnungen, in denen die Änderungen an der GUI (GlassPane) so ohne Probleme liefen. Aber ich werd's testen...

@javimka Manchmal ja, manchmal nein... wenn nicht, dann bleibt es ziemlich am Anfang in der setContentReiter1 stecken. Aber da wird nichts wildes gemacht und auch kein Fehler geworfen
 

Jens81

Gesperrter Benutzer
Da werden nur JTextFields gefüllt...
Java:
private void setContentReiter1() {
		/**
		 * Setzt den geladenen Inhalt für Reiter 1.
		 * - Allgemeine Modellinformationen
		 */
		art.setText(((ItemModell)modell.getSelectedItem()).getArt());
		produktgruppe.setText(((ItemModell)modell.getSelectedItem()).getProduktgruppe());
		ausgangsvariable.setText(((ItemModell)modell.getSelectedItem()).getAusgangsvariable());
		ausgangsvariable.setCaretPosition(0);
		zielvariable.setText(((ItemModell)modell.getSelectedItem()).getZielvariable());
		zielvariable.setCaretPosition(0);
		trainingsdaten.setText(((ItemModell)modell.getSelectedItem()).getTrainingsdaten());
		trainingsdaten.setCaretPosition(0);
...
}
 

Jens81

Gesperrter Benutzer
Die Änderungen an der GUI müssen hier raus. In den Thread sollten nur die Änderungen der Daten vorgenommen werden.

Wieso sollte ich denn hier keine GUI Änderungen reinnehmen? Wie sollte das dann aussehen?
Ist das Setzen von Text in ein JTextField auch schon eine GUI-Änderung?

Ergänzung: Hab die GlassPane und den Mauszeigerwechsel mal deaktiviert und es scheint jetzt durchzulaufen, werd's aber mal in Ruhe testen. Wie gesagt, in anderen Funktionen bin ich ähnlich vorgegangen und da war es nie ein Problem ???:L
 
Zuletzt bearbeitet:

javimka

Top Contributor
Ja, ist es. Modifikationen an der GUI sollten im Event-Dispatching-Thread (EDT) laufen. Um einen Befehl aus einem anderen Thread im EDT ausführen zu lassen, kannst du schreiben
Java:
SwingUtilities.invokeLater(new Runnable() {
  public void run()  {
    // Befehle
  }
});
 

javimka

Top Contributor
Stimmt, setText ist Thread-safe, das wusste ich nicht. Es ist also eine GUI-Änderung, aber die kannst du in jedem Thread aufrufen.
 

Jens81

Gesperrter Benutzer
Ich habe versucht, eure Korrekturen in der Methode umzusetzen und es scheint zu laufen.

Java:
	private void ladeModellNeu() {
		Thread ladeModellNeuThread = new Thread() {
			@Override
			public void run() {
				final DisabledGlassPane glass = new DisabledGlassPane();
				SwingUtilities.invokeLater(new Runnable() {
					public void run()  {
						fenster.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
						JRootPane rootPane = SwingUtilities.getRootPane(fenster);
						rootPane.setGlassPane(glass);
						glass.activate("Bitte warten...");
					}
				});

				ladevorgang = true;
				modell.removeAllItems();
				
				ladeDaten(null);
				
				try {
					SwingUtilities.invokeAndWait(new Runnable() {
						public void run()  {
							setContentReiter1();
							setContentReiter2();
							setContentReiter3();
							setContentReiter4();
							setContentReiter5();
							setContentReiter6(true);
						}
					});
				}
				catch (Exception e) {
					e.printStackTrace();
				} 

				ladevorgang = false;
				
				SwingUtilities.invokeLater(new Runnable() {
					public void run()  {
						glass.deactivate();
						fenster.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
					}
				});
			}
		};
		ladeModellNeuThread.start();
	}
 
G

Gast2

Gast
Wie gesagt ich würde dafür einen SwingWorker nehmen sieht der code ein bischen Übersichtlicher aus =)...
 

Jens81

Gesperrter Benutzer
Im bisherigen Programm ist es ja so, dass ich als erstes ein GlassPane über die Gui lege, dann die Daten lade, die Gui mit den neuen Daten aktualisiere und abschließend die GlassPane wieder deaktiviere.

Wie kann ich denn diesen Ablauf (speziell: GlassPane) in einem SwingWorker abbilden?

Erster Ansatz:

Java:
private void ladeModellNeu() {
		SwingWorker worker = new SwingWorker() {
		
			@Override
			public Object doInBackground() throws Exception {
				ladeDaten(null); //es werden größere Datenmengen geladen
				
				return null; //void geht leider nicht?
			}
			
			@Override
			protected void done(){
				setContentReiter1();
				setContentReiter2();
				setContentReiter3();
				setContentReiter4();
				setContentReiter5();
				setContentReiter6(true);
			}
			
		};
		worker.execute();
}
 
G

Gast2

Gast
Im bisherigen Programm ist es ja so, dass ich als erstes ein GlassPane über die Gui lege, dann die Daten lade, die Gui mit den neuen Daten aktualisiere und abschließend die GlassPane wieder deaktiviere.

Wie kann ich denn diesen Ablauf (speziell: GlassPane) in einem SwingWorker abbilden?

Erster Ansatz:

Java:
private void ladeModellNeu() {
		SwingWorker worker = new SwingWorker() {
		
			@Override
			public Object doInBackground() throws Exception {
				ladeDaten(null); //es werden größere Datenmengen geladen
				
				return null; //void geht leider nicht?
			}
			
			@Override
			protected void done(){
				setContentReiter1();
				setContentReiter2();
				setContentReiter3();
				setContentReiter4();
				setContentReiter5();
				setContentReiter6(true);
			}
			
		};
		worker.execute();
}
Einfach bevor du ihn startest?!
Also vor den SwingWorker
 

Jens81

Gesperrter Benutzer
Aber wenn ich die GlassPane vor und nach dem Worker ausführe, wird sie ja in gar keinem Thread mehr ausgeführt, weder in meinem noch im EDT. ???:L
 
G

Gast2

Gast
Aber wenn ich die GlassPane vor und nach dem Worker ausführe, wird sie ja in gar keinem Thread mehr ausgeführt, weder in meinem noch im EDT. ???:L

Wie wird in gar keinem ausgeführt ^^??? Es wird auf jeden Fall im EDT ausgeführt und da gehört sie hin^^... und wie oben schon gesagt das deactivieren kommt in done

EDIT:

Java:
private void ladeModellNeu() {
      final DisabledGlassPane glass = new DisabledGlassPane();
       fenster.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
        RootPane rootPane = SwingUtilities.getRootPane(fenster);
        rootPane.setGlassPane(glass);
        glass.activate("Bitte warten...");
        SwingWorker worker = new SwingWorker() {
        
            @Override
            public Object doInBackground() throws Exception {
                ladeDaten(null); //es werden größere Datenmengen geladen
                
                return null; //void geht leider nicht?
            }
            
            @Override
            protected void done(){
                setContentReiter1();
                setContentReiter2();
                setContentReiter3();
                setContentReiter4();
                setContentReiter5();
                setContentReiter6(true);
                glass.deactivate();
               //usw. UI SACHEN
            }
            
        };
        worker.execute();
}
 
Zuletzt bearbeitet von einem Moderator:

Jens81

Gesperrter Benutzer
Java:
private void ladeModellNeu() {
		final DisabledGlassPane glass = new DisabledGlassPane();
		fenster.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
		JRootPane rootPane = SwingUtilities.getRootPane(fenster);
		rootPane.setGlassPane(glass);
		glass.activate("Bitte warten...");
		
		SwingWorker worker = new SwingWorker() {
		
			@Override
			public Object doInBackground() throws Exception {
				ladeDaten(null);
				
				return null;
			}
			
			@Override
			protected void done(){
				setContentReiter1();
				setContentReiter2();
				setContentReiter3();
				setContentReiter4();
				setContentReiter5();
				setContentReiter6(true);

				glass.deactivate();
				fenster.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
			}
			
		};
		worker.execute();
}

Edit: Jetzt gehts :)
 
Zuletzt bearbeitet:

Jens81

Gesperrter Benutzer
Hab aber noch eine andere Frage :D

Worin liegt denn der (ablauftechnische) Unterschied zwischen den beiden Verfahren? Lasse ich das Verfahren via SwingWorker laufen, gibt es im setContentReiter6 eine NullPointer Exception (habe noch nicht nach dem Grund gesucht). Dieser wird bei der zweiten Methode (SwingUtilities.invokeAndWait) nciht ausgelöst. Ändere ich die zweite Methode auf SwingUtilities.invokeLater, tritt diese Exception auch auf.

Java:
final DisabledGlassPane glass = new DisabledGlassPane();
		fenster.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
		JRootPane rootPane = SwingUtilities.getRootPane(fenster);
		rootPane.setGlassPane(glass);
		glass.activate("Bitte warten...");
		
		SwingWorker worker = new SwingWorker() {
		
			@Override
			public Object doInBackground() throws Exception {
				ladeDaten(null);
				
				return null;
			}
			
			@Override
			protected void done(){
				setContentReiter1();
				setContentReiter2();
				setContentReiter3();
				setContentReiter4();
				setContentReiter5();
				setContentReiter6(true);
				
				glass.deactivate();
				fenster.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
			}
			
		};
		worker.execute();


Java:
Thread ladeModellNeuThread = new Thread() {
			@Override
			public void run() {
				final DisabledGlassPane glass = new DisabledGlassPane();
				try {
					SwingUtilities.invokeAndWait(new Runnable() {
						public void run()  {
							fenster.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
							JRootPane rootPane = SwingUtilities.getRootPane(fenster);
							rootPane.setGlassPane(glass);
							glass.activate("Bitte warten...");
						}
					});
				} catch (Exception e) {
					e.printStackTrace();
				}

				ladevorgang = true;
				modell.removeAllItems();
				
				ladeDaten(null);
				
				try {
					SwingUtilities.invokeAndWait(new Runnable() {
						public void run()  {
							setContentReiter1();
							setContentReiter2();
							setContentReiter3();
							setContentReiter4();
							setContentReiter5();
							setContentReiter6(true);
						}
					});
				} catch (Exception e) {
					e.printStackTrace();
				} 

				ladevorgang = false;
				
				try {
					SwingUtilities.invokeAndWait(new Runnable() {
						public void run()  {
							glass.deactivate();
							fenster.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
						}
					});
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		};
		ladeModellNeuThread.start();
 
G

Gast2

Gast
Hab aber noch eine andere Frage :D

Worin liegt denn der (ablauftechnische) Unterschied zwischen den beiden Verfahren? Lasse ich das Verfahren via SwingWorker laufen, gibt es im setContentReiter6 eine NullPointer Exception (habe noch nicht nach dem Grund gesucht). Dieser wird bei der zweiten Methode (SwingUtilities.invokeAndWait) nciht ausgelöst. Ändere ich die zweite Methode auf SwingUtilities.invokeLater, tritt diese Exception auch auf.

Java:
final DisabledGlassPane glass = new DisabledGlassPane();
		fenster.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
		JRootPane rootPane = SwingUtilities.getRootPane(fenster);
		rootPane.setGlassPane(glass);
		glass.activate("Bitte warten...");
		
		SwingWorker worker = new SwingWorker() {
		
			@Override
			public Object doInBackground() throws Exception {
				ladeDaten(null);
				
				return null;
			}
			
			@Override
			protected void done(){
				setContentReiter1();
				setContentReiter2();
				setContentReiter3();
				setContentReiter4();
				setContentReiter5();
				setContentReiter6(true);
				
				glass.deactivate();
				fenster.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
			}
			
		};
		worker.execute();


Java:
Thread ladeModellNeuThread = new Thread() {
			@Override
			public void run() {
				final DisabledGlassPane glass = new DisabledGlassPane();
				try {
					SwingUtilities.invokeAndWait(new Runnable() {
						public void run()  {
							fenster.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
							JRootPane rootPane = SwingUtilities.getRootPane(fenster);
							rootPane.setGlassPane(glass);
							glass.activate("Bitte warten...");
						}
					});
				} catch (Exception e) {
					e.printStackTrace();
				}

				ladevorgang = true;
				modell.removeAllItems();
				
				ladeDaten(null);
				
				try {
					SwingUtilities.invokeAndWait(new Runnable() {
						public void run()  {
							setContentReiter1();
							setContentReiter2();
							setContentReiter3();
							setContentReiter4();
							setContentReiter5();
							setContentReiter6(true);
						}
					});
				} catch (Exception e) {
					e.printStackTrace();
				} 

				ladevorgang = false;
				
				try {
					SwingUtilities.invokeAndWait(new Runnable() {
						public void run()  {
							glass.deactivate();
							fenster.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
						}
					});
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		};
		ladeModellNeuThread.start();

Les doch mal die API...
nach dem invokeAndWait warter er... bis das Runnable feritg ist und geht dann erst im Code weiter...
bei invoke schmeißt er das Runnable in eine Queue und geht im Code sofort weiter und fürt die runnables in der Queue nacheinander aus...
 

Jens81

Gesperrter Benutzer
Die API habe ich gelesen und der Unterschied zwischen invokeAndWait und invokeLater ist mir klar. Aber der ablauftechnische Unterschied zwischen den beiden geposteten Code-Schnippseln nicht. Der müsste doch gleich sein ???:L
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
J Swing JMenuItem blockiert JMenuBar AWT, Swing, JavaFX & SWT 2
T SWT Fortschritt, GUI blockiert Abarbeitung AWT, Swing, JavaFX & SWT 0
P Swing GUI noch nicht gezeichnet - Logik läuft - blockiert AWT, Swing, JavaFX & SWT 3
P Event Handling Gedrückte Maus Blockiert MausEvents AWT, Swing, JavaFX & SWT 2
H Gui blockiert AWT, Swing, JavaFX & SWT 8
A JDialog (modal) blockiert alle Fenster! AWT, Swing, JavaFX & SWT 2
V Swing remove(Component) blockiert Thread sehr lange. AWT, Swing, JavaFX & SWT 6
R SWT Statusmeldung im neuen Fenster blockiert aufrufendes Fenster AWT, Swing, JavaFX & SWT 2
J Scheinbar blockiert Swing bei JTree, was mach ich falsch? AWT, Swing, JavaFX & SWT 7
S Listener übergeordneter Componente Blockiert AWT, Swing, JavaFX & SWT 6
C Schweres Problem mit JDialog und Threads! Anzeige blockiert! AWT, Swing, JavaFX & SWT 5
N java Gui friert scheinbar zufällig ein AWT, Swing, JavaFX & SWT 5
Arif Swing Programm friert ein... AWT, Swing, JavaFX & SWT 2
P Frame friert ein AWT, Swing, JavaFX & SWT 6
Q GUI außerhalb GUI-Thread updaten - GUI friert ein AWT, Swing, JavaFX & SWT 18
X JInternalFrame vor Java2D-Zeichnung langsam bzw. Gui friert ein AWT, Swing, JavaFX & SWT 1
J Applet Java-Applet friert mit Firefox ein AWT, Swing, JavaFX & SWT 8
S Swing Problem mit Swing - Fenster friert manchmal ein. AWT, Swing, JavaFX & SWT 7
B GUI "friert ein" AWT, Swing, JavaFX & SWT 8
G GUI friert ein AWT, Swing, JavaFX & SWT 11
J GUI friert ein nur warum? AWT, Swing, JavaFX & SWT 7
P JDialog fenster friert ein beim drücken von button AWT, Swing, JavaFX & SWT 4
X Grafikfenster friert ein AWT, Swing, JavaFX & SWT 2
R Button löst Schleife aus, danach friert die GUI ein ? AWT, Swing, JavaFX & SWT 7

Ähnliche Java Themen


Oben