JavaFX split pane divider position not working - javafx

I have a split pane with a initial divider position set to 0.2, the problem is that after running the application the position is changed to 0.5, I read that it is due to stage.setMaximized(true);
I checked this question, but the answers imply that the current split pane and the main stage are in the same class, but in my case, I have to work in a controller class.
I tried to add a listener to the stage showing property Main.getStage().showingProperty().addListener(...) in the initialize() method, but it doesn't work, it says stage is null, I guess it's because initialize() runs before Main.start()
So how can I make my split pane start with a fixed divider position?
Thanks!
EDIT :
I made a simple example to expose my problem :
Main
#Override
public void start(Stage primaryStage) throws Exception {
FXMLLoader loader=new FXMLLoader(getClass().getResource("views/test.fxml"));
mainStage=primaryStage;
mainStage.setScene(new Scene(loader.load()));
mainStage.show();
Controller_Test ct=loader.getController();
System.out.println("Main:"+ct.sp.getDividerPositions()[0]);
ct.getDividerPos();
}
Controller_Test
#FXML
public SplitPane sp;
#FXML
public void initialize() {
System.out.println("Initialize:"+sp.getDividerPositions()[0]);
}
public void getDividerPos(){
System.out.println("Method:"+sp.getDividerPositions()[0]);
}
Now I set the split pane divider at 1, which means the second pane should not show, I run the application and here is the result :
Okay for this one, the divider is at 1, so only one pane is showing, now I will maximize the window :
The divider position clearly changed.
If you read the code I provide previously, you can see 3 print lines as checkpoints, here is their output after running the application :
Initialize:1.0
Main:0.9933110367892977
Method:0.9933110367892977
Thanks!

Related

JavaFX primaryStage binding with TextField

In JavaFx I'm currently trying to change the height of
primaryStage via binding.
primaryStage.setScene(scene);
primaryStage.setHeight(400.0);
primaryStage.widthProperty().bindBidirectional(textField.textProperty());
It's just a homework problem, not meaningful.
Unfortunately primaryStage is readOnlyDoubleProperty. May I change this settings to gain write-permissions?
I know, there is the possibility to change the window size via EventHandler, but I would like to change the window size on the fly through the TextField with bindings.
So any newly entered number enlarges the window.
Any ideas?
It's definitely possible and I hope there is a better way and no one should ever use this code ever but this is what I managed to make work
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
TextField textField = new TextField();
//Allows for only numeric input
textField.setTextFormatter(new TextFormatter<>(change -> {
if (change.getText().matches("[0-9]*"))
return change;
else
return null;
}));
primaryStage.setScene(new Scene(textField));
primaryStage.setHeight(200.0);
//Allows Program to start without error
primaryStage.setMaxWidth(200);
//Binds min and max to ensure stage width change due to only 1 possible size
primaryStage.minWidthProperty().bind(primaryStage.maxWidthProperty());
//Bind textfield to width
textField.textProperty().bindBidirectional(primaryStage.maxWidthProperty(), new NumberStringConverter());
primaryStage.show();
}
}

changing scenes in full screen

I have read several questions/solutions here that are related to my problems. but nothing seems to work.
so I have a primarystage in fullscreen mode, say if i click a button it changes the scene. but the stage seems to display the taskbar. also I resolved the issue by adding this to all of the scene methods..
stage.setFullScreen(false);
stage.setFullScreen(true);
BUT, the transition in scenes is not that fluid. first it goes to desktop and back to fullscreen.. which is not the ideal solution.
here is my code for the primary stage:
public static Stage stage;
private static AnchorPane mainLayout;
#Override
public void start(Stage primaryStage) throws IOException
{
Main.stage = primaryStage;
Main.stage.setTitle("Raven App");
stage.initStyle(StageStyle.UNDECORATED);
stage.setFullScreen(true);
stage.setFullScreenExitKeyCombination(KeyCombination.NO_MATCH);
Main.showMain();
}
here is my code for changing the scene:
public static void UserLogin() throws IOException
{
FXMLLoader loader=new FXMLLoader();
loader.setLocation(Main.class.getResource("page/UserHomeLogin.fxml"));
mainLayout=loader.load();
Scene scene=new Scene(mainLayout);
stage.setScene(scene);
stage.show();
}
I don't know if this is a bug or something. But i thought if you set your primary stage to full screen. and should be fullscreen all through out regardless of scene.
also, if i have a primary stage in full screen mode.. and a secondary stage NOT in full screen mode. the primary stage seems to disappear if i click a button to show the secondary stage. I wanted to show the secondary page on top of the primary stage, and the primary stage should not be clickable unless the secondary page is closed.
my code for showing the secondary stage:
public static void PasswordVerify() throws IOException
{
Stage stage = new Stage();
Parent root = FXMLLoader.load(Main.class.getResource("page/PassConfirm.fxml"));
stage.setScene(new Scene(root));
stage.setTitle("popup window");
stage.initModality(Modality.APPLICATION_MODAL);
stage.showAndWait();
stage.show();
}
Instead of creating a new scene, just change the root of the existing scene:
public static void UserLogin() throws IOException {
FXMLLoader loader=new FXMLLoader();
loader.setLocation(Main.class.getResource("page/UserHomeLogin.fxml"));
mainLayout=loader.load();
stage.getScene().setRoot(mainLayout);
// or just
// scene.setRoot(mainLayout);
// if you already have a reference to the scene
}
The second thing you are asking is not really possible. In JavaFX, on many platforms "full screen mode" is really implemented as "exclusive screen mode"; so there is a unique window visible. So you would need another solution entirely to this, that didn't involve displaying a new window at all.

stage getHeight does not include decorations

I've been trying to set the minWidth and the minHeight of the scene in the start() method, after calling show(), but it seems the getHeight() call does not include the decorations as it is supposed to. The height of the stage is the same as the root scene.
The doc suggests that this should not be the case. Any idea what I'm doing wrong?
OS: Ubuntu 16.04
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception{
Parent r = FXMLLoader.load(getClass().getResource("things.fxml"));
Scene root = new Scene(r);
primaryStage.setTitle("foo");
primaryStage.setScene(root);
primaryStage.sizeToScene();
primaryStage.centerOnScreen();
primaryStage.show();
// primaryStage.getHeight() and root.getHeight() are the same here!
// doc suggests that they are supposed to be different
primaryStage.setMinWidth(primaryStage.getWidth());
primaryStage.setMinHeight(primaryStage.getHeight());
}
public static void main(String[] args) {
launch(args);
}
}
What is explained in the documentation is correct, you may have misunderstood. I explain according to what is written in there, and according to the mistakes that you made in your code, another thing I use windows so it may be due to your OS :
sizeToScene() method :
Set the width and height of this Window to match the size of the content of this Window's Scene. We understand that your stage will have the same size as your scene, and you have not defined a size to your scene,so it takes just the size properties of its contents Parent/FXML.
Parent r = FXMLLoader.load(getClass().getResource("things.fxml"));
Scene root = new Scene(r); //Size not defined
Which explains the size defined in the last two methods setMinWidth/setMinHeight. Here you only give almost the same value (+16 width and +38 height Those of decoration) to your stage
primaryStage.setMinWidth(primaryStage.getWidth()); //return the same width as Scene+16
primaryStage.setMinHeight(primaryStage.getHeight()); //return the same height as Scene+38
If, for example, the Parent/FXML size is (600x400), the getWidth() method of the stage will return (616) and getHeight() (438). I hope this will help you solve your problem, good luck !

Restore window size to original fixed size in JavaFx 8

I have the following code which maximizes the window when the maximize button is clicked (the green one in the title bar). However it does not comes back to the original size (900x600) when it is clicked again while in maximize position. I see only the left side is shrinked.
//set the original size
final Scene homeScene = new Scene(homePane,900,600);
...
primaryStage.maximizedProperty().addListener(new ChangeListener<Boolean>() {
#Override
public void changed(ObservableValue<? extends Boolean> ov, Boolean t, Boolean t1) {
primaryStage.setX(bounds.getMinX());
primaryStage.setY(bounds.getMinY());
primaryStage.setWidth(bounds.getWidth());
primaryStage.setHeight(bounds.getHeight());
}
});
How do I get back the original position ? The "Changed" method is not triggered when maximize button is clicked again , otherwise I would have set the original size programmatically.
Following code works just fine to listen for the maximized state of a Stage:
primaryStage.maximizedProperty().addListener((w,o,n)->System.out.println(n));
Are using a custom (undecorated) Stage, then you might want to take a look at the Undecorator which has done just this.
I used this code
#FXML
private void btnMaximize(MouseEvent event) {
Stage s = (Stage) borderpane.getScene().getWindow();
s.setFullScreen(true);
}
#FXML
private void btnRestoreDown(MouseEvent event) {
Stage s = (Stage) borderpane.getScene().getWindow();
s.setFullScreen(false);
}
Hope it may help someone who sees this post 😊😊

JavaFx : Disable Divider

I have a JavaFX application with a SplitPane. I want to disable the Divider on SplitPane, so it would not be possible to change its position when application is running. How can I do this?
There's no API for that, so once the scene is shown we have to use a lookup function to find the node by its id. In this case, the Divider has this id: split-pane-divider.
Once we find the node, we set it transparent to mouse events:
#Override
public void start(Stage primaryStage) {
final SplitPane splitPane = new SplitPane();
splitPane.setOrientation(Orientation.HORIZONTAL);
splitPane.setDividerPositions(new double[]{0.5});
splitPane.getItems().add(new StackPane(new Label("Left")));
splitPane.getItems().add(new StackPane(new Label("Right")));
Scene scene = new Scene(splitPane, 300, 250);
primaryStage.setScene(scene);
primaryStage.show();
splitPane.lookupAll(".split-pane-divider").stream()
.forEach(div -> div.setMouseTransparent(true) );
}
None of the above posts worked for me. I have found this solution which worked for me:
This code works for the case when your splitPane is divided in the middle and has only one divider, therefore the divider's position is set to 0.5. If you don't know the position of the divider, you can get it by divider.getPosition();.
Divider divider = splitPane.getDividers().get(0);
divider.positionProperty().addListener(new ChangeListener<Number>()
{
#Override
public void changed( ObservableValue<? extends Number> observable, Number oldvalue, Number newvalue )
{
divider.setPosition(0.5);
}
});
This code is in the initialize() method of the GUI Controller class.
Set mouseTransparent="true" of SplitPane in Fxml file.
<SplitPane dividerPositions="0.5" mouseTransparent="true" prefHeight="652.0" prefWidth="858.0">
You can also modify the Skin class for SplitPane. Just copy the code from GrepCode for SplitPaneSkin (available here) and remove the MouseListeners in method initializeDivderEventHandlers() and also the setCursor calls in method setGrabberStyle() and then you can't resize the pane by dragging the divider ;-) At the end you only have to set the skin to the SplitPane by calling setSkin.

Resources