【问题标题】:Setting up TableColumns Value using Generic Types使用泛型类型设置 TableColumns 值
【发布时间】:2015-12-25 16:04:40
【问题描述】:

我想用 JavaFX 为 MYSQl 数据库编写一个 TableBrowser。

我的第一个问题是:我不知道我从数据库中返回了哪些类型。

所以我决定用 Wrapper-class 包装这些类型。

为了在 GUI 上显示这些值,我使用了 TableColumns setCellValueFactory 方法,它 需要一个实现 ObservableValue 的值。

所以我尝试实现 ObservableValue 接口。

但是当我运行程序时它没有显示正确的值。

TableBrowser after connecting to the Database

有谁知道我在哪里做错了或知道更推荐的实施方式吗?

这是来自 TableBrowser 的部分代码

/*
 * this variable is used to iterate over the tableview's columns.
 * It is a class variable, because it is not possible (for some reasons)
 * to use a local variable while working with it in the context of Lambda-expressions
 */
int t = 0;  

// those two variables are defined in the class Body
private final TableView<Entry> tableview = new TableView<>();  
private final ObservableList<Entry> columndata = FXCollections.observableArrayList();    

// the following Code is inside the Button's Actionlistener

for(int i = 1; i <= maxcol; i++) // adds a new TableColum for every colum in the DB
{
   tableview.getColumns().add(new TableColumn<Entry, String>rsmd.getColumnName(i)));
}

// iterates over the ResultSet
while(rs.next())  
{
    // this is the dataset i put in my TableView
    Entry row = new Entry(maxcol); 

    // for each Column i add the columnvalue to the current dataset
    for(int i = 1; i <= maxcol; i++) 
    {
       int type = rsmd.getColumnType(i);
       Object value = rs.getObject(i);
       row.setCellValue(i-1, type, value);
    }       
    // adds a new dataset to the ObservableList<Entry>
    columndata.add(row);
}
// puts all datasets in the TableView
tableview.setItems(columndata);

 // iterates over all Columns
for(t = 0; t < tableview.getColumns().size(); t++)
{
    // should set the CellValueFactory for each Column so it shows the data

    /*
     * I apologise if there a horrible mistake.
     * I never worked with Lamda before and just copied it form an example page :)
     */
    tableview.getColumns().get(t).setCellValueFactory(celldata -> celldata.getValue().getCellValue(t-1));
}

这是我的Entry类,是TableBrowserclass中的一个内部类

/* 
 * should represent a Dataset. 
 * Has an array, which holdes every columnvalue as a WrapperType
 */
private class Entry
{
    WrapperType<?>[] columns;

    private Entry(int columncount) 
    {
        columns = new WrapperType[columncount];
    }

    private WrapperType<?> getCellValue(int col)
    {
        return columns[col];
    }

    private void setCellValue(int col, int type, Object value)
    {
        columns[col] = MySQLTypeWrapper.getInstance().wrapType(type, value);
    }
}

这里是 MySQLTypeWrapper 类,它将 WrapperType 作为内部类保存

public class MySQLTypeWrapper 
{
    public WrapperType<?> wrapType(int type, Object Value)
    {
       Class<?> typeclass = toClass(type);
       return new WrapperType<>(typeclass.cast(Value));
    }

   /*
    *  returns the appropriate class def for every database type
    *  Expl: VARCHAR returns String.class
    */
    private static Class<?> toClass(int type) {...}

    /*
     * I copied the content of the of the overridden Methods from StringPropertyBase
     * as i have clue how to implement ObservableValue
     */
    class WrapperType<T> implements ObservableValue<WrapperType<T>>
    {
        private T value;
        private ExpressionHelper<WrapperType<T>> helper = null;

        private WrapperType(T value)
        {
            this.value = value;
        }

        @Override
        public void addListener(InvalidationListener listener) 
        {
           helper = ExpressionHelper.addListener(helper, this, listener);
        }

        @Override
        public void removeListener(InvalidationListener listener) 
        {
           helper = ExpressionHelper.removeListener(helper, listener);
        }

        @Override
        public void addListener(ChangeListener<? super WrapperType<T>> listener) 
        {
            helper = ExpressionHelper.addListener(helper, this, listener);
        }

        @Override
        public void removeListener(ChangeListener<? super WrapperType<T>> listener) 
        {
           helper = ExpressionHelper.removeListener(helper, listener);
        }

        @Override
        public WrapperType<T> getValue() 
        {
           return this;
        }

        public String toString()
        {
           return value.toString();
        }
    }
}

提前感谢您的帮助:)

【问题讨论】:

  • 向表中添加项目由table.getItems().addAll(...)table.setItems(...)(如果您已经有ObservableList)完成。 setUserData 用于存储您使用的对象,以供以后检索,而TableView 从不实际使用它。
  • 感谢您的回答。我在我的代码中更改了它,现在表格显示了一些东西。但是我觉得这部分还是有问题的:for(t = 0; t &lt; tableview.getColumns().size(); t++) { tableview.getColumns().get(t).setCellValueFactory(celldata -&gt; celldata.getValue().getCellValue(t)); } 因为现在表格是这样的:fs5.directupload.net/images/151225/ndxdx3xh.jpg
  • 现在我相信您的问题出在 lambda 函数中。看到这个 - stackoverflow.com/questions/29029849/… 基本上,发生的事情是 lambda 获得了对实例变量 t 的引用,但是在 lambda 执行时,这个值是循环到达的最大值。您可以使用辅助生成器方法来克服这个问题。

标签: javafx tablecolumn


【解决方案1】:

正如 cmets 中所述,您的第一个问题是没有使用 TableView 的 Items 属性。

对于第二部分 - 一种解决方案是创建一个辅助方法

private <T> Callback<TableColumn.CellDataFeatures<Entry,T>,ObservableValue<T>> createCellFactory(int columnIndex) {
    return celldata -> celldata.getValue().getCellValue(columnIndex);
}

然后将循环改为

// Now t can be a local variable, as it is not directly passed to the lambda.
for(int t = 0; t < tableview.getColumns().size(); t++)
{
    // should set the CellValueFactory for each Column so it shows the data

    tableview.getColumns().get(t).setCellValueFactory(createCellFactory(t));
}

请注意,这次传递给 lambda 的变量是一个局部有效最终变量,而不是实例变量,因此每次都使用正确的值创建 lambda。

最后一句建议 - 您确定需要这么多的概括性吗?我的意思是 - 通常最好创建一个类来使用适当的 getter 和 setter 直接表示您的数据库结构,然后您可以使用PropertyValueFactory

【讨论】:

  • 非常感谢!我只需要添加一个演员 return celldata -&gt; (ObservableValue&lt;T&gt;) (celldata.getValue().getCellValue(columnIndex)); 因为否则它会说: Type mismatch: cannot convert from ObservableValue to ObservableValue 但现在一切正常。我想我必须告诉自己一些关于 Lamda 的信息:)
猜你喜欢
  • 2021-01-21
  • 2021-12-06
  • 2020-08-06
  • 2013-04-07
  • 1970-01-01
  • 1970-01-01
  • 2021-09-21
  • 2011-02-28
  • 1970-01-01
相关资源
最近更新 更多