在下面的简化代码中,我对第一行进行了硬编码,以跨越TableView的所有三列。
除了选择之外,它似乎运作良好。如果我选择了第一行并按向右键,则选择将进入宽度为零的单元格,因此似乎消失了。同样,如果选择第二行的中间单元格并按下向上,则选择将转到相同的隐藏单元格。
有没有告诉选择模型应该忽略某些单元格?或者我是否更有可能从头开始编写选择模型?
import com.sun.javafx.scene.control.skin.TableRowSkin;
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class TableSkinTest extends Application {
@Override
public void start(Stage stage) throws Exception {
BorderPane pane = new BorderPane();
Scene scene = new Scene(pane, 500, 500);
stage.setScene(scene);
ObservableList<Person> data = FXCollections.observableArrayList(
new Person("This should span columns because it is long", "", ""),
new Person("Isabella", "Johnson", "079155882"),
new Person("Ethan", "Williams", "079155883"),
new Person("Emma", "Jones", "079155884"),
new Person("Michael", "Brown", "079155885")
);
TableView<Person> table = new TableView<>();
table.getSelectionModel().setCellSelectionEnabled(true);
table.setRowFactory(param -> new TableRow<Person>() {
@Override
protected Skin<?> createDefaultSkin() {
return new TableRowSkin<TableSkinTest.Person>(this) {
@Override
protected void layoutChildren(double x, double y, double w, double h) {
checkState();
if (cellsMap.isEmpty()) return;
ObservableList<? extends TableColumnBase> visibleLeafColumns = getVisibleLeafColumns();
if (visibleLeafColumns.isEmpty()) {
super.layoutChildren(x, y, w, h);
return;
}
TableRow<TableSkinTest.Person> control = getSkinnable();
// layout the individual column cells
double width;
double height;
final double verticalPadding = snappedTopInset() + snappedBottomInset();
final double horizontalPadding = snappedLeftInset() + snappedRightInset();
final double controlHeight = control.getHeight();
int index = control.getIndex();
for (int column = 0, max = cells.size(); column < max; column++) {
TableCell<TableSkinTest.Person, ?> tableCell = cells.get(column);
width = snapSize(tableCell.prefWidth(-1)) - snapSize(horizontalPadding);
height = Math.max(controlHeight, tableCell.prefHeight(-1));
height = snapSize(height) - snapSize(verticalPadding);
if (index == 0 && column > 0) {
width = 0; // Hard code for simplification
} else if (index == 0) {
double width1 = snapSize(cells.get(1).getTableColumn().getWidth());
double width2 = snapSize(cells.get(2).getTableColumn().getWidth());
width += width1;
width += width2;
}
tableCell.resize(width, height);
tableCell.relocate(x, snappedTopInset());
x += width;
}
}
};
}
});
TableColumn<Person,String> firstNameCol = new TableColumn<>("First Name");
TableColumn<Person,String> lastNameCol = new TableColumn<>("Last Name");
TableColumn<Person,String> numberCol = new TableColumn<>("Number");
firstNameCol.setCellValueFactory(new PropertyValueFactory<>("firstName"));
lastNameCol.setCellValueFactory(new PropertyValueFactory<>("lastName"));
numberCol.setCellValueFactory(new PropertyValueFactory<>("number"));
table.getColumns().addAll(firstNameCol, lastNameCol, numberCol);
table.getColumns().forEach(col -> col.setPrefWidth(100));
table.setItems(data);
pane.setCenter(table);
stage.show();
}
public static class Person {
private final SimpleStringProperty firstName;
private final SimpleStringProperty lastName;
private final SimpleStringProperty number;
private Person(String fName, String lName, String nNumber) {
this.firstName = new SimpleStringProperty(fName);
this.lastName = new SimpleStringProperty(lName);
this.number = new SimpleStringProperty(nNumber);
}
public String getFirstName() {return firstName.get();}
public void setFirstName(String fName) {firstName.set(fName);}
public String getLastName() {return lastName.get();}
public void setLastName(String fName) {lastName.set(fName);}
public String getNumber() {return number.get();}
public void setNumber(String number) {this.number.set(number);}
}
public static void main(String[] args) {
Application.launch(args);
}
}
答案 0 :(得分:2)
无论如何告诉选择模型应该忽略某些单元格吗?
不,selectionModels没有un / selectable概念。
或者我是否更有可能从头开始编写选择模型?
严格地说,自定义TableViewSelectionModel无法从头开始实现 - 它扩展了MultipleSelectionModelBase,它是包私有的(如TableViewArrayListSelectionModel,TableView中的静态类)。最接近&#34;刮擦&#34;将基本上c&amp; p TableViewArrayListSelectionModel并根据需要实现忽略单元格。需要对隐藏的超级方法/字段进行肮脏,反思的访问......
IMO,没有很好的解决方案来满足您的需求(没有从头开始编写TableView)。如果选择了任何跨越的单元格,可能的脏(与皮肤布置宽度为0的跨越单元格的类似级别)可能会保持选定生成单元格。仍然有一个轻微的可用性故障,因为左/右没有明显的变化 - 但至少选择不会消失。
粗略版本(PlainTableCell是TableColumn中的c&amp; p默认值):
public static class SpanTableCell<S, T> extends PlainTableCell<S, T> {
private ListChangeListener<TablePosition> selectedListener = c -> {
while (c.next()) {
if (c.wasAdded() || c.wasRemoved()) {
updateSelection();
}
}
};
private WeakListChangeListener weakSelectedListener
= new WeakListChangeListener<>(selectedListener);
private ChangeListener<TableView> tableViewListener = (t, old, value) -> {
if (old != null && old.getSelectionModel() != null) {
old.getSelectionModel().getSelectedIndices().removeListener(weakSelectedListener);
}
if (value != null && value.getSelectionModel() != null) {
value.getSelectionModel().getSelectedIndices().addListener(weakSelectedListener);
}
updateSelection();
};
private WeakChangeListener weakTableViewListener = new WeakChangeListener(tableViewListener);
public SpanTableCell() {
tableViewProperty().addListener(weakTableViewListener);
}
private void updateSelection() {
// super will handle (hard-coded not span condition for simplicity)
if (!isInCellSelectionMode() || getIndex() != 0) return;
// TableViewSelectionModel doesn't support row selection in
// cellSelectionMode
TableViewSelectionModel<S> selectionModel = getTableView()
.getSelectionModel();
boolean rowSelected = false;
ObservableList<TableColumn<S, ?>> columns = getTableView()
.getVisibleLeafColumns();
for (TableColumn<S, ?> tableColumn : columns) {
rowSelected = rowSelected
|| selectionModel.isSelected(getIndex(), tableColumn);
}
boolean finalSelected = rowSelected;
Platform.runLater(() -> {
// need to defer, super gets into the way
updateSelected(finalSelected);
});
}
private boolean isInCellSelectionMode() {
TableView<S> tableView = getTableView();
if (tableView == null) return false;
TableSelectionModel<S> sm = tableView.getSelectionModel();
return sm != null && sm.isCellSelectionEnabled();
}
}