当我在JavaFX TreeTableView上按下鼠标右键时,它会选择我点击的节点。我可以理解为什么在大多数情况下这可能是可取的,但并非在所有情况下都如此。
我正在开发一个应用程序,其中我在树表中有多个列,其中一列使用画布小部件来显示自定义图形(波形)。图形列需要能够通过鼠标与各种原因(设置标记,缩放等)进行交互。因此,我不希望鼠标按钮选择表中的行(或与表交互)。
我可以使用第一个鼠标按钮过滤掉点击,为addEventFilter()
添加MouseEvent.MOUSE_CLICKED
event.consume()
。然后我可以按照我想要的方式处理鼠标。
然而,当我右键单击单元格时,表格中的选择将更改为该行。我已经尝试在单元格,表格,行,列上放置事件过滤器,似乎没有任何工作来过滤右键单击选择更改。请注意,canvas小部件设置为鼠标透明。
以下是使用标准地址簿示例的示例,但我将电子邮件列替换为画布窗口小部件。
package sample;
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.stage.Stage;
import javafx.util.Callback;
public class Main extends Application {
private TableView<Person> table = new TableView<Person>();
private ContextMenu menu = new ContextMenu();
private final ObservableList<Person> data =
FXCollections.observableArrayList(
new Person("Jacob", "Smith", "jacob.smith@example.com"),
new Person("Isabella", "Johnson", "isabella.johnson@example.com"),
new Person("Ethan", "Williams", "ethan.williams@example.com"),
new Person("Emma", "Jones", "emma.jones@example.com"),
new Person("Michael", "Brown", "michael.brown@example.com")
);
class MyTableCell extends TableCell<Person, String> {
public MyTableCell(ContextMenu menu) {
super();
setContextMenu(menu);
}
@Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
setText(item);
setGraphic(null);
}
}
class MySpecialCell extends MyTableCell {
Canvas canvas = new Canvas(200.0, 12.0);
public MySpecialCell() {
super(null);
canvas.setMouseTransparent(true);
addEventFilter(MouseEvent.ANY, e -> e.consume());
}
@Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
setText(null);
if (! empty) {
canvas.getGraphicsContext2D().strokeText(item, 5.0, 10.0);
setGraphic(canvas);
} else {
setGraphic(null);
}
}
}
@Override
public void start(Stage stage) throws Exception{
Scene scene = new Scene(new Group());
stage.setTitle("Table View Sample");
stage.setWidth(450);
stage.setHeight(500);
final Label label = new Label("Address Book");
label.setFont(new Font("Arial", 20));
table.setEditable(true);
table.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
menu.getItems().add(new MenuItem("Hello World"));
Callback cellFactory = param -> new MyTableCell(menu);
TableColumn firstNameCol = new TableColumn("First Name");
firstNameCol.setMinWidth(100);
firstNameCol.setCellValueFactory(
new PropertyValueFactory<Person, String>("firstName"));
firstNameCol.setCellFactory(cellFactory);
TableColumn lastNameCol = new TableColumn("Last Name");
lastNameCol.setMinWidth(100);
lastNameCol.setCellValueFactory(
new PropertyValueFactory<Person, String>("lastName"));
lastNameCol.setCellFactory(cellFactory);
TableColumn emailCol = new TableColumn("Email");
emailCol.setMinWidth(200);
emailCol.setCellValueFactory(
new PropertyValueFactory<Person, String>("email"));
emailCol.setCellFactory(param -> new MySpecialCell());
table.setItems(data);
table.getColumns().addAll(firstNameCol, lastNameCol, emailCol);
final VBox vbox = new VBox();
vbox.setSpacing(5);
vbox.setPadding(new Insets(10, 0, 0, 10));
vbox.getChildren().addAll(label, table);
((Group) scene.getRoot()).getChildren().addAll(vbox);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
public static class Person {
private final SimpleStringProperty firstName;
private final SimpleStringProperty lastName;
private final SimpleStringProperty email;
private Person(String fName, String lName, String email) {
this.firstName = new SimpleStringProperty(fName);
this.lastName = new SimpleStringProperty(lName);
this.email = new SimpleStringProperty(email);
}
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 getEmail() {
return email.get();
}
public void setEmail(String fName) {
email.set(fName);
}
}
}
这是使用Java 8u20。在此示例中,MyTableCell
类用于前两列中的单元格。它为这些列添加了一个上下文菜单。 MySpecialCell
类用于最后一列,它将画布放在表中,其中包含电子邮件文本。它也会过度使用并过滤ANY
鼠标事件。
如果您运行此选项,您将看到如果在前两列中使用鼠标按钮1,则可以更改表格中的选择。第三列中的鼠标按钮1不会更改选择。但是,鼠标按钮2(鼠标右键) DOES 会更改第三列中的选择。
我希望它不会改变选择。当有人在列中使用鼠标右键时,有人可以给我一个关于如何防止选择更改的提示吗?
注意:我已尝试使用画布处理鼠标输入(实际上没有使鼠标透明并使其过滤所有鼠标事件),并且表格仍然会在右键单击时更改选择。出于各种原因(数据是这样的,画布实际上是一堆画布小部件的事实,难以确定鼠标在表格中与哪些节点进行交互等)在我的实际应用程序中我希望单元格能够处理鼠标输入。
谢谢!
答案 0 :(得分:1)
重复我的评论:我认为行为可能是一个错误,而不是一个功能 - 我希望消耗任何mouseEvent会阻止右(辅助)按钮与左(主)按钮正常操作相同。 / p>
是evaluated as a feature:缺少的部分是除了mouseEvents之外还要使用contextMenuEvents,比如
public MySpecialCell() {
super(null);
canvas.setMouseTransparent(true);
addEventFilter(MouseEvent.ANY, e -> e.consume());
// move Jonathan's code from table to cell level:
// need to consume contextMenuEvents as well
addEventFilter(ContextMenuEvent.ANY, e -> e.consume());
}
回到不同意评价:
如果需要特殊列上的键盘触发contextMenu,可能仍然需要下面的黑客攻击,但是没有深入挖掘。
无论如何,快速解决方法是通过自定义实现替换默认行为。合作者
类似的东西(注意:工作时,没有经过适当的测试):
class MySpecialCellBehavior extends TableCellBehavior {
public MySpecialCellBehavior(TableCell control) {
super(control);
}
@Override
protected void doSelect(double x, double y, MouseButton button,
int clickCount, boolean shiftDown, boolean shortcutDown) {
// do nothing on secondary button
if (button == MouseButton.SECONDARY) return;
super.doSelect(x, y, button, clickCount, shiftDown, shortcutDown);
}
}
class MySpecialCellSkin extends TableCellSkinBase {
private final TableColumn tableColumn;
public MySpecialCellSkin(TableCell tableCell) {
super(tableCell, new MySpecialCellBehavior(tableCell));
// doesn't make a difference
//consumeMouseEvents(true);
this.tableColumn = tableCell.getTableColumn();
super.init(tableCell);
}
@Override protected BooleanProperty columnVisibleProperty() {
return tableColumn.visibleProperty();
}
@Override protected ReadOnlyDoubleProperty columnWidthProperty() {
return tableColumn.widthProperty();
}
}
class MySpecialCell extends MyTableCell {
Canvas canvas = new Canvas(200.0, 12.0);
public MySpecialCell() {
super(null);
canvas.setMouseTransparent(true);
addEventFilter(MouseEvent.ANY, e -> e.consume());
}
@Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
setText(null);
if (! empty) {
canvas.getGraphicsContext2D().strokeText(item, 5.0, 10.0);
setGraphic(canvas);
} else {
setGraphic(null);
}
}
// create and return the custom skin
@Override
protected Skin<?> createDefaultSkin() {
return new MySpecialCellSkin(this);
}
}