afaik javafx中的TableView有2个列调整大小策略:CONSTRAINED_RESIZE_POLICY和UNCONSTRAINED_RESIZE_POLICY,但是我想要调整列的大小以适应他们的单元格内容我认为这是其他平台中的一个简单问题(如C#中的datagridview)但无法解析
3年后我再次回到这个问题,一些建议正在计算每个单元格中数据文本的大小(根据字体大小,字体系列,填充......这很复杂)
但我意识到当我点击表格标题上的分隔符时,它的大小适合我想要的内容。所以我深入研究JavaFX源代码我终于在TableViewSkin中找到了resizeColumnToFitContent方法,但它是受保护的方法,我们可以通过反射来解决:
import com.sun.javafx.scene.control.skin.TableViewSkin;
import javafx.scene.control.Skin;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class GUIUtils {
private static Method columnToFitMethod;
static {
try {
columnToFitMethod = TableViewSkin.class.getDeclaredMethod("resizeColumnToFitContent", TableColumn.class, int.class);
columnToFitMethod.setAccessible(true);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
public static void autoFitTable(TableView tableView) {
tableView.getItems().addListener(new ListChangeListener<Object>() {
@Override
public void onChanged(Change<?> c) {
for (Object column : tableView.getColumns()) {
try {
columnToFitMethod.invoke(tableView.getSkin(), column, -1);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
}
}
});
}
}
注意我们调用“tableView.getItems()”所以我们必须在setItems()之后调用这个函数
public static void autoFillColumn(TableView<?> table, int col) {
double width = 0;
for (int i = 0; i < table.getColumns().size(); i++) {
if (i != col) {
width += table.getColumns().get(i).getWidth();
}
}
table.getColumns().get(col).setPrefWidth(table.getWidth() - width);
}
myTable.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
for(TableColumn column: myTable.getColumns())
{
column.setMinWidth(200);
}
在测试了以前的解决方案后,我终于找到了一个适合我的解决方所以这是我的(在将数据插入表后调用方法):
public static void autoResizeColumns( TableView<?> table )
{
//Set the right policy
table.setColumnResizePolicy( TableView.UNCONSTRAINED_RESIZE_POLICY);
table.getColumns().stream().forEach( (column) ->
{
//Minimal width = columnheader
Text t = new Text( column.getText() );
double max = t.getLayoutBounds().getWidth();
for ( int i = 0; i < table.getItems().size(); i++ )
{
//cell must not be empty
if ( column.getCellData( i ) != null )
{
t = new Text( column.getCellData( i ).toString() );
double calcwidth = t.getLayoutBounds().getWidth();
//remember new max-width
if ( calcwidth > max )
{
max = calcwidth;
}
}
}
//set the new max-widht with some extra space
column.setPrefWidth( max + 10.0d );
} );
}
我认为只要重写一个返回true的回调函数将解决你的问题,它将禁用列的重新调整大小,并且所有列都将重新调整大小以适合其单元格的内容。
例:
TableView<String[]> table = new TableView<>();
table.setColumnResizePolicy(new Callback<TableView.ResizeFeatures, Boolean>() {
@Override
public Boolean call(ResizeFeatures p) {
return true;
}
});
或者简而言之:
// automatically adjust width of columns depending on their content
configAttributeTreeTable.setColumnResizePolicy((param) -> true );
我在这个问题上使用了其他解决方案,它的效果非常好。但是,这方面的缺点是TableView的宽度大于TableColumns的所需宽度。我已经创建了一个hack来解决这个问题,它运行正常:
orderOverview.setColumnResizePolicy((param) -> true );
Platform.runLater(() -> FXUtils.customResize(orderOverview));
其中FXUtils.customResize()的创建方式如下:
public static void customResize(TableView<?> view) {
AtomicDouble width = new AtomicDouble();
view.getColumns().forEach(col -> {
width.addAndGet(col.getWidth());
});
double tableWidth = view.getWidth();
if (tableWidth > width.get()) {
TableColumn<?, ?> col = view.getColumns().get(view.getColumns().size()-1);
col.setPrefWidth(col.getWidth()+(tableWidth-width.get()));
}
}
我希望这对其他人也有帮助!
如果你想只有一列填充表的剩余宽度,我找到了一个非常直接的解决方案,这个解决方案很简短,不需要上面描述的hacky反射解决方案:
DoubleBinding usedWidth = columnA.widthProperty().add(columnB.widthProperty()).add(columnC.widthProperty());
fillingColumn.prefWidthProperty().bind(tableView.widthProperty().subtract(usedWidth));
此代码以与表宽度相关的比例自动调整所有列宽,
当表宽度低于x 时,它可以将第一列宽度固定为给定值
// To generalize the columns width proportions in relation to the table width, // you do not need to put pixel related values, you can use small float numbers if you wish, // because it's the relative proportion of each columns width what matters here: final float[] widths = { 1.2f, 2f, 0.8f };// define the relational width of each column // whether the first column should be fixed final boolean fixFirstColumm = true; // fix the first column width when table width is lower than: final float fixOnTableWidth = 360; //pixels // calulates sum of widths float sum = 0; for (double i : widths) { sum += i; } // calculates the fraction of the first column proportion in relation to the sum of all column proportions float firstColumnProportion = widths[0] / sum; // calculate the fitting fix width for the first column, you can change it by your needs, but it jumps to this width final float firstColumnFixSize = fixOnTableWidth * firstColumnProportion; // set the width to the columns for (int i = 0; i < widths.length; i++) { table.getColumns().get(i).prefWidthProperty().bind(table.widthProperty().multiply((widths[i] / sum))); // ---------The exact width-------------^-------------^ if (fixFirstColumm) if (i == 0) { table.widthProperty().addListener(new ChangeListener<Number>() { @Override public void changed(ObservableValue<? extends Number> arg0, Number oldTableWidth, Number newTableWidth) { if (newTableWidth.intValue() <= fixOnTableWidth) { // before you can set new value to column width property, need to unbind the autoresize binding table.getColumns().get(0).prefWidthProperty().unbind(); table.getColumns().get(0).prefWidthProperty().setValue(firstColumnFixSize); } else if (!table.getColumns().get(0).prefWidthProperty().isBound()) { // than readd the autoresize binding if condition table.width > x table.getColumns().get(0).prefWidthProperty() .bind(table.widthProperty().multiply(firstColumnProportion)); } } }); } }
建议将代码放在一个单独的TableAutoresizeModel类中,在那里你可以处理进一步的计算,例如在隐藏列上添加监听器...
<TableView fx:id="datalist" layoutX="30.0" layoutY="65.0" prefHeight="400.0" AnchorPane.bottomAnchor="100.0" AnchorPane.leftAnchor="30.0" AnchorPane.rightAnchor="30.0" AnchorPane.topAnchor="100.0">
<columns>
<TableColumn fx:id="number" minWidth="-1.0" prefWidth="-1.0" style="width: auto;" text="number" />
<TableColumn fx:id="id" minWidth="-1.0" prefWidth="-1.0" text="id" />
<TableColumn fx:id="name" minWidth="-1.0" prefWidth="-1.0" text="name" />
<TableColumn fx:id="action" minWidth="-1.0" prefWidth="-1.0" text="todo" />
</columns>
**<columnResizePolicy>
<TableView fx:constant="CONSTRAINED_RESIZE_POLICY" />
</columnResizePolicy>**
</TableView>
经过长时间的研究最佳解决方案是......
tblPlan.setColumnResizePolicy((param) -> true );
Platform.runLater(() -> customResize(tblPlan));
“自定义调整大小”
public void customResize(TableView<?> view) {
AtomicLong width = new AtomicLong();
view.getColumns().forEach(col -> {
width.addAndGet((long) col.getWidth());
});
double tableWidth = view.getWidth();
if (tableWidth > width.get()) {
view.getColumns().forEach(col -> {
col.setPrefWidth(col.getWidth()+((tableWidth-width.get())/view.getColumns().size()));
});
}
}