使用通用类型

时间:2015-12-25 16:04:41

标签: javafx tablecolumn

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

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

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

要在GUI上显示这些值,我使用了TableColumns setCellValueFactory-method, 需要一个实现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();
        }
    }
}

提前感谢您的帮助:)

1 个答案:

答案 0 :(得分:0)

正如评论中所提到的,您的第一个问题是没有使用TableView的项目属性。

对于第二部分 - 一种解决方案是按照

的方式创建一个辅助方法
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