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

JavaFX中用JFXTreeTableView加载MySQL数据遇类型参数错误求助

解决JFXTreeTableView声明时的类型边界错误问题

我来帮你解决这个JFXTreeTableView的类型边界问题,先回顾下你之前用TableView加载MySQL数据的实现代码,再一步步给出适配你原有逻辑的解决方案:


原有TableView实现代码

数据库连接方法

static public ResultSet AllElement() { 
    try { 
        cnx = connecterDB(); 
        st = cnx.createStatement(); 
        rst = st.executeQuery("SELECT * FROM element"); 
    } catch (Exception ex) { 
        ex.printStackTrace(); 
    } 
    return rst; 
}

控制器声明

@FXML private TableView<Object> TableElement; 
@FXML private TableColumn clmID, clmELement, clmPrix, clmQuantite; 
ObservableList<Object> data;

填充表格方法

public void tableElement() { 
    try { 
        data = FXCollections.observableArrayList(); 
        int r = -1; 
        ResultSet rst = Tools.ConnexionJM.AllElement(); 
        while (rst.next()) { 
            ObservableList<String> row = FXCollections.observableArrayList(); 
            for (int i = 1; i <= 4; i++) { 
                row.add("" + rst.getString(i)); 
            } 
            data.add(row); 
        } 
        TableElement.setItems(data); 
    } catch (SQLException ex) { 
        Logger.getLogger(FXMLDocumentController.class.getName()).log(Level.SEVERE, null, ex); 
    }
}

列配置方法

public void fillTableElement() { 
    clmID.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<ObservableList, String>, ObservableValue<String>>() { 
        public ObservableValue<String> call(TableColumn.CellDataFeatures<ObservableList, String> param) { 
            return new SimpleStringProperty(param.getValue().get(0).toString()); 
        } 
    }); 
    clmELement.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<ObservableList, String>, ObservableValue<String>>() { 
        public ObservableValue<String> call(TableColumn.CellDataFeatures<ObservableList, String> param) { 
            return new SimpleStringProperty(param.getValue().get(1).toString()); 
        } 
    }); 
    clmPrix.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<ObservableList, String>, ObservableValue<String>>() { 
        public ObservableValue<String> call(TableColumn.CellDataFeatures<ObservableList, String> param) { 
            return new SimpleStringProperty(param.getValue().get(2).toString()); 
        } 
    }); 
    clmQuantite.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<ObservableList, String>, ObservableValue<String>>() { 
        public ObservableValue<String> call(TableColumn.CellDataFeatures<ObservableList, String> param) { 
            return new SimpleStringProperty(param.getValue().get(3).toString()); 
        } 
    }); 
    tableElement(); 
}

你遇到的问题

当尝试声明JFXTreeTableView时:

private JFXTreeTableView<Object> TableViewAP;

收到错误提示:

type argument Object is not within bounds of type-variable S

问题根源

JFoenix的JFXTreeTableView对泛型参数有强制要求:泛型类型必须继承自RecursiveTreeObject<S>。这个类是JFoenix为树形表格设计的基础数据模型,用来管理节点的父子关系,而Object类显然不满足这个继承要求,所以触发了类型边界错误。


适配你原有逻辑的解决方案

咱们一步步修改代码,既满足JFXTreeTableView的要求,又沿用你原来的MySQL数据加载逻辑:

1. 创建对应数据表的实体类(继承RecursiveTreeObject)

为element表创建一个实体类,让它继承RecursiveTreeObject,这样就能符合JFXTreeTableView的泛型要求。这里对应你的表字段,定义属性和对应的Property:

import com.jfoenix.controls.datamodels.treetable.RecursiveTreeObject;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;

public class Element extends RecursiveTreeObject<Element> {
    private final StringProperty id;
    private final StringProperty elementName;
    private final StringProperty prix;
    private final StringProperty quantite;

    public Element(String id, String elementName, String prix, String quantite) {
        this.id = new SimpleStringProperty(id);
        this.elementName = new SimpleStringProperty(elementName);
        this.prix = new SimpleStringProperty(prix);
        this.quantite = new SimpleStringProperty(quantite);
    }

    // Getter方法和Property暴露方法
    public String getId() {
        return id.get();
    }

    public StringProperty idProperty() {
        return id;
    }

    public String getElementName() {
        return elementName.get();
    }

    public StringProperty elementNameProperty() {
        return elementName;
    }

    public String getPrix() {
        return prix.get();
    }

    public StringProperty prixProperty() {
        return prix;
    }

    public String getQuantite() {
        return quantite.get();
    }

    public StringProperty quantiteProperty() {
        return quantite;
    }
}

2. 修正JFXTreeTableView的控制器声明

现在可以用Element类作为泛型参数,正确声明树形表格:

import com.jfoenix.controls.JFXTreeTableColumn;
import com.jfoenix.controls.JFXTreeTableView;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;

@FXML private JFXTreeTableView<Element> TableViewAP;
@FXML private JFXTreeTableColumn<Element, String> clmTreeID, clmTreeElement, clmTreePrix, clmTreeQuantite;
private ObservableList<Element> treeData;

3. 修改数据填充方法适配树形表格

JFXTreeTableView需要用RecursiveTreeItem包装数据,即使你的数据是平级的(没有父子关系),也需要通过它来构建树形结构:

import com.jfoenix.controls.datamodels.treetable.RecursiveTreeItem;
import javafx.collections.FXCollections;
import javafx.scene.control.TreeItem;
import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;

public void fillTreeTableData() {
    try {
        treeData = FXCollections.observableArrayList();
        ResultSet rst = Tools.ConnexionJM.AllElement();
        while (rst.next()) {
            // 从ResultSet中取出数据,创建Element对象
            Element element = new Element(
                rst.getString(1),
                rst.getString(2),
                rst.getString(3),
                rst.getString(4)
            );
            treeData.add(element);
        }

        // 创建根节点,用RecursiveTreeItem包装数据
        TreeItem<Element> root = new RecursiveTreeItem<>(treeData, RecursiveTreeObject::getChildren);
        TableViewAP.setRoot(root);
        TableViewAP.setShowRoot(false); // 不需要显示根节点的话可以设置为false
    } catch (SQLException ex) {
        Logger.getLogger(FXMLDocumentController.class.getName()).log(Level.SEVERE, null, ex);
    }
}

4. 配置树形表格的列

JFXTreeTableColumn的配置和普通TableColumn类似,但需要绑定到Element类的Property上,代码更简洁:

public void configureTreeTableColumns() {
    // 绑定各列到Element的对应Property
    clmTreeID.setCellValueFactory(cellData -> cellData.getValue().getValue().idProperty());
    clmTreeElement.setCellValueFactory(cellData -> cellData.getValue().getValue().elementNameProperty());
    clmTreePrix.setCellValueFactory(cellData -> cellData.getValue().getValue().prixProperty());
    clmTreeQuantite.setCellValueFactory(cellData -> cellData.getValue().getValue().quantiteProperty());

    // 填充数据
    fillTreeTableData();
}

5. 初始化时调用配置方法

在控制器的initialize方法中调用列配置方法,确保界面加载时自动填充数据:

@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
    configureTreeTableColumns();
}

额外提示

如果之后需要实现真正的树形结构(比如有父子级的分类数据),只需要在Element类中添加ObservableList<Element> children属性,并实现getChildren()方法返回这个列表,RecursiveTreeItem会自动识别并构建树形结构。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 03:55:38