How to bind Pane with another Pane in JavaFX

2020-04-21 02:09发布

问题:

I'm finding the way that how to bind the size of a pane with the outer pane.

I could bind the size ofRectangle with Pane, But couldn't bind an inner pane (Red dotted rectangle) with outer pane (Blue dotted rectangle)

Why I couldn't do it

It seems to be that Pane does not provide bind method for widthProperty

Objects

  • At least, bind width with TextArea of inner Pane with outer Pane
  • I'll make many new tabs, therefore, I prefer to bind inner Pane with outer Pane rather than bind TextArea directly to outer Pane.

Situation

  • Blue and Orange rectangles are bound well with pane dropPane
  • But Blue border pane's width should be the same size as a red border pane!

My Sources

main.kt:

import javafx.application.Application
import javafx.fxml.FXMLLoader
import javafx.scene.*
import javafx.scene.control.*
import javafx.scene.paint.Paint
import javafx.scene.shape.Rectangle
import javafx.stage.Stage

import javafx.scene.layout.*
import javafx.scene.paint.*


fun main(args : Array<String>) {
    println("EntryPoint")

    Application.launch(PaneBindingTest().javaClass, *args)

}

class PaneBindingTest : Application() {

    private var tabCount = 0

    private fun generateNewTab (): Tab {
        val tab = Tab()
        tabCount += 1
        tab.text = "Tab$tabCount"
        val fxml = javaClass.getResource("fxml/Tab.fxml")
        val aTabPane: Pane = FXMLLoader.load(fxml)
        aTabPane.border = Border(BorderStroke(Paint.valueOf("Red"),BorderStrokeStyle.DASHED, CornerRadii.EMPTY, BorderWidths.DEFAULT))
        tab.content = aTabPane
        return tab
    }

    override fun start(primaryStage: Stage) {
        primaryStage.title = "EntryPoint"
        primaryStage.isAlwaysOnTop = true
        val fxml = javaClass.getResource("fxml/EntryPoint.fxml")
        val root: Parent = FXMLLoader.load(fxml)
        val scene = Scene(root)

        val epPane= root.lookup("#EPPane") as AnchorPane // Entry Point Pane
        val dropPane= root.lookup("#DropPane") as AnchorPane // Drop Pane
        val tabPane= root.lookup("#TabPane") as TabPane // Tab Pane
        val singleDropPoint= root.lookup("#ForSingle") as Rectangle // Single-ArchiveSet drop point
        val multiDropPoint = root.lookup("#ForMulti") as Rectangle // Multi-ArchiveSet drop point

        //epPane.background = Background(BackgroundFill(Paint.valueOf("Yellow"), CornerRadii(0.0), Insets(0.0,0.0,0.0,0.0)))
        //dropPane.background = Background(BackgroundFill(Paint.valueOf("Green"), CornerRadii(0.0), Insets(0.0,0.0,0.0,0.0)))
        tabPane.tabClosingPolicy = TabPane.TabClosingPolicy.ALL_TABS // or SELECTED_TAB, UNAVAILABLE
        tabPane.border = Border(BorderStroke(Paint.valueOf("Blue"),BorderStrokeStyle.DASHED, CornerRadii.EMPTY, BorderWidths.DEFAULT))

        singleDropPoint.heightProperty().bind(epPane.heightProperty().divide(32).multiply(23))

        multiDropPoint.yProperty().bind(singleDropPoint.yProperty().add(dropPane.heightProperty().divide(4).multiply(3)))
        multiDropPoint.heightProperty().bind(epPane.heightProperty().divide(4))

        primaryStage.scene = scene
        primaryStage.show()

        val newTab = generateNewTab()
        tabPane.tabs.add(newTab)
        tabPane.selectionModel.select(newTab)

    }
}

fxml/EntryPoint.fxml

<?import javafx.scene.control.TabPane?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.shape.Rectangle?>

<AnchorPane fx:id="EPPane" prefHeight="640.0" prefWidth="1280.0" xmlns="http://javafx.com/javafx/10.0.1" xmlns:fx="http://javafx.com/fxml/1">
<children>
    <TabPane fx:id="TabPane" prefHeight="640.0" prefWidth="1152.0" tabClosingPolicy="ALL_TABS" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="128.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
    </TabPane>
    <AnchorPane fx:id="DropPane" layoutY="128.0" maxWidth="128.0" minWidth="128.0" prefWidth="128.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.topAnchor="0.0">
        <children>
            <Rectangle fx:id="ForSingle" arcHeight="16.0" arcWidth="16.0" fill="DODGERBLUE" height="360.0" width="120.0" stroke="#1100ff" strokeType="INSIDE" strokeWidth="8.0" AnchorPane.leftAnchor="4.0" AnchorPane.rightAnchor="4.0" AnchorPane.topAnchor="4.0"/>
            <Rectangle fx:id="ForMulti" arcHeight="16.0" arcWidth="16.0" fill="#ff9d1f" height="240.0" width="120.0" stroke="#ff8800" strokeType="INSIDE" strokeWidth="8.0" AnchorPane.leftAnchor="4.0" AnchorPane.rightAnchor="4.0" AnchorPane.bottomAnchor="4.0"/>
        </children>
    </AnchorPane>
</children>
</AnchorPane>

fxml/Tab.fxml:

<?import javafx.scene.control.CheckBox?>
<?import javafx.scene.control.ComboBox?>
<?import javafx.scene.control.RadioButton?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.control.ToggleGroup?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.HBox?>

<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="480.0" prefWidth="1000.0" xmlns="http://javafx.com/javafx/10.0.1" xmlns:fx="http://javafx.com/fxml/1">
  <children>
      <TextArea fx:id="FilePaths" layoutX="4.0" layoutY="80.0" prefHeight="128.0" AnchorPane.leftAnchor="4.0" AnchorPane.rightAnchor="4.0" AnchorPane.topAnchor="72.0" />
      <RadioButton layoutX="14.0" layoutY="206.0" mnemonicParsing="false" selected="true" text="Hash/Size only">
        <toggleGroup>
            <ToggleGroup fx:id="AnalyzeMethod" />
        </toggleGroup>
      </RadioButton>
      <RadioButton layoutX="120.0" layoutY="206.0" mnemonicParsing="false" text="FileName" toggleGroup="$AnalyzeMethod" />
      <RadioButton layoutX="200.0" layoutY="206.0" mnemonicParsing="false" text="Directory Structure" toggleGroup="$AnalyzeMethod" />
      <CheckBox fx:id="CheckDiff" layoutX="336.0" layoutY="206.0" mnemonicParsing="false" text="Show Diff" />
      <CheckBox fx:id="CheckSame" layoutX="420.0" layoutY="206.0" mnemonicParsing="false" text="Show Same" />
      <ComboBox fx:id="ComboBox" layoutX="840.0" layoutY="202.0" prefWidth="150.0" />
      <HBox fx:id="LabelBox" layoutX="12.0" layoutY="14.0" prefHeight="64.0" prefWidth="978.0" AnchorPane.leftAnchor="4.0" AnchorPane.rightAnchor="4.0" AnchorPane.topAnchor="4.0" />
  </children>
</AnchorPane>

I've found that almost the same question, but no answer was there.

回答1:

You do not need a binding to achieve this. The problem is the fact that you set the constraints for maxHeight/maxWidth to USE_PREF_SIZE, i.e. to a fixed value that can very well be reached when resizing the window. Remove those constraints to allow the AnchorPane to grow as necessary:

Tab.fxml

<AnchorPane minHeight="-Infinity" minWidth="-Infinity" prefHeight="480.0" prefWidth="1000.0" xmlns="http://javafx.com/javafx/10.0.1" xmlns:fx="http://javafx.com/fxml/1">
    ...
</AnchorPane>

Furthermore I recommend avoiding the use of AnchorPanes, if you can avoid it. It's hard to achieve responsive layouts with this kind of layout. VBox and HBox would do much better jobs in this case.

Example:

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

<?import javafx.scene.control.CheckBox?>
<?import javafx.scene.control.ComboBox?>
<?import javafx.scene.control.RadioButton?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.control.ToggleGroup?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.layout.Region?>

<VBox prefHeight="480.0"
    prefWidth="1000.0" xmlns="http://javafx.com/javafx/10.0.1"
    xmlns:fx="http://javafx.com/fxml/1">
    <padding>
        <Insets topRightBottomLeft="4" />
    </padding>
    <children>
        <HBox fx:id="LabelBox" prefHeight="64.0" prefWidth="978.0" />
        <TextArea VBox.vgrow="ALWAYS" fx:id="FilePaths"
            prefHeight="128.0">
        </TextArea>
        <HBox spacing="10" minWidth="-Infinity">
            <VBox.margin>
                <Insets top="5" left="0" right="0" bottom="0" />
            </VBox.margin>
            <children>
                <RadioButton mnemonicParsing="false" selected="true"
                    text="Hash/Size only">
                    <toggleGroup>
                        <ToggleGroup fx:id="AnalyzeMethod" />
                    </toggleGroup>
                </RadioButton>
                <RadioButton mnemonicParsing="false" text="FileName"
                    toggleGroup="$AnalyzeMethod" />
                <RadioButton mnemonicParsing="false"
                    text="Directory Structure" toggleGroup="$AnalyzeMethod" />
                <CheckBox fx:id="CheckDiff" mnemonicParsing="false"
                    text="Show Diff" />
                <CheckBox fx:id="CheckSame" mnemonicParsing="false"
                    text="Show Same" />
                <Region HBox.hgrow="ALWAYS" /> <!-- placeholder to grow/shrink -->
                <ComboBox fx:id="ComboBox" prefWidth="150.0" />
            </children>
        </HBox>
    </children>
</VBox>