AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / coding / 问题 / 79107348
Accepted
Adalberto José Brasaca
Adalberto José Brasaca
Asked: 2024-10-20 22:48:47 +0800 CST2024-10-20 22:48:47 +0800 CST 2024-10-20 22:48:47 +0800 CST

将复合对象(带有 TextFields 的 GridPane)插入到 ScrolPane 中

  • 772

我有一个使用 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);
            }
        }            
    }    
}
java
  • 1 1 个回答
  • 63 Views

1 个回答

  • Voted
  1. Best Answer
    James_D
    2024-10-21T20:36:28+08:002024-10-21T20:36:28+08:00

    该Initializable接口及其相应的void initialize(URL, ResourceBundle)方法旨在供控制器类用作 FXML 文档的控制器。当FXMLLoader加载在其属性中指定类的 FXML 文件时fx:controller,会FXMLLoader实例化该类,然后initialize(...)对其调用该方法。1

    您的Grid类不是任何 FXML 文档的控制器类。它不是由实例化(您通过调用类FXMLLoader直接实例化它),因此该方法不会在任何时候自动为您调用。var newGrid = new Grid(...)MainViewControllerinitialize(...)

    因此,永远不会调用initialize()中的方法Grid,因此永远不会创建文本字段,也永远不会将其添加到网格窗格中。因此,您添加到滚动窗格的网格是空的,并且什么都看不到。

    类无需Grid实现Initializable,因为它与 FXML 文件无关。initialize()方法中的代码是您希望在Grid创建时执行的代码,因此将其移至构造函数:

    import javafx.scene.control.TextField;
    import javafx.scene.layout.GridPane;
    
    public class Grid extends GridPane {
        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;
            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);
                }
            }
        }
    
    }
    

    这给出了期望的结果:

    窗口中显示的文本字段网格的屏幕截图


    关于您的代码的其他评论:

    请注意,无需在类中复制值horizontalGap和,因为这些值已存储为从继承的和属性。因此,您可以使用以下方法稍微减小类的大小:verticalGaphgapvgapGridPane

    public class Grid extends GridPane {
        private final int totalColumnFields;
        private final int totalRowFields;
        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.fieldHorizontalSize = fieldHorizontalSize;
            this.fieldVerticalSize = fieldVerticalSize;
            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);
                }
            }
        }
    }
    

    如果您需要随时引用这些值,可以使用getHgap()和 来引用getVgap()。

    我还建议不要GridPane在此处进行子类化。在向现有类添加功能时,应保留对现有类进行子类化。在这里,您实际上只是在配置现有类的一个实例。子类化GridPane还会向应用程序的其余部分公开布局策略的内部细节,这可能会使以后更改布局(例如,更改为TilePane某种其他策略)变得更加困难(如果您想要这样做的话)。我建议在此处“优先使用聚合而不是继承”,并且只允许访问聚合,GridPane而不公开您正在使用的布局的详细信息:

    import javafx.scene.Node;
    import javafx.scene.control.TextField;
    import javafx.scene.layout.GridPane;
    
    public class Grid {
        private final int totalColumnFields;
        private final int totalRowFields;
        private final int fieldHorizontalSize;
        private final int fieldVerticalSize;
    
        private final GridPane grid;
    
        public Grid(int totalColumnFields, int totalRowFields, int horizontalGap, int verticalGap, int fieldHorizontalSize, int fieldVerticalSize) {
            this.totalColumnFields = totalColumnFields;
            this.totalRowFields = totalRowFields;
            this.fieldHorizontalSize = fieldHorizontalSize;
            this.fieldVerticalSize = fieldVerticalSize;
    
            grid = new GridPane();
            grid.setHgap(horizontalGap);
            grid.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 );
                    grid.add(arrayLetterField[col][row], col, row);
                }
            }
        }
    
        public Node getView() {
            return grid;
        }
    
    }
    

    然后对客户端代码进行相应的细微修改:

        @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);
            var gridView = newGrid.getView();
            scpGrid.setContent(gridView);
            gridView.setStyle("-fx-alignment: center;");
        }
    

    (1)请注意,从 JavaFX 2.1 开始,该Initializable接口本质上是多余的。摘自文档:

    注意:此接口已被自动将location和resources属性注入控制器所取代。FXMLLoader现在将自动调用控制器定义的任何适当注释的无参数initialize()方法。建议尽可能使用注入方法。

    这意味着,即使是 FXML 文档的控制器类也无需实现Initializable。如果您需要在@FXML注入 -annotated 字段后执行初始化,只需定义一个无参数initialize()方法即可。您甚至可以private在注释此方法后使它成为@FXML,从而更好地执行封装。如果您需要访问location或resources属性,则可以以与 FXML 文件的元素相同的方式注入它们。例如:

    public class MainViewController {
    
        @FXML
        private MenuItem mnuItemNew;
    
        @FXML
        private ScrollPane scpGrid;
        
        @FXML
        // Can omit this field if it is not needed
        // (It is very rare to need this.)
        private URL location;
    
        @FXML
        private 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);
            var gridView = newGrid.getView();
            scpGrid.setContent(gridView);
            gridView.setStyle("-fx-alignment: center;");
        }
    
        @FXML
        private void initialize() {
            // Any required initialization code here
            // If no intialization needed, this method can be omitted
        }
    
    }
    
    • 3

相关问题

  • Lock Condition.notify 抛出 java.lang.IllegalMonitorStateException

  • 多对一微服务响应未出现在邮递员中

  • 自定义 SpringBoot Bean 验证

  • Java 套接字是 FIFO 的吗?

  • 为什么不可能/不鼓励在服务器端定义请求超时?

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    Vue 3:创建时出错“预期标识符但发现‘导入’”[重复]

    • 1 个回答
  • Marko Smith

    为什么这个简单而小的 Java 代码在所有 Graal JVM 上的运行速度都快 30 倍,但在任何 Oracle JVM 上却不行?

    • 1 个回答
  • Marko Smith

    具有指定基础类型但没有枚举器的“枚举类”的用途是什么?

    • 1 个回答
  • Marko Smith

    如何修复未手动导入的模块的 MODULE_NOT_FOUND 错误?

    • 6 个回答
  • Marko Smith

    `(表达式,左值) = 右值` 在 C 或 C++ 中是有效的赋值吗?为什么有些编译器会接受/拒绝它?

    • 3 个回答
  • Marko Smith

    何时应使用 std::inplace_vector 而不是 std::vector?

    • 3 个回答
  • Marko Smith

    在 C++ 中,一个不执行任何操作的空程序需要 204KB 的堆,但在 C 中则不需要

    • 1 个回答
  • Marko Smith

    PowerBI 目前与 BigQuery 不兼容:Simba 驱动程序与 Windows 更新有关

    • 2 个回答
  • Marko Smith

    AdMob:MobileAds.initialize() - 对于某些设备,“java.lang.Integer 无法转换为 java.lang.String”

    • 1 个回答
  • Marko Smith

    我正在尝试仅使用海龟随机和数学模块来制作吃豆人游戏

    • 1 个回答
  • Martin Hope
    Aleksandr Dubinsky 为什么 InetAddress 上的 switch 模式匹配会失败,并出现“未涵盖所有可能的输入值”? 2024-12-23 06:56:21 +0800 CST
  • Martin Hope
    Phillip Borge 为什么这个简单而小的 Java 代码在所有 Graal JVM 上的运行速度都快 30 倍,但在任何 Oracle JVM 上却不行? 2024-12-12 20:46:46 +0800 CST
  • Martin Hope
    Oodini 具有指定基础类型但没有枚举器的“枚举类”的用途是什么? 2024-12-12 06:27:11 +0800 CST
  • Martin Hope
    sleeptightAnsiC `(表达式,左值) = 右值` 在 C 或 C++ 中是有效的赋值吗?为什么有些编译器会接受/拒绝它? 2024-11-09 07:18:53 +0800 CST
  • Martin Hope
    The Mad Gamer 何时应使用 std::inplace_vector 而不是 std::vector? 2024-10-29 23:01:00 +0800 CST
  • Martin Hope
    Chad Feller 在 5.2 版中,bash 条件语句中的 [[ .. ]] 中的分号现在是可选的吗? 2024-10-21 05:50:33 +0800 CST
  • Martin Hope
    Wrench 为什么双破折号 (--) 会导致此 MariaDB 子句评估为 true? 2024-05-05 13:37:20 +0800 CST
  • Martin Hope
    Waket Zheng 为什么 `dict(id=1, **{'id': 2})` 有时会引发 `KeyError: 'id'` 而不是 TypeError? 2024-05-04 14:19:19 +0800 CST
  • Martin Hope
    user924 AdMob:MobileAds.initialize() - 对于某些设备,“java.lang.Integer 无法转换为 java.lang.String” 2024-03-20 03:12:31 +0800 CST
  • Martin Hope
    MarkB 为什么 GCC 生成有条件执行 SIMD 实现的代码? 2024-02-17 06:17:14 +0800 CST

热门标签

python javascript c++ c# java typescript sql reactjs html

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve