JavaFX Wiederholen einer IF-Abfrage beim erneuten Öffnen einer Stage

missy72

Bekanntes Mitglied
Hallo zusammen,
meine grauen Zellen sind mal wieder überstrapaziert.
Diesmal brauche ich kein Code, sondern eine Strategie.

- Ich habe eine MainStage mit zwei Imageview.
- Das erste ImageView soll "clickbar" sein und öffnet eine SecondStage und schließt die MainStage.
Nach Abarbeitung übergibt die SecondStage eine Liste und wird geschlossen. Gleichzeitig wird die MainStage wieder geöffnet.
- Das zweite ImageView soll zunächst inaktiv sein, was ich optisch untermale.

Erst, wenn die Liste aus der SecondStage nicht "null" ist, soll das ImageView und die EventHandler aktiv werden, auch wieder mit einer erkennbaren Visualisierung.

Ich habe die Grafik und die EventHandler über eine If-Abfrage gesteuert. Diese wird ja nur abgefragt, wenn ich die MainStage erstelle.
Beim erneuten Öffnen, mach ich ja da weiter, wo ich die Stage verlassen habe und die If-Abfrage wird nicht erneut durchlaufen.

Als Lösung kommt mir in den Sinn, dass ich die MainStage jedes Mal neuzuerstellen.
Kann man das so lösen und müll ich dadurch den Speicher nicht zu, odergibt es hierfür einen besseren Ansatz?

Gruß MB

PS: Das Problem mit dem Eventhandler ist gelöst. Man muss ja nur die Abfrage um eine "&& Listegefüllt"-Anweisung erweitern.
Bleibt das Problem mit der Grafik.

Java:
        callZeitFahrenIV.setOnMouseClicked(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent event) {
                if (event.getClickCount()==1 && (application.MainModel.mainStarterListe != null)) {  
                ...


1614549551487.png
 
Zuletzt bearbeitet:
Hallo zusammen,
meine grauen Zellen sind mal wieder überstrapaziert.
Diesmal brauche ich kein Code, sondern eine Strategie.

- Ich habe eine MainStage mit zwei Imageview.
- Das erste ImageView soll "clickbar" sein und öffnet eine SecondStage und schließt die MainStage.
Nach Abarbeitung übergibt die SecondStage eine Liste und wird geschlossen. Gleichzeitig wird die MainStage wieder geöffnet.
- Das zweite ImageView soll zunächst inaktiv sein, was ich optisch untermale.

Erst, wenn die Liste aus der SecondStage nicht "null" ist, soll das ImageView und die EventHandler aktiv werden, auch wieder mit einer erkennbaren Visualisierung.

Ich habe die Grafik und die EventHandler über eine If-Abfrage gesteuert. Diese wird ja nur abgefragt, wenn ich die MainStage erstelle.
Beim erneuten Öffnen, mach ich ja da weiter, wo ich die Stage verlassen habe und die If-Abfrage wird nicht erneut durchlaufen.

Als Lösung kommt mir in den Sinn, dass ich die MainStage jedes Mal neuzuerstellen.
Kann man das so lösen und müll ich dadurch den Speicher nicht zu, odergibt es hierfür einen besseren Ansatz?

Gruß MB

PS: Das Problem mit dem Eventhandler ist gelöst. Man muss ja nur die Abfrage um eine "&& Listegefüllt"-Anweisung erweitern.
Bleibt das Problem mit der Grafik.

Java:
        callZeitFahrenIV.setOnMouseClicked(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent event) {
                if (event.getClickCount()==1 && (application.MainModel.mainStarterListe != null)) { 
                ...


Anhang anzeigen 15005
Brauchst du dafür wirklich eine neue Stage?

Ich benutze in der Regel immer nur eine Stage und benutze stattdessen ein StackPane mit zwei Panes (e.g. BorderPane), je nachdem was gewünscht ist, kannst du das passene Pane#toFront machen.
 
Ich favorisiere auch eher den von @lam_tr Weg beschriebenen Weg. Es ist für Nutzer reichlich nervig, wenn ständig Fenster auf und zu gehen.

Grundsätzlich aber haben Stages eine #hide-Methode, die könnte man für so was verwenden - du darfst die Main Stage halt nicht komplett beerdigen und musst ausserdem möglicherweise implicit exit deaktivieren (bin da jetzt bewusst vage, weil ich so noch nie eine Oberfläche gestaltet habe).
 
Eine weitere Variante könnte sein, dass man beim Klick
- das Fenster versteckt
- die neue Stange mit showAndWait() zeigt
- danach das Fenster wieder anzeigt und halt macht, was gemacht werden soll.



Das macht die Abläufe ggf etwas einfacher und übersichtlicher. Aber ich würde auch die andere Lösung bevorzugen ....
 
Brauchst du dafür wirklich eine neue Stage?

Ich benutze in der Regel immer nur eine Stage und benutze stattdessen ein StackPane mit zwei Panes (e.g. BorderPane), je nachdem was gewünscht ist, kannst du das passene Pane#toFront machen.
Übrigens wenn du StackPane nicht magst, man kann es auch über BorderPane#setCenter machen.
 
Vielen Dank, für die Rückmeldungen.
Mag sein, dass es besser Ansätze gibt. Ich möchte erstmal genau dazu eine Lösung finden um halt besser Java zu verstehen.
Dabei sehe ich in meiner Programmstruktur wesentliche Defizite. Dazu werde ich aber noch einen separaten Beitrag erstellen.

Ich habe jetzt an dem Problem noch ein bisschen gesessen. Dabei ist die Stage gar nicht das Problem.
Vielleich sollte ich noch erwähnen, dass ich den Aufbau der Stages über mehre FXML-Datein und ihre Controller steuere.
Also hatte ich vor das ImageView aus einer anderen Klasse heraus mit einem anderen Effect zu überschreiben.
Dabei wollte ich das Objekt "@FXML private ImageView callZeitFahrenIV;" mit static declarieren. Dann bekomme ich aber die Fehlermeldung,
dass das Objekt gleich null ist.

Anbei ein Mini-Programm mit meinem Problem.
iconB ist erst inaktiv. Mit iconA öffne ich ein neues Fenster.
Beim Clicken des Button wird die LISTE gefüllt und das neue Fenster geschlossen. Parallel öffnet sich wieder die MainStage.
Jetzt ist iconB durch die If-Anweisung zwar aktiv, aber der Button soll einen anderen Effect bekommen.

[CODE lang="java" title="MainForum.java"]package application;

import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.effect.ColorAdjust;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Pane;


public class MainForum extends Application implements Initializable {

@FXML private ImageView imageA;
@FXML private ImageView imageB;

public static Stage mainStage = new Stage();
public static Stage secondStage = new Stage();
public static String LISTE = null;

@Override
public void start(Stage primaryStage) {
try {

Pane mainRoot;
mainRoot = FXMLLoader.load(getClass().getResource("/application/mainforum.fxml"));
Scene mainScene = new Scene(mainRoot);
mainStage.setScene(mainScene);
mainStage.show();

} catch(Exception e) {
e.printStackTrace();
}
}

public static void main(String[] args) {
launch(args);
}

@Override
public void initialize(URL location, ResourceBundle resources) {

ColorAdjust swColorAdjust = new ColorAdjust();
swColorAdjust.setSaturation(-1);
ColorAdjust colorAdjust = new ColorAdjust();
colorAdjust.setSaturation(0);

imageA.setEffect(colorAdjust);
imageB.setEffect(swColorAdjust);

imageA.setOnMouseClicked(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
if (event.getClickCount()==1) {
try {

Pane secondRoot;
secondRoot = FXMLLoader.load(getClass().getResource("/application/secondstage.fxml"));

Scene secondScene = new Scene(secondRoot);
secondStage.setScene(secondScene);
mainStage.close();
secondStage.show();

} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
});

imageB.setOnMouseClicked(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
if (event.getClickCount()==1 && (LISTE != null)) {
Platform.exit();
}
}
});

}
}[/CODE]
[CODE lang="java" title="mainforum.fxml"]<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.AnchorPane?>


<AnchorPane prefHeight="200.0" prefWidth="300.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/15.0.1" fx:controller="application.MainForum">
<children>
<ImageView fx:id="imageA" fitHeight="150.0" fitWidth="200.0" layoutX="51.0" layoutY="50.0" pickOnBounds="true" preserveRatio="true" AnchorPane.leftAnchor="20.0" AnchorPane.topAnchor="20.0">
<image>
<Image url="@../../../RSV23_Zeitnahme/src/data/Icon_Hilfe.png" />
</image>
</ImageView>
<ImageView fx:id="imageB" fitHeight="150.0" fitWidth="200.0" layoutX="219.0" layoutY="39.0" pickOnBounds="true" preserveRatio="true" AnchorPane.rightAnchor="20.0" AnchorPane.topAnchor="20.0">
<image>
<Image url="@../../../RSV23_Zeitnahme/src/data/Icon_Hilfe.png" />
</image>
</ImageView>
</children>
</AnchorPane>[/CODE]
[CODE lang="java" title="SeconStageController.java"]package application;

import java.net.URL;
import java.util.ResourceBundle;

import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.input.MouseEvent;

public class SecondStageController implements Initializable {

@FXML private Button buttonA;


@Override
public void initialize(URL arg0, ResourceBundle arg1) {

buttonA.setOnMouseClicked(new EventHandler<MouseEvent>() {

@Override
public void handle(MouseEvent event) {
MainForum.LISTE = "Liste gefüllt";
MainForum.mainStage.show();
MainForum.secondStage.close();
}
});
}
}[/CODE]
[CODE lang="java" title="secondstage.fxml"]<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.AnchorPane?>


<AnchorPane prefHeight="200.0" prefWidth="300.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/15.0.1" fx:controller="application.SecondStageController">
<children>
<Button fx:id="buttonA" layoutX="62.0" layoutY="88.0" mnemonicParsing="false" text="Liste füllen und Fenster schließen" AnchorPane.bottomAnchor="80.0" AnchorPane.leftAnchor="50.0" AnchorPane.rightAnchor="50.0" AnchorPane.topAnchor="80.0" />
</children>
</AnchorPane>
[/CODE]
 
Ich hoffe ich langweile euch noch nicht mit diesem Thema.
Mittlerweile ist der Beitragsname auch nicht mehr ganz so passend.
Ich hatte schon mal was von einem ChangeListener gehört und wollte diesen auf die ObservableList anwenden.
Beim Programmstart ist die Liste = null, erst wenn die Liste != null, soll das ImageView einen neuen Effect bekommen.
Jetzt scheint der Listener keine Inhalte mit null zu akzeptieren.

Cannot invoke "javafx.collections.ObservableList.addListener(javafx.collections.ListChangeListener)" because "application.MainModel.mainStarterListe" is null

Vielleicht ist der Code an der Stelle falsch, oder unvollständig. Wäre nett, wenn jemand noch mal was dazu sagen könnte.
Java:
        MainModel.mainStarterListe.addListener(new ListChangeListener<Fahrer>(){
            @Override
            public void onChanged(Change<? extends Fahrer> arg0) {
             
                callZeitFahrenIV.setScaleX(.9);
                callZeitFahrenIV.setScaleY(.9);
                callZeitFahrenIV.setEffect(colorAdjust);            
            }        
        });
 
Der ChangeListener bezieht sich auf eine Instanz. Wenn die Instanz sich ändert, dann wird über einen ChangeListener informiert.

Das bedeutet, es muss eine Instanz geben. Die Liste kann leer sein. Aber nur wenn Du eine leere Liste hast, dann kann da jemand etwas rein tun, so dass Du dann informiert wirst.

Du musst also diese mainStarterListe auf eine leere Liste setzen. Die Liste wird dann auch nie ersetzt! Du kannst diese leeren (clear() Aufruf) oder einzelne Elemente hinzufügen / entfernen ... aber du darfst die Liste auch nie ersetzen.
 
Hab ich das richtig verstanden. Meine Liste ist in eine weitere Liste packen und die neue Liste dann mit dem Listener überwachen?
Und da die neue Liste einen leeren Inhalt hat, ist diese nicht null.
 
Habe jetzt so einiges probiert. Leider reicht mein Verständnis von Java hier nicht aus.
@kneitzel kannst du mir mit einem Code-Beispiel aushelfen?
Danke....

Scheint totaler Blödsinn zu sein. monitorFahrerList ist auch [null].
Java:
        ObservableList<ObservableList<Fahrer>> monitorFahrerList;
        monitorFahrerList = FXCollections.observableArrayList();
        monitorFahrerList.add(MainModel.mainStarterListe);
        System.out.println(monitorFahrerList);
 
Zuletzt bearbeitet:
Nein, du wirst doch irgend einen Code haben, der mainStarterListe eine Liste zuweist. Ich habe aber bisher aber keinerlei Code gesehen, der mir zeigt, von welchem Typ diese Variable ist und wo und wie Du diese initialisierst....

Also Du hast von mir aus sowas:
ObservableList<String> mainStarterListe = FXCollections.observableArrayList();

Die Instanzvariable wird direkt initialisiert. Damit ist diese nie null. Das behebt den Fehler mit dem ChangeListener aber auch frühere Checks auf null werden dann sinnlos. Du musst also ggf. noch mehr anpassen.

Weitere Zuweisungen gibt es zu der Variable nicht! Die Instanz wird nie ersetzt.

Statt dessen kannst Du die Methoden dieser List nutzen, um Elemente hinzu zu fügen oder zu entfernen.
 
[CODE lang="java" title="Also Du hast von mir aus sowas: Ob"]ObservableList<String> mainStarterListe = FXCollections.observableArrayList();[/CODE]
Hatte ich nicht. Das wars. Vielen, Dank.
 

Zurück
Oben