JavaFX TabPane not filling space - layout

I've placed some content inside a TabPane's tab, but the TabPane's width seems to me being equal to the longest element inside the tab (the longest element is not visible on the picture).
The TabPane is inside an AnchorPane with zero valued anchors, that's why I would expect it to fill the whole space, not just the size of the longest element inside..
How could I make the TabPane fill all available space?
UPDATE:
I've forgot to mention, that my a TabView is loaded through the FXMLLoader.load() method and it's added as a child to the AnchorPane..

If you add the tabPane in the code, you could try like this :
AnchorPane anchorPaneContent = new AnchorPane();
TabPane node = new TabPane();
AnchorPane.setTopAnchor(node, 0.0);
AnchorPane.setLeftAnchor(node, 0.0);
AnchorPane.setRightAnchor(node, 0.0);
AnchorPane.setBottomAnchor(node, 0.0);
anchorPaneContent.getChildren().add(node);
If you add the tabPane in the SceneBuilder, you just need to make the tabpane fit it's parent by right clicking on the node.

Related

JavaFX scene builder questions

I'm working with JavaFX scene builder and have two questions.
Fisrt one:"How to add border to Pane in JavaFX scene builder?"
Second one: "How to split cells in HBox?"
I dont know why you would want to join HBox cells as you can set the resize behaviour for every child of the hbox.
There is a example in HBox's Javadoc:
//For example, if an hbox needs the TextField to be allocated all extra space:
HBox hbox = new HBox();
TextField field = new TextField();
HBox.setHgrow(field, Priority.ALWAYS);
hbox.getChildren().addAll(new Label("Search:"), field, new Button("Go"));
Joining cells would be possible in a GridPane with the row- and/or columnSpan.
GridPane gridpane = new GridPane();
gridpane.add(new Button(), 0, 0, 2, 2); // column=0 row=0, spans over 2 columns and 2 rows
gridpane.add(new Label(), 3, 1); // column=3 row=1 (spans over 1 column and 1 row (default))
row-/columnSpan and the vertical horizontal Grow can be specified in the Properties bar of the Scene Builder, residing on the right side, by default.
You can set border by using setStyle() and use some styles like -fx-border
examples
P.S. styles are the same, as like css, but with -fx- prefix

JavaFX SplitPane Divider Position Inconsistent Behaviour

I have two StackPanes (pane1 & pane2) being displayed in a SplitPane (splitPane). The SplitPane's divider position is set to .3 in the builder. The seond StackPane (pane2) contains a Button which also sets the SplitPane's divider position to .3.
Ceteris paribus, the expected behaviour would be that both actions (setting the divider position in the builder & setting the divider position through an action) either work or not.
Yet, only the latter actually works.
What changes between the construction of the SplitPane and the onAction of the Button. What hinders the placement of the divider in the builder?
StackPane pane1 = new StackPane();
StackPane pane2 = new StackPane();
final SplitPane splitPane = SplitPaneBuilder.create()
.items(pane1, pane2)
// Environment A
.dividerPositions(new double[] {.3}) // splitPane.setDividerPosition(s)(...), etc. yield same result
.orientation(Orientation.HORIZONTAL)
.build();
// The following line influences environment A outcome, though it does not fix the issue
SplitPane.setResizableWithParent(pane1, false);
pane2.getChildren().add(ButtonBuilder.create()
.text("Divider Position")
.onAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
// Environment B
splitPane.setDividerPositions(.3);
}
})
.build());
Scene primaryScene = SceneBuilder.create()
.root(splitPane)
.build();
primaryStage.setScene(primaryScene);
primaryStage.setTitle("Name");
primaryStage.setWidth(500);
primaryStage.setHeight(500);
primaryStage.show();
I had a problem regarding the position of the split pane and it seems similar with yours. Here it is: I have a tabpane, and whenever I add a new tab, I load the content of the tab from an fxml, in which there exists a split pane, with divider position fixed to 0.8.
When the first tab is loaded, it is ok, the divider is positioned at 0.8. When I add the second tab, exactly in the same way with the first tab via fxml, the position of the split pane in the second tab is 0.5, i.e. the default value.
I tried to programatically set the divider position with setDividerPositions method after loading the content of the tab, but it did not work. Then as in your case, if I place the setDividerPositions call in an onAction method, it successfully sets the divider position.
As I stated, my problem is not exactly same as yours, but seems similar. So I am not sure but hope my work around will help you: In my situation, placing the setDividerPositions call in Platform.runLater did the trick.
So, thanks to James D in the Oracle support forums, here is the full answer:
"The issue appears to be that the scene's size is smaller than that of its window. This causes an additional layout pass when the window is first displayed; the second layout pass counts as a "window resize" and consequently the divider position of the split pane is not respected on this pass."
(https://forums.oracle.com/forums/thread.jspa?threadID=2503701)
Workaround 1
Set the Scene's size instead of the Stage's size:
Scene primaryScene = SceneBuilder.create()
.root(splitPane)
.width(500)
.height(500)
.build();
primaryStage.setScene(primaryScene);
primaryStage.setTitle("Name");
primaryStage.show();
Workaround 2
As Ramazan has correctly pointed out, another solution would be to set the divider position in Platform.runLater(...).
Followups
I have filed a bug at jira (http://javafx-jira.kenai.com/browse/RT-28607), referencing the original bug report (http://javafx-jira.kenai.com/browse/RT-17229) which had been marked "unresolveable". I guess the final solution would be to provide methods for the absolute positioning of the divider.

How can I create resizing spacers in JavaFX?

First of all, I'm a long time Java/Swing developer. I recently installed JavaFX 2.2 to play around with.
I'm creating a fairly simple app, whose main window has a toolbar on top and content in the rest of the window. The obvious way to accomplish this is to use a BorderPane, and stick a ToolBar into the top section. So far, so good. However, I would like some of the controls in the toolbar to be at the left edge of the window, and some at the right edge. I can find no way to do this. I can put an invisible spacer object into the toolbar, but I only know how to give it a fixed width; it doesn't resize when the window is resized.
So I thought that instead of using a ToolBar object, I'll just use an HBox; it should be equivalent to a horizontally-oriented Swing Box object, right? And the Swing Box class has a createHorizontalGlue() method that inserts an auto-sizing spacer. Well, I can't find an equivalent in the JavaFX HBox class. Is there no simple way to do this?
I figured out how to do it using an HBox instead of a ToolBar to hold the controls; the key is the HBox.setHgrow() method, which allows you to set a spacer object to grow to fill the available space. I still don't know if it's possible to do this with an actual ToolBar instance.
/**
* Creates and populates the Node that serves as the window toolbar.
*
* #return a newly constructed and populated toolbar component
*/
private Node makeToolbar() {
// Auto-sizing spacer
Region spacer = new Region();
HBox.setHgrow(spacer, Priority.ALWAYS);
// Horizontal box containing toolbar controls
HBox box = new HBox();
box.setPadding(new Insets(8));
box.setAlignment(Pos.CENTER);
box.getChildren().addAll(openButton, spacer, resizeSlider);
// Colored background panel with drop shadow
Pane bgRect = new Pane();
bgRect.setStyle("-fx-background-color: #e0e0e0;");
bgRect.setEffect(DropShadowBuilder.create().width(1).build());
// StackPane to hold box and rectangle
StackPane stack = new StackPane();
stack.getChildren().addAll(bgRect, box);
return stack;
}
i do it this way:
private Node makeFooter(Node left, Node right) {
ToolBar footer = new ToolBar();
Region spacer = new Region();
HBox.setHgrow(spacer, Priority.ALWAYS);
spacer.setMinWidth(Region.USE_PREF_SIZE);
footer.getItems().addAll(left, spacer, right);
return footer;
}
hope i could help someone

Display UIMenuController in UIBarButton Click

I am trying to display a UIMenuController in a Toolbar button. I have the code below but I am unsure as to what should be in the "SetTargetRect" method.
What should I put in the SetTargetRect method to display the Menu?
Is there anything else that is missing from this code?
ToolbarItems = new UIBarButtonItem[] {
new UIBarButtonItem ("Sort", UIBarButtonItemStyle.Bordered, (sender, e) => {
var menu = UIMenuController.SharedMenuController;
menu.MenuItems = new UIMenuItem[] {
new UIMenuItem ("Current", new Selector ("SortRaceEntrants")),
new UIMenuItem ("Movers", new Selector ("SortRaceEntrants")),
new UIMenuItem ("Opening", new Selector ("SortRaceEntrants")),
new UIMenuItem ("Number", new Selector ("SortRaceEntrants"))
};
//menu.SetTargetRect ();
menu.SetMenuVisible (true, true);
}),
};
UIBarButtonItem inherits from UIBarItem and NSObject, so finding a frame for them is not easy if not impossible. UINavigationBar inherits from UIView and thus is a view (go figure) and has a frame, etc.
What I do is point to a rect inside that view where the UIBarButtonItem should be.
For example:
[myMenu setTargetRect:CGRectMake(10, 10, 20, 25)
inView:self.navigationController.navigationBar];
This will make the UIMenuController 'point' at the leftBarButtonItem.
The same technique can be used for the toolbar.
In your case something like:
[menu setTargetRect:CGRectMake(0,0,40,40)
inView:self.navigationController.toolBar];
would point to the center of the toolBar and thus the center button in the toolBar
According to the API docs, the target rect defines the area that you want to display the menu relative to - iOS will either show the menu above or below the area defined by TargetRect.
When you make this menu visible, UIMenuController positions it
relative to a target rectangle on the screen; this rectangle usually
defines a selection. The menu appears above the target rectangle or,
if there is not enough space for it, below it. The menu’s pointer is
placed at the center of the top or bottom of the target rectangle, as
appropriate. Be sure to set the tracking rectangle before you make the
menu visible. You are also responsible for detecting, tracking, and
displaying selections.
and
This target rectangle (targetRect) is usually the bounding rectangle
of a selection. UIMenuController positions the editing menu above this
rectangle; if there is not enough space for the menu there, it
positions it below the rectangle. The menu’s pointer is placed at the
center of the top or bottom of the target rectangle as appropriate.
Note that if you make the width or height of the target rectangle
zero, UIMenuController treats the target area as a line or point for
positioning (for example, an insertion caret or a single point).
Once it is set, the target rectangle does not track the view; if the
view moves (such as would happen in a scroll view), you must update
the target rectangle accordingly.

Set scene width and height

I have been trying to set the scene's width and height outside of the constructor and it's been to no avail. After looking through the Scene API I saw a method that lets you get the height and width respectively but not one to set the method.. :s (design flaw maybe).
After further research I came across the SceneBuilder and found methods that could modify the height and width. However, I do not know how to apply it to a scene object already created or how to create a SceneBuilder object that could be used in place of the scene object.
Once you created Scene and assigned it to the Stage you can use Stage.setWidth and Stage.setHeight to change both stage and scene sizes simultaneously.
SceneBuilder can't be applied to an already created object, it can only be used for the scene creation.
It seems not possible to set the size of the Scene after it has been created.
Setting the size of the Stage means to set the size of the window, which includes the size of the decoration. So the Scene is smaller in size, unless the Stage is undecorated.
My solution is to compute the size of the decoration while initialization and add it to the size of the Stage when resizing:
private Stage stage;
private double decorationWidth;
private double decorationHeight;
public void start(Stage stage) throws Exception {
this.stage = stage;
final double initialSceneWidth = 720;
final double initialSceneHeight = 640;
final Parent root = createRoot();
final Scene scene = new Scene(root, initialSceneWidth, initialSceneHeight);
this.stage.setScene(scene);
this.stage.show();
this.decorationWidth = initialSceneWidth - scene.getWidth();
this.decorationHeight = initialSceneHeight - scene.getHeight();
}
public void resizeScene(double width, double height) {
this.stage.setWidth(width + this.decorationWidth);
this.stage.setHeight(height + this.decorationHeight);
}
I just wanted to post another answer for those who might have had a similar problem as mine.
http://docs.oracle.com/javase/8/javafx/api/javafx/scene/Scene.html
There is no setWidth() or setHeight(), and the property is ReadOnly, but if you look at
Constructors
Scene(Parent root)
Creates a Scene for a specific root Node.
Scene(Parent root, double width, double height)
Creates a Scene for a specific root Node with a specific size.
Scene(Parent root, double width, double height, boolean depthBuffer)
Constructs a scene consisting of a root, with a dimension of width and height, and specifies whether a depth buffer is created for this scene.
Scene(Parent root, double width, double height, boolean depthBuffer, SceneAntialiasing antiAliasing)
Constructs a scene consisting of a root, with a dimension of width and height, specifies whether a depth buffer is created for this scene and specifies whether scene anti-aliasing is requested.
Scene(Parent root, double width, double height, Paint fill)
Creates a Scene for a specific root Node with a specific size and fill.
Scene(Parent root, Paint fill)
Creates a Scene for a specific root Node with a fill.
As you can see, this is where you can set the height and width if you need to.
For me, I am using SceneBuilder, just as you described you were doing, and needed the width and height of that. I am creating custom controls, so it was weird that it didn't do it automatically, so this is how to do it if you need to.
I could have used setWidth() / setHeight() from the Stage as well.
I had an similar challenge when I wanted to switch between different size scenes in JavaFX.
I did my scene switching by changing the Parent resource of a Scene. The new resource would have larger dimensions than the previous resource so the entire Scene wasn't visible.
Like user2229691's answer stated - my issue turned out to be the Window not matching the Scene's dimensions.
Although I'm not able to comment about decorations - I was able to solve my issue by using:
sceneName.getWindow().sizeToScene();
It works when downsizing and upsizing from my own testing.
Here's some example code so you can better understand what I did:
public void start(Stage stage) throws IOException {
// Height of 300, width of 300
Parent scene1 = FXMLLoader.load(getClass().getResource("scene1.fxml"));
// Height of 400, width of 400
Parent scene2 = FXMLLoader.load(getClass().getResource("scene2.fxml"));
// Starting off in the smaller scene
Scene mainScene = new Scene(scene1); // Scene & Window are 300x300
stage.setScene(mainScene);
stage.show();
// Switching to the larger scene resource, that doesn't fit in the window
mainScene.setRoot(scene2); // Scene is 400x400 but can only see 300x300
// Resizing the window so the larger scene fits
mainScene.getWindow().sizeToScene(); // Window is now 400x400 & everything is visible
}
I hope this helps someone.
Source:
https://docs.oracle.com/javase/8/javafx/api/javafx/stage/Window.html#sizeToScene--

Resources