How to transfer a container from one window to another in JavaFX - java

I got a Button called "Transfer" with the onclick method and a VBox with 3 Buttons in one window.
The second window only has a HBox container.
I wanna understand how to send the VBox to the HBox in the other window by pressing the transfer Button.
And what would also help is feedback regarding my code/file organization.
Main Class:
package testproject;
import javafx.application.Application;
import testproject.screen1.Screen1;
import testproject.screen2.Screen2;
import javafx.stage.Stage;
public class Main extends Application {
private Screen1 screen1;
private Screen2 screen2;
#Override
public void start(Stage primaryStage) throws Exception{
screen1 = new Screen1(this, new Stage());
screen2 = new Screen2(this, primaryStage);
}
public static void main(String[] args) {
Application.launch(args);
}
}
Screen1 Class:
package testproject.screen1;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import testproject.Main;
import java.io.IOException;
public class Screen1 {
public Screen1(Main main, Stage stage){
FXMLLoader loader = new FXMLLoader();
try {
Parent root =
loader.load(getClass().getResourceAsStream("/testproject/screen1/screen1.fxml"));
stage.setTitle("Screen 1");
stage.setScene(new Scene(root, 300, 275));
}
catch (IOException e) {
e.printStackTrace();
}
stage.show();
}
}
Screen2 Class:
package testproject.screen2;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import testproject.Main;
import java.io.IOException;
public class Screen2 {
public Screen2(Main main, Stage stage) {
FXMLLoader loader = new FXMLLoader();
try {
Parent root =
loader.load(getClass().getResourceAsStream("/testproject/screen2/screen2.fxml"));
stage.setTitle("Screen 2");
stage.setScene(new Scene(root, 300, 275));
}
catch (IOException e) {
e.printStackTrace();
}
stage.show();
}
}
Screen1Controller Class:
package testproject.screen1;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.VBox;
public class Screen1Controller {
#FXML
private AnchorPane Pane1;
#FXML
private VBox VBoxScreen1;
#FXML
private Button TransferButton;
#FXML
void transferToScreen2(MouseEvent event){
}
}
Screen2Controller Class:
package testproject.screen2;
import javafx.fxml.FXML;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.HBox;
public class Screen2Controller {
#FXML
private AnchorPane Pane2;
#FXML
private HBox HBoxScreen2;
}

One way I can think of is to pass a callback/consumer to the screen2 controller to let it know what to do with its node. Having said that, there can be many other approaches to this requirement.
As per my view, you dont need separate classes to load the screens. You can check the below working demo.
Main.java
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
FXMLLoader loader2 = new FXMLLoader(getClass() .getResource("screen2.fxml"));
VBox screen2 = loader2.load();
Screen2Controller screen2Controller = loader2.getController();
Stage screen2Stage = new Stage();
Scene scene2 = new Scene(screen2);
screen2Stage.setScene(scene2);
screen2Stage.setTitle("Screen 2");
screen2Stage.setX(900);
screen2Stage.setY(100);
screen2Stage.show();
FXMLLoader loader1 = new FXMLLoader(getClass() .getResource("screen1.fxml"));
VBox screen1 = loader1.load();
Screen1Controller screen1Controller = loader1.getController();
// Set a consumer to the screen1 to let it know what to do
screen1Controller.setTransferer(screen2Controller::moveNode);
Scene scene1 = new Scene(screen1);
primaryStage.setScene(scene1);
primaryStage.setTitle("Screen 1");
primaryStage.setX(100);
primaryStage.setY(100);
primaryStage.show();
}
public static void main(String[] args) {
Application.launch(args);
}
}
Screen1Controller.java
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.layout.VBox;
import java.util.function.Consumer;
public class Screen1Controller {
#FXML
private VBox pane1;
#FXML
private VBox vBoxScreen1;
#FXML
private Button transferButton;
private Consumer<Node> transferer;
#FXML
void transferToScreen2(ActionEvent event) {
// First remove the node from the parent.
pane1.getChildren().remove(vBoxScreen1);
// Then send the node to do the other operation.
this.transferer.accept(vBoxScreen1);
}
public void setTransferer(Consumer<Node> transferer) {
this.transferer = transferer;
}
}
screen1.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.geometry.Insets?>
<VBox fx:id="pane1" xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
fx:controller="com.stackoverflow.javafx.issue7.Screen1Controller"
prefHeight="400.0" prefWidth="600.0" spacing="10">
<children>
<VBox fx:id="vBoxScreen1" spacing="10" style="-fx-border-width:2px;-fx-border-color:red;-fx-background-color:yellow;" prefWidth="200" maxWidth="200" prefHeight="200">
<children>
<Button text="Button 1"/>
<Button text="Button 2"/>
<Button text="Button 3"/>
</children>
<padding>
<Insets topRightBottomLeft="10" />
</padding>
</VBox>
<Button fx:id="transferButton" text="Transfer" onAction="#transferToScreen2"/>
</children>
<padding>
<Insets topRightBottomLeft="10" />
</padding>
</VBox>
Screen2Controller.java
import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
public class Screen2Controller {
#FXML
private VBox pane2;
#FXML
private HBox hBoxScreen2;
public void moveNode(Node node){
hBoxScreen2.getChildren().add(node);
}
}
screen2.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.*?>
<?import javafx.geometry.Insets?>
<VBox fx:id="pane2" xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
fx:controller="com.stackoverflow.javafx.issue7.Screen2Controller"
prefHeight="400.0" prefWidth="600.0" spacing="10">
<children>
<HBox fx:id="hBoxScreen2" spacing="10">
<padding>
<Insets topRightBottomLeft="10" />
</padding>
</HBox>
</children>
<padding>
<Insets topRightBottomLeft="10" />
</padding>
</VBox>

Related

How can I alter GUI elements of a stages owner?

I'm currently trying to figure out how to implement a feature in which the user clicks a button and a popup appears, and then the user enters data into that popup, clicks a confirm button, and the data becomes visible in the popups owner. I was able to make data from the owner stage carry over to the popup stage after follow Bro Code's tutorial on making controllers communicate, however getting it to work the other way around is proving troublesome. Below is a project in which I've isolated the issue to try and figure it out.
App.java
package org.example;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import java.util.Objects;
public class App extends Application {
public static Stage stage;
#Override
public void start(Stage primaryStage) throws Exception {
Parent root = FXMLLoader.load(Objects.requireNonNull(getClass().getResource("primary.fxml")));
Scene scene = new Scene(root);
stage = new Stage();
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch();
}
}
PrimaryController.java
package org.example;
import java.io.IOException;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.stage.Modality;
import javafx.stage.Stage;
public class PrimaryController {
#FXML
Label label;
#SuppressWarnings("unused")
public void login(ActionEvent event) throws IOException{
FXMLLoader loader = new FXMLLoader(getClass().getResource("secondary.fxml"));
Parent root = loader.load();
SecondaryController secondaryController = loader.getController();
secondaryController.stage = new Stage();
secondaryController.stage.initModality(Modality.APPLICATION_MODAL);
secondaryController.stage.initOwner(App.stage);
Scene scene = new Scene(root);
secondaryController.stage.setScene(scene);
secondaryController.stage.show();
}
public void displayMessage(String message){
label.setText(message);
}
}
SecondaryController.java
package org.example;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.control.TextField;
import javafx.stage.Stage;
import java.io.IOException;
public class SecondaryController {
#FXML
TextField textField;
public Stage stage;
#SuppressWarnings("unused")
public void writeToOwner(ActionEvent event) throws IOException {
String message = textField.getText();
FXMLLoader loader = new FXMLLoader(getClass().getResource("primary.fxml"));
Parent root = loader.load();
PrimaryController primaryController = loader.getController();
primaryController.displayMessage(message);
stage.close();
}
}
primary.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1" fx:controller="org.example.PrimaryController">
<children>
<Button layoutX="270.0" layoutY="230.0" mnemonicParsing="false" onAction="#login" text="Login" />
<Label fx:id="label" layoutX="280.0" layoutY="191.0" />
</children>
</AnchorPane>
secondary.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1" fx:controller="org.example.SecondaryController">
<children>
<TextField fx:id="textField" layoutX="219.0" layoutY="187.0" onAction="#writeToOwner" />
</children>
</AnchorPane>
The current behavior that I get from this code is almost what I want, except when the user would submit the text, it closes the popup but doesn't change the popups owner.
In your SecondaryController, it looks like you're creating a second instance of PrimaryController, leaving the first unchanged when invoking writeToOwner().
One approach is to arrange for the controllers to see a common model, much as they share a common stage in your example. The simplest such model is a single ObservableValue, illustrated here. To see the effect,
Add a StringProperty named text to your SecondaryController and make it accessible. In writeToOwner(), simply update the text and the bound label will follow.
public class SecondaryController {
#FXML
TextField textField;
public Stage stage;
private final StringProperty text = new SimpleStringProperty();
public StringProperty textProperty() {
return text;
}
#SuppressWarnings("unused")
public void writeToOwner(ActionEvent event) throws IOException {
text.set(textField.getText());
stage.close();
}
}
In your PrimaryController, bind the label's textProperty() to the textProperty() of the SecondaryController.
public class PrimaryController {
#FXML
Label label;
public StringProperty text = new SimpleStringProperty();
#SuppressWarnings("unused")
public void login(ActionEvent event) throws IOException {
…
secondaryController.stage.initOwner(App.stage);
label.textProperty().bind(secondaryController.textProperty());
…
}
}
In practice, you'll want to avoid public access to class members.

How to set line color of a particular fxml chart using css?

I would like to know how to define colors line and symbol for a specific chart with css.
Current css it's ok with class selector, but how to adapt that for a specific linechart with his Id #myChart ?
here is the code:
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Paths;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import vue.VuetestCtrl2;
public class ChartTestMain extends Application {
public static void main(String[] args) { launch(args);}
#Override
public void start(Stage stage) throws Exception { loadIhm( stage) ;}
void loadIhm(Stage stage) throws URISyntaxException {
URL location = ChartTestMain.class.getResource("/repTest/vuetest.fxml");
final FXMLLoader loader = new FXMLLoader(location);
File fic = Paths.get(location.toURI()).toFile();
System.out.println("fic = "+ fic);
try {
Parent root = (Parent) loader.load();
VuetestCtrl2 controller = (VuetestCtrl2) loader.getController();
stage.setScene(new Scene(root));
stage.show();
} catch (IOException e) { e.printStackTrace(); }
}
}
controller :
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.ResourceBundle;
import org.jfree.data.xy.XYSeriesCollection;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
public class VuetestCtrl2 implements Initializable{
#FXML private NumberAxis xAxisLine;
#FXML private NumberAxis yAxisLine;
#FXML private LineChart<Number,Number> xyChart;
#Override
public void initialize(URL location, ResourceBundle resources) {
XYChart.Series<Number, Number> serie = new XYChart.Series<Number, Number>();
xyChart.getData().add(serie);
serie.getData().add (new XYChart.Data<Number,Number>(10,10));
serie.getData().add (new XYChart.Data<Number,Number>(50,5));
serie.getData().add (new XYChart.Data<Number,Number>(100,30));
}
}
vuetest.fxml :
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.chart.LineChart?>
<?import javafx.scene.chart.NumberAxis?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="964.0" prefWidth="1209.0" stylesheets="#../../extension/extension.css" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="vue.VuetestCtrl2">
<children>
<LineChart id="myChart" layoutX="174.0" layoutY="108.0" prefHeight="475.0" prefWidth="750.0" fx:id="xyChart">
<xAxis>
<NumberAxis side="BOTTOM" fx:id="xAxisLine" />
</xAxis>
<yAxis>
<NumberAxis fx:id="yAxisLine" side="LEFT" />
</yAxis>
</LineChart>
</children>
</AnchorPane>
extension.css
.default-color0.chart-line-symbol { /* hollow circle */
-fx-background-color: blue , white;
-fx-background-radius: 6px;
-fx-padding: 6px ;
-fx-background-insets: 0, 2;
}
.default-color0.chart-series-line {
-fx-stroke: blue ;
}

How to make a Media view with a link from YouTube in Java fx

I want to use a Media View in Scene Builder such that if I click on a button that it should play a video from YouTube link that I gave it before. How would I go about doing this?
I don't want that a browser open when I click,I want that video playing in Media viewer field.
Here is a rather minimal example to get you started making use of Web View Control. It takes a YouTube URL and convert it into an embedded one.
Preview Image
I have provided two examples one as a complete single class and another using the scene builder.
Example 1: Complete Single class
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextArea;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Main extends Application {
public class YTPlayer extends VBox{
private Button plyButton;
private WebView webView4 = new WebView();
private HBox hBox;
private TextArea textArea;
private String url = "";
private final Pattern pattern = Pattern.compile("(?<=watch\\?v=|/videos/|embed\\/|youtu.be\\/|\\/v\\/|\\/e\\/|watch\\?v%3D|watch\\?feature=player_embedded&v=|%2Fvideos%2F|embed%\u200C\u200B2F|youtu.be%2F|%2Fv%2F)[^#\\&\\?\\n]*");
public YTPlayer(double width, double height){
super();
this.setPrefHeight(height);
this.setPrefWidth(width);
hBox = new HBox();
hBox.setPrefHeight(0.045*height);
hBox.setPrefWidth(width);
textArea = new TextArea();
textArea.setPrefHeight(0.175*height);
textArea.setPrefWidth(0.913*width);
textArea.setPromptText("URL");
plyButton = new Button();
plyButton.setPrefHeight(0.095*height);
plyButton.setPrefWidth(0.0867*width);
plyButton.setText("Play");
plyButton.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent mouseEvent) {
if(!textArea.getText().equals("")){
setUrl(textArea.getText());
play();
}
}
});
hBox.getChildren().addAll(plyButton,textArea);
webView4.setPrefHeight(0.9025*height);
webView4.setPrefWidth(width);
this.getChildren().addAll(webView4,hBox);
}
void play (){
webView4.getEngine().load(this.url);
}
void setUrl(String url){
Matcher matcher = pattern.matcher(url);
if(matcher.find()){
this.url ="https://www.youtube.com/embed/"+matcher.group(0);
System.out.println(this.url);
}else{
System.out.println("Invalid Url!");
}
}
}
#Override
public void start(Stage primaryStage) throws Exception{
double sceneWidth = 600;
double sceneHeight =400;
YTPlayer player =new YTPlayer(sceneWidth,sceneHeight);
Pane root = new Pane();
root.getChildren().addAll(player);
Scene myscene =new Scene(root, sceneWidth,sceneHeight);
primaryStage.setScene(myscene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Example 2: Using Scene Builder
FXML file (sample.fxml) :
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.web.*?>
<VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/10.0.2-internal" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.Controller">
<children>
<WebView fx:id="webView" prefHeight="361.0" prefWidth="600.0" />
<HBox prefHeight="18.0" prefWidth="600.0">
<children>
<Button mnemonicParsing="false" onAction="#play" prefHeight="38.0" prefWidth="52.0" text="Play" />
<TextArea fx:id="urlTxtArea" prefHeight="7.0" prefWidth="548.0" promptText="URL" />
</children>
</HBox>
</children>
</VBox>
Controller class (Controller.java):
import javafx.fxml.FXML;
import javafx.scene.control.TextArea;
import javafx.scene.web.WebView;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Controller {
private final Pattern pattern = Pattern.compile("(?<=watch\\?v=|/videos/|embed\\/|youtu.be\\/|\\/v\\/|\\/e\\/|watch\\?v%3D|watch\\?feature=player_embedded&v=|%2Fvideos%2F|embed%\u200C\u200B2F|youtu.be%2F|%2Fv%2F)[^#\\&\\?\\n]*");
private String url;
#FXML
private WebView webView;
#FXML
private TextArea urlTxtArea;
#FXML
void play() {
if(!urlTxtArea.getText().equals("")){
Matcher matcher = pattern.matcher(this.urlTxtArea.getText());
if(matcher.find()){
this.url ="https://www.youtube.com/embed/"+matcher.group(0);
webView.getEngine().load(this.url);
System.out.println(this.url);
}else{
System.out.println("Invalid Url!");
}
}
}
}
Main class (Main.java):
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception{
Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
primaryStage.setTitle("Simple Youtube video Player");
primaryStage.setScene(new Scene(root, 600, 400));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}

JavaFX Windows needs resize to display content

I have this problem with my JavaFX windows, where I added a Scrollpan containing a graph. When I launch the app I need to resize the windows so that the content appears.
Here is the Model:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<VBox xmlns:fx="http://javafx.com/fxml/1" prefHeight="544.0" prefWidth="788.0" xmlns="http://javafx.com/javafx/8.0.121"
fx:controller="Solution.SolutionController">
<MenuBar fx:id="menuBar">
<menus>
<Menu text="File">
<items>
<MenuItem text="Save"/>
</items>
</Menu>
</menus>
</MenuBar>
<VBox fx:id="contenu" alignment="CENTER">
<HBox alignment="CENTER">
<ScrollPane style="-fx-background: WHITE" fx:id="pane" focusTraversable="false" prefHeight="608.0"
prefWidth="700">
</ScrollPane>
</HBox>
<Label fx:id="counter">
</Label>
<VBox.margin>
<Insets top="17.0"/>
</VBox.margin>
</VBox>
<HBox alignment="CENTER" prefWidth="690.0">
<Button onAction="#handleGauche" text="Gauche"/>
<Button onAction="#handleDroite" text="Droite"/>
</HBox>
</VBox>
Here is the controller:
package Solution;
import Main.Individual;
import javafx.embed.swing.SwingNode;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
import javafx.scene.control.MenuBar;
import javafx.scene.control.ScrollPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
public class SolutionController {
public VBox contenu;
public Label counter;
public MenuBar menuBar;
public ScrollPane pane;
ArrayList<Individual> graph;
JPanel panel;
int i;
public void init() {
i = 0;
panel = new JPanel();
panel.setBackground(Color.WHITE);
panel.add(graph.get(i).chopper.getContentPane());
panel.validate();
panel.repaint();
counter.setText((i+1) + "/" + graph.size());
SwingNode sn = new SwingNode();
sn.setContent(panel);
pane.setContent(sn);
}
#FXML
void handleDroite(ActionEvent event) {
i = (i + 1) % graph.size();
changeContent();
}
#FXML
void handleGauche(ActionEvent event) {
i = (graph.size() + (i - 1)) % graph.size();
changeContent();
}
public void changeContent(){
counter.setText((i+1) + "/" + graph.size());
panel.add(graph.get(i).chopper.getContentPane());
panel.repaint();
SwingNode sn = new SwingNode();
sn.setContent(panel);
pane.setContent(sn);
}
}
And here is the view:
package Solution;
import Main.Individual;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import java.io.IOException;
import java.util.ArrayList;
public class SolutionApplication extends Application{
ArrayList<Individual> graphI;
public SolutionApplication(ArrayList<Individual> graph) {
graphI = new ArrayList<>(graph);
}
public void start(Stage primaryStage) throws IOException {
FXMLLoader loader = new FXMLLoader(getClass().getResource("Solution.fxml"));
Parent root = loader.load();
SolutionController controller = loader.getController();
controller.graph = new ArrayList<>(graphI);
controller.init();
primaryStage.setTitle("Main Window");
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
}
I did stumble on this post
javafx SwingNode not working until window is resized
However they say its a bug with the JDK? I use version 10
I'd like to know how I can fix this.
Thanks for reading.

javafx how to keep data on secondary window while its closed

question is simple i have created small program that have 2 stages the main and the secondary, the main window has a button to launch the secondary stage and the secondary stage has text field and button and label when i enter a text in the text field and pressed the button the text will be shown in the label , what i want to do is when i close the secondary stage and the program is still running i want the data to be same so when pressed button and launch the secondary stage again i will see the last result as if i never closed the secondary stage
here is the main class
package sample;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Modality;
import javafx.stage.Stage;
import java.io.IOException;
public class Main extends Application {
private Stage primaryStage;
#Override
public void start(Stage primaryStage) throws Exception{
this.primaryStage=primaryStage;
mainWindow();
}
void mainWindow() {
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("FirstWindow.fxml"));
Parent root = loader.load();
Controller controller = loader.getController();
controller.setMain(this ,primaryStage);
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}catch (IOException e){
e.printStackTrace();
}
}
public void secondaryWindow() {
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("SecondWindow.fxml"));
Parent root = loader.load();
Scene scene = new Scene(root);
Stage secondaryStage=new Stage();
secondaryStage.initOwner(primaryStage);
secondaryStage.initModality(Modality.WINDOW_MODAL);
swController controller = loader.getController();
controller.setMain(this,secondaryStage);
secondaryStage.setScene(scene);
secondaryStage.show();
}catch (IOException e){
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
and the secondstage control class
package sample;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.stage.Stage;
import java.net.URL;
import java.util.ResourceBundle;
/**
* Created by ahmednageeb on 11/29/16.
*/
public class swController implements Initializable {
private Main main;
private Stage secondaryStage;
public void setMain(Main main, Stage secondaryStage) {
this.main = main;
this.secondaryStage = secondaryStage;}
#FXML
private Label label;
#FXML
private TextField text;
#FXML
private void change(ActionEvent event) {
String a=text.getText();
label.setText(a);
text.clear();
}
public void goBack() {
secondaryStage.close();
}
#Override
public void initialize(URL location, ResourceBundle resources) {
}
}
and finally the firststage controller
package sample;
import javafx.stage.Stage;
public class Controller {
private Main main;
private Stage primaryStage;
public void setMain(Main main,Stage primaryStage){
this.main=main;
this.primaryStage =primaryStage;
}
public void close(){
primaryStage.close();
}
public void changeWindow(){
main.secondaryWindow();
}
}
One solution could be to load the secondary window on start up but hide it. Then use the button to show it. When you close it, hide it again.
See if something like this works!
Main:
package hidepopup;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class HidePopup extends Application {
#Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.setTitle("first stage");
stage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
First FXML:
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane id="AnchorPane" prefHeight="200" prefWidth="320" xmlns:fx="http://javafx.com/fxml/1" fx:controller="hidepopup.FXMLDocumentController">
<children>
<Button layoutX="126" layoutY="90" text="Click Me!" onAction="#handleButtonAction" fx:id="button" />
<Label layoutX="126" layoutY="120" minHeight="16" minWidth="69" fx:id="label" />
</children>
</AnchorPane>
First Controller:
package hidepopup;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.stage.Stage;
public class FXMLDocumentController implements Initializable {
#FXML
private Label label;
FXMLLoader loader;
Parent root2;
Stage stage2;
#FXML
private void handleButtonAction(ActionEvent event) {
try
{
Scene scene2 = new Scene(root2);
stage2.setScene(scene2);
stage2.setTitle("second stage");
stage2.showAndWait();
}
catch(IllegalArgumentException ex)
{
stage2.show();
}
}
#Override
public void initialize(URL url, ResourceBundle rb) {
try
{
loader = new FXMLLoader(getClass().getResource("FXMLPopup.fxml"));
root2 = loader.load();
FXMLPopupController dac = (FXMLPopupController) loader.getController();
stage2 = new Stage();
}
catch (IOException ex)
{
Logger.getLogger(FXMLDocumentController.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
Second FXML:
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane id="AnchorPane" prefHeight="200" prefWidth="320" xmlns:fx="http://javafx.com/fxml/1" fx:controller="hidepopup.FXMLPopupController">
<children>
<Button layoutX="126" layoutY="90" text="Click Me!" onAction="#handleButtonAction" fx:id="button" />
<Label layoutX="126" layoutY="120" minHeight="16" minWidth="69" fx:id="label" />
</children>
</AnchorPane>
Second Controller
package hidepopup;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
public class FXMLPopupController implements Initializable {
#FXML
public Label label;
#FXML
private void handleButtonAction(ActionEvent event){
label.getScene().getWindow().hide();
}
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
}
}
The layout for both windows are exactly the same, so after you press the button you might want slide the top layout over. Also, I didn't test to see if the second stage held its data. Add a text box to the second stage and test it out. I hope this helps.

Categories

Resources