当前位置: 首页 > 知识库问答 >
问题:

动态窗格的JavaFX约束问题

常元章
2023-03-14

下面是主界面,我想动态添加包含名称、作者、描述和按钮的窗格。

在这里,它很好地扩展到可用的宽度。

这是我上面UI的FXML代码

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

<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?>


<VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" style="-fx-background-color: white;" xmlns="http://javafx.com/javafx/10.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="ResultsUI">
   <children>
      <AnchorPane prefWidth="600.0" style="-fx-background-color: white;" VBox.vgrow="NEVER">
         <children>
            <TextField id="queryOldTF" fx:id="queryOldTF" layoutX="14.0" layoutY="14.0" prefHeight="40.0" prefWidth="518.0" style="-fx-min-height: 40; -fx-border-radius: 50%; -fx-border-color: #007BFF; -fx-background-color: white;" AnchorPane.bottomAnchor="14.0" AnchorPane.leftAnchor="14.0" AnchorPane.rightAnchor="68.0" AnchorPane.topAnchor="14.0" />
            <Button id="serachAgainBtn" fx:id="serachAgainBtn" layoutX="532.0" layoutY="14.0" mnemonicParsing="false" onAction="#searchAgain" style="-fx-background-color: #007BFF; -fx-min-height: 40; -fx-min-width: 40; -fx-text-fill: white; -fx-border-radius: 50%; -fx-background-radius: 50%;" text="GO" AnchorPane.rightAnchor="14.0" AnchorPane.topAnchor="14.0" />
         </children>
         <VBox.margin>
            <Insets />
         </VBox.margin>
      </AnchorPane>
      <AnchorPane prefHeight="700.0" prefWidth="600.0" style="-fx-background-color: white;" VBox.vgrow="ALWAYS">
         <children>
            <ScrollPane id="scrollPane" fx:id="scrollPane" fitToWidth="true" layoutX="1.0" prefHeight="339.0" prefWidth="574.0" style="-fx-background-color: white;" vbarPolicy="ALWAYS" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="1.0" AnchorPane.rightAnchor="1.0" AnchorPane.topAnchor="0.0">
              <content>
                  <AnchorPane prefHeight="206.0" style="-fx-background-color: white;">
                     <children>
                        <TextArea id="descTl" fx:id="descTl" editable="false" layoutY="46.0" prefHeight="111.0" prefRowCount="4" style="-fx-background-color: white;" wrapText="true" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0">
                           <font>
                              <Font name="Calibri Light" size="12.0" />
                           </font>
                        </TextArea>
                        <Label id="nameTl" fx:id="nameTl" prefHeight="27.0" style="-fx-font-size: 18;" text="Name" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="1.0" AnchorPane.topAnchor="1.0" />
                        <Label id="authorTl" fx:id="authorTl" layoutX="4.0" layoutY="27.0" prefHeight="17.0" style="-fx-font-style: italic;" text="Authors" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" />
                        <Button id="openBtn" fx:id="openBtn" layoutY="164.0" mnemonicParsing="false" style="-fx-background-color: white; -fx-border-color: #007BFF; -fx-border-radius: 25%;" text="Open" AnchorPane.bottomAnchor="14.800000000000011" AnchorPane.leftAnchor="0.0" />
                     </children>
                  </AnchorPane>
              </content>
               <padding>
                  <Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
               </padding>
            </ScrollPane>
         </children>
      </AnchorPane>
   </children>
</VBox>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.Pane?>
<fx:root xmlns:fx="http://javafx.com/fxml" type="javafx.scene.layout.Pane">
    <Pane id="resPane" fx:id="resPane" prefHeight="200.0" prefWidth="200.0">
        <children>
            <Label id="descTl" fx:id="descTl" layoutX="14.0" layoutY="75.0" text="Description" />
            <Label id="nameTl" fx:id="nameTl" layoutX="14.0" layoutY="14.0" style="-fx-font-size: 18;" text="Name" />
            <Label id="authorTl" fx:id="authorTl" layoutX="14.0" layoutY="49.0" text="Authors" />
            <Button id="openBtn" fx:id="openBtn" layoutX="12.0" layoutY="161.0" mnemonicParsing="false" text="Open" />
        </children>
    </Pane>
</fx:root>

public class ResultsUI { @FXML
    private ResourceBundle resources;

    @FXML
    private URL location;

    @FXML
    private TextField queryOldTF;

    @FXML
    private Button serachAgainBtn;

    @FXML
    private VBox resContainer;

    @FXML
    private ScrollPane scrollPane;

    @FXML
    void searchAgain(ActionEvent event) {
        String query = queryOldTF.getText().toString();
        queryOldTF.setText(query);
        getFromOwn = true;
        initialize();
    }

    private boolean getFromOwn = false;

    @FXML
    void initialize() {
        assert queryOldTF != null : "fx:id=\"queryOldTF\" was not injected: check your FXML file 'Second.fxml'.";
        assert serachAgainBtn != null : "fx:id=\"serachAgainBtn\" was not injected: check your FXML file 'Second.fxml'.";
        assert resContainer != null : "fx:id=\"resContainer\" was not injected: check your FXML file 'Second.fxml'.";
        assert scrollPane != null : "fx:id=\"scrollPane\" was not injected: check your FXML file 'Second.fxml'.";

        System.out.println(MainUI.query);
        if (!getFromOwn)
            queryOldTF.setText(MainUI.query);

        HashMap<Integer, Double> documents = ExtendedBooleanModel.returnRankedDocuments(queryOldTF.getText().toString().trim());
        Map<Integer, Paper> papers = ObjectHandler.getPapersCollection();

        List<MyPane> panes = new ArrayList<>();
        for (int index:
             documents.keySet()) {

            MyPane docPane = new MyPane(papers.get(index).getContent(), papers.get(index).getTitle(), papers.get(index).getAuthor(), papers.get(index).getName());
            panes.add(docPane);
        }

        VBox pane = new VBox();
        pane.getChildren().addAll(panes);

        scrollPane.setContent(pane);
    }
}
public class MyPane extends Pane {

    @FXML
    public TextArea descTl;

    @FXML
    public Label nameTl;

    @FXML
    public Label authorTl;

    public MyPane(String desc, String name, String author, String doc) {
        FXMLLoader loader = new FXMLLoader(getClass().getResource("subFXML.fxml"));
        loader.setRoot(this);
        loader.setController(this);
        try {
            loader.load();

            descTl.setText(desc);
            nameTl.setText(name);
            authorTl.setText(author);
            openBtn.setOnAction(event -> {
                File myFile = new File("pdfs/" + doc.replace(".txt", ".pdf"));
                try {
                    Desktop.getDesktop().open(myFile);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            });

        } catch (IOException exception) {
            throw new RuntimeException(exception);
        }
    }

    @FXML
    private Button openBtn;

    public void setOnAction(EventHandler<ActionEvent> handler) {
        System.out.println("test");
        openBtn.setOnAction(handler);
    }

    public EventHandler<ActionEvent> getOnAction() {
        return openBtn.getOnAction();
    }
}

任何帮助都会得到很大的支持...

共有1个答案

莫振
2023-03-14

正如我在对您上一个问题的评论中提到的,我强烈建议您不要使用anchorpane。使用实际布局它们的子级(“自动”)的布局,您将会有更好的时间。例如,您的主FXML文件可以简化为以下内容:

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

<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ListView?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>

<VBox xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" 
      fx:controller="ResultsUI" prefWidth="600" prefHeight="500">

    <HBox spacing="10">
        <padding>
            <Insets topRightBottomLeft="10"/>
        </padding>
        <TextField fx:id="queryOldTF" HBox.hgrow="ALWAYS"/>
        <Button fx:id="searchAgainBtn" text="GO" onAction="#searchAgain"/>
    </HBox>

    <ListView fx:id="resultsListView" VBox.vgrow="ALWAYS"/>

</VBox>

使用此设置,您不必担心绝对定位(例如layoutxarchivePane.RightAnchor等)。这也使用了Sedrick建议的ListView;因为ListView是一个虚拟控件,所以即使有许多结果要显示,它也能保持性能。

在控制器中,您可以自定义ListViewCellFactory来正确显示您的项目(请参阅此问题)。您还可以将“子部分”FXML文件(可能用作单元格图形的文件)简化为如下内容:

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

<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.layout.VBox?>

<fx:root xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1"
         type="javafx.scene.layout.VBox">

    <Label fx:id="titleLabel" text="Title"/>
    <Label fx:id="authorsLabel" text="Authors"/>
    <!-- The parent VBox will grow the TextArea horizontally -->
    <TextArea fx:id="descArea" editable="false" wrapText="true" prefRowCount="6"/>
    <Button text="Open" onAction="#openFile"/>

</fx:root>

您看到的灰色框很可能是ScrollPane的背景,尽管它可能是其他祖先节点,甚至是Scene。由于您的节点并没有按照您的意愿增长以填充空间,所以祖先节点的背景是“窥视”通过的。一些问题可以通过修改布局来解决,这样节点就被掩盖了。但是,您可能需要设置某些节点的背景颜色。这将是最容易的使用CSS;请参阅JavaFX CSS参考指南。

使用Scene Builder的CSS分析器在这里可以是一个很有帮助的工具。要显示它,请转到视图>显示CSS分析器或按Ctrl+6(Windows)。

 类似资料:
  • 我知道你可以在fxml中添加AnchorPane,比如:“AnchorPane.bottomAnchor=“0.0”,但是你能在java代码中设置AnchorPane约束吗?

  • 我正在JavaFx中开发一个应用程序,其中我有两个选项卡。 在第一个选项卡中,我有ComboBox: 在第二个选项卡中,我有这样的Gridpane: 我想要的是当用户从Tab A的组合框中选择3时,例如: 它应该在Tab B的Gridpane中添加3行,每列添加文本字段、复选框和datepicker。A列有文本字段,B列有复选框,C列有日期选择器,如下所示: 请帮助我如何才能实现这一点,实现后,我

  • 我试图将乘法VBox添加到scrollpane中的gridpane(在下面的codesnippet中称为refPane)。 它在一行中添加不超过ITEMS_PER_ROW的Vbox,并在下一行中继续。也不应该有更多的行,然后ITEMS_PER_COLUM可见。问题是,如果我添加更多的ITEMS_PER_ROW*ITEMS_PER_COLUMN到网格中,而不是obingbeingscrollable

  • 我正在评估OptaPlanner的一个规划问题。我已经看到了几个关于这个话题的回应,但没有一个完全像我正在寻找的。 似乎OptaPlanner在求解时需要静态数量的实体/变量。 如有任何指示,将不胜感激。

  • 我有一些可视化的元素,它们有可以相互连接的端口。元素的端口是表示元素的javafx窗格的子元素。我现在想知道什么是将连接线的起点和终点绑定到端口位置的最佳方法,因为端口可能位于元素层次结构的相当深的位置。这就是为什么我认为我可能需要这些端口的绝对位置,但没有找到一个简单的方法来获得它们。现在,这些线就在场景根的正下方。

  • 问题内容: 当内容的高度增加时,有什么方法可以自动向下滚动ScrollPane控件?例如,我在屏幕底部(在ScrollPane内部)有一个TitledPane,当我展开它时,我希望ScrollPane向下滚动,以便可以看到TitledPane的全部内容。 问题答案: 您可以结合使用和和来实现该行为 第一个是获取titlePane的坐标,第二个是设置scrollPane的垂直栏位置。请注意,它的范围