简体   繁体   English

JavaFX BorderPane 布局(拉伸左右窗格)

[英]JavaFX BorderPane Layout (Stretch Left and Right Pane)

I am using a BorderPane to implement a layout in JavaFX.我正在使用 BorderPane 在 JavaFX 中实现布局。

Suppose the BorderPane's maxPrefWidth is set to 1000. There is a button in the left pane, and a button in the right pane.假设 BorderPane 的 maxPrefWidth 设置为 1000。左窗格中有一个按钮,右窗格中有一个按钮。 In the center pane, there is another button with an unknown size.在中心窗格中,还有另一个大小未知的按钮。

  • If: the middle element's width is 500, then the left and right nodes should be 250 in width.如果:中间元素的宽度是500,那么左右节点的宽度应该是250。
  • If: the middle element's width is 600, then the left and right nodes should be 200 in width.如果:中间元素的宽度是600,那么左右节点的宽度应该是200。

Is there a way to tell the left and right pane to automatically grow (horizontally) until the center node's is hit?有没有办法告诉左右窗格自动增长(水平)直到中心节点被击中?

BorderPane expands middle area, by design BorderPane通过设计扩展了中间区域

Your intentions do not mesh with the design intentions of BorderPane .您的意图与BorderPane的设计意图不符。

To quote the Javadoc:引用 Javadoc:

The top and bottom children will be resized to their preferred heights and extend the width of the border pane.顶部和底部的孩子将被调整到他们喜欢的高度并扩展边框窗格的宽度。 The left and right children will be resized to their preferred widths and extend the length between the top and bottom nodes.左右子节点将被调整为其首选宽度并延长顶部和底部节点之间的长度。 And the center node will be resized to fill the available space in the middle.并且中心节点将调整大小以填充中间的可用空间。 Any of the positions may be null.任何位置都可以是 null。

This means:这表示:

  • The center expands to take all extra space.该中心扩展以占用所有额外的空间。
  • The top and bottom take maximum width and their preferred height.顶部和底部采用最大宽度和它们的首选高度。
  • The left and right areas take their preferred width and maximum height.左侧和右侧区域采用其首选宽度和最大高度。

Imagine the middle as a box with a strongman inside pushing up, down, and out.把中间想象成一个盒子,里面有一个强人向上、向下和向外推。

BorderPane 的五个区域的图表,显示了中心如何扩展而外部区域折叠其宽度或高度

This logic is often quite handy for many business apps.对于许多业务应用程序来说,这种逻辑通常非常方便。 The outside areas are often used for navigation , breadcrumbs , menu bar , tool bar , status bar , and so on.外部区域通常用于导航面包屑菜单栏工具栏状态栏等。 The inner area then holds the main content of interest.内部区域则保存主要的兴趣内容。 Given such usage, it makes sense to allocate only necessary space to the outer areas, and allocate most space to the inner content area.鉴于这种用法,只为外部区域分配必要的空间,而将大部分空间分配给内部内容区域是有意义的。

For example, here is an entire example app using JavaFX 14.例如,这是一个使用 JavaFX 14 的完整示例应用程序。

使用 BorderPane 布局的示例 JavaFX 应用程序的屏幕截图,以显示彩色中心区域如何增长以占用所有额外空间

In the center area of this example app, we place an HBox layout containing a single button.在这个示例应用程序的中心区域,我们放置了一个包含单个按钮的HBox布局。 We set the background color of that layout to cornflowerblue color to make visible how the content of the center area expands to take all extra space.我们将该布局的背景颜色设置为cornflowerblue蓝色,以显示中心区域的内容如何扩展以占用所有额外空间。

package work.basil.example;

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ToolBar;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;

import java.time.ZonedDateTime;

/**
 * JavaFX App
 */
public class App extends Application
{

    @Override
    public void start ( Stage stage )
    {
        // Widgets
        ToolBar toolBar = new ToolBar();
        Button button = new Button( "Click Me" );
        toolBar.getItems().add( button );

        Button buttonLeft = new Button( "Left" );
        Button buttonRight = new Button( "Right" );

        HBox appContent = new HBox( new Button( "Bonjour le monde" ) );
        appContent.setStyle( "-fx-background-color: cornflowerblue;" );

        HBox statusBar = new HBox( new Label( "Status goes here. Now: " + ZonedDateTime.now() ) );

        // Arrange
        BorderPane borderPane = new BorderPane();
        borderPane.setTop( toolBar );
        borderPane.setLeft( buttonLeft );
        borderPane.setCenter( appContent );
        borderPane.setRight( buttonRight );
        borderPane.setBottom( statusBar );

        var scene = new Scene( borderPane , 1000 , 1000 );
        stage.setScene( scene );
        stage.show();
    }

    public static void main ( String[] args )
    {
        launch();
    }
}

Choose another layout选择其他布局

As commented on the Question, you should be using a different layout manager given your intentions.正如对问题的评论,您应该根据您的意图使用不同的布局管理器。

You might be able to get by with a HBox .您也许可以使用HBox For maximum control, you will need to invest some time into mastering the GridPane .为了最大限度地控制,您需要花一些时间来掌握GridPane

GridPane

Your Question is not completely clear.你的问题并不完全清楚。 If what you want is for the center content to be fixed width of 500 pixels while the left and right are flexible, being allocated any extra space proportionally, then use GridPane while setting the ColumnConstraints to Priority.SOMETIMES or Priority.ALWAYS on the left and right cells.如果您想要的是中心内容的固定宽度为 500 像素,而左侧和右侧是灵活的,按比例分配任何额外空间,然后使用GridPane将左侧的ColumnConstraints设置为Priority.SOMETIMESPriority.ALWAYS和正确的细胞。

Here is a complete example app.这是一个完整的示例应用程序。

We put one button, each nested in a colored HBox , in each cell of the single-row GridPane .我们在单行GridPane的每个单元格中放置一个按钮,每个按钮都嵌套在一个彩色HBox中。 The colors dramatize the sizing behavior being shown here. colors 戏剧化了此处显示的大小调整行为。 Alternatively, you could drop the colored HBox , instead calling gridPane.setStyle( "-fx-grid-lines-visible: true;" ) to show border lines around each cell.或者,您可以删除彩色HBox ,而是调用gridPane.setStyle( "-fx-grid-lines-visible: true;" )来显示每个单元格周围的边框线。

package work.basil.example;

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ToolBar;
import javafx.scene.layout.*;
import javafx.stage.Stage;

import java.time.ZonedDateTime;

/**
 * JavaFX App
 */
public class App extends Application
{

    @Override
    public void start ( Stage stage )
    {
        // Widgets
        Button buttonLeft = new Button( "Left" );
        HBox left = new HBox( buttonLeft );
        left.setStyle( "-fx-background-color: Salmon;" );

        Button buttonCenter = new Button( "Center" );
        HBox center = new HBox( buttonCenter );
        center.setStyle( "-fx-background-color: CornflowerBlue;" );

        Button buttonRight = new Button( "Right" );
        HBox right = new HBox( buttonRight );
        right.setStyle( "-fx-background-color: MediumSeaGreen;" );

        // GridPane
        GridPane gridPane = new GridPane();
        gridPane.addRow( 0 , left , center , right );  // Add these widgets in first row (annoying zero-based counting means index 0 is row 1).
        gridPane.setStyle( "-fx-grid-lines-visible: true ;" );  // Add lines to the edges of each cell (row/column) in the grid. Useful for learning and debugging. https://docs.oracle.com/javafx/2/api/javafx/scene/doc-files/cssref.html#gridpane

        // Grid constraints
        ColumnConstraints column1 = new ColumnConstraints();
        column1.setHgrow( Priority.SOMETIMES ); // Extra space alloted to this column.

        ColumnConstraints column2 = new ColumnConstraints( 500 ); // Fixed width of 500 pixels.

        ColumnConstraints column3 = new ColumnConstraints();
        column3.setHgrow( Priority.SOMETIMES );// Extra space alloted to this column.

        gridPane.getColumnConstraints().addAll( column1 , column2 , column3 ); // first column gets any extra width

        // Render
        var scene = new Scene( gridPane , 1000 , 150 );
        stage.setScene( scene );
        stage.setTitle( "Example of JavaFX GridPane, by Basil Bourque" );
        stage.show();
    }


    public static void main ( String[] args )
    {
        launch();
    }
}

Screenshot of the app running.正在运行的应用程序的屏幕截图。 Notice how the left and right get remaining space of 250 pixels each.请注意左右如何分别获得 250 像素的剩余空间。 We set the window ( Stage ) to 1,000 pixels, and fixed the width of the center piece to 500 pixels.我们将 window ( Stage ) 设置为 1,000 像素,并将中心部分的宽度固定为 500 像素。 That leaves 500 pixels remaining to allocate.剩下 500 个像素要分配。 Both left and right cells were set to the same priority level, so they split the space evenly between them: 500/2 = 250 pixels each.左右单元格都设置为相同的优先级,因此它们在它们之间平均分配空间:每个 500/2 = 250 像素。

JavaFX 14 应用程序的屏幕截图显示了一个 3 列和 1 行的 GridPane,其中左侧和右侧单元格在中心占用 500 像素宽度后获得任何额外空间。

If the user narrows the width of the window to 600 pixels, the left and right cells will be 50 pixels each: 600 - 500 = 100, 100/2 = 50 pixels each.如果用户将 window 的宽度缩小到 600 像素,则左右单元格将分别为 50 像素:600 - 500 = 100、100/2 = 50 像素。

在此处输入图像描述

Generally I would recommend posting code rather than attempting to describe it.一般来说,我建议发布代码而不是试图描述它。 For example this mre can represent your question:例如,这个mre可以代表您的问题:

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;

public class Main extends Application {
    @Override
    public void start(Stage stage) throws Exception   {

        Button leftBtn = new Button("Left");
        Button centerBtn = new Button("Center");
        centerBtn.widthProperty().addListener((obs, oldValue,newValue)-> {
                //change the logic as needed
                leftBtn.setPrefWidth(newValue.doubleValue() >= 600 ? 200 : 250);
        });
        centerBtn.setPrefSize(600, 0);
        Button rightBtn = new Button("Right");
        Pane root = new BorderPane(centerBtn, null, rightBtn, null, leftBtn);
        root.setPrefSize(1000, 150);
        Scene scene = new Scene(root);
        stage.setScene(scene);
        stage.show();
    }

public static void main(String[] args) {
        launch(args);
    }
}

This also makes helping much easier.这也使帮助变得更加容易。 For example a solution with HBox as proposed in the comments just requires minor changes in the mre (action box added to the center button to change its width):例如,评论中提出的带有HBox的解决方案只需要对 mre 进行细微更改(将操作框添加到中心按钮以更改其宽度):

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.Priority;
import javafx.stage.Stage;

public class Main extends Application {

    private static final double MIN = 300, MAX = 700, DELTA = 100;
    private Button centerBtn;
    @Override
    public void start(Stage stage) throws Exception   {

        Button leftBtn = new Button("Left");
        HBox.setHgrow(leftBtn, Priority.NEVER);

        centerBtn = new Button("Click to change width");
        HBox.setHgrow(leftBtn, Priority.NEVER);
        centerBtn.widthProperty().addListener((obs, oldValue,newValue)-> {
            //change the logic as needed
            leftBtn.setPrefWidth(newValue.doubleValue() >= 600 ? 200 : 250);
        });
        centerBtn.setPrefSize(600, 0);
        centerBtn.setOnAction(e-> changeCenterBtnWidth());
        Button rightBtn = new Button("Right");
        HBox.setHgrow(rightBtn, Priority.ALWAYS);
        Pane root = new HBox(leftBtn,centerBtn,rightBtn);
        root.setPrefSize(1000, 150);
        Scene scene = new Scene(root);
        stage.setScene(scene);
        stage.show();
    }

    private void changeCenterBtnWidth() {
        double newWidth = centerBtn.getWidth() +  DELTA;
        newWidth = newWidth < MAX ? newWidth : MIN;
        centerBtn.setPrefWidth(newWidth);
    }

    public static void main(String[] args) {
        launch(args);
    }
}

Demonstrating a solution based on GridPane rquires only some samll changes:演示基于GridPane的解决方案只需要一些小改动:

    public void start(Stage stage) throws Exception   {

        Button leftBtn = new Button("Left");

        centerBtn = new Button("Click to change width");
        centerBtn.widthProperty().addListener((obs, oldValue,newValue)-> {
            //change the logic as needed
            leftBtn.setPrefWidth(newValue.doubleValue() >= 600 ? 200 : 250);
        });
        centerBtn.setPrefSize(600, 0);
        centerBtn.setOnAction(e-> changeCenterBtnWidth());
        Button rightBtn = new Button("Right");

        GridPane root = new GridPane();
        root.add(leftBtn,0, 0);
        root.add(centerBtn,1, 0);
        root.add(rightBtn,2, 0);
        root.setPrefSize(1000, 150);
        Scene scene = new Scene(root);
        stage.setScene(scene);
        stage.show();
   }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM