Focus lost on textfields inside custom menu item - java

I have a button which display a menu containing only one custom menu item. This menu item contains a textfield and a button. Here is my code:
helloApplication.java:
package com.example.demo;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.stage.Stage;
import java.io.IOException;
public class HelloApplication extends Application {
#Override
public void start(Stage stage) throws IOException {
FXMLLoader fxmlLoader = new FXMLLoader(HelloApplication.class.getResource("hello-view.fxml"));
Scene scene = new Scene(fxmlLoader.load(), 320, 240);
stage.setTitle("Hello!");
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch();
}
}
helloController.java:
package com.example.demo;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
public class HelloController {
#FXML
private Label welcomeText;
#FXML
protected void onHelloButtonClick() {
welcomeText.setText("Welcome to JavaFX Application!");
}
}
hello-view.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.CustomMenuItem?>
<?import javafx.scene.control.MenuButton?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<VBox alignment="CENTER" spacing="20.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/18" fx:controller="com.example.demo.HelloController">
<padding>
<Insets bottom="20.0" left="20.0" right="20.0" top="20.0" />
</padding>
<children>
<MenuButton mnemonicParsing="false" text="MenuButton">
<items>
<CustomMenuItem hideOnClick="false" mnemonicParsing="false" text="Unspecified Action">
<content>
<HBox prefHeight="100.0" prefWidth="200.0">
<children>
<TextField />
<Button mnemonicParsing="false" text="Button" />
</children>
</HBox>
</content>
</CustomMenuItem>
</items>
</MenuButton>
</children>
</VBox>
This menu I want this menu item to be unselectable, just a pane poping to display the textfield. It is already not hidden when clicked. The problem is that when i enter some text in the textfield, and move the mouse cursor, the focus in the text field is lost because the menu item takes the focus:
How can I prevent the menu item to react and let the text field keep the focus ? Is a custom menu item a good solution if I want only one menu item containing components ?

Related

View Injection in FXML

#Override
public void start(Stage stage) throws Exception {
BorderPane root = FXMLLoader.load(getClass().getClassLoader().getResource("mainView.fxml"));
When i run this it doesnt show the injected views
Im building a new application with JavaFX for the main page im using 3 views build by 3 fxml files
each view has its controller. for the main page i want to inject the three fxml files in a mainView.fxml via fx:include the mainView.fxml has also a controller how can i do that?
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.text.Font?>
<fx:root alignment="CENTER_LEFT" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="93.0" prefWidth="600.0" style="-fx-min-width: 800; -fx-min-height: 100; -fx-spacing: 30;" type="javafx.scene.layout.HBox" xmlns="http://javafx.com/javafx/16" xmlns:fx="http://javafx.com/fxml/1">
<children>
<Label fx:id="title" alignment="CENTER" prefHeight="91.0" prefWidth="179.0" style="-fx-label-padding: 20; -fx-line-spacing: 20;" text="News" textFill="#00a4f2">
<font>
<Font name="Arial Black" size="36.0" />
</font>
<opaqueInsets>
<Insets bottom="20.0" left="20.0" right="20.0" top="20.0" />
</opaqueInsets></Label>
<Button fx:id="refresh" alignment="CENTER" contentDisplay="CENTER" mnemonicParsing="false" style="-fx-alignment: CENTER; -fx-background-color: #66a6ff;" text="Button" textAlignment="CENTER">
<opaqueInsets>
<Insets bottom="30.0" left="30.0" right="30.0" top="30.0" />
</opaqueInsets></Button>
<Button fx:id="stat" alignment="CENTER" mnemonicParsing="false" style="-fx-background-color: #feada6;" text="Button">
<opaqueInsets>
<Insets bottom="30.0" left="30.0" right="30.0" top="30.0" />
</opaqueInsets></Button>
</children>
</fx:root>
This is per example the topView.fxml
package ch.bfh.spacenews;
import java.io.IOException;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;
public class TopBarController extends HBox {
#FXML
public Label title;
#FXML
public Button refresh;
#FXML
public Button stat;
TopBarController(){
FXMLLoader load = new FXMLLoader(getClass().getClassLoader().getResource("topView.fxml"));
load.setRoot(this);
load.setController(this);
try {
System.out.println("TopBarController");
load.load();
}catch(IOException e) {
e.printStackTrace();
}
}
}
This is the corresponding controller of the topView.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.control.*?>
<BorderPane fx:controller="ch.bfh.spacenews.mainController" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" xmlns="http://javafx.com/javafx/16" xmlns:fx="http://javafx.com/fxml/1">
<top>
<fx:include fx:id="topBar" source="topView.fxml"/>
</top>
<center>
<fx:include fx:id="article" source="sample.fxml"/>
</center>
<right>
<fx:include fx:id="seacrh" source="searchView.fxml"/>
</right>
</BorderPane>
This is where i want to inject the topView.fxml
package ch.bfh.spacenews;
import javafx.fxml.FXML;
public class mainController {
#FXML
TopBarController topBarController;
#FXML
ArticleController articleController;
#FXML
SearchController searchController;
#FXML
public void initialize() {
}
}
And this is the Controller of the mainView.fxml where i want to inject the topView.fxml
In the FXML custom component pattern the controller classes also serve as the wrapper for the view, by subclassing an appropriate Node subclass. This means you can just instantiate them directly in the FXML via the FXMLLoader. For example, the <TopBarController> element instructs the FXMLLoader to instantiate the TopBarController by calling its no-argument constructor. That constructor, as per your code, loads topView.fxml, etc. There is no need to use <fx:include>, which is an instruction for the FXMLLoader to load another FXML file, since you already have code in your TopBarController to do that.
So your main view FXML file should look like:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.control.*?>
<?import ch.bfh.spacenews.TopBarController?>
<!-- other imports... -->
<BorderPane fx:controller="ch.bfh.spacenews.MainController" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" xmlns="http://javafx.com/javafx/16" xmlns:fx="http://javafx.com/fxml/1">
<top>
<TopBarController fx:id="topBar" />
</top>
<center>
<ArticleController fx:id="article" />
</center>
<right>
<SearchController fx:id="search" />
</right>
</BorderPane>
And the corresponding controller is
package ch.bfh.spacenews;
import javafx.fxml.FXML;
public class MainController {
#FXML
TopBarController topBar;
#FXML
ArticleController article;
#FXML
SearchController search;
#FXML
public void initialize() {
}
}
Note that it's really critical to follow standard naming conventions here. The FXMLLoader explicitly relies on the case of an element to determine if it's referring to a class name or a property name.
Main class : Launch.java
public class Launch extends Application {
#Override
public void start(Stage stage) throws Exception {
Controller.show(stage);
}
public static void main(String[] args) {
launch(args);
}
}
You can add view from controller :
public class Controller {
public BorderPane mainPane; // fx:id of your pane
public static Stage current;
public static void show(Stage stage) {
this.current = stage;
Scene scene = null;
BorderPane pane = null;
try {
scene = new Scene(FXMLLoader.load(getClass().getResource("mainView.fxml")));
pane = (BorderPane) scene.lookup("#mainPane");
// Add .fxml view to mainView
pane.setCenter(FXMLLoader.load(getClass().getResource("sample.fxml")));
pane.setTop(FXMLLoader.load(getClass().getResource("topView.fxml")));
pane.setRight(FXMLLoader.load(getClass().getResource("searchView.fxml")));
} catch (IOException e) {
e.printStackTrace();
}
stage.setTitle("MainView");
stage.setScene(scene);
stage.show();
}
}

JavaFX Window not opening

if i run the Main Class my JavaFX is not opening. A Java symbol appears in my menubar but no window appears. I don't get any error in the console. I am on a Mac machine and I am using eclipse, together with e(fx)clipes and Gluon Scene Builder. The code is actually 1 by 1 written down from a tutorial. In the tutorial the run configuration JRE is set to JavaSE-1.8. - however, I tested every available JRE, without any success. What do I need to adjust?
Main Class:
package application;
import java.io.IOException;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.AnchorPane;
public class Main extends Application {
private Stage primaryStage;
#Override
public void start(Stage primaryStage) {
this.primaryStage = primaryStage;
}
public void mainWindow() {
try {
FXMLLoader loader = new FXMLLoader(Main.class.getResource("MainWindow.fxml"));
AnchorPane pane = loader.load();
primaryStage.setMinHeight(400.00);
primaryStage.setMinWidth(500.00);
MainWindowController mainWindowController = loader.getController();
mainWindowController.setMain(this);
Scene scene = new Scene(pane);
primaryStage.setScene(scene);
primaryStage.show();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
Controller class:
package application;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
public class MainWindowController {
public Main main;
#FXML private Label label;
#FXML private TextField field;
#FXML private Button clear;
#FXML private Button changeText;
public void setMain(Main main) {
// TODO Auto-generated method stub
this.main = main;
}
#FXML
public void handleChangeText() {
String text = field.getText();
label.setText(text);
}
#FXML
public void handleClear() {
field.clear();
}
}
FXML file:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?>
<AnchorPane prefHeight="400.0" prefWidth="500.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.MainWindowController">
<children>
<VBox alignment="CENTER" layoutY="83.0" spacing="30.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
<Label fx:id="label" text="Label">
<font>
<Font size="24.0" />
</font></Label>
<HBox alignment="CENTER">
<children>
<TextField fx:id="field" prefWidth="220.0" />
</children>
</HBox>
<HBox alignment="CENTER" spacing="20.0">
<children>
<Button fx:id="changeText" mnemonicParsing="false" onAction="#handleChangeText" text="Change Text" />
<Button fx:id="clear" mnemonicParsing="false" onAction="#handleClear" text="Clear" />
</children>
</HBox>
</children>
</VBox>
</children>
</AnchorPane>
You didn't do anything in you start method. All you did was set your primaryStage variable, you should call your mainWindow method after that.

Replace TabPane with separate scenes (JAVAFX)

Currently i have TabPane with 3 active tabs. I have to manually switch between them, which isn't ideal. What i would like to do is replace the TabPane all together and have one scene inside the stage, which would then switch to next scene (From Tab1, to Tab2, to Tab3) upon press of a button.
It is important to maintain the set label text functionality.
Tab1
Tab2
Main.java
package application;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception{
Parent root = FXMLLoader.load(getClass().getResource("../view/Main.fxml"));
primaryStage.setTitle("Hello World");
primaryStage.setScene(new Scene(root, 300, 275));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
MainController.java
package controller;
import javafx.fxml.FXML;
import controller.tab.Tab1Controller;
import controller.tab.Tab2Controller;
import controller.tab.Tab3Controller;
public class MainController {
#FXML Tab1Controller tab1Controller;
#FXML Tab2Controller tab2Controller;
#FXML Tab3Controller tab3Controller;
public void initialize() {
tab1Controller.init(this);
tab2Controller.init(this);
tab3Controller.init(this);
}
public void setTab2LabelText(String text) {
tab3Controller.lbl3.setText(text);
tab2Controller.lbl2.setText(text);
}
}
Tab1Controller.java
package controller.tab;
import controller.MainController;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import java.io.IOException;
public class Tab1Controller {
private MainController main;
#FXML public Label lbl1;
#FXML private Button btn1Send;
#FXML private void btn1SendClicked(ActionEvent event) throws IOException {
main.setTab2LabelText("abc");
}
public void init(MainController mainController) {
main = mainController;
}
}
Tab2Controller.java
package controller.tab;
import controller.MainController;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
public class Tab2Controller {
private MainController main;
#FXML public Label lbl2;
public void init(MainController mainController) {
main = mainController;
}
}
Tab3Controller.java
package controller.tab;
import controller.MainController;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
public class Tab3Controller {
private MainController main;
#FXML public Label lbl3;
public void init(MainController mainController) {
main = mainController;
}
}
Main.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Tab?>
<?import javafx.scene.control.TabPane?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane prefHeight="432.0" prefWidth="443.0" xmlns="http://javafx.com/javafx/8.0.60" xmlns:fx="http://javafx.com/fxml/1" fx:controller="controller.MainController">
<children>
<TabPane prefHeight="299.0" prefWidth="309.0" tabClosingPolicy="UNAVAILABLE" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<tabs>
<Tab closable="false" text="Tab 1">
<content>
<fx:include fx:id="tab1" source="tab/Tab1.fxml" />
</content></Tab>
<Tab closable="false" text="Tab 2">
<content>
<fx:include fx:id="tab2" source="tab/Tab2.fxml" />
</content></Tab>
<Tab closable="false" text="Tab 3">
<content>
<fx:include fx:id="tab3" source="tab/Tab3.fxml" />
</content></Tab>
</tabs>
</TabPane>
</children>
</AnchorPane>
Tab2.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane prefHeight="206.0" prefWidth="226.0" xmlns="http://javafx.com/javafx/8.0.60" xmlns:fx="http://javafx.com/fxml/1" fx:controller="controller.tab.Tab1Controller">
<children>
<Button fx:id="btn1Send" layoutX="42.0" layoutY="74.0" mnemonicParsing="false" onAction="#btn1SendClicked" prefHeight="58.0" prefWidth="142.0" text="Send to Tab2 & Tab3" />
</children>
</AnchorPane>
Tab2.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane prefHeight="206.0" prefWidth="226.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="controller.tab.Tab2Controller">
<children>
<Label fx:id="lbl2" alignment="CENTER" layoutX="37.0" layoutY="46.0" prefHeight="17.0" prefWidth="152.0" text="Default Tab2 text" />
</children>
</AnchorPane>
Tab3.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane prefHeight="206.0" prefWidth="226.0" xmlns="http://javafx.com/javafx/8.0.60" xmlns:fx="http://javafx.com/fxml/1" fx:controller="controller.tab.Tab3Controller">
<children>
<Label fx:id="lbl3" alignment="CENTER" layoutX="37.0" layoutY="46.0" prefHeight="17.0" prefWidth="152.0" text="Default Tab3 text" />
</children>
</AnchorPane>
Here is a example
fxml
create 3 panes, with its own button and label
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane id="AnchorPane" prefHeight="380.0" prefWidth="387.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="ask.FXMLDocumentController">
<children>
<Pane fx:id="p3" prefHeight="380.0" prefWidth="387.0" visible="false">
<children>
<Label layoutX="184.0" layoutY="181.0" text="p3" />
<Button fx:id="p3previous" layoutX="152.0" layoutY="225.0" mnemonicParsing="false" text="previous" />
</children>
</Pane>
<Pane fx:id="p2" prefHeight="380.0" prefWidth="387.0" visible="false">
<children>
<Label layoutX="184.0" layoutY="181.0" text="p2" />
<Button fx:id="p2previous" layoutX="78.0" layoutY="255.0" mnemonicParsing="false" text="previous" />
<Button fx:id="p2next" layoutX="239.0" layoutY="255.0" mnemonicParsing="false" text="next" />
</children>
</Pane>
<Pane fx:id="p1" prefHeight="380.0" prefWidth="387.0">
<children>
<Button fx:id="p1next" layoutX="167.0" layoutY="210.0" mnemonicParsing="false" text="next" />
<Label layoutX="184.0" layoutY="181.0" text="p1" />
</children>
</Pane>
</children>
</AnchorPane>
controller
add button action event, use setVisible(boolean) to control which pane should show.
import java.net.URL;
import java.util.ResourceBundle;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.layout.Pane;
public class FXMLDocumentController implements Initializable {
#FXML Pane p1;
#FXML Pane p2;
#FXML Pane p3;
#FXML Button p1next;
#FXML Button p2next;
#FXML Button p2previous;
#FXML Button p3previous;
public void initialize(URL url, ResourceBundle rb)
{
p1next.setOnAction(e->{ p1.setVisible(false); p2.setVisible(true); });
p2next.setOnAction(e->{ p2.setVisible(false); p3.setVisible(true); });
p2previous.setOnAction(e->{ p2.setVisible(false); p1.setVisible(true); });
p3previous.setOnAction(e->{ p3.setVisible(false); p2.setVisible(true); });
}
}
You do not need to add all the content you create in a fxml file to the scene. the <fx:define> tag can be used to create Node that are not part of the object scene (yet). Use a suitable Parent that allows you to proper display the content.
Example:
<StackPane fx:id="container" prefHeight="432.0" prefWidth="443.0" xmlns="http://javafx.com/javafx/8.0.60" xmlns:fx="http://javafx.com/fxml/1" fx:controller="controller.MainController">
<children>
<fx:include fx:id="tab1" source="tab/Tab1.fxml" />
<fx:define>
<fx:include fx:id="tab2" source="tab/Tab2.fxml" />
<fx:include fx:id="tab3" source="tab/Tab3.fxml" />
</fx:define>
</children>
</StackPane>
public class MainController {
#FXML private Tab1Controller tab1Controller;
#FXML private Tab2Controller tab2Controller;
#FXML private Tab3Controller tab3Controller;
#FXML private Node tab1;
#FXML private Node tab2;
#FXML private Node tab3;
#FXML private StackPane container;
public void initialize() {
tab1Controller.init(this);
tab2Controller.init(this);
tab3Controller.init(this);
}
public void setTab2LabelText(String text) {
tab3Controller.lbl3.setText(text);
tab2Controller.lbl2.setText(text);
}
public void toTab2() {
container.getChildren().setAll(tab2);
}
}

JavaFX FXML not responding to text input or Click (Events)

I have simple JavaFx project, with main class as eclipse JavaFx project default.
I have defined a controller , it looks like the skeleton generated by SceneBuilder, so everything is pretty much default.
When I run my application, In the UI I can't input data to the two textfields, or see the console output from my button event handlers.
A welcome.fxml file as shown below (deleted all other code to simplify)
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.*?>
<?import javafx.scene.effect.*?>
<?import javafx.scene.image.*?>
<?import javafx.scene.paint.*?>
<?import javafx.scene.*?>
<?import javafx.scene.canvas.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.text.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<Pane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" mouseTransparent="true" prefHeight="720.0" prefWidth="1100.0" style="-fx-background-color: #000000;" xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.Welcome_Controller">
<children>
<Button alignment="CENTER" contentDisplay="CENTER" depthTest="ENABLE" graphicTextGap="10.0" layoutX="496.0" layoutY="360.0" mouseTransparent="true" onAction="#OnSignInClick" opacity="0.82" prefHeight="38.0" prefWidth="109.0" style="-fx-background-radius: 100;" text="Sign In" textAlignment="CENTER" />
<Button alignment="CENTER" contentDisplay="CENTER" layoutX="496.0" layoutY="409.0" mnemonicParsing="false" opacity="0.82" prefHeight="38.0" prefWidth="109.0" style="-fx-background-radius: 1000;" text="Sign Up" textAlignment="CENTER" />
<Text fill="WHITE" layoutX="899.0" layoutY="702.0" strokeType="OUTSIDE" strokeWidth="0.0" text="Copyright 2015, Dawood and Irtiza." />
<TextField fx:id="tf_username" layoutX="427.0" layoutY="277.0" prefHeight="25.0" prefWidth="279.0" promptText="Enter new Username if you dont have an account " />
<TextField fx:id="tf_password" layoutX="427.0" layoutY="312.0" prefHeight="25.0" prefWidth="279.0" promptText="Enter new password if you dont have an account" />
<Label layoutX="355.0" layoutY="281.0" text="Username :" textFill="WHITE">
<font>
<Font size="14.0" />
</font>
</Label>
<Label layoutX="355.0" layoutY="315.0" text="Password :" textFill="WHITE">
<font>
<Font size="14.0" />
</font>
</Label>
</children>
</Pane>
Welcome_controller.java looks like a default skeleton generated by scene builder, code below
package application;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.stage.Stage;
public class Welcome_Controller implements Initializable {
#FXML // fx:id="btn_xxx"
private Button btn_signin; // Value injected by FXMLLoader
#FXML
private Button btn_signup;
#FXML
private TextField tf_username;
#FXML
private TextField tf_password;
#Override // This method is called by the FXMLLoader when initialization is complete
public void initialize(URL fxmlFileLocation, ResourceBundle resources)
{
//assert btn_signin != null : "fx:id=\"btn_signin\" was not injected: check your FXML file 'welcome.fxml'.";
//assert btn_signup != null : "fx:id=\"btn_signup\" was not injected: check your FXML file 'welcome.fxml'.";
// initialize your logic here: all #FXML variables will have been injected
}
#FXML private void OnSignInClick(ActionEvent event) throws IOException
{
System.out.println("clicked");
}
#FXML
void OnSignupClick(ActionEvent event) {
System.out.println("clicked 2");
}
}
EDIT : This is the class with the main method.
package application;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
Pane root = (Pane) FXMLLoader.load(Main.class.getResource("welcome.fxml"));
Scene scene_1 = new Scene(root,1100,720);
//scene_1.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
//we can set the different scenes when it need to
primaryStage.setScene(scene_1);
primaryStage.setTitle("Translate Messenger");
primaryStage.show();
} catch(Exception e) {
System.out.println("main may exception");
e.printStackTrace();
}
}
public static void main(String[] args)
{
launch(args);
}
}
When I run my application, In the UI I can't input data to the two textfields, or see the console output from my button event handlers.
Any help would be appreciated.
You have made the root pane transparent to the mouse with mouseTransparent="true". This means that any mouse clicks on the root pane, or any of its descendent nodes (i.e. the whole UI) will be ignored. Consequently you cannot click the buttons or put focus on the text fields using the mouse. (Notice though you can navigate the UI using the tab key, and use the space key to generate a button click when it has the focus.)
Remove mouseTransparent="true" from the pane and from the "Sign In" button and it will work fine.

How to create tabs dynamically in JavaFX using FXML?

How do you create a new tab using JavaFX/FXML? I've created a tabpane in my FXML but I want to click a button that causes a new tab to come up.
Here is my FXML:
<?import javafx.scene.effect.*?>
<?import javafx.scene.text.*?>
<?import javafx.scene.layout.*?>
<?import java.lang.*?>
<?import javafx.scene.control.*?>
<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.Controller">
<top>
<MenuBar BorderPane.alignment="CENTER">
<menus>
<Menu mnemonicParsing="false" text="File">
<items>
<MenuItem mnemonicParsing="false" text="New..." onAction="#btnNew"/>
<MenuItem mnemonicParsing="false" text="Save..." />
<MenuItem mnemonicParsing="false" text="Save As..." />
<MenuItem mnemonicParsing="false" text="Open..." />
<MenuItem mnemonicParsing="false" text="Close" />
</items>
</Menu>
<Menu mnemonicParsing="false" text="Help">
<items>
<MenuItem mnemonicParsing="false" text="About Blank" onAction="#btnAbout"/>
</items>
</Menu>
</menus>
</MenuBar>
</top>
<center>
<TabPane prefHeight="200.0" prefWidth="200.0" tabClosingPolicy="UNAVAILABLE" BorderPane.alignment="CENTER" fx:id="tabPane">
<tabs>
<Tab text="Untitled Tab 1">
<content>
<AnchorPane>
<children>
<TextFlow maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" />
</children>
</AnchorPane>
</content>
</Tab>
</tabs>
</TabPane>
Here is my code that I'm trying right now in my controller:
package sample;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.*;
import java.net.URL;
import java.util.ResourceBundle;
public class Controller implements Initializable {
#FXML
private Button btnAbout;
#FXML
private Button btnNew;
#FXML
private TabPane tabPane;
//tab array
int intTabs = 0;
Tab[] openTabs;
#FXML
private void btnNew(ActionEvent event){
try{
intTabs++;
openTabs = new Tab[intTabs];
//System.out.println(openTabs.length);
tabAdder(intTabs, openTabs);
}catch(Exception e){
e.printStackTrace();
}
}
private TabPane tabAdder(int tabNum, Tab[] tabs){
//System.out.println(tabNum);
tabPane.getTabs().add(tabs[tabNum]);
return tabPane;
}
#FXML
private void btnAbout(ActionEvent event){
Alert alert = new Alert(Alert.AlertType.INFORMATION);
alert.setTitle("Blank: Information");
alert.setHeaderText(null);
alert.setContentText("This is Blank, a simple and soon to be elegant cross platform text editor.");
alert.showAndWait();
}
public void initialize(URL url, ResourceBundle rb){
//tabPane.getTabs().add
}
}
I'm not really sure what the problem is I've been going through a bunch of resources and I know how to add a regular tab.
I know that if I make a tab like this:
Tab fapTab = new Tab();
I can add it like this:
tabPane.getTabs().add(fapTab);
But I want to create them dynamically because I don't know how many tabs my user's would want. So my approach was to create an array of tabs that gets bigger whenever a user clicks "new" and then have a function that adds that new tab to the gui. It's not working though and I've tried several different approaches, adapting people's code to my own.
So my question is does anyone know what I'm doing wrong?
Here are some of those sources:
javafx open a new fxml file in new tab dynamically
http://javafx-albert-af77.blogspot.com/2012/06/tabs-fxml.html
https://www.youtube.com/watch?v=NhoiSMk3f5U
You have already given the answer: just create a new tab and add it to the tab pane:
Tab tab = new Tab();
tabPane.getTabs().add(tab);
Complete example:
AddTabsExample.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.control.TabPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.control.Button?>
<BorderPane xmlns:fx="http://javafx.com/fxml/1"
fx:controller="AddTabsController">
<center>
<TabPane fx:id="tabPane" />
</center>
<bottom>
<HBox alignment="center">
<Button text="Add tab" onAction="#addTab" />
<Button text="List tabs" onAction="#listTabs" />
</HBox>
</bottom>
</BorderPane>
AddTabsController.java:
import javafx.fxml.FXML;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
public class AddTabsController {
#FXML
private TabPane tabPane ;
public void initialize() {
tabPane.getTabs().add(new Tab("Tab 1"));
}
#FXML
private void addTab() {
int numTabs = tabPane.getTabs().size();
Tab tab = new Tab("Tab "+(numTabs+1));
tabPane.getTabs().add(tab);
}
#FXML
private void listTabs() {
tabPane.getTabs().forEach(tab -> System.out.println(tab.getText()));
System.out.println();
}
}
Application (AddTabsExample.java):
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class AddTabsExample extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
BorderPane root = FXMLLoader.load(getClass().getResource("AddTabsExample.fxml"));
primaryStage.setScene(new Scene(root, 800, 600));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Use this instead. You have to override initialize() method:
#Override
public void initialize(URL location, ResourceBundle resources) {
tabPane.getTabs().add(new Tab("Tab 1"));
}
Not this:
public void initialize() {
tabPane.getTabs().add(new Tab("Tab 1"));
}

Categories