pre load things on JavaFX scene - java

How to load something, like items in ComboBox at JavaFX scene automatically/at start?
I use Java 1.8.0_40
I thought it should be like this, but it won`t working
public class Main extends Application {
public static void main(String[] args) throws SQLException {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
primaryStage.setTitle("Print Shop");
primaryStage.setScene(new Scene(root));
primaryStage.show();
Controller.addSelect();
}
public class Controller implements Initializable {
#FXML
private ComboBox<String> firstSortSelect;
public void addSelect() {
List<String> select = new ArrayList<String>();
select.add("smts1");
select.add("smts2");
for (String cat : select) {
firstSortSelect.getItems().add(cat);
}
}
The errors is
Error:(26, 19) java: non-static method addSelect() cannot be referenced from a static context
if I change method to static
Error:(202, 13) java: non-static variable firstSortSelect cannot be referenced from a static context
I don`t want to create interface/scene dynamically, only data

Sorry guys, I figured out that myself.
Just use initialize method in Controller
#Override
public void initialize(URL location, ResourceBundle resources) {
addSelect();
}

Related

JavaFX Changing scenes with different sizes

I tried creating a simple password manager, just for my personal project, I have come across a problem where I switch scenes, but it will maintain the primary scene size.
I followed this and created a project (Modular with Maven): https://openjfx.io/openjfx-docs/#IDE-Intellij
I have tried putting .sizeToScene() on my start() on my Main, but it didn't work. Here is the code for my Main:
public class App extends Application {
private static Scene scene;
LoginPageAppData loginPageAppData = new LoginPageAppData();
#Override
public void start(Stage stage) throws IOException {
scene = new Scene(loadFXML("Login"));
stage.setScene(scene);
stage.show();
}
static void setRoot(String fxml) throws IOException {
scene.setRoot(loadFXML(fxml));
}
private static Parent loadFXML(String fxml) throws IOException {
FXMLLoader fxmlLoader = new FXMLLoader(App.class.getResource(fxml + ".fxml"));
return fxmlLoader.load();
}
public static void main(String[] args) {
launch();
}
}
Here is my Primary Controller (I removed some code so I can show the important parts)
public class LoginPageController {
App app = new App();
#FXML
private PasswordField passwordfield;
#FXML
private void switchToMain() throws IOException {
App.setRoot("MainPage");
}
#FXML
void passwordpressed(KeyEvent event) throws IOException {
if (event.getCode().equals(KeyCode.ENTER)) {
app.loginPageAppData.setUsername(getUsername());
app.loginPageAppData.setPassword(getPassword());
if (app.loginPageAppData.verifyUsername() == true && app.loginPageAppData.verifyPassword() == true) {
switchToMain();
} else System.out.println(false);
}
}
Here is with image example if you are confused:
Here is the primary scene:
Second scene: it should not look like this:
Second scene: it should look like this:
It's not clear where your code is going awry.
Starting from this complete SceneSelector, note how each scene's size is defined in the corresponding .fxml file. This is done solely for demonstration: ordinarily, one would allow the scene to adopt the preferred size of its children.
To illustrate the effect, I updated the changeScene() method as shown below to enlarge (artificially) and center the selected view. Try altering one of the .fxml files and leaving the preferred sizes alone to see how it works
private void changeScene(…) throws IOException {
Region region = FXMLLoader.load(…);
…
region.setPrefWidth(640);
region.setPrefHeight(480);
stage.sizeToScene();
stage.centerOnScreen();
stage.show();
}
Ok so if you have followed this one
I followed this and created a project (Modular with Maven): https://openjfx.io/openjfx-docs/#IDE-Intellij
and java will autogenerate some methods for you and one of those are setRoot( ) that contains the following
static void setRoot(String fxml) throws IOException {
scene.setRoot(loadFXML(fxml));
}
Now Add the scene.getWindow().sizeToScene();
static void setRoot(String fxml) throws IOException {
scene.setRoot(loadFXML(fxml));
scene.getWindow().sizeToScene();
}
#trashgod here you go :)

"java.lang.IllegalStateException: Toolkit not initialized" when exporting project to jar

When I launch my application in my development enviroment(Eclipse) it runs, however, when I try to export it to a runnable .jar-file, it gives me the following error:
Exception in thread "main" java.lang.ExceptionInInitializerError
at mallApp.MainTwo.<clinit>(MainTwo.java:24)
at java.base/java.lang.Class.forName0(Native Method)
at java.base/java.lang.Class.forName(Class.java:398)
at org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader.main(JarRsrcLoader.java:59)
Caused by: java.lang.IllegalStateException: Toolkit not initialized
at com.sun.javafx.application.PlatformImpl.runLater(PlatformImpl.java:410)
at com.sun.javafx.application.PlatformImpl.runLater(PlatformImpl.java:405)
at com.sun.javafx.application.PlatformImpl.setPlatformUserAgentStylesheet(PlatformImpl.java:695)
at com.sun.javafx.application.PlatformImpl.setDefaultPlatformUserAgentStylesheet(PlatformImpl.java:657)
at javafx.scene.control.Control.<clinit>(Control.java:99)
... 4 more
With "Caused by: java.lang.IllegalStateException: Toolkit not initialized" being the issue.
There are numerous threads here about similar issues, but none of them seem to be quite the same, and the fixes that I have tried do not work for me. My class extends Application and therefore has Application.launch(args) in the main method. This should initialize the Toolkit but it does not for some reason when exported to a .jar.
When I try to add the Toolkit in a different way, for example using JFXPanel or Platform.startup(Runnable), it gives me the opposite error, saying that Toolkit is already initialized.
public class MainTwo extends Application {
...
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage arg0) throws Exception {
model = new Main2Model();
c = model.getCompanyList();
primaryStage = arg0;
primaryStage.setTitle("MallApp");
primaryStage.centerOnScreen();
showMainView();
}
The problem was that I had initialized static javafx-attributes when i declared them. The issue was resolved and the JAR became runnable when I moved the initalization of the fields to the start-method as shown below:
Instead of having:
private static TextField total = new TextField();
private static ObservableList<String> items = FXCollections.observableArrayList();
public void start(Stage arg0) throws Exception {
model = new Main2Model();
c = model.getCompanyList();
primaryStage = arg0;
primaryStage.setTitle("MallApp");
primaryStage.centerOnScreen();
showMainView();
}
I have:
private static TextField total;
private static ObservableList<String> items;
#Override
public void start(Stage arg0) throws Exception {
total = new TextField();
items = FXCollections.observableArrayList();
model = new Main2Model();
c = model.getCompanyList();
primaryStage = arg0;
primaryStage.setTitle("MallApp");
primaryStage.centerOnScreen();
showMainView();
}

#FXML Annotation not working correctly

I'm currently working on a 'small' project with JavaFX. I used the SceneBuilder to create the first sketch of my GUI. it still needs some adjustment and styling but I wanted to see if it's working so far.
I have 2 hyperlinks on the GUI, if the user clicks one of them the default system-browser should open with a specific URL.
So far I got this:
Main.java:
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws MalformedURLException, IOException {
DataBean dataBean= new DataBean(primaryStage);
Controller controller = new Controller(dataBean);
controller.show();
}
public static void main(String[] args) {
launch(args);
}
}
DataBean.java:
public class DataBean {
private Stage primaryStage;
public DataBean(Stage stage) {
primaryStage = stage;
}
public Stage getPrimaryStage() {
return primaryStage;
}
}
TestautomatView.java:
public class TestautomatView implements Initializable {
#FXML
private ComboBox<String> environmentCombo;
#FXML
private Hyperlink crhl;
#FXML
private Hyperlink help;
#Override
public void initialize(URL location, ResourceBundle resources) {
}
private Scene scene;
private BorderPane root;
public TestautomatView() throws MalformedURLException, IOException {
root = FXMLLoader.load(new URL(TestautomatView.class.getResource("Sample.fxml").toExternalForm()));
scene = new Scene(root);
}
public void show(Stage stage) {
stage.setTitle("CrossReport Testautomat");
stage.setScene(scene);
stage.show();
}
public ComboBox<String> getEnvironmentCombo() {
return environmentCombo;
}
public Hyperlink getCrhl() {
return crhl;
}
public Hyperlink getHelp() {
return help;
}
public Scene getScene() {
return scene;
}
}
In my controller I want to set the ActionHandler to the hyperlinks but it's not working because the getters in my view return null.
public class Controller {
private DataBean dataBean;
private TestautomatView view;
public Controller(DataBean databean) throws MalformedURLException, IOException {
this.dataBean = databean;
this.view = new TestautomatView();
setActionHandlers();
}
public void show() throws MalformedURLException, IOException {
view.show(dataBean.getPrimaryStage());
}
private void setActionHandlers() {
// setHyperlink(view.getCrhl(), "www.example.com");
// setHyperlink(view.getHelp(), "www.example2.com");
}
private void setHyperlink(Hyperlink hl, String uri) {
hl.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
//TODO - Open Default Browser
}
});
}
}
When I start my application, I can see the GUI but when I want to add the ActionHandlers I get a NullPointerException.
In the ´Sample.fxml´ file the hyperlinks are children of a HBox
<Hyperlink fx:id="crhl" text="Report" />
<Hyperlink fx:id="help" text="Help" />
But it's not just the hyperlinks even the ComboBox is null when I inspect my app in the debugger.
Where is my mistake?
The problem is that you are creating your controller manually by using new TestautomatView(). It must be created by FXMLLoader for annotations to work. You must also set fx:controller attribute in Sample.fxml to your controller (TestautomatView) fully qualified class name.
Example code:
FXMLLoader fl = new FXMLLoader(new URL(TestautomatView.class.getResource("Sample.fxml").toExternalForm()));
root = fl.load();
TestautomatView controller = fl.getController();
PS: You should rename your TestautomatView to TestautomatController. FXML file is your "view".
As pointed out in another answer, the issue is that you create an instance of TestautomatView "by hand". The default behavior of the FXMLLoader is to create an instance of the controller class specified in the FXML file, and use that instance as the controller. Consequently, you have two instances of TestautomatView: the one you created (and have a reference to), and the one that was created by the FXMLLoader. It is the second one that has the #FXML-annotated fields initialized.
You can change this default behavior by creating an FXMLLoader instance, and setting the controller on it directly. E.g. consider doing:
public class TestautomatView implements Initializable {
#FXML
private ComboBox<String> environmentCombo;
#FXML
private Hyperlink crhl;
#FXML
private Hyperlink help;
#Override
public void initialize(URL location, ResourceBundle resources) {
}
private Scene scene;
private BorderPane root;
public TestautomatView() throws MalformedURLException, IOException {
FXMLLoader loader = new FXMLLoader(TestautomatView.class.getResource("Sample.fxml"));
loader.setController(this);
root = loader.load();
scene = new Scene(root);
}
// etc...
}
Since you are directly setting the controller, you need to remove the fx:controller attribute from the Sample.fxml file for this to work.
You may also be interested in this pattern, which is quite similar (though not exactly the same) as what you are trying to do here.

JavaFX & Spring Boot - NPE

I'm still fighting with my issue. I want to use Spring Framework in order to incject dependencies and I have to use Spring boot to integrate both.
Unfortunately, in first view autowiring is run correctly, but if I go next Stage, I got still only Null Pointer Exception.
Thats main class:
#SpringBootApplication(scanBasePackages = "boxingchallenge")
public class BoxingChallengeApplication extends Application {
public ConfigurableApplicationContext springContext;
private Parent root;
public static Stage stage;
#Override
public void init() throws Exception {
springContext = SpringApplication.run(BoxingChallengeApplication.class);
springContext.getAutowireCapableBeanFactory().autowireBean(this);
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/FXML/start.fxml"));
fxmlLoader.setControllerFactory(springContext::getBean);
root = fxmlLoader.load();
}
#Override
public void start(Stage primaryStage) throws Exception {
stage = primaryStage;
primaryStage.setTitle("Boxing challenge");
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}
#Override
public void stop() {
springContext.stop();
}
public static void main(String[] args) {
launch(BoxingChallengeApplication.class, args);
}
}
Here in first controller class autowiring run cool:
#Component
public class Start {
#FXML
public Button loadGame;
#FXML
public Button create;
#Autowired
private Boxer boxer;
public void load(ActionEvent event) {
System.out.println(boxer.getName());
}
//next stage
public void createNew(ActionEvent event) throws IOException {
Parent root = FXMLLoader.load(getClass().getResource("/FXML/creator.fxml"));
BoxingChallengeApplication.stage.setScene(new Scene(root));
}
}
Here in second stage, autowiring not working:
#Component
public class Creator {
#FXML
public Button ready;
public TextField nation;
public TextField name;
public Boxer boxer;
/*#Autowired
private ApplicationContext context;*/
#Autowired
public void setBoxer(Boxer boxer) {
this.boxer = boxer;
}
public void createdAndPlay(ActionEvent event) {
if (boxer == null)
System.out.println("boxer is null");
else
System.out.println("Injected correctly");
}
}
Thanks, i hope it's going to finished...
#Jewelsea's comment is correct: you must set the controller factory when you load creator.fxml. If you don't do this, the FXMLLoader will create the controller simply by calling its no-arg constructor, so Spring will know nothing about it and will have no opportunity to inject any dependencies.
To do this, all you need is access to the ApplicationContext in Start, and you can inject "well-known objects", of which the ApplicationContext is an example, into your Spring-managed beans:
#Component
public class Start {
#FXML
public Button loadGame;
#FXML
public Button create;
#Autowired
private Boxer boxer;
#Autowired
private ApplicationContext context ;
public void load(ActionEvent event) {
System.out.println(boxer.getName());
}
//next stage
public void createNew(ActionEvent event) throws IOException {
FXMLLoader loader = new FXMLLoader(getClass().getResource("/FXML/creator.fxml"));
load.setControllerFactory(context::getBean);
Parent root = loader.load();
BoxingChallengeApplication.stage.setScene(new Scene(root));
}
}
As an aside, you almost certainly want a new instance of any controller when you load an FXML file, so you should probably make any controllers prototype scope.

Auto Updating Tableview in JAVA Fx

In my project when a client will be disconnected, server will delete the name from observable list and the tableview should stop showing the name. But the tableview is not updating.
Controller class
public class Controller {
#FXML
public TableView tableView;
#FXML
private TableColumn<clientLoginData,String> client;
#FXML
private TableColumn<clientLoginData,String> activeTime;
void initialize(ObservableList<clientLoginData> data)
{
client.setCellValueFactory(new PropertyValueFactory<>("clientName"));
client.setCellFactory(TextFieldTableCell.<clientLoginData>forTableColumn());
activeTime.setCellValueFactory(new PropertyValueFactory<>("time"));
activeTime.setCellFactory(TextFieldTableCell.<clientLoginData>forTableColumn());
tableView.setItems(data);
tableView.setEditable(true);
}
}
main class
public class Main extends Application{
volatile public ObservableList<clientLoginData> data= FXCollections.observableArrayList();
public Controller controller;
#Override
public void start(Stage primaryStage) throws Exception {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("server.fxml"));
Parent root = loader.load();
data.addAll(new clientLoginData((new SimpleStringProperty("john")),new SimpleStringProperty(ZonedDateTime.now().getHour()+":"+ZonedDateTime.now().getMinute())));
controller=loader.getController();
controller.initialize(data);
primaryStage.setTitle("Server");
primaryStage.setScene(new Scene(root, 600, 400));
primaryStage.show();
Thread t=new Thread(new messengerServer(this));
t.start();
}
public static void main(String[] args) {
launch(args);
}
}
updating class
public class messengerReadThread implements Runnable {
private Thread thr;
private NetworkUtil nc;
public Hashtable<SimpleStringProperty, NetworkUtil> table;
SimpleStringProperty oldName;
Main main;
public messengerReadThread(NetworkUtil nc, Hashtable<SimpleStringProperty, NetworkUtil> table, SimpleStringProperty s, Main main) {
this.nc = nc;
this.thr = new Thread(this);
thr.start();
this.table=table;
oldName=s;
this.main=main;
}
public void run() {
try {
while(true) {
String s1=(String)nc.read();
StringTokenizer st=new StringTokenizer(s1);
if(st.nextToken().equals("Name"))
{
String sn=s1.substring(5,s1.length());
NetworkUtil n1=table.get(oldName);
table.remove(oldName);
oldName=new SimpleStringProperty(sn);
table.put(oldName, n1);
main.data.add(new clientLoginData(oldName,new SimpleStringProperty(ZonedDateTime.now().getHour()+":"+ZonedDateTime.now().getMinute())));
}
else
{
System.out.println("here it is"+s1);
}
}
} catch(Exception e) {
System.out.println("disconnected "+oldName.toString());
main.data.remove(oldName);
//System.out.println(main.data.contains(oldName));
main.controller.tableView.refresh();//the tableview should update
}
nc.closeConnection();
}
}
There are some modification I should to to that code, like avoid using those "static references", by defining the ObservableList and move your Updating Code inside Controller so you can have a 2 classes code, the Main Class and your Controller... but i'll try to keep it simple.
First, you need to define the ObservableList inside you controller.
Then place your "updating" code inside the controller in a method. I suggest you to use a Task<> to keep your controller updated in the JavaFX Thread.
Try something like this:
private void updateTable(){
Task<Void> myUpdatingTask=new Task<Void>() {
#Override
protected Void call() throws Exception {
//Your Updating Code Here
}
}
//and then you run it like this:
Thread hilo=new Thread(myUpdatingTask);
hilo.setDaemon(true);
hilo.start();
}
Then, remove the parameter from your Initialize Method and define it private with the #FXML annotation like this:
#FXML
private void initialize(){
//Your Stuff to initialize
//here is were you fill your table like you did in the Main
//and don't forget to call you updateTable Method
this.updateTable();
}
Since this a dirty hack as pointed out by #kleopatra I am going to decorate it as a dirty hack.
****************************Dirty Hack*****************************************
Try hiding a column and displaying it again and your tableview should refresh

Categories