I have this super class extending TableView
, that every table I want to make is supposed to inherit from.
This line of code needs to be executed for every class that inherits from the superclass and needs a ContextMenu
:
// Sets the context menu for each specific row. This way no
// context menu will appear if we click on a row that is
// empty.
setRowFactory(r -> {
TableRow<ObservableList<String>> row = new TableRow<ObservableList<String>>() {
public void updateItem(ObservableList<String> item, boolean empty) {
super.updateItem(item, empty);
if (isEmpty()) {
setContextMenu(null);
} else {
setContextMenu(contextMenu);
}
}
};
});
The problem is that the ContextMenu
needs to be instantiated before this code can be executed, hence I can't put in the constructor of the super class.
How do I ensure that every class inheriting from the super class does the following steps in this order if the table needs a ContextMenu
(not always the case):
ContextMenu
with MenuItem
instances (I guess the MenuItem
instances could be instantiated and added later on, theoretically).I've had a few iterations on solving this issue, and still failed to come up with a satisfying solution. Maybe I'm missing something obvious.
Edit: Would be perfect if you could somehow disable the user from using the originalsetContextMenu
method of TableView
, to ensure that `ContextMenu is being added in the correct way. But I guess this isn't possible.
It looks like you are simply trying to suppress showing the context menu on empty rows in the table. The simpler way to do this is
public class MyTableView<T> extends TableView<T> {
public MyTableView() {
setRowFactory(tv -> {
TableRow<T> row = new TableRow<>();
row.setOnContextMenuRequested(e -> {
if (row.isEmpty()) {
e.consume();
}
}
return row ;
});
}
// ...
}
To answer the question you asked (ensuring you only (and always) call setRowFactory
after a call to setContextMenu
):
You can either do
public class MyTableView<T> extends TableView<T> {
private final ContextMenu contextMenu ;
public MyTableView(ContextMenu contextMenu) {
this.contextMenu = contextMenu ;
setRowFactory(r -> {
TableRow<ObservableList<String>> row = new TableRow<ObservableList<String>>() {
public void updateItem(ObservableList<String> item, boolean empty) {
super.updateItem(item, empty);
if (isEmpty()) {
setContextMenu(null);
} else {
setContextMenu(contextMenu);
}
}
};
});
}
// ...
}
or
public class MyTableView<T> extends TableView<T> {
private ContextMenu rowContextMenu ;
public ContextMenu getRowContextMenu() {
return rowContextMenu ;
}
public void setRowContextMenu(ContextMenu contextMenu) {
this.rowContextMenu = contextMenu ;
setRowFactory(r -> new TableRow<ObservableList<String>>() {
public void updateItem(ObservableList<String> item, boolean empty) {
super.updateItem(item, empty);
if (isEmpty()) {
setContextMenu(null);
} else {
setContextMenu(rowContextMenu);
}
}
});
}
// ...
}
or even
public class MyTableView<T> extends TableView<T> {
public MyTableView() {
contextMenuProperty().addListener((obs, oldContextMenu, newContextMenu) -> {
if (newContextMenu == null) {
setRowFactory(r -> new TableRow<>());
} else
setRowFactory(r -> new TableRow<ObservableList<String>>() {
public void updateItem(ObservableList<String> item, boolean empty) {
super.updateItem(item, empty);
if (isEmpty()) {
setContextMenu(null);
} else {
setContextMenu(newContextMenu);
}
}
});
}
});
}
// ...
}