Hello I'm new to javaFX, and trying to create a simulation application of the scheduling algorithms.
I did the logic package, but still have problems with the UI. what i want to do is to allow the user to enter the number of jobs and in the next window i want to display text fields where he can put the executing time of each job, in other words i should display the text fields n time as the number of jobs given by the user.
this is what i did for the first interface :
<?xml version="1.0" encoding="UTF-8"?>
<GridPane xmlns:fx="http://javafx.com/fxml/1" alignment="center" hgap="10" styleClass="mainFxmlClass" vgap="10" fx:controller="ui.FXMLController">
<padding><Insets bottom="10" left="25" right="25" top="25" /></padding>
<stylesheets>
<URL value="#fxml.css" />
</stylesheets>
<children>
<Text id="welcome-text" text="Welcome" GridPane.columnIndex="0" GridPane.columnSpan="2" GridPane.rowIndex="0" />
<Label text="Le nombre de Processus:" GridPane.columnIndex="0" GridPane.rowIndex="1" />
<TextField fx:id="textField" GridPane.columnIndex="1" GridPane.rowIndex="1" />
<Label text="Choisissez un Algorithm d'Ordonancement :" GridPane.columnIndex="0" GridPane.rowIndex="2" />
<HBox alignment="bottom_right" spacing="10" GridPane.columnIndex="1" GridPane.rowIndex="5" />
<Text fx:id="actiontarget" GridPane.columnIndex="1" GridPane.rowIndex="7" />
<Button onAction="#handleButtonAction" text="Next" GridPane.columnIndex="1" GridPane.rowIndex="4" />
<MenuButton mnemonicParsing="false" prefHeight="25.0" prefWidth="150.0" text="Algo ... " GridPane.columnIndex="1" GridPane.rowIndex="2">
<items>
<MenuItem mnemonicParsing="true" text="Fifo" onAction="#handleButtonAction" />
<MenuItem mnemonicParsing="false" text="Tourniquet" />
<MenuItem mnemonicParsing="false" text="PCTER" />
<MenuItem mnemonicParsing="false" text="PCTE" />
</items>
</MenuButton>
</children>
</GridPane>
this is my controller :
public class FXMLController implements Initializable {
#FXML
private Label label;
#FXML
private Button button;
#FXML
private TextField textField;
#FXML
private Integer i;
#FXML
public void handleButtonAction() throws IOException{
String t = textField.getText();
IntegerStringConverter a = new IntegerStringConverter();
this.i = a.fromString(t);
Parent window = FXMLLoader.load(getClass().getResource("FXML1.fxml"));
Scene secondScene = new Scene(window);
Stage stage = new Stage();
stage.setScene(secondScene);
stage.show();
stage.show();
}
}
i dont know if there is a way to pass parameters from the controller to the FXML file and to do a loop in the FXML.. please help
If I understand you correctly, you want to request user input and create nodes in the GUI according to the input.
You can't create loops respectively control structures in a fxml file, but you can dynamically add and remove nodes (i.e. TextFields) by
defining a Vertical Box / Horizontal Box,
<VBox id="HBox" fx:id="myVBox" ...>
get the input as an integer,
int sum = Integer.parseInt(textField.getText());
and add the nodes in a for-loop,
for(int i=0, i<sum, i++) {
myVBox.getChildren().add(new TextField("executing time"));
}
and update the view.
Hope it helps.
AFAIK, you can't do that. You have to reverse the controL flow:
The controller should create the necessary controls (labels, textfields etc.) in a loop, possibly using a different FXML, which just defines that part.
Related
I am creating an application which requires a graph consisting of nodes and edges to be displayed. Each node is represented by a Circle object and each edge is a Line.
I have multiple scenes in the application, but the graph needs to be displayed in more than one of these scenes. So, I have created a fxml file using scene builder which only consists of an anchor pane which I want to be able to display my graph on. I have included this fxml file in the other scenes that require the graph to be displayed, so that I can use one controller to add the graph to a single anchor pane which will be shared across many scenes.
However, when I add my circles and lines as children to the anchor pane using the controller, they are not visible. Using the debug tool I can see that they are indeed children of the anchor pane, but they are not being displayed. I can see objects that I add to the anchor pane using scene builder (for example, I used scene builder to add a circle to the anchor pane and I could see that when running my GUI, but none of the other children which I added via code).
To reduce the scope of the problem, I attempted to create a single circle and add it to the anchor pane through my controller class. Despite being a child of the anchor pane, this circle was not visible when running the GUI.
GraphPaneController.java
public class GraphPaneController {
#FXML Pane paneGraph;
public void addCircle() {
Circle circle = new Circle();
circle.setFill(Color.RED);
circle.setRadius(50);
circle.setCenterX(0);
circle.setCenterY(0);
paneGraph.getChildren().add(circle);
}
}
MainMenuController.java
public class MainMenuController {
public void startButtonClicked() {
FXMLLoader loader = new FXMLLoader(getClass().getResource("graph_pane.fxml"));
Parent root = loader.load();
GraphPaneController gpController = loader.getController();
controller.addCircle();
Frontend.setRoot("gamemode_select");
}
}
Frontend.java
public class Frontend extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage mainStage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("mainmenu.fxml"));
Scene scene = new Scene(root, 600, 400);
mainStage.setScene(scene);
mainStage.show();
}
public static void setRoot(String fxml) throws IOException {
newScene.setRoot(loadFXML(fxml));
}
public static Parent loadFXML(String fxml) throws IOException {
FXMLLoader fxmlLoader = new FXMLLoader(Frontend.class.getResource(fxml + ".fxml"));
return fxmlLoader.load();
}
}
mainmenu.fxml
<VBox prefHeight="400.0" prefWidth="640.0" xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1" fx:controller="graphvis.group30.MainMenuController">
<children>
<AnchorPane id="ap" maxHeight="-1.0" maxWidth="-1.0" prefHeight="-1.0" prefWidth="-1.0" VBox.vgrow="ALWAYS">
<children>
<ImageView fitHeight="400.0" fitWidth="640.0" opacity="0.19" pickOnBounds="true" />
<Label layoutX="198.0" layoutY="112.0" text="Graph Colouring Game">
<font>
<Font size="24.0" />
</font>
</Label>
<Button id="btnInputGraphFromFile" layoutX="255.0" layoutY="200.0" mnemonicParsing="false" onAction="#btnInputGraphFromFileClicked" prefHeight="25.0" prefWidth="130.0" text="Input graph from file" />
<Button id="btnCreateRandomGraph" layoutX="255.0" layoutY="235.0" mnemonicParsing="false" onAction="#btnCreateRandomGraphClicked" text="Create random graph" />
<Label layoutX="197.0" layoutY="138.0" prefHeight="61.0" prefWidth="245.0" text="Made by Nathan Macdonald, Kasper van der Horst, Oguz Kagan Yarim, Miriam Espinosa, Dorina Sili" textAlignment="CENTER" wrapText="true">
<font>
<Font size="10.0" />
</font>
</Label>
<Button layoutX="255.0" layoutY="269.0" mnemonicParsing="false" onAction="#btnQuitClicked" prefHeight="25.0" prefWidth="130.0" text="Quit" />
</children>
</AnchorPane>
</children>
</VBox>
graph_pane.fxml
<AnchorPane fx:id="paneGraph" 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="graphvis.group30.GraphPaneController" />
gamemode_select.fxml
<VBox prefHeight="400.0" prefWidth="640.0" xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1" fx:controller="graphvis.group30.GamemodeSelectController">
<children>
<AnchorPane maxHeight="-1.0" maxWidth="-1.0" prefHeight="-1.0" prefWidth="-1.0" VBox.vgrow="ALWAYS">
<children>
<fx:include source="graph_pane.fxml" />
<Label layoutX="139.0" layoutY="14.0" prefHeight="63.0" prefWidth="159.0" text="Select Gamemode:" wrapText="true">
<font>
<Font size="18.0" />
</font>
</Label>
<Button fx:id="btnGamemode1" layoutX="299.0" layoutY="33.0" mnemonicParsing="false" onAction="#btnGamemode1Clicked" text="untill death" />
<Button fx:id="btnGamemode2" layoutX="384.0" layoutY="33.0" mnemonicParsing="false" onAction="#btnGamemode2Clicked" text="timed" />
<Button fx:id="btnGamemode3" layoutX="440.0" layoutY="33.0" mnemonicParsing="false" onAction="#btnGamemode3Clicked" text="random " />
<Button fx:id="btnBack" layoutX="14.0" layoutY="360.0" mnemonicParsing="false" onAction="#btnBackClicked" text="back" />
</children>
</AnchorPane>
</children>
</VBox>
When viewing the gamemode select screen, I expect to see the circle that I added to the graph pane through the GraphPaneController, but it is not there. What do I do so that I can add visual components to a pane which is shared across multiple scenes?
So I got this to work by creating a model class (GraphModel) and a viewer class (GraphView) for the graph. The model class handles creating the vertices and edges, and the viewer class is reponsible for displaying the graph.
GraphView extends javafx.scene.layout.Pane and contains an AnchorPane attribute, containing the elements of the graph to be displayed, which can be added to scenes by calling a getAnchorPane method on the GraphView object.
I made a NavigationBar fxml document, and linked that to a NavigationController class. I've managed to change scenes when pressing the different buttons, but I want to make the button of the current scene focused/different color. However, when I change the style nothing happens.
This is my NavigationBar:
<HBox alignment="CENTER_LEFT" prefHeight="43.0" prefWidth="600.0" spacing="10.0" BorderPane.alignment="CENTER" fx:controller="com.kalkulator.snuskalkulator.NavigationController" xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml" stylesheets="assets/focused.css">
<children>
<Button mnemonicParsing="false" fx:id="profileBtn" onAction="#handleProfileBtn" text="Profil"/>
<Button mnemonicParsing="false" fx:id="snusBtn" onAction="#handleSnusBtn" text="Snus" />
<Button mnemonicParsing="false" fx:id="taperBtn" onAction="#handleTaperBtn" text="Nedtrapning" />
<Button mnemonicParsing="false" fx:id="settingsBtn" onAction="#handleSettingsBtn" text="Innstillinger" />
<Button mnemonicParsing="false" fx:id="graphBtn" onAction="#handleGraphBtn" text="Graf" />
</children>
<BorderPane.margin>
<Insets />
</BorderPane.margin>
<padding>
<Insets left="20.0" />
</padding>
</HBox>
This is my NavigationController:
public class NavigationController {
#FXML
Button profileBtn, graphBtn, settingsBtn, taperBtn, snusBtn;
public void handleSettingsBtn() throws Exception{
Parent root = FXMLLoader.load(getClass().getResource("Innstillinger.fxml"));
Stage window = (Stage) settingsBtn.getScene().getWindow();
settingsBtn.setStyle("-fx-background-color: red;");
window.setScene(new Scene(root, 500, 500));
}
}
Here I try to change the color of the settingsBtn, but nothing happens.
Inside of "Innstillinger.fxml" I I include the fxml of the NavigationBar like this:
<fx:include source="NavigationBar.fxml"/>
I have no clue what the reason for the style not changing is. Any help would be appreciated.
to start here's the FXML, a simple Hbox with Buttons inside :
<HBox fx:id="hboxOfCategories" alignment="CENTER_LEFT" spacing="10.0">
<children>
<Button maxHeight="1.7976931348623157E308" mnemonicParsing="false" prefHeight="57.0" prefWidth="82.0" text="Boissons" />
<Button layoutX="10.0" layoutY="10.0" maxHeight="1.7976931348623157E308" mnemonicParsing="false" prefHeight="57.0" prefWidth="82.0" text="Burger" />
<Button layoutX="102.0" layoutY="10.0" maxHeight="1.7976931348623157E308" mnemonicParsing="false" prefHeight="57.0" prefWidth="82.0" text="Tacos" />
<Button layoutX="378.0" layoutY="10.0" maxHeight="1.7976931348623157E308" mnemonicParsing="false" prefHeight="57.0" prefWidth="82.0" text="Pizza" />
<Button layoutX="194.0" layoutY="10.0" maxHeight="1.7976931348623157E308" mnemonicParsing="false" prefHeight="57.0" prefWidth="82.0" text="Baguette Farcie" textAlignment="CENTER" wrapText="true" />
<Button layoutX="286.0" layoutY="10.0" maxHeight="1.7976931348623157E308" mnemonicParsing="false" prefHeight="57.0" prefWidth="82.0" text="Souflee" />
</children>
</HBox>
i saved his content inside an Observable list , it had to be type Node because the .getChildren() method returns something that's type Node :
fxml controller code :
#FXML
private void initialize(){
ObservableList<Node> hboxButtons = hboxOfCategories.getChildren();
}
How can i grab those buttons and add a listener to them that triggers when the buttons are clicked ?
something like this :
hboxofCategories.getchildren().addlistener(e -> {
doEpicStuff();
});
This should do the trick :
for(Node button : hboxOfCategories.getChildren())
{
((Button)button).setOnAction(a -> {
System.out.println("Pressed : "+ ((Button)button).getText());
});
}
Output :
EDIT :
Here is how you can get the index :
for(int i=0;i<hboxOfCategories.getChildren().size();i++)
{
Button button=(Button)hboxOfCategories.getChildren().get(i);
int index=i;
button.setOnAction(a->
{
System.out.println("Name : "+button.getText()+" | Index : "+index);
});
}
We're currently developing a social media platform as a project at school (to be handed in in 2 weeks), and we've ran into some issues when trying to get the UI to scale with the application window. Currently it works as supposed when previewing it in SceneBuilder (see the first link) , but it seems to be stuck in the upper left corner when running the actual application via IntelliJ IDEA. I've also linked a screenshot of how it's actual behavior is (second link).
This is how the scaling should work, and as you can see it does work when i use SceneBuilder's preview function.
This is how the scaling is working when we run the app, which isn't scaling at all.
At the moment we're just trying to understand whats wrong, therefore our only focus is the 'discover page' of the platform (you access the page from the events page). So i will post the fxml code for the discover page as well as the events controller. Bare in mind this is my first ever post on here, so if there's anything else that could help you help us just tell me and i'll get it uploaded! Here is a screenshot of all the classes in our project, if there's any other class that would be helpful if i post just say the word :)
All classes in the project.
FXML for the Discover page:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ChoiceBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.effect.DropShadow?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.text.Font?>
<?import javafx.scene.text.Text?>
<BorderPane fx:id="borderPaneDiscover" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" prefHeight="600.0" prefWidth="900.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="JavaFX.DiscoverController">
<center>
<AnchorPane prefHeight="200.0" prefWidth="900.0" BorderPane.alignment="CENTER">
<children>
<TableView fx:id="tableViewDiscover" layoutY="62.0" onMouseClicked="#showDetails" prefHeight="331.0" prefWidth="900.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="65.0">
<columns>
<TableColumn fx:id="eventNameColumnDiscover" minWidth="180.0" prefWidth="75.0" text="Event name" />
<TableColumn fx:id="eventLocationColumnDiscover" minWidth="180.0" prefWidth="75.0" text="Event location" />
<TableColumn fx:id="eventDateColumnDiscover" minWidth="180.0" prefWidth="75.0" text="Event date" />
<TableColumn fx:id="eventCategoryColumnCategory" minWidth="180.0" prefWidth="75.0" text="Event category" />
<TableColumn fx:id="eventCreatorColumnDiscover" minWidth="180.0" prefWidth="75.0" text="Event Creator" />
</columns>
<columnResizePolicy>
<TableView fx:constant="CONSTRAINED_RESIZE_POLICY" />
</columnResizePolicy>
</TableView>
<Label alignment="CENTER" prefHeight="18.0" prefWidth="190.0" text="Choose category of the event:" textAlignment="CENTER" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" />
<ChoiceBox fx:id="choiceBoxDiscover" layoutX="375.0" layoutY="20.0" prefHeight="30.0" prefWidth="150.0" AnchorPane.leftAnchor="375.0" AnchorPane.rightAnchor="375.0" AnchorPane.topAnchor="20.0" />
<Button fx:id="buttonGo" layoutX="505.0" mnemonicParsing="false" onAction="#showTableDiscover" prefHeight="30.0" prefWidth="55.0" style="-fx-background-color: #313131; -fx-text-fill: #FFF; -fx-font-weight: BOLD;" text="Go" AnchorPane.rightAnchor="15.0" AnchorPane.topAnchor="20.0">
<effect>
<DropShadow />
</effect>
</Button>
</children>
</AnchorPane>
</center>
<bottom>
<AnchorPane prefHeight="145.0" prefWidth="900.0" BorderPane.alignment="CENTER">
<children>
<TextArea fx:id="textAreaDescription" editable="false" layoutX="60.0" layoutY="20.0" prefHeight="120.0" prefWidth="250.0" wrapText="true" AnchorPane.bottomAnchor="10.0" AnchorPane.leftAnchor="60.0" AnchorPane.rightAnchor="590.0" AnchorPane.topAnchor="20.0" />
<TextArea fx:id="textAreaParticipants" editable="false" layoutX="360.0" layoutY="20.0" prefHeight="120.0" prefWidth="250.0" wrapText="true" AnchorPane.bottomAnchor="10.0" AnchorPane.rightAnchor="290.0" AnchorPane.topAnchor="20.0" />
<Button fx:id="attendButton" layoutX="660.0" layoutY="45.0" mnemonicParsing="false" onAction="#attendEvent" prefHeight="50.0" prefWidth="100.0" style="-fx-background-color: #313131; -fx-text-fill: #ffffff; -fx-font-weight: BOLD;" text="Attend" AnchorPane.bottomAnchor="50.0" AnchorPane.rightAnchor="40.0" AnchorPane.topAnchor="45.0">
<effect>
<DropShadow />
</effect>
</Button>
<Text layoutX="65.0" layoutY="15.0" strokeType="OUTSIDE" strokeWidth="0.0" style="-fx-font-size: 14; -fx-font-weight: BOLD;" text="Description:" AnchorPane.leftAnchor="60.0" AnchorPane.topAnchor="2.0">
<font>
<Font name="Segoe UI Symbol" size="14.0" />
</font>
</Text>
<Text layoutX="365.0" layoutY="15.0" strokeType="OUTSIDE" strokeWidth="0.0" style="-fx-font-size: 14; -fx-font-weight: BOLD;" text="Participants:" AnchorPane.rightAnchor="457.0" AnchorPane.topAnchor="2.0">
<font>
<Font name="Segoe UI Symbol" size="14.0" />
</font>
</Text>
</children>
</AnchorPane>
</bottom>
<top>
<AnchorPane prefHeight="16.0" prefWidth="900.0" BorderPane.alignment="CENTER">
<children>
<Label alignment="CENTER" contentDisplay="CENTER" layoutX="315.0" prefHeight="54.0" prefWidth="289.0" text="Discover events" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0">
<font>
<Font name="System Bold" size="36.0" />
</font>
</Label>
<Button alignment="CENTER_RIGHT" layoutX="833.0" layoutY="10.0" mnemonicParsing="false" onAction="#BackToEvents" prefHeight="34.0" prefWidth="55.0" style="-fx-background-color: #313131; -fx-text-fill: #FFF; -fx-font-size: 14; -fx-font-weight: BOLD;" text="Back" AnchorPane.rightAnchor="15.0" AnchorPane.topAnchor="10.0">
<font>
<Font name="Segoe UI Symbol" size="20.0" />
</font>
<effect>
<DropShadow />
</effect>
</Button>
</children>
</AnchorPane>
</top>
</BorderPane>
FXML for the events page:
package JavaFX;
import javafx.collections.*;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.ChoiceBox;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
import java.io.IOException;
public class EventsController {
private ObservableList<String> usersChoice = FXCollections.observableArrayList("My events(attended/to attend and created)", "Discover(search by category and attend)", "Create event");
#FXML
private BorderPane eventsPane;
#FXML
private ChoiceBox <String> choicebox;
#FXML
private Label labelOfUserChoice;
#FXML
private void initialize(){
choicebox.setItems(usersChoice);
//choicebox.getSelectionModel().selectedItemProperty().addListener(changeListener);
}
#FXML
private void changeLabel() throws IOException/*, InterruptedException*/{
switch (choicebox.getValue()) {
//ask sokol about it
case ("My events(attended/to attend and created)"):
labelOfUserChoice.setText("You have chosen: " + choicebox.getValue());
choicebox.setDisable(true);
//TimeUnit.SECONDS.sleep(5);
loadMyEvents();
break;
case ("Discover(search by category and attend)"):
labelOfUserChoice.setText("You have chosen: " + choicebox.getValue());
choicebox.setDisable(true);
//TimeUnit.SECONDS.sleep(1);
loadDiscover();
break;
case ("Create event"):
labelOfUserChoice.setText("You have chosen: " + choicebox.getValue());
//TimeUnit.SECONDS.sleep(1);
loadCreateEvent();
break;
default:
System.out.println("YOU'VE BETTER LEARN HOW TO USE JFX!");
}
}
#FXML
private void goToMainMenu(ActionEvent event) throws IOException {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("/resources/mainMenu.fxml"));
BorderPane pane = loader.load();
eventsPane.getChildren().setAll(pane);
}
#FXML
private void goToProfile(ActionEvent event) throws IOException {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("/resources/profile.fxml"));
BorderPane pane = loader.load();
eventsPane.getChildren().setAll(pane);
}
#FXML
private void goToFriends(ActionEvent event) throws IOException {
FXMLLoader loader = new FXMLLoader(getClass().getResource("/resources/friendsPage.fxml"));
loader.setLocation(getClass().getResource("/resources/friendsPage.fxml"));
BorderPane pane = loader.load();
eventsPane.getChildren().setAll(pane);
}
#FXML
private void goToChat(ActionEvent event) throws IOException {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("/chatclient/FXMLDocument.fxml"));
BorderPane pane = loader.load();
eventsPane.getChildren().setAll(pane);
}
private void loadMyEvents() throws IOException {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("/resources/myEvents.fxml"));
BorderPane pane = loader.load();
eventsPane.getChildren().setAll(pane);
}
private void loadDiscover() throws IOException{
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("/resources/discover.fxml"));
BorderPane pane = loader.load();
eventsPane.getChildren().setAll(pane);
}
private void loadCreateEvent() throws IOException{
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("/resources/createEvent.fxml"));
BorderPane pane = loader.load();
eventsPane.getChildren().setAll(pane);
}
}
So far i've read probably all the posts in here that are issues remotely like ours, but none of them have seemed to work. I haven't been able to find a post stating the exact same issue as ours, where the preview window in SceneBuilder works as supposed and the program when we run it doesn't. I hope someone can help us out, thanks in advance! :)
I am trying to create an HTML editor (learning purposes) and I am trying to make program as dynamic as possible. I want to find FXML variable, like TextField, by it's id and retrieve the text in the textfield when I press the button.
I have 2 Map variables set up
public FXMLDocumentController() {
this.HTMLtags = new HashMap<>();
HTMLtags.put("pressMeButton", "h2.fx-h2");
HTMLtags.put("setNewsMessageButton", "p.fx-message");
this.elementsMap = new HashMap<>();
elementsMap.put("pressMeButton", "newsTitle");
elementsMap.put("setNewsMessageButton", "newsMessage");
}
HTMLtags holds the button ID and HTML tag, which is going to be edited.
elementsMap holds button ID and TextView ID that it suppose to grab text from. Kinda like "binding specific button to specific textfield".
private void changeText(ActionEvent event) throws IOException {
Object source = event.getSource();
Button clickedButton = (Button) source;
System.out.println(HTMLtags.get(clickedButton.getId()));
System.out.println(elementsMap.get(clickedButton.getId()));
writeToHTML(HTMLtags.get(clickedButton.getId()), elementsMap.get(clickedButton.getId()));
}
Method above correctly retrieves IDs of buttons and HTML tags that need to be edited.
Here is the code that sets the text in the HTML
private void writeToHTML(String HTMLTag, String textField) {
File input = new File(filePath);
Document doc;
try {
doc = Jsoup.parse(input, "UTF-8");
Element head = doc.select(HTMLTag).first();
originalText = head.toString();
TextField textFieldName = new TextField();
textFieldName.setId(textField);
head.text(textFieldName.getText());
System.out.println("Original Text is: " + originalText);
System.out.println("Modified Text is: " + head);
Path path = Paths.get(filePath);
Charset charset = StandardCharsets.UTF_8;
String content = new String(Files.readAllBytes(path), charset);
content = content.replaceAll(originalText, head.toString());
Files.write(path, content.getBytes(charset));
} catch (IOException ex) {
Logger.getLogger(FXMLDocumentController.class.getName()).log(Level.SEVERE, null, ex);
}
}
The problem is that I dunno how to find and retrieve text from textfield specifically in this part of code
TextField textFieldName = new TextField();
textFieldName.setId(textField);
head.text(textFieldName.getText());
I want to do it dynamically without declaring each FXML element through
#FXML private TextField "name of the fx:id" and matching each element through loop.
I want to do it similar to the way I get ID/value of the button through ActionEvent.
EDIT:
here is the full FXML btw
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.*?>
<?import javafx.scene.text.*?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane id="AnchorPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="600.0" prefWidth="800.0" xmlns="http://javafx.com/javafx/8.0.66" xmlns:fx="http://javafx.com/fxml/1" fx:controller="newsletter.editor.FXMLDocumentController">
<children>
<ScrollPane fitToWidth="true" prefHeight="800.0" prefWidth="1280.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<content>
<VBox alignment="CENTER" prefHeight="450.0">
<children>
<HBox alignment="CENTER">
<children>
<Label alignment="CENTER" minHeight="25.0" minWidth="192.0" prefHeight="50.0" prefWidth="192.0" text="Newsletter Title" wrapText="true">
<font>
<Font size="18.0" />
</font>
</Label>
<TextField id="newsTitle" fx:id="newsTitle" prefHeight="28.0" prefWidth="180.0" promptText="Write here" HBox.hgrow="ALWAYS" />
</children>
</HBox>
<HBox prefHeight="100.0" prefWidth="200.0">
<children>
<TextArea fx:id="newsMessage" prefHeight="100.0" prefWidth="766.0" />
</children>
</HBox>
<HBox prefHeight="100.0" prefWidth="200.0" />
<HBox prefHeight="100.0" prefWidth="200.0" />
<HBox alignment="CENTER" prefHeight="100.0" prefWidth="200.0">
<children>
<Button fx:id="setNewsMessageButton" mnemonicParsing="false" onAction="#changeText" text="MAGIC" />
<Button fx:id="pressMeButton" mnemonicParsing="false" onAction="#changeText" text="Press Me for Magic">
<HBox.margin>
<Insets right="10.0" />
</HBox.margin>
</Button>
<Button fx:id="filePathButton" mnemonicParsing="false" onAction="#filePathSave" text="Select Path">
<HBox.margin>
<Insets right="10.0" />
</HBox.margin>
</Button>
<Button fx:id="popoverButton" mnemonicParsing="false" onAction="#popOverTrigger" text="PopOver Test">
<HBox.margin>
<Insets right="10.0" />
</HBox.margin>
</Button>
</children>
</HBox>
</children>
<padding>
<Insets left="20.0" right="20.0" />
</padding>
</VBox>
</content>
</ScrollPane>
</children>
</AnchorPane>
You can perform an id lookup to find the TextField.
Parent parent = getTextFieldParent(); // the Parent (or Scene) that contains the TextFields
TextField textField = (TextField) parent.lookup("#myTextField");
if (textField != null)
String text = textField.getText();
Yes, your need method lookup(). Not only Parent class has this method, it also has at Panel classes like FlowPane, AnchorPane and many other. Also this method in Scene class.
But! This method looking only after scene show. I don't now, why it happens, but before Scene show(), lookup() only finds top-level panel. And after show() it finds element by id, like scene.lookup("#myId");
Symbol # is required.
Also lookup() method can find element without id, by the type.
Example: scene.lookup("FlowPane"); (without #) will find the first FlowPane in your .fxml file. And scene.lookupAll("ImageView"); will return the massive with all ImageView elements in scene.