我有一个使用 GridPane 构建带有 TextFields 数组的网格的类。我需要将此网格插入到只接受 setContent() 方法中的 Node 的 ScrollPane 中。因此我从 GridPane 扩展了此类。Grid 类由 MainViewController.java 类的 onMnuItemNewAction 方法在 ScrollPane 中实例化和设置,但网格未显示。感谢您的帮助。
主视图.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Menu?>
<?import javafx.scene.control.MenuBar?>
<?import javafx.scene.control.MenuItem?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.VBox?>
<BorderPane prefHeight="277.0" prefWidth="495.0" xmlns="http://javafx.com/javafx/17" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="br.com.ablogic.crossword.MainViewController">
<top>
<VBox prefWidth="100.0" BorderPane.alignment="CENTER">
<children>
<MenuBar fx:id="mnuBar" prefHeight="25.0" prefWidth="360.0">
<menus>
<Menu mnemonicParsing="false" text="File">
<items>
<MenuItem fx:id="mnuItemNew" mnemonicParsing="false" onAction="#onMnuItemNewAction" text="New grid" />
</items>
</Menu>
</menus>
</MenuBar>
</children>
</VBox>
</top>
<center>
<ScrollPane fx:id="scpGrid" fitToHeight="true" fitToWidth="true" pannable="true" style="-fx-background-color: #dbbb92; -fx-background: #dbbb92;" BorderPane.alignment="CENTER" />
</center>
</BorderPane>
主程序
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.stage.Stage;
import java.io.IOException;
public class Main extends Application {
@Override
public void start(Stage stage) throws IOException {
FXMLLoader fxmlLoader = new FXMLLoader(Main.class.getResource("MainView.fxml"));
Scene scene = new Scene(fxmlLoader.load(), 800, 600);
stage.setTitle("Grid Demo");
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch();
}
}
MainViewController.java(调用方法)
import javafx.geometry.Pos;
import javafx.scene.control.MenuItem;
import javafx.scene.control.ScrollPane;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import java.net.URL;
import java.util.ResourceBundle;
public class MainViewController implements Initializable {
@FXML
private MenuItem mnuItemNew;
@FXML
private ScrollPane scpGrid;
@FXML
public void onMnuItemNewAction() {
int cols = 10;
int rows = 10;
int horizontalGap = 1;
int verticalGap = 1;
int fieldHorizontalSize = 40;
int fieldVerticalSize = 40;
var newGrid = new Grid(cols, rows, horizontalGap, verticalGap, fieldHorizontalSize, fieldVerticalSize);
scpGrid.setContent(newGrid);
newGrid.setAlignment(Pos.CENTER);
}
@Override
public void initialize(URL url, ResourceBundle rb) {
}
}
网格.java
import javafx.fxml.Initializable;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
import java.net.URL;
import java.util.ResourceBundle;
public class Grid extends GridPane implements Initializable {
private final int totalColumnFields;
private final int totalRowFields;
private final int horizontalGap;
private final int verticalGap;
private final int fieldHorizontalSize;
private final int fieldVerticalSize;
public Grid(int totalColumnFields, int totalRowFields, int horizontalGap, int verticalGap, int fieldHorizontalSize, int fieldVerticalSize) {
this.totalColumnFields = totalColumnFields;
this.totalRowFields = totalRowFields;
this.horizontalGap = horizontalGap;
this.verticalGap = verticalGap;
this.fieldHorizontalSize = fieldHorizontalSize;
this.fieldVerticalSize = fieldVerticalSize;
}
@Override
public void initialize(URL url, ResourceBundle rb) {
this.setHgap(horizontalGap);
this.setVgap(verticalGap);
TextField[][] arrayLetterField = new TextField[totalColumnFields][totalRowFields];
for (int row = 0; row < totalRowFields; row++) {
for (int col = 0; col < totalColumnFields; col++) {
arrayLetterField[col][row] = new TextField();
arrayLetterField[col][row].setMinSize(fieldHorizontalSize, fieldVerticalSize);
arrayLetterField[col][row].setMaxSize(fieldHorizontalSize, fieldVerticalSize );
this.add(arrayLetterField[col][row], col, row);
}
}
}
}
该
Initializable
接口及其相应的void initialize(URL, ResourceBundle)
方法旨在供控制器类用作 FXML 文档的控制器。当FXMLLoader
加载在其属性中指定类的 FXML 文件时fx:controller
,会FXMLLoader
实例化该类,然后initialize(...)
对其调用该方法。1您的
Grid
类不是任何 FXML 文档的控制器类。它不是由实例化(您通过调用类FXMLLoader
直接实例化它),因此该方法不会在任何时候自动为您调用。var newGrid = new Grid(...)
MainViewController
initialize(...)
因此,永远不会调用
initialize()
中的方法Grid
,因此永远不会创建文本字段,也永远不会将其添加到网格窗格中。因此,您添加到滚动窗格的网格是空的,并且什么都看不到。类无需
Grid
实现Initializable
,因为它与 FXML 文件无关。initialize()
方法中的代码是您希望在Grid
创建时执行的代码,因此将其移至构造函数:这给出了期望的结果:
关于您的代码的其他评论:
请注意,无需在类中复制值
horizontalGap
和,因为这些值已存储为从继承的和属性。因此,您可以使用以下方法稍微减小类的大小:verticalGap
hgap
vgap
GridPane
如果您需要随时引用这些值,可以使用
getHgap()
和 来引用getVgap()
。我还建议不要
GridPane
在此处进行子类化。在向现有类添加功能时,应保留对现有类进行子类化。在这里,您实际上只是在配置现有类的一个实例。子类化GridPane
还会向应用程序的其余部分公开布局策略的内部细节,这可能会使以后更改布局(例如,更改为TilePane
某种其他策略)变得更加困难(如果您想要这样做的话)。我建议在此处“优先使用聚合而不是继承”,并且只允许访问聚合,GridPane
而不公开您正在使用的布局的详细信息:然后对客户端代码进行相应的细微修改:
(1)请注意,从 JavaFX 2.1 开始,该
Initializable
接口本质上是多余的。摘自文档:这意味着,即使是 FXML 文档的控制器类也无需实现
Initializable
。如果您需要在@FXML
注入 -annotated 字段后执行初始化,只需定义一个无参数initialize()
方法即可。您甚至可以private
在注释此方法后使它成为@FXML
,从而更好地执行封装。如果您需要访问location
或resources
属性,则可以以与 FXML 文件的元素相同的方式注入它们。例如: