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.
Related
I want to add close button to top right corner of a dialog box.
I tried using setbounds with addactor and just add and setposition with setsize and addactor, but nothing works. I know that dialog works with table layout, it has a table for content and for buttons. I don't want to use this layout and put the button outside this layout like on the border of the dialog.
How can I do it?
This is how it should be:
The easiest solution I could come up with now, is to use negative padding for your button to move it "outside" of it's cell.
Button closeButton = new TextButton("X", skin, "default");
getTitleTable().add(closeButton).size(60, 40).padRight(-30).padTop(-20);
With this padding hack you have the problem, that the button will be outside of your Dialog, and by default, Window checks the bounds of your window when it performs Actor.hit(...) evaluation.
We need to disable clipping for that reason, but the rendering of the window depends on it. That's why we use another hack to enable it, just for the rendering:
#Override
public void draw(Batch batch, float parentAlpha) {
setClip(true);
super.draw(batch, parentAlpha);
setClip(false);
}
Do this:
private Stage stage;
private Window window;
private Table table;
#Override
public void show() {
table = new Table();
table.setSize(Gdx.graphics.getWidth() / 2
, Gdx.graphics.getHeight() / 5);
window = new Window("", skin);
window.setSize(table.getWidth(), table.getHeight());
Button btnWindow = new Button(skin, "close");
btnWindow.addListener(new ClickListener() {
#Override
public void clicked(InputEvent event, float x, float y) {
window.setVisible(false);
}
});
window.addActor(btnWindow);
btnWindow.setSize(50, 50);
btnWindow.setPosition(window.getWidth() - btnWindow.getWidth()
, window.getHeight() - btnWindow.getHeight());
table.addActor(window);
window.setModal(true);
table.setPosition(Gdx.graphics.getWidth() / 2 - window.getWidth() / 2
, Gdx.graphics.getHeight() / 2 - window.getHeight() / 2 +
100);
window.addAction(Actions.sequence(Actions.alpha(0)
, Actions.fadeIn(.1f)
, Actions.moveTo(+50, +50, 1)));
stage.addActor(table);
}
I had a similar problem. After a bit of searching this thread helped me.
Basically to tell the alignment of the actors inside a table, and to tell the alignment of the table itself are two separate things. Setting the alignment of the table top top-left would produce the desired behavior.
table = new Table();
table.setFillParent(true);
table.setSkin(usedSkin);
table.setDebug(true);
table.top().left();
stage.addActor(table);
table.add(exitBtn);
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
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--
I have a FlowLayoutPanel and a UserControl.
I've added multiple usercontrols into the FlowLayoutPanel, and I'm trying to dock them to the top, so when I change the size of the FlowLayoutPanel the size (width) of the usercontrols changes accordingly.
You cannot dock anything inside a FlowLayoutPanel, it's simply ignored.
Check out the answer here apparently posted by the Microsoft team.
They say:
The FlowLayoutPanel relies on a largest control to effectively define the column/row within it. The code below set's the size of the first control to the width of the FLP to achieve a layout similar to what you want.
private void flowLayoutPanel1_Layout(object sender, LayoutEventArgs e)
{
flowLayoutPanel1.Controls[0].Dock = DockStyle.None;
for (int i = 1; i < flowLayoutPanel1.Controls.Count; i++)
{
flowLayoutPanel1.Controls[i].Dock = DockStyle.Top;
}
flowLayoutPanel1.Controls[0].Width = flowLayoutPanel1.DisplayRectangle.Width - flowLayoutPanel1.Controls[0].Margin.Horizontal;
}
Key thing is to use the Layout event.
This solution worked for me up to a point. Your UserControls have to have AutoSize turned off / stay a uniform size.
In my case I wanted AutoSize turned on so as to allow the UserControl to expand/contract vertically while filling the width of the FlowLayoutPanel.
I had to find a different solution. But the above might help you in your case.
I am developing a game app for blackberry where i want to place the buttons in a semi circle fashion on the home screen.....so far I have seen all the buttons being aligned either horizontally or vertically....is there any way out where we can place buttons at custom locations such as using a layout in android and hardcoding to place them in terms of pixels? Any help is greatly appreciated
thanks
You may do this by overriding sublayout in your field manager.
In the following example setPositionChild defines the X,Y position of the first field (field 0) added to this manager. To add additional fields increment the number in this.getField() and add the fields to hfm in the order you position them.
public HorizontalFieldManager testingXYPlacement() {
HorizontalFieldManager hfm = new HorizontalFieldManager() {
// Define the x,y, positions of the fields
protected void sublayout( int width, int height ) {
super.sublayout( width, height );
Field field = null;
field = this.getField(0);
if (field != null && equals(field.getManager())) {
setPositionChild(field, XPOS, YPOS);
}
setExtent( width, height);
}
};
hfm.add(new ButtonField("hello!"));
return hfm;
}
if you are used custom button than sometimes set margin is not working properly so used button.setpadding for place your desire location .please keep USEALLWIDTH for your Horizontal or Vertical layout
If your layout is a RelativeLayout you can position elements relative to other elements within the layout (or to the entire RelativeLayout). This directly lets you place views next to other views, and you can apply margins to offset the views from others.