Change the layout on button click [duplicate] - java

This question already exists:
I Can't Change The Layout
Closed 6 years ago.
I want to change the page when I click the button. I can do it as soon as the program open, but I want to change the center of the Main class' BorderPane when I clicked the button. (I have a number of buttons and I want to go to different controllers with them).
I want to change the center of the Main Controller without changing it. I tried so many things but couldn't do that. On action method addClicked is working but doesn't change the center controller to another controller.
I have Main.class, MainController.java and AddTaskController.java.
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.BorderPane;
import javafx.scene.layout.HBox;
public class Main extends Application {
private Stage window;
private BorderPane layout;
#Override
public void start(Stage primaryStage) throws Exception{
window = primaryStage;
try {
MainController con1 = showMainView();
setLayout(con1.setLay("addssss.fxml"));
} catch(Exception e) {
e.printStackTrace();
}
}
public void setLayout(HBox lay){
layout.setCenter(lay);
}
private MainController showMainView() throws IOException {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(Main.class.getResource("MainInterface.fxml"));
layout = loader.load();
Scene scene = new Scene(layout);
window.setScene(scene);
window.show();
return loader.getController();
}
public static void main(String[] args) {
launch(args);
}
}
MainController.java:
package application;
import java.io.IOException;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.layout.HBox;
public class MainController {
#FXML
void addClicked(ActionEvent e) throws IOException{
}
public HBox setLay(String kaynak) throws IOException{
HBox layout;
FXMLLoader loader = new FXMLLoader();
loader.setLocation(AddTaskController.class.getResource(kaynak));
layout = loader.load();
return layout;
}
}
And AddTaskController.java (There is no code):
package application;
public class AddTaskController {
}

What exactly is your problem? What have you tried to solve it?
If you want to change the layout of your buttons, I see two possible solutions.
You remove the old layout from your scene (or where ever it was added). Then you add the buttons to a new layout and add the new layout to your scene. (Though I am not sure if this works or not, since the SceneGraph only allows components to be added once).
You have multiple layouts prepared with different buttons and in every layout there is one button calling the "addClicked" method. So there are different Buttons in different Layouts behaving the same way. (You can also prepare a new Layout with new Buttons on the fly, like the first solution does)

Related

How to switch the root from controllers without resizing the window in JavaFX?

(James_D has showed me the solution. I'll just elaborate on how it helped me and what I did at the end of this question. Hopefully others find it useful.)
My wrong initial approach:
There are several FXML files and their controllers in my program. I loaded the FXML files and changed the scenes. It caused the window size to change when it was maximized.
Then this answer showed that I should change the root instead.
Current approach and question:
I tried the code given in the answer there and it works flawlessly. First I set a root in the start method and switched to anther root after a time delay. It's just to check. It looks like this:
package com;
import java.io.IOException;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.util.Duration;
public class Launcher extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) throws Exception {
StackPane root = FXMLLoader.load(getClass().getResource("/com/Scene2.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.setMaximized(true);
stage.show();
Timeline timeline2 = new Timeline(new KeyFrame(Duration.millis(1000), e2 -> {
try {
StackPane root2 = FXMLLoader.load(getClass().getResource("/com/Scene1.fxml"));
scene.setRoot(root2);
} catch (IOException e1) {
e1.printStackTrace();
}
}));
timeline2.play();
}
}
In my actual program the start method loads an FXML file. Later I click buttons or something on the screen which should change the root. So I'll have to use a similar code in controllers. But to set the root, I need to get the scene. In the start method the scene is already created and available. I can't figure out how to get that in a controller. So I tried creating a new scene in the controller. But it's not working. It doesn't throw exceptions or anything. The program simply doesn't do anything when I press the button. This is the relevent code in the controller.
public void changeRoot(ActionEvent event) throws IOException {
try {
Parent root2 = FXMLLoader.load(getClass().getResource("/com/Scene2.fxml"));
// I added the line below.
Scene scene = new Scene(root2);
scene.setRoot(root2);
} catch (IOException e1) {
e1.printStackTrace();
}
}
The solution:
Right then. As you can see from the comment below, I can get the scene by calling getScene() on any node in the current scene. In my example code I have a button on the current screen. A button is a node. So I use it to get the scene. I'll just share the code of the controller class so you know what I mean.
package com;
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.layout.StackPane;
import javafx.stage.Stage;
public class Scene1Controller implements Initializable {
#FXML
private Button button;
#Override
public void initialize(URL location, ResourceBundle resources) {
}
public void changeRoot(ActionEvent event) throws IOException {
try {
Parent root2 = FXMLLoader.load(getClass().getResource("/com/Scene2.fxml"));
button.getScene().setRoot(root2); // Here I get the scene using the button and set the root.
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
Now there's something you should keep in mind. You have to make sure you give an fx:id for the node in FXML. It should match the given variable name of the node in the controller. For example, in my controller I have a Button. I've named it 'button'. I've also made sure the id for the Button in the FXML file is 'button'. It's very easy to set the fx:id. I used the Gluon Scene Builder. (Sometimes the changes I make there doesn't get updated in Eclipse right away. Refreshing the project makes sure the changes are updated in Eclipse too.)

javafx form not appear [duplicate]

This question already has answers here:
javafx : javafx.scene.layout.AnchorPane cannot be cast to javafx.scene.layout.BorderPane
(3 answers)
Closed 5 years ago.
When I run the javafx programme not showing javafx windows form that I created.console shows like below picture..
here is my code:
package Employee;
import java.io.IOException;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class main extends Application {
private Stage primaryStage;
private BorderPane mainLayout;
#Override
public void start(Stage primaryStage) throws IOException {
this.primaryStage=primaryStage;
this.primaryStage.setTitle("My windows");
showMainView();
}
private void showMainView() throws IOException
{
FXMLLoader loader=new FXMLLoader();
loader.setLocation(main.class.getResource("view/Mainview.fxml"));
mainLayout=loader.load();
Scene scene=new Scene(mainLayout);
primaryStage.setScene(scene);
}
public static void main(String[] args) {
launch(args);
}
}
and after execute it console shows like this
enter image description here
Two things:
Your mainLayout in your FXML is not a BorderPane
You are missing a call to show:
primaryStage.show();
is the root of your view/Mainview.fxml a BorderPane? If not you will get a ClassCastException like the one you are seeing. Even if it is, you may need to write that line as an explicit cast like this: mainLayout=(BorderPane)loader.load() Also, you will need to make a call to primaryStage.show() after you set the scene, otherwise your window won't show up.

JavaFX, switching panes in a root window and retaining memory

As stated in the title, I have fxml files, I have a UI that is set up with three labels/buttons up top and the lower half of the window has a pane. Every time a label/button is clicked, the pane must switch to that corresponding fxml file. So in other words, the pane must always be in the same position, kind of like a tabbed layout but without tabs.
I know I can achieve this with just loading a new instance of an fxml file but, I want to avoid that because when a user click on a tab he previously was on, he should be able to see his earlier input.
I have some main.java that starts the program. Some controller.java that controls the UI when it is first loaded, and some fxml file corresponding to that initial view. How can I go about implementing this transition functionality? P.S. I am very novice at JavaFX.
Here is a MCVE of how you can achieve it.
It can of course be implemented using FXML :
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextArea;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class StageTest extends Application{
private Pane pane1, pane2, mainPane;
#Override
public void start(Stage stage) throws Exception {
stage.setTitle("Switch Panes");
Button button1 = new Button("Show Pane 1");
button1.setOnAction(e -> showPane1());
Button button2 = new Button("Show Pane 2");
button2.setOnAction(e -> showPane2());
HBox buttonsPane = new HBox(5.);
buttonsPane.getChildren().addAll(button1, button2);
pane1 = getPane("PANE ONE");
pane2 = getPane("PANE TWO");
mainPane = new StackPane(pane1);
BorderPane root = new BorderPane();
root.setTop(buttonsPane);
root.setCenter(mainPane);
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
private void showPane1() {
mainPane.getChildren().clear();
mainPane.getChildren().add(pane1);
}
private void showPane2() {
mainPane.getChildren().clear();
mainPane.getChildren().add(pane2);
}
private Pane getPane(String txt) {
VBox pane = new VBox();
pane.getChildren().addAll(new TextArea(txt+" add text here: "));
return pane;
}
public static void main(String[] args) {
launch(args);
}
}

Horizontal Scrolling Listener

I feel like I have searched half the Web and found no solution...
I have a java application displaying a Map(different countries etc.).
currently you are able to scroll down and up using your mouse wheel...
I want it so, that you are able to scroll sideways (horizontally).
All I need is a Listener (in Swing or Javafx does not matter) triggering whenever the mousewheel gets tilted, without the need for a focus of the map (hovering with your mouse should be enough the windows should still be focused) and without any visible scrollbars.
Using the following code every time you scroll sideways a message gets printed out...
import javafx.application.Application;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.event.EventType;
import javafx.scene.Scene;
import javafx.scene.input.ScrollEvent;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
BorderPane root = new BorderPane();
Scene scene = new Scene(root,400,400);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
scene.setOnScroll(new EventHandler<ScrollEvent>(){
#Override
public void handle(ScrollEvent event) {
System.out.println("Scroll:" + event.getDeltaX());
}
});
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
One thing to consider:
Apparently when embedding a JFXPanel into a JFrame the sideway scrolling event is not getting passed.

Sending notification with javafx without stage

You can send a desktop notification with JavaFx like this (requires jdk 8u20 or later):
package sample;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.stage.Stage;
import org.controlsfx.control.Notifications;
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception{
// Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
Button notifyButton = new Button("Notify");
notifyButton.setOnAction(e -> {
Notifications.create().title("Test").text("Test Notification!").showInformation();
});
primaryStage.setTitle("Hello World");
primaryStage.setScene(new Scene(notifyButton, 100, 50));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
But this way you have to create a main window (stage), is it possible to avoid this? I am looking for a way to send notification like using zenity in bash: most of the code is non-gui, but uses some gui elements for informing or interacting with user in a very basic fashion.
It looks like the ControlsFX notifications require a existing stage. You can create a hidden utility stage. Try something like this.
package sample;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import org.controlsfx.control.Notifications;
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception{
}
public static void main(String[] args) {
new JFXPanel();
notifier("Good!", "It's working now!");
}
private static void notifier(String pTitle, String pMessage) {
Platform.runLater(() -> {
Stage owner = new Stage(StageStyle.TRANSPARENT);
StackPane root = new StackPane();
root.setStyle("-fx-background-color: TRANSPARENT");
Scene scene = new Scene(root, 1, 1);
scene.setFill(Color.TRANSPARENT);
owner.setScene(scene);
owner.setWidth(1);
owner.setHeight(1);
owner.toBack();
owner.show();
Notifications.create().title(pTitle).text(pMessage).showInformation();
}
);
}
}
new JFXPanel() initializes the JavaFX thread without having to extend Application. You have to call this before any calls to Platform.runLater() otherwise you will get a thread exception. You only need to call it once for the whole application though. Honestly it is probably better to create your own notification stage and display it directly. Create a stage like above and put your own contents. You can probably reuse some of the styling from the ControlsFX source.

Categories

Resources