使用通用类型设置 TableColumns 值
Setting up TableColumns Value using Generic Types
我想用 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));
}
这是我的条目 class,它是 TableBrowserclass
中的一个内部 Class
/*
* 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 class,它将 WrapperType 作为内部 class
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();
}
}
}
提前感谢您的帮助:)
如评论中所述,您的第一个问题是没有使用 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 的变量是局部 effectively-final 变量而不是实例变量,因此每次都会使用正确的值创建 lambda。
最后一点建议 - 你确定你需要这么多的普遍性吗?我的意思是 - 通常最好创建一个 class 以使用适当的 getter 和 setter 直接表示您的数据库结构,然后您可以使用 PropertyValueFactory
.
我想用 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));
}
这是我的条目 class,它是 TableBrowserclass
中的一个内部 Class/*
* 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 class,它将 WrapperType 作为内部 class
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();
}
}
}
提前感谢您的帮助:)
如评论中所述,您的第一个问题是没有使用 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 的变量是局部 effectively-final 变量而不是实例变量,因此每次都会使用正确的值创建 lambda。
最后一点建议 - 你确定你需要这么多的普遍性吗?我的意思是 - 通常最好创建一个 class 以使用适当的 getter 和 setter 直接表示您的数据库结构,然后您可以使用 PropertyValueFactory
.