I need to insert values in list view in one by one like chatting.
now my code is
#FXML
private ListView<String> messageList;
private ObservableList<String> messages = FXCollections.observableArrayList();
messageList.setItems(messages);
This may be similar to what you are asking.
Main:
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class ChatApp 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.ResourceBundle;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.ListView;
import javafx.scene.control.TextField;
public class FXMLDocumentController implements Initializable {
#FXML private ListView lvChatWindow;
#FXML private TextField tfUser1, tfUser2;
ObservableList<String> chatMessages = FXCollections.observableArrayList();//create observablelist for listview
//Method use to handle button press that submits the 1st user's text to the listview.
#FXML
private void handleUser1SubmitMessage(ActionEvent event) {
chatMessages.add("User 1: " + tfUser1.getText());//get 1st user's text from his/her textfield and add message to observablelist
tfUser1.setText("");//clear 1st user's textfield
}
//Method use to handle button press that submits the 2nd user's text to the listview.
#FXML
private void handleUser2SubmitMessage(ActionEvent event) {
chatMessages.add("User 2: " + tfUser2.getText());//get 2nd user's text from his/her textfield and add message to observablelist
tfUser2.setText("");//clear 2nd user's textfield
}
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
lvChatWindow.setItems(chatMessages);//attach the observablelist to the listview
}
}
FXML:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ListView?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane id="AnchorPane" prefHeight="349.0" prefWidth="549.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8.0.60" fx:controller="chatapp.FXMLDocumentController">
<children>
<Button fx:id="bntUser1Send" layoutX="99.0" layoutY="299.0" onAction="#handleUser1SubmitMessage" text="send message user1" />
<Label fx:id="label" layoutX="126" layoutY="120" minHeight="16" minWidth="69" />
<Button fx:id="btnUser2Send" layoutX="351.0" layoutY="299.0" mnemonicParsing="false" onAction="#handleUser2SubmitMessage" text="send message user2" />
<ListView fx:id="lvChatWindow" layoutX="75.0" layoutY="29.0" prefHeight="200.0" prefWidth="419.0" />
<TextField fx:id="tfUser1" layoutX="36.0" layoutY="258.0" prefHeight="25.0" prefWidth="239.0" />
<TextField fx:id="tfUser2" layoutX="293.0" layoutY="258.0" prefHeight="25.0" prefWidth="239.0" />
</children>
</AnchorPane>
This app simulates two different users sending messages to one listview. Similar to a chat. More comments in Controller
Related
I have a FXML view that contains a TabView with multiple tabs.
Every Tab has it's own FXML component + controller.
I would like all tabs to report progress via a component defined defined in the main view.
I know that I can inject child controllers into the main controller via FXML.
But to my current understanding, I need to access the parent controller inside my child controllers since the component is located in the main view.
I can also access the child controllers inside the initialize method of my main view. If I follow this path, I would need to modify the child controllers to set the shared component.
This is suboptimal, since the child components would be dependent on a main view that is performing those changes.
I created a MWE to illustrate the dilemma.
The question in short:
How can I report progress of Service1 and Service2 to the progressAndStatusGrid in the main view?
Callenge in short:
Make this application not throw a NPE and report progress to the progress component ;)
MWE:
Launcher:
package org.example;
public class Launcher {
public static void main(final String[] args) {
SimpleApplication.main(args);
}
}
Application:
package org.example;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class SimpleApplication extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/fxml/MainView.fxml"));
#SuppressWarnings("unused")
MainViewController controller = fxmlLoader.getController();
final Parent root = fxmlLoader.load();
final Scene scene = new Scene(root);
primaryStage.setTitle("Hello World");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
Application.launch(args);
}
}
MainController:
package org.example;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.layout.GridPane;
import java.net.URL;
import java.util.ResourceBundle;
public class MainViewController implements Initializable {
#FXML
GridPane progressAndStatusGrid;
#Override
public void initialize(URL url, ResourceBundle resourceBundle) {
}
}
MainView:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Tab?>
<?import javafx.scene.control.TabPane?>
<?import javafx.scene.layout.BorderPane?>
<BorderPane prefHeight="150.0" prefWidth="350.0" xmlns="http://javafx.com/javafx/17.0.2-ea"
xmlns:fx="http://javafx.com/fxml/1" fx:controller="org.example.MainViewController">
<padding>
<Insets top="4" right="4" bottom="4" left="4"/>
</padding>
<top>
</top>
<center>
<TabPane>
<Tab text="tab1" closable="false">
<fx:include fx:id="tab1" source="Tab1View.fxml"/>
</Tab>
<Tab text="tab2" closable="false">
<fx:include fx:id="tab2" source="Tab2View.fxml"/>
</Tab>
</TabPane>
</center>
<bottom>
<fx:include fx:id="progressAndStatusGrid"
source="ProgressAndStatusGridComponent.fxml"/>
</bottom>
</BorderPane>
"Shared" componentController:
package org.example;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar;
import javafx.scene.layout.HBox;
import java.net.URL;
import java.util.ResourceBundle;
public class ProgressAndStatusGridComponentController implements Initializable {
#FXML
ProgressBar progressBar;
#FXML
HBox progressStatusBox;
#FXML
Label progressLabel;
#Override
public void initialize(URL url, ResourceBundle resourceBundle) {
}
}
"Shared" componentView:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ProgressBar?>
<?import javafx.scene.layout.*?>
<GridPane xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
fx:controller="org.example.ProgressAndStatusGridComponentController"
hgap="4" vgap="4">
<padding>
<Insets top="4" right="4" bottom="4" left="4"/>
</padding>
<fx:define>
<ColumnConstraints fx:id="colConstraints2" percentWidth="100"/>
</fx:define>
<columnConstraints>
<fx:reference source="colConstraints2"/>
<fx:reference source="colConstraints2"/>
</columnConstraints>
<ProgressBar fx:id="progressBar" GridPane.columnIndex="0" GridPane.rowIndex="0"/>
<HBox fx:id="progressStatusBox" alignment="CENTER" spacing="4" GridPane.columnIndex="1" GridPane.rowIndex="0">
<padding>
<Insets top="4" right="4" bottom="4" left="4"/>
</padding>
<Label fx:id="progressLabel"/>
</HBox>
</GridPane>
Tab1Controller:
package org.example;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import java.net.URL;
import java.util.ResourceBundle;
public class Tab1Controller implements Initializable {
#FXML
Button button1;
Service1 service1 = new Service1();
// How to get a reference, that is already initialized?
#FXML
ProgressAndStatusGridComponentController progressAndStatusGridComponentController;
#Override
public void initialize(URL url, ResourceBundle resourceBundle) {
button1.disableProperty().bind(service1.runningProperty());
}
public void handleButtonClick(ActionEvent actionEvent) {
service1.cancel();
service1.reset();
progressAndStatusGridComponentController.progressBar.progressProperty().bind(service1.progressProperty());
progressAndStatusGridComponentController.progressLabel.textProperty().bind(service1.messageProperty());
service1.start();
}
}
Tab1View:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.BorderPane?>
<BorderPane xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
fx:controller="org.example.Tab1Controller">
<center>
<Button fx:id="button1" text="Start Background Progress #1" onAction="#handleButtonClick"/>
</center>
</BorderPane>
Tab2Controller:
package org.example;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import java.net.URL;
import java.util.ResourceBundle;
public class Tab2Controller implements Initializable {
#FXML
Button button2;
Service2 service2 = new Service2();
// How to get a reference, that is already initialized?
#FXML
ProgressAndStatusGridComponentController progressAndStatusGridComponentController;
#Override
public void initialize(URL url, ResourceBundle resourceBundle) {
button2.disableProperty().bind(service2.runningProperty());
}
public void handleButtonClick(ActionEvent actionEvent) {
service2.cancel();
service2.reset();
progressAndStatusGridComponentController.progressBar.progressProperty().bind(service2.progressProperty());
progressAndStatusGridComponentController.progressLabel.textProperty().bind(service2.messageProperty());
service2.start();
}
}
Tab2View:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.BorderPane?>
<BorderPane xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
fx:controller="org.example.Tab2Controller">
<center>
<Button fx:id="button2" text="Start Background Progress #2" onAction="#handleButtonClick"/>
</center>
</BorderPane>
Service1:
package org.example;
import javafx.concurrent.Service;
import javafx.concurrent.Task;
public class Service1 extends Service<Void> {
static final int workLoad = 100;
#Override
protected Task<Void> createTask() {
return new Task<>() {
#Override
protected Void call() throws Exception {
updateMessage("Starting Task #1..");
for (int i = 0; i < workLoad; i++) {
Thread.sleep(200);
updateProgress(i, workLoad);
updateMessage(i + " elements done");
}
updateMessage("Task #1 done!");
return null;
}
};
}
}
Service2:
package org.example;
import javafx.concurrent.Service;
import javafx.concurrent.Task;
public class Service2 extends Service<Void> {
static final int workLoad = 100;
#Override
protected Task<Void> createTask() {
return new Task<>() {
#Override
protected Void call() throws Exception {
updateMessage("Starting Task #2..");
for (int i = 0; i < workLoad; i++) {
Thread.sleep(200);
updateProgress(i, workLoad);
updateMessage(i + " elements done");
}
updateMessage("Task #2 done!");
return null;
}
};
}
}
This is how I unbindBiDirectional from a class FamilyMember that contains a string variable called 'txtName'. I unbind the old value and clear it, and then bind the new value.
Unbinding:
((TreeItem<FamilyMember>)oldValue).getValue().nameProperty().unbindBidirectional(txtName.textProperty());
txtName.clear();
Binding:
txtName.setText(((TreeItem<FamilyMember>)newValue).getValue().nameProperty().getValue());
((TreeItem<FamilyMember>)newValue).getValue().nameProperty().bindBidirectional(txtName.textProperty());
But im confused as to how to do this for a ComboBox. My ComboBox is for selecting a gender with 3 options as strings, (ComboBox), Male, Female and Other. How can I achieve the above using a ComboBox with String Property instead?
Controller Class:
package sample;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import java.net.URL;
import java.util.Random;
import java.util.ResourceBundle;
public class Controller implements Initializable {
#FXML
private ComboBox<String> genderComboBox;
#FXML
private Label selectedGenderLabel;
private Random random = new Random();
#Override
public void initialize(URL location, ResourceBundle resources) {
// Add items:
genderComboBox.getItems().addAll("Male", "Female", "Other");
// Bind selection of combo box to string property:
selectedGenderLabel.textProperty().bind(genderComboBox.valueProperty());
}
#FXML
public void handleUnbindBtnClick() {
// Un-bind and clear:
selectedGenderLabel.textProperty().unbind();
selectedGenderLabel.setText("");
}
#FXML
public void handleBindBtnClick() {
// Make a random selection:
genderComboBox.getSelectionModel().select(random.nextInt(3));
// Re-bind:
selectedGenderLabel.textProperty().bind(genderComboBox.valueProperty());
}
}
FXML file:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ComboBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.VBox?>
<VBox xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.Controller">
<children>
<ComboBox fx:id="genderComboBox" />
<Label text="Selected Gender:" />
<Label fx:id="selectedGenderLabel" />
<Button mnemonicParsing="false" onAction="#handleUnbindBtnClick" text="Unbind" />
<Button mnemonicParsing="false" onAction="#handleBindBtnClick" text="Bind" />
</children>
</VBox>
I'm working on a personal weather project that contains Main.fxml, MainController.java, EnterCityDocument.fxml, and EnterCityDocumentController.java.
Main.fxml: contains a border-pane and at its center it has a ListView that displays names of cities. It also has a "Add" Button to open a new modal window(EnterCityDocument.fxml) to add a city to its ListView.
EnterCityDocument.fxml: has a listView that contains names of cities and a "Select" button to select a city the user wants to display in Main.fxml. When the user clicks the "Select" Button, the modal window (EnterCityDocument.fxml) closes and the Main.fxml continues to run.
MainController.java is the parent class of EnterCityDocumentController.java.
I've been looking for passing data from the child class(EnterCityDocumentController.java) to the parent class (MainController.java) and found a way to do it, but all of the methods i've found require to refresh the MainController.java class whenever the user selects a city in EnterCityDocumentController.java.
Is there a way to update the Main.fxml without refreshing the main scene when a new city is added into the listView of the Main.fxml?
Hope my question is clear enough. If you need a further explanation/code, please let me know!
All you need to do is arrange for the new city from the dialog to be added to the list view's backing list. Since you are using showAndWait() this is very easy: just define a method in the EnterCityDocumentController class that returns the new city, and call it after showAndWait():
public class EnterCityDocumentController {
#FXML
private TextField cityNameField ;
// other fields, etc...
#FXML
private void okButtonPressed() {
// just close the window:
cityNameField.getScene().getWindow().hide();
}
public City getUserCity() {
return new City(cityNameField.getText());
}
}
Then in the main controller:
public class MainController {
#FXML
private ListView<City> listView ;
// handler method:
#FXML
public void addNewCity() throws IOException {
FXMLLoader loader = new FXMLLoader(EnterCityDocumentController.class.getResource("EnterCityDocument.fxml"));
Scene scene = new Scene(loader.load());
Stage stage = new Stage();
stage.setScene(scene);
stage.showAndWait();
listView.getItems().add(controller.getUserCity());
}
}
Here is a SSCCE:
app/Main.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ListView?>
<?import javafx.scene.layout.BorderPane?>
<BorderPane xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="app.MainController">
<center>
<ListView fx:id="listView" prefHeight="200.0" prefWidth="200.0" BorderPane.alignment="CENTER" />
</center>
<bottom>
<Button mnemonicParsing="false" onAction="#addNewElement" text="Add..." BorderPane.alignment="CENTER">
<BorderPane.margin>
<Insets bottom="2.0" left="2.0" right="2.0" top="2.0" />
</BorderPane.margin>
</Button>
</bottom>
</BorderPane>
app/AddNewElement.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<GridPane hgap="5.0" vgap="5.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="app.AddNewElementController">
<rowConstraints>
<RowConstraints />
<RowConstraints />
</rowConstraints>
<columnConstraints>
<ColumnConstraints halignment="CENTER" />
<ColumnConstraints halignment="CENTER" />
</columnConstraints>
<children>
<TextField fx:id="textField" GridPane.columnSpan="2" />
<Button defaultButton="true" mnemonicParsing="false" onAction="#ok" text="OK" GridPane.rowIndex="1" />
<Button cancelButton="true" mnemonicParsing="false" onAction="#cancel" text="Cancel" GridPane.columnIndex="1" GridPane.rowIndex="1" />
</children>
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</padding>
</GridPane>
app/AddNewElementController.java:
package app;
import javafx.fxml.FXML;
import javafx.scene.control.TextField;
public class AddNewElementController {
#FXML
private TextField textField ;
private boolean approved ;
public boolean isApproved() {
return approved ;
}
public String getUserText() {
return isApproved() ? textField.getText() : null ;
}
#FXML
private void cancel() {
approved = false ;
hide();
}
#FXML
private void ok() {
approved = true ;
hide();
}
private void hide() {
textField.getScene().getWindow().hide();
}
}
app/MainController.java:
package app;
import java.io.IOException;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.ListView;
import javafx.stage.Modality;
import javafx.stage.Stage;
public class MainController {
#FXML
private ListView<String> listView ;
#FXML
private void addNewElement() throws IOException {
FXMLLoader loader = new FXMLLoader(AddNewElementController.class.getResource("AddNewElement.fxml"));
Parent root = loader.load();
AddNewElementController controller = loader.getController();
Scene scene = new Scene(root);
Stage stage = new Stage();
stage.initModality(Modality.APPLICATION_MODAL);
stage.initOwner(listView.getScene().getWindow());
stage.setScene(scene);
stage.showAndWait();
if (controller.isApproved()) {
listView.getItems().add(controller.getUserText());
}
}
}
app/Main.java:
package app;
import java.io.IOException;
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 IOException {
FXMLLoader loader = new FXMLLoader(MainController.class.getResource("Main.fxml"));
Parent root = loader.load();
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Another, very slightly different approach, is to pass the listview's backing list to the second controller. Then the second controller can add the item directly to the list (and the list view will automatically update, as before). This approach can be used even if you are not using showAndWait() (it doesn't rely on the code blocking until the user dismisses the window).
package app;
import java.util.List;
import javafx.fxml.FXML;
import javafx.scene.control.TextField;
public class AddNewElementController {
#FXML
private TextField textField ;
private List<String> itemList ;
public void setItemList(List<String> itemList) {
this.itemList = itemList ;
}
#FXML
private void cancel() {
hide();
}
#FXML
private void ok() {
itemList.add(textField.getText());
hide();
}
private void hide() {
textField.getScene().getWindow().hide();
}
}
and
package app;
import java.io.IOException;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.ListView;
import javafx.stage.Modality;
import javafx.stage.Stage;
public class MainController {
#FXML
private ListView<String> listView ;
#FXML
private void addNewElement() throws IOException {
FXMLLoader loader = new FXMLLoader(AddNewElementController.class.getResource("AddNewElement.fxml"));
Parent root = loader.load();
AddNewElementController controller = loader.getController();
controller.setItemList(listView.getItems());
Scene scene = new Scene(root);
Stage stage = new Stage();
stage.initModality(Modality.APPLICATION_MODAL);
stage.initOwner(listView.getScene().getWindow());
stage.setScene(scene);
stage.showAndWait();
}
}
I'm a total beginner in programming. I've been trying to create a simple program that gets two values from the user (two grades from 0 to 10) and returns the average between them. I've done it with Swing and JOptionPane but using javafx I got nothing. Here goes the code.
package fxcalcmedia;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class FXCalcMedia 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();
stage.setTitle("CALCULADORA DE MÉDIA");
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
package fxcalcmedia;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.text.Text;
public class FXMLDocumentController implements Initializable {
#FXML
private Label lblMedia;
private Button btnCalc;
private Text txtMedia;
private Text txtNota1;
private Text txtNota2;
#FXML
private void clicouBotao(ActionEvent event) {
double nota1 = Double.parseDouble(txtNota1.getText());
double nota2 = Double.parseDouble(txtNota2.getText());
double media = (nota1+nota2)/2;
txtMedia.setText(Double.toString(media));
}
#Override
public void initialize(URL url, ResourceBundle rb) {
}
}
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.text.*?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane id="AnchorPane" prefHeight="155.0" prefWidth="303.0"
xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="fxcalcmedia.FXMLDocumentController">
<children>
<Label fx:id="lblMedia" layoutX="30.0" layoutY="119.0"
text="Média" />
<Label layoutX="28.0" layoutY="33.0" text="Nota 1" />
<Label layoutX="28.0" layoutY="76.0" text="Nota 2" />
<Button fx:id="btnCalc" layoutX="212.0" layoutY="71.0"
mnemonicParsing="false" onAction="#clicouBotao" text="Calcular"
/>
<TextField fx:id="txtNota1" layoutX="90.0" layoutY="28.0"
prefHeight="25.0" prefWidth="78.0" />
<TextField fx:id="txtNota2" layoutX="90.0" layoutY="71.0"
prefHeight="25.0" prefWidth="78.0" />
<TextField fx:id="txtMedia" layoutX="90.0" layoutY="114.0"
onAction="#clicouBotao" prefHeight="25.0" prefWidth="78.0" />
</children>
</AnchorPane>
So... the window appears, I insert the grades but when I click on the button to get the average grade, nothing happens. I've tried a lot of things, I've searched a lot... I hope somebody can help. Thanks again.
You need to place #FXML annotation on each Node that have fx:id="" in fxml file. It is necessary for FXMLLoader to create correct instances and inject them to controller.
Another problem is components type in fxml file. In fxml you use TextField
<TextField fx:id="txtNota1" layoutX="90.0" layoutY="28.0"
prefHeight="25.0" prefWidth="78.0" />
<TextField fx:id="txtNota2" layoutX="90.0" layoutY="71.0"
prefHeight="25.0" prefWidth="78.0" />
<TextField fx:id="txtMedia" layoutX="90.0" layoutY="114.0"
onAction="#clicouBotao" prefHeight="25.0" prefWidth="78.0" />
but in cotntroller you use Text:
private Text txtMedia;
private Text txtNota1;
private Text txtNota2;
Solution:
#FXML
private Label lblMedia;
#FXML
private Button btnCalc;
#FXML
private TextField txtMedia;
#FXML
private TextField txtNota1;
#FXML
private TextField txtNota2;
As an extension to #MBec's answer. A very nice tool for creating GUIs for javaFX is JavaFX Scene Builder. It provides you with drag & drop functionality and also gives templates for each fxml file's Controller class.
I created a javaFX fxml application in NetBeans and want to display an image using a filechooser opened in a handleButtonAction event.
If I drag an ImageView into the panel using the gui builder I see no way to get it's object generated in code.
If I add an Imageview manually to the main class, I do not have the button handler method available, and if I add it to the controller class, I do not have the main panel available to attach the Imageview to. I think I am not understanding how to elements from the ui builder generated into code.
The generated NetBeans projects starts with a hello button that also has no visible object in the source files, so it seems clear that I am missing something about how the ui builder sets the proper xml data to have those elements available to the controller, but there doesn't appear to me to be any way add these to the controller from the ui builder. Is it just that the UI builder is unreliable?
Any help would be appreciated.
The main application class looks like:
package javafxapplication2;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class JavaFXApplication2 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);
}
}
And the Controller:
package javafxapplication2;
import java.net.URL;
import java.util.ResourceBundle;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.embed.swing.SwingFXUtils;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
//import javafx.scene.image.Image;
//import javafx.scene.image.ImageView;
//import javafx.stage.FileChooser;
//import javax.imageio.ImageIO;
//import java.io.File;
//import java.io.IOException;
public class FXMLDocumentController implements Initializable {
// private ImageView imgview = new ImageView();
// private FileChooser filechooser = new FileChooser();
#FXML
private void handleButtonAction(ActionEvent event) {
//commented out because it displays nothing
// try {
// File infile = filechooser.showOpenDialog(null);
// Image img = SwingFXUtils.toFXImage(ImageIO.read(infile), null);
// imgview.setImage(img);
// } catch (IOException ex) {
// Logger.getLogger(FXMLDocumentController.class.getName()).log(Level.SEVERE, null, ex);
// }
System.out.println("button clicked");
}
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
}
}
And the XML:
<?import javafx.scene.image.*?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane id="AnchorPane" prefHeight="355.0" prefWidth="411.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="javafxapplication2.FXMLDocumentController">
<children>
<Button fx:id="button" layoutX="14.0" layoutY="312.0" onAction="#handleButtonAction" text="open file" />
<ImageView fitHeight="150.0" fitWidth="200.0" layoutX="84.0" layoutY="73.0" pickOnBounds="true" preserveRatio="true" />
<Button layoutX="212.0" layoutY="310.0" mnemonicParsing="false" text="Button" />
</children>
</AnchorPane>
You aren't using the ImageView that you have created in the FXML, inside your controller.
You should assign the ImageView a fx:id and then inject it in the controller. This way the same ImageView will be used while setting the Image in the ImageView.
In FXML:
<ImageView fx:id="imgview" fitHeight="150.0" fitWidth="200.0"
layoutX="84.0" layoutY="73.0" pickOnBounds="true" preserveRatio="true" />
In Controller:
public class FXMLDocumentController implements Initializable {
#FXML
private ImageView imgview;
...
}
MCVE
FXML
<?import javafx.scene.control.Button?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane id="AnchorPane" prefHeight="355.0" prefWidth="411.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="FXMLDocumentController">
<children>
<Button fx:id="button" layoutX="14.0" layoutY="312.0" onAction="#handleButtonAction" text="open file" />
<ImageView fx:id="imageView" fitHeight="150.0" fitWidth="200.0" layoutX="84.0" layoutY="73.0" pickOnBounds="true" preserveRatio="true" />
<Button layoutX="212.0" layoutY="310.0" mnemonicParsing="false" text="Button" />
</children>
</AnchorPane>
Controller
import javafx.embed.swing.SwingFXUtils;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.stage.FileChooser;
import javax.imageio.ImageIO;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import java.util.logging.Level;
import java.util.logging.Logger;
public class FXMLDocumentController implements Initializable {
#FXML
private ImageView imageView;
private FileChooser filechooser = new FileChooser();
#FXML
private void handleButtonAction(ActionEvent event) {
try {
File infile = filechooser.showOpenDialog(null);
Image img = SwingFXUtils.toFXImage(ImageIO.read(infile), null);
imageView.setImage(img);
} catch (IOException ex) {
Logger.getLogger(TestController.class.getName()).log(Level.SEVERE, null, ex);
}
}
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
}
}
Main
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 stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}