Java FX Probleme beim Schließen einer Stage

cyrano

Mitglied
Hallo zusammen,

ich habe die folgende Programmstruktur:

Von einem Hauptprogramm rufe ich mehrere Fenster als neue Stages auf, die ich bei Bedarf wieder schließe. Dazu habe ich in der Start-Stage eine Methode mit der ich die Stage-Instanz abrufen kann. Das klappt auch alles super. Wenn ich jetzt ein neues Fenster öffne, sind dort mehrere Controls, für mein Problem sind aber 2 maßgeblich: Der End-Button und eine Combo-Box. Der End-Button ruft eine eigene Methode "endStage" auf, da ich diese Methode auch von anderen Stellen ansprechen will, habe ich sie außerhalb des EventHandlers des Buttons geschrieben und rufe im EventHandler nur diese Methode auf. Auch das klappt problemlos.

Über die Combo-Box stelle ich eine Verbindung über die serielle Schnittstelle her, dann werden ein paar Daten eingelesen, die das angeschlossene Modul sendet und wenn es sich um eine gültiges Modul handelt werden die Konfigurationsdaten dargestellt. Ist kein Modul angeschlossen oder es ist keine gültige Konfiguration, dann soll eine Fehlermeldung ausgegeben werden und das Fenster geschlossen.

Starte ich nun das Programm und ein Konfigurationsfenster und schließe es sofort wieder über den End-Button tritt kein Fehler auf. Wähle ich die Combo-Box an, öffnet sich auch die Schnittstelle und wenn es ein korrektes Modul ist wird die Konfiguration ausgelesen. Ist es aber ein ungültiges Modul und die "endStage"-Methode wird aufgerufen, erhalte ich eine Exception, in der Form:

Java:
Exception in thread "JavaFX Application Thread" java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
	at javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1762)
	at javafx.fxml.FXMLLoader$ControllerMethodEventHandler.handle(FXMLLoader.java:1645)

Irgendwie stehe ich auf dem Schlauch :bahnhof: und mache wohl einen Denkfehler, aber ist es nicht gleichberechtigt, ob ich die endStage-Methode über den Eventhandler vom Button aufrufe oder aus dem Eventhandler der ComboBox?

Hat jemand eine Idee, wo mein Fehler liegen kann? Für alle Tipps schon mal vielen Dank!
 
Poste doch den ganzen StackTrace und nicht nur die ersten zwei Zeilen. Des Weiteren könntest du mal mehr Code zeigen, denn von deiner Denkweise her sehe ich nichts falsches. Eventuell noch ein wenig Code schadet nie.
 
Hallo cyrano,

wie flown es bereits genannt hat, poste bitte den gesamten Stacktrace, alles andere führt nur zu Vermutungen.

Die Zeilen, die du genannt hast tauchen bei mir meistens dann auf, wenn ich irgendwelche FXML-Methoden nicht implementiert habe, obwohl ein Button eine FXML-Methode aufruft. Schau hier doch in diese Richtung nach, ob du da evtl. eine Methode vergessen hast.
 
Oder Eclipse (falls du es nutzt) hat die Änderung am FXML noch nicht mitbekommen und du mußt aktualisieren und dann nochmal dein Programm starten.

Wenn ich mit SceneBuilder arbeite hab ich immer die FXML in Eclipse auch offen und nach dem Speichern im SceneBuilder reicht dann normal ein Klick in die FXML-Datei bei Eclipse, damit es aktualisiert wird.
 
Zuletzt bearbeitet:
Hallo... erstmal schon mal vielen Dank für Eure Bemühungen und hier ist auch der komplette Stack-Trace (zumindest so viel, wie mir angezeigt wird):

Code:
Exception in thread "JavaFX Application Thread" java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
	at javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1770)
	at javafx.fxml.FXMLLoader$ControllerMethodEventHandler.handle(FXMLLoader.java:1653)
	at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
	at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
	at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
	at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
	at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
	at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
	at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
	at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
	at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
	at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
	at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
	at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:49)
	at javafx.event.Event.fireEvent(Event.java:198)
	at javafx.scene.Node.fireEvent(Node.java:8390)
	at com.sun.javafx.scene.control.skin.ComboBoxListViewSkin.handleControlPropertyChanged(ComboBoxListViewSkin.java:256)
	at com.sun.javafx.scene.control.skin.BehaviorSkinBase.lambda$registerChangeListener$61(BehaviorSkinBase.java:197)
	at com.sun.javafx.scene.control.skin.BehaviorSkinBase$$Lambda$149/25657206.call(Unknown Source)
	at com.sun.javafx.scene.control.MultiplePropertyChangeListenerHandler$1.changed(MultiplePropertyChangeListenerHandler.java:55)
	at javafx.beans.value.WeakChangeListener.changed(WeakChangeListener.java:89)
	at com.sun.javafx.binding.ExpressionHelper$Generic.fireValueChangedEvent(ExpressionHelper.java:361)
	at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81)
	at javafx.beans.property.ObjectPropertyBase.fireValueChangedEvent(ObjectPropertyBase.java:105)
	at javafx.beans.property.ObjectPropertyBase.markInvalid(ObjectPropertyBase.java:112)
	at javafx.beans.property.ObjectPropertyBase.set(ObjectPropertyBase.java:146)
	at javafx.scene.control.ComboBoxBase.setValue(ComboBoxBase.java:150)
	at javafx.scene.control.ComboBox.updateValue(ComboBox.java:471)
	at javafx.scene.control.ComboBox.access$300(ComboBox.java:187)
	at javafx.scene.control.ComboBox$4.changed(ComboBox.java:454)
	at com.sun.javafx.binding.ExpressionHelper$Generic.fireValueChangedEvent(ExpressionHelper.java:361)
	at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81)
	at javafx.beans.property.ReadOnlyObjectWrapper$ReadOnlyPropertyImpl.fireValueChangedEvent(ReadOnlyObjectWrapper.java:176)
	at javafx.beans.property.ReadOnlyObjectWrapper.fireValueChangedEvent(ReadOnlyObjectWrapper.java:142)
	at javafx.beans.property.ObjectPropertyBase.markInvalid(ObjectPropertyBase.java:112)
	at javafx.beans.property.ObjectPropertyBase.set(ObjectPropertyBase.java:146)
	at javafx.scene.control.SelectionModel.setSelectedItem(SelectionModel.java:102)
	at javafx.scene.control.ComboBox$ComboBoxSelectionModel.lambda$new$154(ComboBox.java:502)
	at javafx.scene.control.ComboBox$ComboBoxSelectionModel$$Lambda$72/16281768.invalidated(Unknown Source)
	at com.sun.javafx.binding.ExpressionHelper$SingleInvalidation.fireValueChangedEvent(ExpressionHelper.java:137)
	at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81)
	at javafx.beans.property.ReadOnlyIntegerWrapper$ReadOnlyPropertyImpl.fireValueChangedEvent(ReadOnlyIntegerWrapper.java:176)
	at javafx.beans.property.ReadOnlyIntegerWrapper.fireValueChangedEvent(ReadOnlyIntegerWrapper.java:142)
	at javafx.beans.property.IntegerPropertyBase.markInvalid(IntegerPropertyBase.java:113)
	at javafx.beans.property.IntegerPropertyBase.set(IntegerPropertyBase.java:147)
	at javafx.scene.control.SelectionModel.setSelectedIndex(SelectionModel.java:68)
	at javafx.scene.control.SingleSelectionModel.updateSelectedIndex(SingleSelectionModel.java:215)
	at javafx.scene.control.SingleSelectionModel.select(SingleSelectionModel.java:149)
	at com.sun.javafx.scene.control.skin.ComboBoxListViewSkin.lambda$createListView$321(ComboBoxListViewSkin.java:695)
	at com.sun.javafx.scene.control.skin.ComboBoxListViewSkin$$Lambda$161/21503894.invalidated(Unknown Source)
	at com.sun.javafx.binding.ExpressionHelper$Generic.fireValueChangedEvent(ExpressionHelper.java:349)
	at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81)
	at javafx.beans.property.ReadOnlyIntegerWrapper$ReadOnlyPropertyImpl.fireValueChangedEvent(ReadOnlyIntegerWrapper.java:176)
	at javafx.beans.property.ReadOnlyIntegerWrapper.fireValueChangedEvent(ReadOnlyIntegerWrapper.java:142)
	at javafx.beans.property.IntegerPropertyBase.markInvalid(IntegerPropertyBase.java:113)
	at javafx.beans.property.IntegerPropertyBase.set(IntegerPropertyBase.java:147)
	at javafx.scene.control.SelectionModel.setSelectedIndex(SelectionModel.java:68)
	at javafx.scene.control.MultipleSelectionModelBase.select(MultipleSelectionModelBase.java:395)
	at javafx.scene.control.MultipleSelectionModelBase.clearAndSelect(MultipleSelectionModelBase.java:348)
	at javafx.scene.control.ListView$ListViewBitSetSelectionModel.clearAndSelect(ListView.java:1400)
	at com.sun.javafx.scene.control.behavior.CellBehaviorBase.simpleSelect(CellBehaviorBase.java:260)
	at com.sun.javafx.scene.control.behavior.CellBehaviorBase.doSelect(CellBehaviorBase.java:224)
	at com.sun.javafx.scene.control.behavior.CellBehaviorBase.mousePressed(CellBehaviorBase.java:150)
	at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(BehaviorSkinBase.java:95)
	at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(BehaviorSkinBase.java:89)
	at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:218)
	at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
	at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
	at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
	at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
	at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
	at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
	at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
	at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
	at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
	at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
	at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
	at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
	at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
	at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
	at javafx.event.Event.fireEvent(Event.java:198)
	at javafx.scene.Scene$MouseHandler.process(Scene.java:3758)
	at javafx.scene.Scene$MouseHandler.access$1500(Scene.java:3486)
	at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1762)
	at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2495)
	at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:350)
	at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:275)
	at java.security.AccessController.doPrivileged(Native Method)
	at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$350(GlassViewEventHandler.java:385)
	at com.sun.javafx.tk.quantum.GlassViewEventHandler$$Lambda$241/29794786.get(Unknown Source)
	at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:404)
	at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:384)
	at com.sun.glass.ui.View.handleMouseEvent(View.java:555)
	at com.sun.glass.ui.View.notifyMouse(View.java:927)
	at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
	at com.sun.glass.ui.win.WinApplication.lambda$null$145(WinApplication.java:101)
	at com.sun.glass.ui.win.WinApplication$$Lambda$36/17230114.run(Unknown Source)
	at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.reflect.InvocationTargetException
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:497)
	at sun.reflect.misc.Trampoline.invoke(MethodUtil.java:71)
	at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:497)
	at sun.reflect.misc.MethodUtil.invoke(MethodUtil.java:275)
	at javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1765)
	... 97 more
Caused by: java.util.ConcurrentModificationException
	at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901)
	at java.util.ArrayList$Itr.next(ArrayList.java:851)
	at com.sun.javafx.tk.quantum.GlassStage.windowsSetEnabled(GlassStage.java:166)
	at com.sun.javafx.tk.quantum.WindowStage.setVisible(WindowStage.java:441)
	at javafx.stage.Window$9.invalidated(Window.java:860)
	at javafx.beans.property.BooleanPropertyBase.markInvalid(BooleanPropertyBase.java:109)
	at javafx.beans.property.BooleanPropertyBase.set(BooleanPropertyBase.java:144)
	at javafx.stage.Window.setShowing(Window.java:910)
	at javafx.stage.Window.hide(Window.java:935)
	at usmCockpitFX.CupidREL2Controller.endStage(CupidREL2Controller.java:175)
	at usmCockpitFX.CupidREL2Controller.cBoxAction(CupidREL2Controller.java:204)
	... 107 more

Und hier ist der Code, den ich durch das ComboBox-Event ausführen lasse:

Java:
@FXML
    private void cBoxAction(ActionEvent event)
    {
        sCOM = cbCOMselect.getSelectionModel().getSelectedItem();
        myPort.open(sCOM);
          
        thisStage.setTitle("USM Cupid REL2 an: " + sCOM);
        idProductPicture.setOpacity(1.0);
        butGetConfig.setDisable(false);
        butSendConfig.setDisable(false);
        butReset.setDisable(false);
        
        myPort.write("c");
        
        try {
            Thread.sleep(150);
        } catch (InterruptedException ex) {
            Logger.getLogger(StartUSMController.class.getName()).log(Level.SEVERE, null, ex);
        }
        sConfig = myPort.getsHexConfig(); 
        
        if (!(sConfig.substring(2,4).equals("0A")))
        {
//            Alert alert = new Alert(Alert.AlertType.WARNING);
//            alert.setContentText(sConfig);
//            alert.showAndWait();
            endStage();
        }
        
        olMode = FXCollections.observableArrayList("Undefiniert", "Alternierend", "Stromstoß");
        
        olInput = FXCollections.observableArrayList("Pull-Up", "Pull-Down");
        modeID.setItems(olMode);
        inputRA.setItems(olInput);
        inputRB.setItems(olInput);
    }

Wie Ihr sehen könnt, öffne ich einfach nur die Schnittstelle (nicht verwirren lassen, myPort ist eine Instanz einer eigenen Wrapper-Klasse für den seriellen Port). Ich schicken mit "myPort.write()" ein Kommando zum Lesen der Konfiguration, warte ein bißchen, damit das Modul auch antworten kann und werte den Konfigurations-String aus. Wenn der Part für die Modul-ID nicht stimmt (in diesem Fall sollte sie 0A sein, dann wird eine Fehlermeldung ausgegeben und die Stage geschlossen. Die Methode endStage() wird auch von meinem Ende-Button aufgerufen und dort läuft alles fehlerfrei.

Jetzt kommt das Seltsame: Zunächst hatte ich die Fehlermeldung über JOptionPane.showMessageDialog() ausgegeben. Die Abfrage funktioniert, das Programm springt also im Fehlerfall in die Ausgabe, schließt auch die Stage aber ich erhalte eben die oben aufgeführte Exception. Dann habe ich die Ausgabe mal weg gelassen, weil ich beim Mischen von Swing und JavaFX immer etwas Bedenken habe. Aber es bleibt bei der Fehlermeldung. Dann las ich, dass seite 1.8_45 eine Alert-Funktion gibt. Da ich die eh vermisste, habe ich das neue JDK heruntergeladen und die Alert wie oben aufgeführt genutzt und siehe da, es läuft ohne Probleme. Als Gegenprobe habe ich dann die Ausgabe noch mal auskommentiert, aber jetzt tritt der Fehler wieder auf.

Wenn ich also von vornherein mit Alert gearbeitet hätte, wäre der Fehler nie aufgetreten, aber mich interessiert natürlich trotzdem weiterhin der Grund für das Verhalten.
 
Dein Problem ist, dass du irgendwo eine ArrayList verwendest denn dein eigentliches Problem ist das hier:

Code:
Caused by: java.util.ConcurrentModificationException

Was passiert denn in der endStage? Versuch doch nach dem Methodenaufruf endStage ein return einzufügen.
 
Hallo Flown,

vielen Dank für Deine Antwort. Mir dämmert da langsam etwas. Als ich die Wrapper-Klasse für die rxtx-Bibliothek geschrieben habe, musste ich eine Enumeration, die in rxtx für die Schnittstellen-Einträge erzeugt wird in eine ObservableList wandeln. Ich kann mich auch erinnern, dass mir Eclipse damals einen Fehler anzeigte, da ich aber fast nur in Netbeans arbeite, hatte ich das nicht weiter berücksichtigt, dort gab es nämlich keine Fehlermeldung. Die Konvertierung hatte ich damals wie folgt vorgenommen (die jetzt auskommentierten Zeilen waren bis vorhin noch aktiv, in der 3. Zeile stand dann anstelle von "...FXCollections.observableArrayList()" -> "...FXCollections.observableList(list)"die :

Java:
 public ObservableList<String> getCOMobList()
    {
//        List<String> list;
//        list = new ArrayList();
        ObservableList<String> olCOMList = FXCollections.observableArrayList();
        Enumeration portList;

        portList = CommPortIdentifier.getPortIdentifiers();

        while (portList.hasMoreElements()) {
            serialPortId = (CommPortIdentifier) portList.nextElement();
            if (serialPortId.getName().substring(0,3).equals("COM"))   
                olCOMList.add(serialPortId.getName());
        }
        return olCOMList;
    }

Nach Deinem Tipp habe ich mich auf die Suche nach einem ArrayList gemacht und eben diese Stelle gefunden. Ich habe sie jetzt in die Version mit den Kommentaren geändert, um das ArrayList zu umgehen. Nachdem Neuübersetzen der Bibliothek und des Programms kommt aber genau die gleiche Fehlermeldung. 🙁

Die endStage-Methode ist nicht sehr aufwendig:

Java:
 private void endStage()
    {
        if (myPort.getIsOpen()== true)
            myPort.close();
        thisStage = StartUSMController.getStage();
        thisStage.hide();
    }

Deinen Hinweis mit dem return habe ich nicht ganz verstanden. Wohin sollte ich den Aufruf setzen und welchen Wert soll ich "returnen".

Was mich auch total verwirrt ist die Tatsache, dass die Exception nur dann auftritt, wenn ich die Alert-Meldung vorher nicht ausgebe :bahnhof:
 
Probiers doch mit:

Java:
if (!(sConfig.substring(2,4).equals("0A"))) {
  endStage();
  return;
}
 
Hab ich mal probiert, aber es ändert sich nichts. Kann denn return() überhaupt noch erreicht werden? In endStage() schließe ich ja diese Stage in der sich dann der return() Aufruf befindet?
 
Klar erreichst du das. So in weiterer Folge fällt mir jetzt nichts ein, was etwas haben könnte.
Eine ConcurrentModificationException ist, wenn du über etwas iterierst und während dessen etwas gelöscht wird (extern und nicht vom Iterator).
 
Ich benutze für meine Dialoge auch eine eigene Stage, die schließe ich aber anders:

Code:
((Stage)ctrlSplash.getScene().getWindow()).close();

ctrlSplash ist dabei meine Parent-Node (BorderPane ect.), aber man kann auch irgendeine andere Node nehmen (Button, ImageView, etc). Braucht man ja nur, um die Scene zu bekommen.

Und mit den Zuweisungen der Art
Code:
olMode = FXCollections.observableArrayList("Undefiniert", "Alternierend", "Stromstoß");
olInput = FXCollections.observableArrayList("Pull-Up", "Pull-Down");
hatte ich auch schon Probleme.

Ich hab mir jetzt angewöhnt, beim init die Observable's leer zu initialisieren und beim Füllen bzw. Ändern mache ich immer ein obs.clear() und dann obs.addAll() z.B. Weiß aber gerade nicht mehr, was das Problem war. Glaub die TableView wurde ansonsten nicht aktualisiert.
 
ob ich die endStage-Methode über den Eventhandler vom Button aufrufe oder aus dem Eventhandler der ComboBox?

Evtl. macht das auch keinen Unterschied ... teste es aus, in deiner geposteten Methode machst du deutlich mehr:

Java:
@FXML
private void cBoxAction(ActionEvent event)
{
    endStage();
}
 

Zurück
Oben