You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在JavaFX中构建可自适应缩放的元素周期表?

JavaFX元素周期表自适应缩放实现方案

1. 先搞定元素数据加载

把txt里的元素信息封装成实体类,用IO流读取后存到列表:

// 元素实体类
public class Element {
    private String name;
    private String symbol;
    private double mass;
    private int period; // 周期
    private int group;  // 族

    public Element(String name, String symbol, double mass, int period, int group) {
        this.name = name;
        this.symbol = symbol;
        this.mass = mass;
        this.period = period;
        this.group = group;
    }

    // 生成getter方法
}

// 读取txt数据的方法
private List<Element> loadElements() throws IOException {
    List<Element> elements = new ArrayList<>();
    // 假设txt每行格式:名称,符号,质量,周期,族
    try (BufferedReader br = new BufferedReader(new FileReader("elements.txt"))) {
        String line;
        while ((line = br.readLine()) != null) {
            String[] parts = line.split(",");
            Element elem = new Element(
                parts[0], parts[1], Double.parseDouble(parts[2]),
                Integer.parseInt(parts[3]), Integer.parseInt(parts[4])
            );
            elements.add(elem);
        }
    }
    return elements;
}

2. 主布局用GridPane实现自适应网格

周期表是固定行列结构,GridPane最适合,通过行列约束让单元格随窗口缩放:

private GridPane buildPeriodicTableGrid() {
    GridPane tableGrid = new GridPane();
    tableGrid.setPadding(new Insets(10));
    tableGrid.setHgap(5);
    tableGrid.setVgap(5);

    // 设置18列,每列自动占满宽度
    for (int i = 0; i < 18; i++) {
        ColumnConstraints colConst = new ColumnConstraints();
        colConst.setHgrow(Priority.ALWAYS); // 列随窗口宽度拉伸
        colConst.setFillWidth(true);
        tableGrid.getColumnConstraints().add(colConst);
    }

    // 设置7行,每行自动占满高度
    for (int i = 0; i < 7; i++) {
        RowConstraints rowConst = new RowConstraints();
        rowConst.setVgrow(Priority.ALWAYS); // 行随窗口高度拉伸
        rowConst.setFillHeight(true);
        tableGrid.getRowConstraints().add(rowConst);
    }

    return tableGrid;
}

3. 让元素卡片支持响应式缩放

加载FXML卡片后,确保内部控件能随卡片尺寸变化:

  • 在FXML里给控件设置maxWidth="Infinity"、maxHeight="Infinity",并绑定字体大小到容器尺寸:
<!-- elementCard.fxml 示例 -->
<VBox fx:id="cardRoot" alignment="CENTER" spacing="5" style="-fx-border-color: black; -fx-padding: 10;">
    <Label fx:id="symbolLabel" text="H" style="-fx-font-weight: bold;" 
           maxWidth="Infinity" alignment="CENTER"/>
    <Label fx:id="nameLabel" text="氢" maxWidth="Infinity" alignment="CENTER"/>
    <Label fx:id="massLabel" text="1.008" maxWidth="Infinity" alignment="CENTER"/>
</VBox>
  • 在卡片控制器里绑定字体大小:
public class ElementCardController {
    @FXML private VBox cardRoot;
    @FXML private Label symbolLabel;
    @FXML private Label nameLabel;
    @FXML private Label massLabel;

    public void setElementData(Element elem) {
        symbolLabel.setText(elem.getSymbol());
        nameLabel.setText(elem.getName());
        massLabel.setText(String.valueOf(elem.getMass()));

        // 绑定符号字体大小到卡片宽度的1/4
        symbolLabel.fontProperty().bind(
            new SimpleObjectProperty<>(Font.font("Arial", FontWeight.BOLD, 
                cardRoot.widthProperty().divide(4)))
        );
        // 其他标签字体大小绑定到卡片宽度的1/8
        nameLabel.fontProperty().bind(
            new SimpleObjectProperty<>(Font.font("Arial", cardRoot.widthProperty().divide(8)))
        );
        massLabel.fontProperty().bind(
            new SimpleObjectProperty<>(Font.font("Arial", cardRoot.widthProperty().divide(8)))
        );
    }
}

4. 整合主应用并添加窗口缩放支持

把所有部分拼起来,加载元素、生成网格、添加卡片:

public class PeriodicTableApp extends Application {
    @Override
    public void start(Stage primaryStage) throws IOException {
        List<Element> elements = loadElements();
        GridPane tableGrid = buildPeriodicTableGrid();

        // 给网格添加元素卡片
        for (Element elem : elements) {
            FXMLLoader loader = new FXMLLoader(getClass().getResource("elementCard.fxml"));
            VBox card = loader.load();
            ElementCardController controller = loader.getController();
            controller.setElementData(elem);

            // 点击卡片打开新窗口
            card.setOnMouseClicked(e -> {
                Stage detailStage = new Stage();
                detailStage.setTitle(elem.getName() + " - 详情");
                // 可以复制卡片内容到新窗口,或者加载专门的详情FXML
                VBox detailCard = (VBox) card.clone();
                detailStage.setScene(new Scene(detailCard, 350, 450));
                detailStage.show();
            });

            // 把卡片放到对应周期和族的位置(注意GridPane索引从0开始)
            tableGrid.add(card, elem.getGroup() - 1, elem.getPeriod() - 1);
        }

        Scene scene = new Scene(tableGrid, 1200, 800);
        primaryStage.setTitle("元素周期表");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    // 这里放上前面的loadElements()和buildPeriodicTableGrid()方法

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

关键注意点

  • 确保txt文件路径正确,若放在资源目录下,改用getClass().getResourceAsStream("elements.txt")读取。
  • 如果GridPane的自适应效果不够理想,可以监听场景的尺寸变化,手动调整卡片大小:
scene.widthProperty().addListener((obs, oldWidth, newWidth) -> {
    double cardWidth = (newWidth.doubleValue() - 20 - 17*5) / 18; // 减去padding和gap
    tableGrid.getChildren().forEach(node -> node.setPrefWidth(cardWidth));
});

内容的提问来源于stack exchange,提问作者Enrico Sombini

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 01:11:08