Thật không may, old issue vẫn không được sửa trong fx9 hoặc fx10. Vì vậy, xem lại các hacks trong bối cảnh của fx9.Đã có những thay đổi, tốt và xấu người:
- Skins di chuyển vào một gói phần mềm nào mà bây giờ cho phép phân lớp chúng mà không cần truy cập vào các lớp ẩn (tốt)
- di chuyển introduced a bug mà không cho phép cài đặt một tùy chỉnh VirtualFlow (cố định trong fx10)
- truy cập phản chiếu cho các thành viên ẩn sẽ được khấu trừ mạnh mẽ (đọc: không thể) đôi khi trong tương lai
trong khi đào, tôi nhận thấy bao giờ trục trặc nên nhẹ với hacks (lưu ý: tôi đã làm không chạy chúng với fx8, ese có thể có sự khác biệt do ở FX8 vs fx9!)
- các buộc trong-/tầm nhìn của placeholder/lưu lượng làm việc tốt, trừ khi khởi động với một bảng trống (placeholder được hiển thị) và mở rộng bàn trong khi rỗng (các Vùng "mới" trông trống)
- giả mạo mụcCount to not-empty cho phép các hàng biến mất khi nhấn phím điều hướng (có thể không phải là vấn đề lớn vì người dùng có xu hướng không điều hướng một bảng trống) - điều này chắc chắn được giới thiệu trong fx9 , hoạt động tốt trong fx8
Vì vậy, tôi quyết định đi với khả năng hiển thị mức độ nhẹ: lý do cho sự lờ mờ nhẹ ches là layoutChildren không bố trí dòng chảy nếu nó nghĩ rằng giữ chỗ có thể nhìn thấy. Đó là xử lý bằng cách bao gồm các dòng chảy trong bố trí nếu siêu không.
Da tùy chỉnh:
/**
* TableViewSkin that doesn't show the placeholder.
* The basic trick is keep the placeholder/flow in-/visible at all
* times (similar to https://stackoverflow.com/a/27543830/203657).
* <p>
*
* Updated for fx9 plus ensure to update the layout of the flow as
* needed.
*
* @author Jeanette Winzenburg, Berlin
*/
public class NoPlaceHolderTableViewSkin<T> extends TableViewSkin<T>{
private VirtualFlow<?> flowAlias;
private TableHeaderRow headerAlias;
private Parent placeholderRegionAlias;
private ChangeListener<Boolean> visibleListener = (src, ov, nv) -> visibleChanged(nv);
private ListChangeListener<Node> childrenListener = c -> childrenChanged(c);
/**
* Instantiates the skin.
* @param table the table to skin.
*/
public NoPlaceHolderTableViewSkin(TableView<T> table) {
super(table);
flowAlias = (VirtualFlow<?>) table.lookup(".virtual-flow");
headerAlias = (TableHeaderRow) table.lookup(".column-header-background");
// startet with a not-empty list, placeholder not yet instantiatet
// so add alistener to the children until it will be added
if (!installPlaceholderRegion(getChildren())) {
installChildrenListener();
}
}
/**
* Searches the given list for a Parent with style class "placeholder" and
* wires its visibility handling if found.
* @param addedSubList
* @return true if placeholder found and installed, false otherwise.
*/
protected boolean installPlaceholderRegion(
List<? extends Node> addedSubList) {
if (placeholderRegionAlias != null)
throw new IllegalStateException("placeholder must not be installed more than once");
List<Node> parents = addedSubList.stream()
.filter(e -> e.getStyleClass().contains("placeholder"))
.collect(Collectors.toList());
if (!parents.isEmpty()) {
placeholderRegionAlias = (Parent) parents.get(0);
placeholderRegionAlias.visibleProperty().addListener(visibleListener);
visibleChanged(true);
return true;
}
return false;
}
protected void visibleChanged(Boolean nv) {
if (nv) {
flowAlias.setVisible(true);
placeholderRegionAlias.setVisible(false);
}
}
/**
* Layout of flow unconditionally.
*
*/
protected void layoutFlow(double x, double y, double width,
double height) {
// super didn't layout the flow if empty- do it now
final double baselineOffset = getSkinnable().getLayoutBounds().getHeight()/2;
double headerHeight = headerAlias.getHeight();
y += headerHeight;
double flowHeight = Math.floor(height - headerHeight);
layoutInArea(flowAlias, x, y,
width, flowHeight,
baselineOffset, HPos.CENTER, VPos.CENTER);
}
/**
* Returns a boolean indicating whether the flow should be layout.
* This implementation returns true if table is empty.
* @return
*/
protected boolean shouldLayoutFlow() {
return getItemCount() == 0;
}
/**
* {@inheritDoc} <p>
*
* Overridden to layout the flow always.
*/
@Override
protected void layoutChildren(double x, double y, double width,
double height) {
super.layoutChildren(x, y, width, height);
if (shouldLayoutFlow()) {
layoutFlow(x, y, width, height);
}
}
/**
* Listener callback from children modifications.
* Meant to find the placeholder when it is added.
* This implementation passes all added sublists to
* hasPlaceHolderRegion for search and install the
* placeholder. Removes itself as listener if installed.
*
* @param c the change
*/
protected void childrenChanged(Change<? extends Node> c) {
while (c.next()) {
if (c.wasAdded()) {
if (installPlaceholderRegion(c.getAddedSubList())) {
uninstallChildrenListener();
return;
}
}
}
}
/**
* Installs a ListChangeListener on the children which calls
* childrenChanged on receiving change notification.
*
*/
protected void installChildrenListener() {
getChildren().addListener(childrenListener);
}
/**
* Uninstalls a ListChangeListener on the children:
*/
protected void uninstallChildrenListener() {
getChildren().removeListener(childrenListener);
}
}
Cách sử dụng Ví dụ:
public class EmptyPlaceholdersInSkin extends Application {
private Parent createContent() {
// initially populated
//TableView<Person> table = new TableView<>(Person.persons()) {
// initially empty
TableView<Person> table = new TableView<>() {
@Override
protected Skin<?> createDefaultSkin() {
return new NoPlaceHolderTableViewSkin<>(this);
}
};
TableColumn<Person, String> first = new TableColumn<>("First Name");
first.setCellValueFactory(new PropertyValueFactory<>("firstName"));
table.getColumns().addAll(first);
Button clear = new Button("clear");
clear.setOnAction(e -> table.getItems().clear());
clear.disableProperty().bind(Bindings.isEmpty(table.getItems()));
Button fill = new Button("populate");
fill.setOnAction(e -> table.getItems().setAll(Person.persons()));
fill.disableProperty().bind(Bindings.isNotEmpty(table.getItems()));
BorderPane pane = new BorderPane(table);
pane.setBottom(new HBox(10, clear, fill));
return pane;
}
@Override
public void start(Stage stage) throws Exception {
stage.setScene(new Scene(createContent()));
stage.show();
}
public static void main(String[] args) {
Application.launch(args);
}
@SuppressWarnings("unused")
private static final Logger LOG = Logger
.getLogger(EmptyPlaceholdersInSkin.class.getName());
}
+1 Tôi đang tìm kiếm một cách để làm điều này quá. Trong mã hóa nó ra, bạn có thể tự đặt placeHolder, tôi đã thường đặt nó vào một hình ảnh: 'table.setPlaceholder (new ImageView (new Image (new FileInputStream (" someImage.png "))));' Nhưng tôi ' d muốn có nó chỉ hiển thị hàng trống ... cũng là một cách để làm điều đó trong FXML sẽ là tiện dụng – SnakeDoc
Yêu cầu tính năng trong trình theo dõi vấn đề JavaFX: [RT-31086 Không buộc tôi sử dụng 'trình giữ chỗ' mặc định trong một trống TableView] (https://javafx-jira.kenai.com/browse/RT-31086). – jewelsea
tọa độ lỗi trong đại diện openjdk: https://bugs.openjdk.java.net/browse/JDK-8090949 - vẫn chưa được giải quyết trong fx9/10 – kleopatra