I have two good working windows (main window, first window) in seperate .java files, at the same package.
The program handles, if I call the the First window (from the main), the Main stays in the background. The only problem is that I still can use the main window if I click there, and create infinity first windows.
One solution is to shut down the Main window, to avoid clicking there again, but I would like to keep there. In order to make the solution I need a code which makes the background window somehow disabled until I click something in the First Window.
But to do that I need to give the rights to the "handler.java" to operate with the main.
Anybody has any idea how to do that?
Let me show you the 2 java file's methods:
Main.java:
public class program extends Application {
#Override
public void start(Stage main) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("mainwindow.fxml"));
Scene scene = new Scene(root);
main.setScene(scene);
main.setTitle("Main);
main.setWidth(800);
main.setHeight(600);
main.setResizable(false);
main.show();
First.java
public void first() throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("first.fxml"));
Scene scene = new Scene(root);
Stage first = new Stage();
first.setScene (scene);
first.setTitle("Köszöntjük az Útiokosban!");
first.setWidth(400);
first.setHeight(200);
first.setResizable(false);
first.show();
}
Use Stage.initModality to make one of your Stages modal (blocking).
Note: You need to set the modality before displaying the Stage.
Try using the advisory in the chapter "Modality" in this link:
http://docs.oracle.com/javase/8/javafx/api/javafx/stage/Stage.html
Related
I am familiarizing with JavaFX. I have created a loginStage and a mainStage. When pressing the 'Login' Button on the loginStage, I want to switch to the mainStage. The loginStage is a lot smaller than the mainStage. I want the mainStage to be located such that the former loginStage was positioned right in the middle of the mainStage (if we hadn't closed it).
I managed to switch from the loginStage to the mainStage. But for some reason the mainStage does not position itself correctly; it seems to me that its X- and Y-coordinate are not set at all!
Here is my code:
public void switchWindow() {
FXMLLoader loader = new FXMLLoader();
try {
Stage loginStage = (Stage) btnLogin.getScene().getWindow();
loginStage.setScene(null);
loginStage.hide();
Pane mainPane= (Pane) loader.load(getClass().getResource("/mainStage.fxml"));
Stage mainStage= new Stage();
mainStage.initStyle(StageStyle.TRANSPARENT);
Scene mainScene= new Scene(mainPane);
mainStage.setScene(mainScene);
mainStage.setX(loginStage.getX() + loginStage.getWidth()/2 - mainStage.getWidth()/2);
mainStage.setY(loginStage.getY() + loginStage.getHeight()/2 - mainStage.getHeight()/2);
mainStage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
Also: I will be creating more stages. Hence, I figured it might be a good idea to create a switchWindow() function inside a separate package. I might just call the function with parameters oldStage and newPane. I wanted to ask you: What is the best practice of switching between stages? So that I do not reproduce the same code over and over again?
I figured it out - and yes, I am sorry, this seems to have been answered before.
The problem is that .getWidth() or .getHeight() methods can only be invoked AFTER the .show() method. Therefore, either change the order of calling the functions. This works fine - the mainStage seems to be at the correct x,y-coordinates from begin on. But to be sure that it does not get moved there after showing the stage, we could also just look up the width and the height of the mainStage inside the .fxml file and then substract these values in .setX() and .setY() respectively.
I have an image viewer appplication. It works perfectly, but I'd like to make a full screen mode for it. It's an FXML project in Netbeans so, the main java is a separated file, therefore I cannot use this:
stage.setFullScreen(true);
because I can't reach the stage from my main .java file.
So I have a file, its name is imageViewer.java, it has this:
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("image_view.fxml"));
Scene scene = new Scene(root);
String css = this.getClass().getResource("style.css").toExternalForm();
scene.getStylesheets().add(css);
stage.setMinHeight(640);
stage.setMinWidth(960);
stage.setScene(scene);
stage.show();
}
and I have another file, it has fxml implements, and the ActionEvent void methods, you know, click the button, next picture etc...
The mentioned method (start method above) it's a method, therefore I can't return the stage. I have to reach the stage from image_viewController.java (the main java), what includes the other methods, functions and FXML implements etc...
I'd like to do this:
public void fullScreen(ActionEvent e) {
stage.setFullScreen(true);
}
But I can't reach the stage from another .java file. This is the first problem. And the second problem.
How can I make position absolute my panes, Vboxes etc like in html??? If my ImageView (what contains my image) get the full width and height, pulls down my HBox (what includes the buttons). If HBox were in absolute position, it wouldn't happened this, would it?
And the final problem, how can I make that, my HBox doesn't appear, just triggered by a hover effect. Is it possible with a separated css file? As I know, it is possible to make with FXML files.
Thanks for the answers!
I have a parent Window which displays people i.e:
FirsName:John
LastName:Brown
Age:18
I click the Edit button, child window opens, change first name and then click accept, child window closes, the changes are in mysql database saved but the parent window still shows the old values. I do have a refresh method which works, but how can I call it from the child window or set it to be called after closing the child window?
Both Parent and Child Windows have controller and fxml. Any help would be appreciated.
James_D's Answer (better)
Thanks to #James_D, you should use setOnHidden instead of setOnCloseRequest, that way you can again just call .close() and the EventHandler will be called.
My Answer
You could make use of setOnCloseRequest:
childStage.setOnCloseRequest(new EventHandler<WindowEvent>() {
public void handle(WindowEvent we) {
// Refresh the parent window here
}
});
To invoke this close request on a child form you can do:
childStage.getOnCloseRequest().handle(new WindowEvent(childStage, WindowEvent.WINDOW_CLOSE_REQUEST));
// or
childStage.fireEvent(new WindowEvent(childStage, WindowEvent.WINDOW_CLOSE_REQUEST));
So you could implement the close button on the child stage like so:
Button closeButton = new Button("Close");
closeButton.setOnAction(event -> childStage.fireEvent(new WindowEvent(childStage, WindowEvent.WINDOW_CLOSE_REQUEST)));
I think the best way to have automatic field updates in JavaFX is by the use of properties. If the name field in the parent window is bound to a SimpleStringProperty you only need to set the property's value when the child window is closed to notify the parent window of the update.
I made a small parent / child example to test the concept and the relevant piece of code is this, placed on the child creation method:
FXMLLoader loader = new FXMLLoader(getClass().getResource("Child.fxml"));
Parent root = loader.load();
ChildController controller = loader.getController();
name.textProperty().bind(controller.name.textProperty());
The field name is a Label in the parent and a TextField in the child. Any change in the child's text is immediately reflected in the parent.
This is an interesting topic. I will make a full example and post ir in my 'a cup of java' blog as soon as possible.
If you use popup, you can set the method to showandwait instead of just show from the Stage object, and after run the method that update the GUI. Because showandwait method pause the main frame while the popup is running, once the popup closes it will run your update code.
stage.showAndWait();
updateGUI();
we think we have two stage(window),1-parent stage,2-child window(pop up window)
first send the stage object of parent stage to child stage
in child stage set :
childStage.setOnHidden(event->{
Parent root=FXMLLoader.load(getClass().getResource(parent fxml));
Scene scene=new Scene(root);
parentStage.SetScene(scene);
parentStage.show();
`
I'm currently writing an HexEditor Application with JavaFX 8 for various reasons. (Important is, that I have to do this I can't just use another HexEditor)
My problem is that when I want to update my UI for example with
textarea.setText(line);
table.setItems(getListForTable());
I get a NullPointerException because textarea(TextArea) and table (TableView) are null, but if I have data before I intialize my stage and set that to the components it works.
In other questions I read that Platfrom.runLater() should solve that but somehow it doesn`t work for me, I still get the NullPointerException. Also I'm sure I'm in the applications main thread, because my application only uses one thread.
Here is the full code from the method:
public void openFile() //this is called when the user presses the "Open"-MenuItem
{
FileChooser fc = new FileChooser();
fc.getExtensionFilters().addAll(
new ExtensionFilter("Text Files", "*.txt"),
new ExtensionFilter("All Files", "*.*"));
file = fc.showOpenDialog(primaryStage);
if(file != null)
{
create();
Platform.runLater(() -> textarea.setText(line)); //NPE
}
}
Also I tried using a button to update the UI but that works only if the user presses the button and also not with the Button.fire() Method, but thats not a good workaround if you have to press that button everytime you did something to see the changes.
EDIT: here are the methods initializing the code in the start() Method. And as I said: I`m sure there getting assigned correctly, because I can use them for setting up listeners and such while starting the program.
private TextArea textarea;
private TableView<Row> table; //Row is my own class used to get the contents to the table
public static void main(String[] args){
launch(args);
}
#Override
public void start(Stage primaryStage) {
this.primaryStage = primaryStage;
initRootLayout();
showContentScene();
}
private void initRootLayout() { //initializes root layout as frame for Content
try {
// Load root layout from fxml file.
FXMLLoader loader = new FXMLLoader();
loader.setLocation(Editor.class.getResource("RootLayout.fxml"));
rootLayout = (BorderPane) loader.load();
// Show the scene containing the root layout.
Scene scene = new Scene(rootLayout);
primaryStage.setScene(scene);
primaryStage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
private void showContentScene() { //initializes Content View
try {
// Load Content (panel).
FXMLLoader loader = new FXMLLoader();
loader.setLocation(Editor.class.getResource("Content.fxml"));
ContentPane = (AnchorPane) loader.load();
table = (TableView<Row>) loader.getNamespace().get("table");
textarea = (TextArea) loader.getNamespace().get("textarea");
// Set Content into the center of root layout.
rootLayout.setCenter(ContentPane);
} catch (IOException e) {
e.printStackTrace();
}
}
EDIT: I overworked the code structure but now I have another exception from the loader telling me "Root cannot be null".
EDIT: For everyone viewing this: It was mostly a structure problem, make sure that every .fxml-file you use has its own Controller.
Your structure is very unusual. Usually you either construct nodes in your code and don't use and FXMLLoader OR you let the FXMLLoader construct nodes for you. In your case you are doing both, which can work, but is tricky to get right (as you have discovered).
So, given you are using FXML, just use it for constructing all of your nodes and place references to the constructed nodes in a controller, with the references annotated with #FXML so that the FXMLLoader initializes them. Then, never assign the references to new nodes you create.
Ensure that the references and controller are in different classes from your Application class, because you never really want to make the main application class a controller, all the main application class should do is invoke the FXMLLoader, it does not need any node references.
You never need to use Platform.runLater unless you are running on a non-JavaFX application thread and you want to execute some code on the JavaFX application thread. For your example this is clearly not the case, because the comment for openFile is this is called when the user presses the "Open"-MenuItem. The JavaFX framework handles the input event for the user pressing the open menu item and ensures that an event handler for it is invoked on the JavaFX application thread, so trying to use Platform.runLater in such a situation is both confusing and redundant.
Even if you address some of the issues mentioned in this answer, your program may still not work as you expect as it may have other issues, which cannot be verified with the current code in your question. For instance, the question code includes neither FXML or controller code. Those would be required to truly find all the issues with code and address this.
Our maven/Netbeans platform application uses a custom image on startup, by replacing
Nbm-branding > core.jar > org.netbeans.core.startup > splash.gif
I tried making it an animated .gif, but only the first frame is displayed.
How would one possibly go about implementing an animated splash screen, maybe by running some JavaFX window animations?
I've seen another other SO question, but it wasn't really answered - please notice I'm asking about how to integrate a custom splash screen with my Netbeans Platform application, and not how to actually build it.
Surprisingly enough, I found out how to plug in a custom splash screen based on this post about user authentication and authorization.
Basically, one needs to write another start-up class, instead of the platform's default:
import java.lang.reflect.Method;
public class CustomStartup {
private static final String NB_MAIN_CLASS = "org.netbeans.core.startup.Main";
public static void main(String[] args) throws Exception {
// do whatever you need here (e.g. show a custom login form)
System.out.println("Hello world! I am a custom startup class");
JWindow splash = initSplash();
// once you're done with that, hand control back to NetBeans
ClassLoader classloader = Thread.currentThread().getContextClassLoader();
Class<?> mainClass = Class.forName(NB_MAIN_CLASS, true, classloader);
Object mainObject = mainClass.newInstance();
Method mainMethod = mainClass.getDeclaredMethod("main", new Class[]{String[].class});
mainMethod.invoke(mainObject, (Object) args);
splash.setVisible(false);
}
}
In that class, one can create a JavaFX stage, embed it into a JWindow, and show it:
public JWindow initSplash(){
JWindow window = new JWindow();
final JFXPanel fxPanel = new JFXPanel();
window.add(fxPanel);
window.setVisible(true);
window.setLocationRelativeTo(null);
Platform.runLater(new Runnable() {
#Override
public void run() {
Scene scene = new Scene(new CustomFxSplash(), 475, 300, true);
fxPanel.setScene(scene);
}
}
return window;
}
Other things to remember are:
Suppress the original NetBeans splash screen by running your app with the --nosplash parameter.
Call your custom initialization class by running your app with the -J-Dnetbeans.mainclass=com.package.splash.CustomStartup parameter
As the link suggests this custom class has to be on the platform's initialization classpath, meaning inside the platform/core folder.
The current version of the NetBeans class that is responsible for rendering the splash screen can be viewed online here: org.netbeans.core.startup.
The culprit code that prevents the gif from animating is this line (line 546)
graphics.drawImage(image, 0, 0, null);
In order for the gif to animate the ImageObserver will have to be specified instead of being set to null and then repaint must be called when imageUpdate() is called on the ImageObserver.
An example of displaying an animated gif can be viewed here: Relationship Between Animated Gif and Image Observer
So as far as I can see you will either have to change the above NetBeans platform code and rebuild it for your application or you will have to create your own splash screen from scratch to use instead of the NetBeans one.
Hope you find this useful!