14

More specifically, why are my JavaFX controls not being centered? Here are two screenshots, the first just after starting (I moved the window into a more visible spot but have not yet resized it), and the second is just after resizing it to show off my problem. Bonus points if you help me ensure it's properly sized (on all DPIs) when it first shows:

A small window with the title "Checking", and only a small sliver of content, on top of its own code The same scene, but the window now shows the title "Checking for Updates...", its content more apparent, where the components are centered, but not their content.

Conveniently, the relevant code is included in those screenshots. If you still need it as text, here you go:

private void initJFXPanel(JFXPanel holder)
{
    {
        {
            rootGrid = new GridPane();
            rootGrid.setAlignment(Pos.CENTER);
            rootGrid.setPadding(new Insets(16));
            rootGrid.setHgap(16);
            rootGrid.setVgap(8);
        }

        interior = holder.getScene();
        if (interior == null)
            holder.setScene(interior = new Scene(rootGrid));
        interior.setRoot(rootGrid);

    }
    {
        statusLabel = new Label("Checking for Updates...");
        statusLabel.setAlignment(Pos.CENTER);
        statusLabel.setTextAlignment(TextAlignment.CENTER);
        rootGrid.add(statusLabel, 0, 0);
    }
    {
        progressBar = new ProgressBar();
        progressBar.setProgress(-1);
        progressBar.setPrefWidth(Constants.MAX_WIN_BOUNDS.width / 5d); // 1/5 the width of the screen
        rootGrid.add(progressBar, 0, 1);
    }
    {
        downloadButton = new Button("Get it!");
        downloadButton.setAlignment(Pos.CENTER);
        rootGrid.add(downloadButton, 0, 2);
    }
    holder.setMinimumSize(new Dimension((int)(rootGrid.getPrefWidth() + .5), (int)(rootGrid.getPrefHeight() + .5)));
    setMinimumSize(holder.getMinimumSize());
}
Ky -
  • 30,724
  • 51
  • 192
  • 308

2 Answers2

27

Solution

Place your controls in a VBox (or other similar root layout pane) and set the VBox alignment to center.

Layout Advice

This is my personal advice on starting with layout in JavaFX (it's just advice and not applicable to everybody, you can take it or leave it):

  • Your window and all controls and layouts will automatically size to their preferred size.
  • Let the in-built layout managers and layout system do as many calculations for you as possible with you just providing the minimum layout hints necessary to get your result.
  • Stick to using JavaFX only or Swing only code until you are familar with both styles of code development and really need to mix them.
  • Use the SceneBuilder tool to play around with different layouts and get familiar with JavaFX layout mechanisms.
  • Study the JavaFX layout tutorial.
  • Review a presentation on JavaFX layout.
  • To center a stage the screen call stage.centerOnScreen().
  • Consider using the built-in dialog support of Java 8u40 (when it is released).

Hi-dpi support

See the answer to:

FXML based sample code for your dialog

update-check

You can load the following up in SceneBuilder to easily display it:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>

<VBox alignment="CENTER" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" spacing="8.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
   <children>
      <Label fx:id="updateStatus" text="Checking for Updates..." />
      <ProgressBar fx:id="updateProgress" prefWidth="200.0" progress="0.0" />
      <Button fx:id="updateAction" mnemonicParsing="false" text="Get it!" />
   </children>
   <padding>
      <Insets bottom="16.0" left="16.0" right="16.0" top="16.0" />
   </padding>
</VBox>
Community
  • 1
  • 1
jewelsea
  • 150,031
  • 14
  • 366
  • 406
  • `SceneBuilder`'s documentation says: _Deprecated. This class is deprecated and will be removed in the next version_ – Ky - Oct 03 '14 at 00:05
  • I have no idea where you get that text from. What documentation do you refer to? Can you provide a link? – jewelsea Oct 03 '14 at 00:08
  • it's in the JavaDoc comment in the source, and `SceneBuilder` doesn't exist in JavaFX 8. Citations: http://sta.sh/01f8u7ntv30x and http://docs.oracle.com/javase/8/javafx/api/javafx/scene/package-summary.html – Ky - Oct 03 '14 at 02:41
  • Oh, that is not the SceneBuilder, I meant. I meant the SceneBuilder graphical design tool I linked in my answer, not some deprecated builder class. Sorry for the confusion, the two completely different things just incidentally have the same name. – jewelsea Oct 03 '14 at 10:31
  • Alright. So how do I change the progress in the progress bar as the download progresses? – Ky - Oct 05 '14 at 18:13
  • Updating the progress for download is a different question from this one. Please ask your new question as a new question, though, that is already asked in [how to show file progress in realtime in javafx?](http://stackoverflow.com/questions/17914747/how-to-show-file-progress-in-realtime-in-javafx), which somebody might answer later. – jewelsea Oct 06 '14 at 02:27
4

Resize Issue

Make sure you are adding a size to your JFrame

frame.setSize(500, 300);

Center Issue

I am not sure whether you are taking about centering your frame or the JavaFX controls in the GridPane, so I am adding answers for both of them

Frame Screen Centering

Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
frame.setLocation(dim.width/2-frame.getSize().width/2, 
                                        dim.height/2-frame.getSize().height/2);

screenshot

GridPane Child Centering

You need to add

GridPane.setHalignment(child, HPos.CENTER);

to your code, remove the rest unnecessary code

I edited your code :

{
    Label statusLabel = new Label("Checking for Updates...");
    //statusLabel.setAlignment(Pos.CENTER);
    //statusLabel.setTextAlignment(TextAlignment.CENTER);
    rootGrid.add(statusLabel, 0, 0);
    GridPane.setHalignment(statusLabel, HPos.CENTER);
}
{
    ProgressBar progressBar = new ProgressBar();
    progressBar.setProgress(-1);
    progressBar.setPrefWidth(400); // 1/5 the width of the screen
    rootGrid.add(progressBar, 0, 1);
}
{
    Button downloadButton = new Button("Get it!");
    //downloadButton.setAlignment(Pos.CENTER);
    rootGrid.add(downloadButton, 0, 2);
    GridPane.setHalignment(downloadButton, HPos.CENTER);
}

and the result is

enter image description here

Neuron
  • 5,141
  • 5
  • 38
  • 59
ItachiUchiha
  • 36,135
  • 10
  • 122
  • 176
  • 1
    So what do `setAlignment` and `setTextAlignment` do, then? – Ky - Oct 03 '14 at 00:02
  • On your resize issue solution: setting it to a specific pixel width is NOT what I want. I want it to snugly fit the components as I have them, in case the user has a custom font, if high DPIs play strange, etc. Same issue with the progress bar width – Ky - Oct 03 '14 at 02:50
  • I commented out the lines you did, and added `GridPane.setHalignment(rootGrid, HPos.CENTER);`, but the text and button are still left-aligned – Ky - Oct 03 '14 at 02:52
  • [`setAlignment`](http://docs.oracle.com/javafx/2/api/javafx/scene/control/Labeled.html#setAlignment(javafx.geometry.Pos)) - Specifies how the text and graphic within the `Labeled` should be aligned when there is empty space within the `Labeled`. – ItachiUchiha Oct 03 '14 at 13:21
  • The `GridPane/layout which extends Parent`, will resize itself according to the space available. Doc says - *By default a Region inherits the layout behavior of its superclass, Parent, which means that it will resize any resizable child nodes to their preferred size, but will not reposition them. If an application needs more specific layout behavior, then it should use one of the Region subclasses: StackPane, HBox, VBox, TilePane, FlowPane, BorderPane, GridPane, or AnchorPane*. If there is some specific issue that you are facing, please specify – ItachiUchiha Oct 03 '14 at 13:27
  • 1
    `GridPane.setHalignment(statusLabel, HPos.CENTER);` and `GridPane.setHalignment(downloadButton, HPos.CENTER);` is what you need to use. You need to specify the `control`, not the `GridPane reference` – ItachiUchiha Oct 03 '14 at 13:28