i created a simple GUI, using JavaFX with fxml. One part of the program is using fxml and other generate dynamic GUI. So, i created javafx.scene.controller.Accordion with fxml and add panes inside it with code:
#FXML
Accordion accordionPlant;
public void init(){
accordionPlant.getPanes().add(createTitledPanePlant(1));
accordionPlant.getPanes().add(createTitledPanePlant(2));
}
protected TitledPane createTitledPanePlant(int index){
TilePane tile = new TilePane(Orientation.HORIZONTAL, 5, 5);
Label typeLabel = new Label("Тип выпуска");
TextField typeText = new TextField();
VBox typeContainer = new VBox(typeLabel,typeText);
Label bankLabel = new Label("Берег");
Tooltip.install(bankLabel, new Tooltip("Берег, с которого производится выпуск"));
TextField bankText = new TextField();
VBox bankContainer = new VBox(bankLabel,bankText);
tile.getChildren().addAll(typeContainer, bankContainer);
TitledPane titledPane = new TitledPane("Параметры выпуска " + index, tile);
return titledPane;
}
After that user click on the button and the program should find all TextField and calculate their value. So how it must be done correctly or comfortable?
I tried to get all panes of accordion:
void test(){
for (TitledPane pane: accordionPlant.getPanes()) {
pane.getChildrenUnmodifiable().get(0); //blah, blah
}
}
but i think it isn't a good idea, especially using index. I need only textfields. Is there any way of implements of ?
If you have dynamic elements, why not just store them in a List when you create them? That way you don't have to try to get them from a container. You are probably only interested in the Controller, but I posted the whole app. If you look in createTitledPanePlant you can see where I add the TextFields to the List -> List<TextField> textFieldContainer = new ArrayList();
Main
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
/**
*
* #author blj0011
*/
public class JavaFXApplication115 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.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args)
{
launch(args);
}
}
Controller
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.geometry.Orientation;
import javafx.scene.control.Accordion;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.control.TitledPane;
import javafx.scene.control.Tooltip;
import javafx.scene.layout.TilePane;
import javafx.scene.layout.VBox;
/**
*
* #author blj0011
*/
public class FXMLDocumentController implements Initializable
{
#FXML
private Label label;
#FXML
private Accordion accordionMain;
List<TextField> textFieldContainer = new ArrayList();
#FXML
private void handleButtonAction(ActionEvent event)
{
//Sum TextField
double total = 0;
for (TextField node : textFieldContainer) {
double value;
try {
value = Double.parseDouble(node.getText());
}
catch (NumberFormatException e) {
value = 0;
}
total += value;
}
label.setText("Sum: " + total);
}
#Override
public void initialize(URL url, ResourceBundle rb)
{
// TODO
accordionMain.getPanes().add(createTitledPanePlant(1));
accordionMain.getPanes().add(createTitledPanePlant(2));
}
protected TitledPane createTitledPanePlant(int index)
{
TilePane tile = new TilePane(Orientation.HORIZONTAL, 5, 5);
Label typeLabel = new Label("Тип выпуска");
TextField typeText = new TextField();
textFieldContainer.add(typeText);//Add your textField to the container when you create it
VBox typeContainer = new VBox(typeLabel, typeText);
Label bankLabel = new Label("Берег");
Tooltip.install(bankLabel, new Tooltip("Берег, с которого производится выпуск"));
TextField bankText = new TextField();
textFieldContainer.add(bankText);//Add your textField to the container when you create it
VBox bankContainer = new VBox(bankLabel, bankText);
tile.getChildren().addAll(typeContainer, bankContainer);
TitledPane titledPane = new TitledPane("Параметры выпуска " + index, tile);
return titledPane;
}
}
FXML
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Accordion?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane id="AnchorPane" prefHeight="486.0" prefWidth="431.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8.0.141" fx:controller="javafxapplication115.FXMLDocumentController">
<children>
<Button fx:id="button" layoutX="179.0" layoutY="437.0" onAction="#handleButtonAction" text="Sum nodes" />
<Label fx:id="label" layoutX="163.0" layoutY="37.0" minHeight="16" minWidth="69" prefHeight="17.0" prefWidth="106.0" />
<Accordion fx:id="accordionMain" layoutX="115.0" layoutY="72.0" prefHeight="310.0" prefWidth="202.0" />
</children>
</AnchorPane>
Related
I'm working on a project and I need to display the information of a Medicine object from a ListView to another Scene.
The user would select a Medicine from the ListView and press the Button to see it's details in the next Scene that would be displayed by Labels. The problem now is, I have transferred the info, and the text property of the Label has changed (observed through println and debugging), but the Label just won't display the changed text.
this is the main
package app;
import app.data.MedicineData;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.input.MouseEvent;
import javafx.stage.Stage;
import org.w3c.dom.events.Event;
import java.io.IOException;
public class Pharmachine extends Application {
public static final double WIDTH = 480;
public static final double HEIGHT = 720;
#Override
public void start(Stage stage) throws Exception{
Parent homePage = FXMLLoader.load(getClass().getResource("homepage.fxml"));
Scene homePageScene = newDefaultScene(homePage);
stage.setResizable(false);
stage.setScene(homePageScene);
stage.setTitle("Pharmachine");
stage.show();
}
#Override
public void init(){
MedicineData.getInstance().loadData();
}
public static Scene newDefaultScene(Parent parent){
Scene scene = new Scene(parent, WIDTH, HEIGHT);
scene.addEventHandler(MouseEvent.MOUSE_CLICKED,
(mouseEvent) -> {
Node targetNode = scene.getFocusOwner();
if(targetNode != null && targetNode.isFocused()) {
if(targetNode.getParent() != null)
targetNode.getParent().requestFocus();
mouseEvent.consume();
}
}
);
return scene;
}
public static void navigateTo(ActionEvent actionEvent, String filename){
Stage mainWindow = (Stage) ((Node) actionEvent.getSource()).getScene().getWindow();
Scene currentScene = ((Node) actionEvent.getSource()).getScene();
try {
currentScene.setRoot(FXMLLoader.load(Pharmachine.class.getResource(filename)));
mainWindow.setScene(currentScene);
} catch(IOException e){
e.printStackTrace();
}
}
public static void main(String[] args){ launch(args); }
}
this is the fxml for the list's page
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ListView?>
<BorderPane xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml"
fx:controller="app.ListpageController" fx:id="pageRoot"
stylesheets="#styles/main.css">
<left>
<GridPane fx:id="listArea" alignment="CENTER">
<ListView fx:id="medicineList"
GridPane.rowIndex="1"/>
</GridPane>
</left>
<center>
<GridPane fx:id="buttonsArea" alignment="CENTER"
hgap="10" vgap="10">
<Button text="Back"
onAction="#displayHomePage"
GridPane.halignment="CENTER"/>
<Button text="Details"
onAction="#displayDetailsPage"
GridPane.rowIndex="1"
GridPane.halignment="CENTER"/>
</GridPane>
</center>
</BorderPane>
here is the controller for the list's page
package app;
import app.data.Medicine;
import app.data.MedicineData;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.Label;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.util.Callback;
import java.io.IOException;
public class ListpageController {
#FXML
private BorderPane pageRoot;
#FXML
private GridPane listArea;
#FXML
private GridPane buttonsArea;
#FXML
private ListView<Medicine> medicineList;
#FXML public void initialize(){
listArea.setMaxWidth(Pharmachine.WIDTH * 3/5);
medicineList.setMinWidth(listArea.getMaxWidth());
medicineList.setMinHeight(Pharmachine.HEIGHT);
medicineList.setItems(MedicineData.getInstance().getMedicines());
medicineList.setCellFactory(new Callback<>() {
#Override
public ListCell<Medicine> call(ListView<Medicine> medicineListView) {
ListCell<Medicine> listCell = new ListCell<>(){
#Override
public void updateItem(Medicine medicine, boolean empty){
super.updateItem(medicine, empty);
if(!empty){
HBox medName = new HBox(new Label(medicine.getName()));
HBox.setHgrow(medName, Priority.ALWAYS);
HBox medPrice = new HBox(new Label(String.format("RM%.2f", medicine.getPrice())));
HBox medLabel = new HBox(medName, medPrice);
setGraphic(medLabel);
}
}
};
listCell.setOnMouseClicked(
(mouseEvent) -> {
if(mouseEvent.getClickCount() == 2){
medicineList.getSelectionModel().clearSelection();
}
}
);
return listCell;
}
});
}
#FXML private void displayHomePage(ActionEvent actionEvent){
Pharmachine.navigateTo(actionEvent, "homepage.fxml");
}
#FXML private void displayDetailsPage(ActionEvent actionEvent){
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("detailspage.fxml"));
try {
loader.load();
} catch(IOException e){
e.printStackTrace();
}
DetailspageController controller = loader.getController();
Medicine selectedMedicine = medicineList.getSelectionModel().getSelectedItem();
if(selectedMedicine != null) {
controller.setInfo(selectedMedicine);
Pharmachine.navigateTo(actionEvent, "detailspage.fxml");
}
}
}
this is the fxml for the next scene (just simple for now)
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.text.Text?>
<BorderPane xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml"
fx:id="pageRoot" fx:controller="app.DetailspageController"
stylesheets="#styles/main.css">
<center>
<GridPane fx:id="detailsArea"
alignment="CENTER" hgap="10" vgap="10">
<Label text="Details"/>
<Text text="Name: "
GridPane.rowIndex="1"/>
<Label fx:id="medNameLabel" text="~"
GridPane.rowIndex="1" GridPane.columnIndex="1"/>
<Text text="Price: "
GridPane.rowIndex="2"/>
<Label fx:id="medPriceLabel" text="~"
GridPane.rowIndex="2" GridPane.columnIndex="1"/>
</GridPane>
</center>
</BorderPane>
and this is the scene's controller
package app;
import app.data.Medicine;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import java.net.URL;
import java.util.ResourceBundle;
public class DetailspageController implements Initializable {
private Medicine selectedMedicine;
#FXML
private BorderPane pageRoot;
#FXML
private GridPane detailsArea;
#FXML
private Label medNameLabel;
#FXML
private Label medPriceLabel;
#Override
public void initialize(URL url, ResourceBundle rb){
}
public void setInfo(Medicine medicine){
selectedMedicine = medicine;
medNameLabel.setText(selectedMedicine.getName());
medPriceLabel.setText(String.format("RM%.2f", selectedMedicine.getPrice()));
System.out.println(medNameLabel.textProperty());
System.out.println(medNameLabel.getText());
medNameLabel.setStyle("-fx-background-color: red;");
}
}
The help would mean a lot. Thank you :]
In your displayDetailsPage method, you load a scene from detailspage.fxml, and you update its labels by calling the setInfo method of the controller.
Then, you call Pharmachine.navigateTo, which loads detailspage.xml again and replaces the scene root with the newly loaded root. You updated the text of the labels in the first details page, but the second details page is brand new, so it doesn’t have those changes.
The second argument in the navigateTo method should be of type Parent rather than a String. navigateTo should not attempt to load any .fxml file; let that be the caller’s responsibility.
Side note: When a list has multiple attributes for each data item, you should probably use a TableView rather than a ListView.
I'm writing a simple quiz-game application using JavaFx. I want set text on label and buttons with data from a list and table.
I created three class: Main, Controller and Quiz.fxml. I have problem with communication classes and method.
In 'Main.java' I created object "Controller controller = new Controller()" and I call method "controller.setText" from 'Controller.java' class.
Now, I have a few options:
-if declate list(ArrayList questions) and tab(String[][] answers) in constuctor 'public Controller(){}' app doesnt work, I get error in this line " "
-if declare everything in 'Text()' method(list, tab and setting text on label) application run but values buttons and label are not changed
-if I declare list and tab in 'setData()', and next I want to change the buttons and label value from 'Text()' method, I cant see the list and I have to declare the same list 'questions' in 'Text()'
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
try {
Parent root = FXMLLoader.load(getClass().getResource("/Controller/Quiz.fxml"));
Scene scene = new Scene(root,500,400)
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
Controller controller = new Controller();
controller.Text();}
Controller class:
public class Controller {
#FXML private Label questionLabel;
#FXML private RadioButton answer_btn1;
#FXML private RadioButton answer_btn2;
#FXML private RadioButton answer_btn3;
#FXML private RadioButton answer_btn4;
#FXML private Button nextBtn;
public void Text() {
List <String> questions = new ArrayList<String>();
questions.add("pytanie1");
questions.add("pytanie2");
questions.add("pytanie3");
questions.add("pytanie4");
questions.add("pytanie5");
questions.add("pytanie6");
questions.add("pytanie7");
questions.add("pytanie8");
questions.add("pytanie9");
questions.add("pytanie10");
String[][] answers = new String[1][4];
answers[1][1] = "a) odp";
answers[1][2] = "b) odp";
answers[1][3] = "c) odp";
answers[1][4] = "d) odp";
questionLabel.setText("");
questionLabel.setText(questionLabel.getText()+answers[1][1]);
answer_btn1.setText("aaa");
}
What do I have to do to change name buttons and label?
You have a couple problems with your code.
Array index starts at zero and if necessary should end at arrayLength - 1. Your code: answers[1][1] = "a) odp"; ... answers[1][4] = "d) odp";. What it should be: answers[0][0] = "a) odp"; ... answers[0][3] = "d) odp";
Initialzing the Controller should be done in the Controller's initialize method.
The sample code below:
Main:
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
/**
*
* #author blj0011
*/
public class JavaFXApplication226 extends Application
{
#Override
public void start(Stage stage) throws Exception
{
Parent root = FXMLLoader.load(getClass().getResource("Controller/Quiz.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args)
{
launch(args);
}
}
Controller:
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.ResourceBundle;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.RadioButton;
/**
*
* #author blj0011
*/
public class FXMLDocumentController implements Initializable
{
#FXML
private Label questionLabel;
#FXML
private RadioButton answer_btn1;
#FXML
private RadioButton answer_btn2;
#FXML
private RadioButton answer_btn3;
#FXML
private RadioButton answer_btn4;
#FXML
private Button nextBtn;
#Override
public void initialize(URL url, ResourceBundle rb)
{
// TODO
List<String> questions = new ArrayList();
questions.add("pytanie1");
questions.add("pytanie2");
questions.add("pytanie3");
questions.add("pytanie4");
questions.add("pytanie5");
questions.add("pytanie6");
questions.add("pytanie7");
questions.add("pytanie8");
questions.add("pytanie9");
questions.add("pytanie10");
String[][] answers = new String[1][4];
answers[0][0] = "a) odp";
answers[0][1] = "b) odp";
answers[0][2] = "c) odp";
answers[0][3] = "d) odp";
questionLabel.setText("");
questionLabel.setText(questionLabel.getText() + answers[0][0]);
answer_btn1.setText("aaa");
}
}
FXML
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.RadioButton?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane id="AnchorPane" prefHeight="200" prefWidth="320" xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1" fx:controller="javafxapplication226.FXMLDocumentController">
<children>
<Button fx:id="nextBtn" layoutX="118.0" layoutY="161.0" text="Click Me!" />
<Label fx:id="questionLabel" layoutX="124.0" layoutY="36.0" minHeight="16" minWidth="69" />
<RadioButton fx:id="answer_btn1" layoutX="47.0" layoutY="92.0" mnemonicParsing="false" text="RadioButton" />
<RadioButton fx:id="answer_btn2" layoutX="193.0" layoutY="92.0" mnemonicParsing="false" text="RadioButton" />
<RadioButton fx:id="answer_btn3" layoutX="47.0" layoutY="128.0" mnemonicParsing="false" text="RadioButton" />
<RadioButton fx:id="answer_btn4" layoutX="183.0" layoutY="128.0" mnemonicParsing="false" text="RadioButton" />
</children>
</AnchorPane>
I am assuming your project structure looks like the following from your code.
Your issue is that you are instantiating a new controller which is not bound to the view.
You get the controller from the loader like this:
FXMLLoader loader = new FXMLLoader(getClass().getResource("/Controller/Quiz.fxml"));
Parent root = loader.load();
Controller controller = loader.getController();
This way everything will be wired up properly.
I'm making a paint program but where there is a DropShadow around the drawings the user makes. When they erase, it also erases the DropShadow. If I try to reapply the DropShadow (to get it to surround the drawing's new boundaries), it works, but it makes the rest of the already applied DropShadow darker which I don't want.
The solutions I can think of are two-fold:
Remove DropShadow effect and reapply it on every erase. As far as I know this is not possible while using GraphicsContext.applyEffect()
Apply DropShadow on a separate canvas and clear it and redraw on every erase. The code below implements my embarrassing attempt at this solution.
Here is a picture of what happens currently:
Here is my code
FXMLDocument.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.canvas.Canvas?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.Pane?>
<AnchorPane id="AnchorPane" prefHeight="399.0" prefWidth="465.0" xmlns="http://javafx.com/javafx/8.0.60" xmlns:fx="http://javafx.com/fxml/1" fx:controller="cartographerfx.FXMLDocumentController">
<children>
<Pane fx:id="canvasPane" layoutX="26.0" layoutY="20.0" prefHeight="362.0" prefWidth="417.0" style="-fx-border-style: solid;">
<children>
<Canvas fx:id="canvas" height="362.0" onMouseDragged="#CanvasMouseDragged" onMousePressed="#CanvasMouseDown" onMouseReleased="#CanvasMouseUp" width="417.0" />
</children>
</Pane>
</children>
</AnchorPane>
FXMLDocumentController.java
package cartographerfx;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.effect.DropShadow;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
/**
*
* #author Dan
*/
public class FXMLDocumentController implements Initializable {
#FXML
Canvas canvas;
Canvas shadowLayer;
#FXML
Pane canvasPane;
private GraphicsContext gc;
private GraphicsContext sgc;
private boolean isDragging;
private double lastX;
private double lastY;
#FXML
public void CanvasMouseDragged(MouseEvent event) {
if (isDragging) {
if (event.getButton() == MouseButton.PRIMARY) {
gc.setStroke(Color.BLUE);
gc.setLineWidth(10);
gc.strokeLine(lastX, lastY, event.getX(), event.getY());
} else if (event.getButton() == MouseButton.SECONDARY) {
gc.clearRect(event.getX(), event.getY(), 10, 10);
}
lastX = event.getX();
lastY = event.getY();
}
}
#FXML
public void CanvasMouseDown(MouseEvent event) {
isDragging = true;
lastX = event.getX();
lastY = event.getY();
if (event.getButton() == MouseButton.MIDDLE)
{
sgc = gc;
sgc.applyEffect(new DropShadow());
}
}
#FXML
public void CanvasMouseUp(MouseEvent event) {
isDragging = false;
}
#Override
public void initialize(URL url, ResourceBundle rb) {
gc = canvas.getGraphicsContext2D();
isDragging = false;
shadowLayer = new Canvas(canvas.getWidth(), canvas.getHeight());
sgc = shadowLayer.getGraphicsContext2D();
canvasPane.getChildren().add(shadowLayer);
shadowLayer.toBack();
}
}
CartographerFX.java
package cartographerfx;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
/**
*
* #author Dan
*/
public class CartographerFX 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.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
I don't understand why everybody seems to be using the Canvas when the scene-graph would be much better suited for the task. Why don't you just use an ordinary Pane and a Path. You can then apply the drop shadow effect directly to the path. The advantage of the scene-graph is that you can edit every element individually as often as you want whereas the canvas basically is conceptually just an image which you cannot edit at all once it is drawn.
I am building a GUI for my project and I need to show information that is coming from various types of data structures: ArrayList,HashMap,TreeSet in a table.
Basically I need to show information from query methods I got in my model package in my view package.
My implementation right now includes a controller for each and every table I build with the object type specified every time I declare a TableView.
I wonder if there is a way to create a class that its constructor will build me the table I need(with as many columns this object require). some sort of a generic table builder that can read an object and find out how many columns it needs to be represented. for example: to present Reservation Object that has 4 fields/columns compare to Member object that has 6 fields/columns. according to the data-structure it will get. therefore I will be able to create an instance of this class and instantiate a table of my need and show it on the screen.
I also need a way to be able to control it from the scene builder as this is my main tool for building the GUI graphically.
I am adding one of my table codes here and I hope someone can help me with this tedious task :)
package view;
import java.util.ArrayList;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.stage.Stage;
import model.Reservation;
public class QRYClientReservationsTableController {
private ObservableList<Reservation> ReservationsData = FXCollections.observableArrayList();
#FXML
private TableView<Reservation> ReservationforClient;
#FXML
private TableColumn<Reservation, String> ReservationIdColumn;
#FXML
private TableColumn<Reservation, String> LocationIdColumn;
#FXML
private TableColumn<Reservation, String> AddressColumn;
#FXML
private TableColumn<Reservation, String> DescriptionColumn;
#FXML
private TableColumn<Reservation, String> StartTimeAndDateColumn;
#FXML
private TableColumn<Reservation, String> EndTimeAndDateColumn;
#FXML
private TextField memId;
/**
* The constructor.
* The constructor is called before the initialize() method.
*/
public QRYClientReservationsTableController() {
}
/**
* Initializes the controller class. This method is automatically called
* after the fxml file has been loaded.
*/
#FXML
private void initialize() {
// Initialize the Location table with the tree columns.
ReservationIdColumn.setCellValueFactory(cellData -> cellData.getValue().ReservationIdProperty());
LocationIdColumn.setCellValueFactory(cellData -> cellData.getValue().LocationIdProperty());
AddressColumn.setCellValueFactory(cellData -> cellData.getValue().LocationAddressProperty());
DescriptionColumn.setCellValueFactory(cellData -> cellData.getValue().LocationDescriptionProperty());
StartTimeAndDateColumn.setCellValueFactory(cellData -> cellData.getValue().StartDateProperty());
EndTimeAndDateColumn.setCellValueFactory(cellData -> cellData.getValue().EndDateProperty());
}
#FXML
Button CloseBtn = new Button();//close button inside AddLocation window
#FXML
public void handleCloseButtonAction(ActionEvent event) {//for all close Button's this method is called
Stage stage = (Stage) CloseBtn.getScene().getWindow();
stage.close();
}
/**
* Is called by the main application to give a reference back to itself.
*
* #param Locaion
*/
public void setQRYClientReservationsTableController(String memId) {
this.memId.setEditable(true);
this.memId.setText(memId);
this.memId.setEditable(false);
ArrayList<Reservation> reservationsAdd = new ArrayList<Reservation>();
reservationsAdd.addAll(ViewLogic.controlLogic.Q_getAllReservationsForMember(memId));
ReservationsData.addAll(reservationsAdd);
// Add observable list data to the table
ReservationforClient.setItems(ReservationsData);
ReservationIdColumn.sortableProperty().setValue(false);
LocationIdColumn.sortableProperty().setValue(false);
AddressColumn.sortableProperty().setValue(false);
DescriptionColumn.sortableProperty().setValue(false);
StartTimeAndDateColumn.sortableProperty().setValue(false);
EndTimeAndDateColumn.sortableProperty().setValue(false);
}
}
The next code is in my ViewLogic Class inside my View package and this code summons the FXML file that loads up a small window to choose a member Id, by this Id I am getting the info to build the table on the code above.
the code for this method in ViewLogic is as follows:
#FXML
Button ShowReservationsForClientBtn= new Button();/*Code for pressing the get reservations for client button to open window after pressing the button in Queries*/
#FXML
public void pressShowReservationsForClientBtn(ActionEvent event) throws Exception {
try {
FXMLLoader fxmlLoader = new FXMLLoader(ChooseAClientForReservationsQueryWindowController.class.getResource("/view/ChooseAClientForReservationsQueryWindow.fxml"));
AnchorPane chooseMemberIdForQuery = (AnchorPane) fxmlLoader.load();
ChooseAClientForReservationsQueryWindowController controller = fxmlLoader.getController();
controller.setAddTripToReservationClass();
Stage stage = new Stage();
stage.setTitle("Please Choose a Member Id");
stage.setScene(new Scene(chooseMemberIdForQuery));
stage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
It then calls this class where you choose your member and then the table code above is initiated, the mini window code is:
package view;
import java.util.ArrayList;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonType;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Stage;
public class ChooseAClientForReservationsQueryWindowController {
private String memIdChosen;
#FXML
private ComboBox<String> MemberIds;
public void initialize() {
}
#FXML
Button CloseBtn = new Button();//close button inside AddLocation window
#FXML
public void handleCloseButtonAction(ActionEvent event) {//for all close Button's this method is called
Stage stage = (Stage) CloseBtn.getScene().getWindow();
stage.close();
}
#FXML
Button EraseBtn = new Button();//erase Button
#FXML
public void handleEraseButtonAction(ActionEvent event) {//erase Button code
MemberIds.setValue(null);
}
#FXML
Button GoBtn = new Button();//Go button
#FXML
public void handleGoBtn(ActionEvent event) throws Exception {//for all close Button's this method is called
try{
if(MemberIds.getValue()==null)
throw new Exception();
FXMLLoader fxmlLoader = new FXMLLoader(QRYClientReservationsTableController.class.getResource("/view/QRYClientReservationsTableController.fxml"));
AnchorPane qryShowAllReservationsForMember = (AnchorPane) fxmlLoader.load();
QRYClientReservationsTableController controller = fxmlLoader.getController();
controller.setQRYClientReservationsTableController(memIdChosen);
Stage stage = new Stage();
stage.setTitle("Query - Show all reservations for member Id: "+memIdChosen+".");
stage.setScene(new Scene(qryShowAllReservationsForMember));
stage.show();
handleCloseButtonAction(event);
}
catch (Exception e){
Alert alert = new Alert(AlertType.WARNING,"One of the fields is empty", ButtonType.OK);
alert.setTitle("One of the fields is empty");
alert.setHeaderText("One of the fields is empty");
alert.setContentText("Please fill the empty fields");
alert.showAndWait();
}
}
/**
* The constructor.
* The constructor is called before the initialize() method.
*/
public ChooseAClientForReservationsQueryWindowController() {
}
public void setAddTripToReservationClass(){
ArrayList<String> memIds = new ArrayList<String>();
memIds.addAll(ViewLogic.controlLogic.getMembers().keySet());
MemberIds.getItems().setAll(memIds);
MemberIds.valueProperty().addListener(new ChangeListener<String>(){
#Override
public void changed(ObservableValue<? extends String> arg0, String arg1, String arg2) {
memIdChosen=arg2;
}
});
}
}
That's the relevant FXML file for the table code above if it helps:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.text.*?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="600.0" prefWidth="1450.0" xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1" fx:controller="view.QRYClientReservationsTableController">
<children>
<ButtonBar layoutX="44.0" layoutY="541.0" prefHeight="40.0" prefWidth="700.0" AnchorPane.bottomAnchor="19.0">
<buttons>
<Button fx:id="CloseBtn" mnemonicParsing="false" onAction="#handleCloseButtonAction" prefHeight="31.0" prefWidth="212.0" text="Close" />
</buttons>
</ButtonBar>
<TableView fx:id="ReservationforClient" layoutX="5.0" layoutY="55.0" prefHeight="486.0" prefWidth="893.0" AnchorPane.bottomAnchor="59.0" AnchorPane.leftAnchor="5.0" AnchorPane.rightAnchor="2.0" AnchorPane.topAnchor="55.0">
<columns>
<TableColumn fx:id="ReservationIdColumn" prefWidth="121.0" text="Reservation Id" />
<TableColumn fx:id="LocationIdColumn" prefWidth="128.0" text="Location Id" />
<TableColumn fx:id="AddressColumn" prefWidth="276.0" text="Address" />
<TableColumn fx:id="DescriptionColumn" prefWidth="382.0" text="Description" />
<TableColumn fx:id="StartTimeAndDateColumn" prefWidth="282.0" text="Start Time and Date" />
<TableColumn fx:id="EndTimeAndDateColumn" prefWidth="252.0" text="EndTime and Date" />
</columns>
</TableView>
<Label layoutX="394.0" layoutY="8.0" prefHeight="40.0" prefWidth="350.0" text="Reservations for Client Id:" AnchorPane.leftAnchor="394.0" AnchorPane.rightAnchor="706.0" AnchorPane.topAnchor="8.0">
<font>
<Font name="System Bold" size="28.0" />
</font>
</Label>
<TextField fx:id="memId" editable="false" layoutX="738.0" layoutY="10.0" prefHeight="40.0" prefWidth="191.0" />
</children>
</AnchorPane>
Thank you
Tom
I stumbled across the similar problem and have created a simple library that solves it.
It uses your model class to build a TableView that represents the fields of the given class.
I've published it on GitHub with a sample and instruction.
If you have any suggestions, I would like to hear from you.
You can do it through reflection. This will make an editable String column for each SimpleStringProperty field. Doing it like this means you can't add them in FXML.
for (Field f : TableInfo.class.getDeclaredFields()) {
if (f.getType().equals(SimpleStringProperty.class)){
TableColumn<TableInfo, String> tc = new TableColumn<>(f.getName());
tv.getColumns().add(tc);
tc.setCellValueFactory(new PropertyValueFactory<>(f.getName()));
tc.setCellFactory(TextFieldTableCell.forTableColumn());
}//else if more field types...
}
I have a well established Swing application that I'm partially upgrading to JavaFX using JFXPanel. The JFrame with the JFXPanel gets a scene from another class which creates a root node in code (not FXML) that is an HBox with a pretty simple left-hand sidebar with dynamically generated links and buttons and stuff and a right-hand side that is dynamically filled in with content based on the button a user presses on the left side. The right-side content is built with several sets of FXML and controller classes.
Within each of these right-side content classes, I have to bring up some standard Swing JDialogs or JOptionPane's that accept a parent (JFrame or JDialog) in the constructor for screen placement and modality. (These JDialogs and JOptionPanes come from a library of common components that we have written over the years)
Is there a way at runtime for me to get a reference to the JFrame containing the JFXPanel so I can instantiate them with proper modality?
** EDIT **
Modality actually works
What I really want to do now is center the dialog over the parent. Of course, I'm sure that this will be useful for a myriad of other reasons for me in the future.
Here is an abbreviated version. I have been able to run it, so it should work for you.
I apologize if this is a bit messy :-S
Thanks a ton for your assistance!
This is the main class:
import java.awt.*;
import java.io.IOException;
import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;
import javafx.scene.Scene;
import javafx.fxml.FXML;
import javax.swing.*;
public class SwingMain extends JFrame {
public static final String TITLE = "Main JFrame";
private GridBagLayout gridBagLayout1 = new GridBagLayout();
private JPanel jPanel = new JPanel();
private JFXPanel jfxPanel = new JFXPanel();
private JFXSceneMaker sceneMaker = new JFXSceneMaker(this);
public SwingMain() {
super();
try {
init();
} catch (Exception ex) {
ex.printStackTrace();
}
}
public static void main(String[] args) {
final SwingMain swingMainTest = new SwingMain();
swingMainTest.setVisible(true);
}
void init() throws Exception {
Dimension minimumSize = new Dimension(1280, 864);
this.setMinimumSize(minimumSize);
this.setPreferredSize(minimumSize);
jPanel.setLayout(gridBagLayout1);
this.setTitle(TITLE);
Platform.setImplicitExit(false);
try {
prepareScene();
} catch (Exception ex) {
// log error
}
getContentPane().add(jPanel);
jPanel.add(jfxPanel, new GridBagConstraints(0, 1, 1, 1, 1.0, 1.0,
GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(
0, 0, 0, 0), 0, 0));
}
protected void prepareScene() {
Platform.runLater(new Runnable() {
#Override
public void run() {
try {
Scene scene = sceneMaker.getScene();
jfxPanel.setScene(scene);
} catch (IOException ioex) {
// log error
}
}
});
}
}
This is the class that provides the scene for the JFXPanel
import java.io.IOException;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javafx.animation.*;
import javafx.application.Platform;
import javafx.collections.ListChangeListener;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXMLLoader;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.SceneBuilder;
import javafx.scene.control.Hyperlink;
import javafx.scene.control.Label;
import javafx.scene.control.Toggle;
import javafx.scene.control.ToggleButton;
import javafx.scene.control.ToggleGroup;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.Priority;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import javafx.scene.text.TextAlignment;
import javafx.util.Duration;
public class JFXSceneMaker {
private static final Interpolator interpolator = Interpolator.SPLINE(0.4829, 0.5709, 0.6803, 0.9928);
// To obtain a scalable page layout, you define all positions and sizes in terms of “root em” (rem),
// the em size of the default font
private final double rem = Math.rint(new Text("").getLayoutBounds().getHeight());
private double SIDEBAR_WIDTH = rem * 13;
private Pane root;
private StackPane currentPane, sparePane;
private VBox sideBar;
private int currentPaneIndex = 0;
private Timeline timeline;
private ContentPane nextPane = null;
private int nextPaneIndex;
private JFrame swingParent;
public static final String TITLE = "JavaFX Rocks!";
private ContentPane[] panes;
public JFXSceneMaker(JFrame frame) {
// This is a reference to the Swing parent JFrame that I want to place the JOptionPanes and JDialogs over
this.swingParent = frame;
}
public Scene getScene() throws IOException {
Parent pane1 = FXMLLoader.load(Pane1Controller.class.getResource("pane1contentPane.fxml"));
Parent pane2 = FXMLLoader.load(Pane2Controller.class.getResource("pane2contentPane.fxml"));
Parent pane3 = FXMLLoader.load(Pane3Controller.class.getResource("pane3contentPane.fxml"));
panes = new ContentPane[]{
new ContentPane("Panel1", pane1),
new ContentPane("Panel2", pane2),
new ContentPane("Panel3", pane3)
};
// create the left-hand side bar
sideBar = new VBox(0);
sideBar.setId("SideBar");
sideBar.setPrefWidth(SIDEBAR_WIDTH);
sideBar.setMinWidth(SIDEBAR_WIDTH);
sideBar.setMaxWidth(SIDEBAR_WIDTH);
sideBar.setStyle("-fx-background-color: #25282c");
HBox.setHgrow(sideBar, Priority.NEVER);
PersistentButtonToggleGroup toggleGroup = new PersistentButtonToggleGroup();
for (int i=0; i < panes.length; i++) {
final int index = i;
final ContentPane contentPane = panes[i];
final ToggleButton button = new ToggleButton(contentPane.getName());
if (i==0) {
Platform.runLater(new Runnable() {
#Override public void run() {
button.setSelected(true);
button.requestFocus();
}
});
}
button.setMaxWidth(Double.MAX_VALUE);
button.setAlignment(Pos.CENTER_LEFT);
button.setTextAlignment(TextAlignment.LEFT);
button.setToggleGroup(toggleGroup);
button.setOnAction(new EventHandler<ActionEvent>() {
#Override public void handle(ActionEvent t) {
switchcontentPane(contentPane, index);
}
});
sideBar.getChildren().add(button);
}
// current Pane and sparePane are used for switching between panes
currentPane = new StackPane();
currentPane.getChildren().setAll(panes[0].getContent());
sparePane = new StackPane();
sparePane.setVisible(false);
// contentPanePane is the right side of the scene where the relevant content is displayed
StackPane contentPanePane = new StackPane();
HBox.setHgrow(contentPanePane, Priority.ALWAYS);
contentPanePane.getChildren().addAll(currentPane, sparePane);
AnchorPane.setTopAnchor(currentPane, 0.0);
AnchorPane.setRightAnchor(currentPane, 0.0);
AnchorPane.setBottomAnchor(currentPane, 0.0);
AnchorPane.setLeftAnchor(currentPane, 0.0);
//create root node
root = new HBox();
root.setMinSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE);
root.setPrefSize(1250, 844);
root.getChildren().addAll(sideBar,contentPanePane);
return SceneBuilder.create()
.root(root)
.build();
}
public void switchcontentPane(ContentPane newcontentPane, final int contentPaneIndex) {
// check if existing animation running
if (timeline != null) {
nextPane = newcontentPane;
nextPaneIndex = contentPaneIndex;
timeline.setRate(4);
return;
} else {
nextPane = null;
nextPaneIndex = -1;
}
// load new content
sparePane.getChildren().setAll(newcontentPane.getContent());
sparePane.setCache(true);
currentPane.setCache(true);
// wait one pulse then animate
Platform.runLater(new Runnable() {
#Override public void run() {
// animate switch
if (contentPaneIndex > currentPaneIndex) { // animate from bottom
currentPaneIndex = contentPaneIndex;
sparePane.setTranslateY(root.getHeight());
sparePane.setVisible(true);
timeline = TimelineBuilder.create().keyFrames(
new KeyFrame(Duration.millis(0),
new KeyValue(currentPane.translateYProperty(),0,interpolator),
new KeyValue(sparePane.translateYProperty(),root.getHeight(),interpolator)
),
new KeyFrame(Duration.millis(800),
animationEndEventHandler,
new KeyValue(currentPane.translateYProperty(),-root.getHeight(),interpolator),
new KeyValue(sparePane.translateYProperty(),0,interpolator)
)
)
.build();
timeline.play();
} else { // from top
currentPaneIndex = contentPaneIndex;
sparePane.setTranslateY(-root.getHeight());
sparePane.setVisible(true);
timeline = TimelineBuilder.create()
.keyFrames(
new KeyFrame(Duration.millis(0),
new KeyValue(currentPane.translateYProperty(),0,interpolator),
new KeyValue(sparePane.translateYProperty(),-root.getHeight(),interpolator)
),
new KeyFrame(Duration.millis(800),
animationEndEventHandler,
new KeyValue(currentPane.translateYProperty(),root.getHeight(),interpolator),
new KeyValue(sparePane.translateYProperty(),0,interpolator)
)
)
.build();
timeline.play();
}
}
});
}
private EventHandler<ActionEvent> animationEndEventHandler = new EventHandler<ActionEvent>() {
#Override public void handle(ActionEvent t) {
// switch panes
StackPane temp = currentPane;
currentPane = sparePane;
sparePane = temp;
// cleanup
timeline = null;
currentPane.setTranslateY(0);
sparePane.setCache(false);
currentPane.setCache(false);
sparePane.setVisible(false);
sparePane.getChildren().clear();
// start any animations
// check if we have a animation waiting
if (nextPane != null) {
switchcontentPane(nextPane, nextPaneIndex);
}
}
};
public static class PersistentButtonToggleGroup extends ToggleGroup {
PersistentButtonToggleGroup() {
super();
getToggles().addListener(new ListChangeListener<Toggle>() {
#Override
public void onChanged(Change<? extends Toggle> c) {
while (c.next())
for (final Toggle addedToggle : c.getAddedSubList())
((ToggleButton) addedToggle).addEventFilter(MouseEvent.MOUSE_RELEASED,
new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent mouseEvent) {
if (addedToggle.equals(getSelectedToggle()))
mouseEvent.consume();
}
});
}
});
}
}
}
This is the class that will contain the content for the right side panes
import javax.swing.JFrame;
import javafx.scene.Parent;
public class ContentPane {
private String name;
private Parent content;
protected JFrame swingParent;
public ContentPane(String name, Parent content) {
this.name = name;
this.content = content;
}
public String getName() {
return name;
}
public Parent getContent() {
return content;
}
}
This is the fxml for the first content pane
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane fx:id="content" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="Pane1Controller">
<children>
<VBox AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<children>
<Label maxWidth="1.7976931348623157E308" minHeight="-Infinity" prefHeight="48.0" style="-fx-font-size: 24; -fx-text-fill: #e6e6e6; -fx-background-color: #0072bc; -fx-label-padding: 0 0 0 12;" text="Pane 1" VBox.vgrow="NEVER" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
</Label>
<AnchorPane xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<children>
<StackPane prefHeight="25.0" prefWidth="125.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<children>
<Button fx:id="optionButton1" mnemonicParsing="false" text="Show a JOptionPane" />
</children>
</StackPane>
</children>
</AnchorPane>
</children>
</VBox>
</children>
</AnchorPane>
This is the controller for the first pane
import java.net.URL;
import java.util.ResourceBundle;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javafx.event.ActionEvent;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.fxml.Initializable;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
public class Pane1Controller implements Initializable {
#FXML private Button optionButton1;
private JFrame swingParent;
#Override
public void initialize(URL arg0, ResourceBundle arg1) {
optionButton1.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent e) {
showJOptionPane();
}
});
}
private void showJOptionPane() {
JOptionPane.showMessageDialog(swingParent, "So...now what?");
}
}
Second pane fxml...
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane fx:id="content" prefHeight="73.0" prefWidth="161.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="Pane2Controller">
<children>
<VBox AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<children>
<Label maxWidth="1.7976931348623157E308" minHeight="-Infinity" prefHeight="48.0" style="-fx-font-size: 24; -fx-text-fill: #e6e6e6; -fx-background-color: #0072bc; -fx-label-padding: 0 0 0 12;" text="Pane 2" VBox.vgrow="NEVER" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
</Label>
<AnchorPane xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<children>
<StackPane prefHeight="25.0" prefWidth="125.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<children>
<Button fx:id="optionButton2" mnemonicParsing="false" text="Show another JOptionPane" />
</children>
</StackPane>
</children>
</AnchorPane>
</children>
</VBox>
</children>
</AnchorPane>
Second pane controller...
import java.net.URL;
import java.util.ResourceBundle;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javafx.event.ActionEvent;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.fxml.Initializable;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
public class Pane2Controller implements Initializable {
#FXML private Button optionButton2;
private JFrame swingParent;
#Override
public void initialize(URL arg0, ResourceBundle arg1) {
optionButton2.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent e) {
showJOptionPane();
}
});
}
private void showJOptionPane() {
JOptionPane.showMessageDialog(swingParent, "Here we go again.");
}
}
Third pane fxml...
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane fx:id="content" prefHeight="73.0" prefWidth="161.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="Pane3Controller">
<children>
<VBox AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<children>
<Label maxWidth="1.7976931348623157E308" minHeight="-Infinity" prefHeight="48.0" style="-fx-font-size: 24; -fx-text-fill: #e6e6e6; -fx-background-color: #0072bc; -fx-label-padding: 0 0 0 12;" text="Pane 3" VBox.vgrow="NEVER" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
</Label>
<AnchorPane xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<children>
<StackPane prefHeight="25.0" prefWidth="125.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<children>
<Button fx:id="optionButton3" mnemonicParsing="false" text="Show yet another JOptionPane" />
</children>
</StackPane>
</children>
</AnchorPane>
</children>
</VBox>
</children>
</AnchorPane>
3rd controller...
import java.net.URL;
import java.util.ResourceBundle;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javafx.event.ActionEvent;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.fxml.Initializable;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
public class Pane3Controller implements Initializable {
#FXML private Button optionButton3;
private JFrame swingParent;
#Override
public void initialize(URL arg0, ResourceBundle arg1) {
optionButton3.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent e) {
showJOptionPane();
}
});
}
private void showJOptionPane() {
JOptionPane.showMessageDialog(swingParent, "Here we go again.");
}
}
JFXPanel extends JComponent, therefore you should be able to get a runtime reference to the JFrame the same way you would using any Swing component. I'm assuming you're using something like getRootPane(...).
As an alternative to getting a runtime reference, you could always create your own class extending JFXPanel and pass in a reference to the JFrame in your custom constructor.
Edit
If you make your SwingMain class into a singleton, you should be able to easily get a references to any of it's fields. Here's a demo of how you could use it.
import java.awt.Color;
import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;
import javafx.scene.*;
import javafx.scene.text.*;
import javax.swing.*;
public class SwingJFXCombo {
/**
* The control who starts everything.
* This should have the references you need.
* Uses the singleton pattern
*/
public static class MainController{
//Top level fields we may need access too
JFXPanel jfxPanel;
JPanel jp;
JFrame frame;
//Doing singleton stuff
private static MainController instance;
public static MainController getInstance(){
if(instance == null){
instance = new MainController();
}
return instance;
}
private MainController(){
jfxPanel = new JFXPanel();
jp = new JPanel();
jp.add(jfxPanel);
jp.setVisible(true);
jp.setBackground(Color.CYAN);
//Setup to display swing stuff
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
frame.add(jp);
frame.pack();
}
public static void initialize(){
getInstance();
Platform.runLater(new Runnable() {
#Override
public void run() {
MainController mc = getInstance();
Scene scene = mc.initScene();
mc.jfxPanel.setScene(scene);
}
});
}
private Scene initScene(){
Group root = new Group();
Scene scene = new Scene(root, javafx.scene.paint.Color.ALICEBLUE);
Text text = new Text(40,100,"JavaFX Scene");
text.setFont(new Font(25));
root.getChildren().add(text);
return (scene);
}
}
/**
* Another random class for demonstration purposes
* This would be similar to your FX Controllers
*/
public static class RandomController{
public void printFrameColor(){
//Now from anywhere, I can get any of the top level items by calling the singleton
System.out.println(MainController.getInstance().frame.getBackground());
}
}
public static void main(String[] args){
MainController.initialize();
new RandomController().printFrameColor();
}
}