检测 TableView JavaFX 行上的双击
Posted
技术标签:
【中文标题】检测 TableView JavaFX 行上的双击【英文标题】:Detect doubleclick on row of TableView JavaFX 【发布时间】:2014-12-21 04:54:57 【问题描述】:我需要检测对TableView
的一行的双击。
如何监听该行任何部分的双击并获取该行的所有数据以将其打印到控制台?
【问题讨论】:
使用双击单元格的解决方案会起作用,因为您始终可以在单元格上调用getTableRow().getItem()
来获取该行的项目。更好的是直接在表格行中注册一个监听器(见答案)。
【参考方案1】:
我有类似的情况,没有检测到 TableView 上的鼠标双击事件。 最重要的是,样品工作得很好。但我的应用程序根本没有检测到双击事件。
但是我发现如果TableView处于可编辑状态,就无法检测到鼠标双击事件!!
如果 TableView 像这样可编辑,请检查您的应用程序。
tableView.setEditable( true );
如果这样,双击事件只会在选中的同一行上引发。
【讨论】:
【参考方案2】:这对我有用:
table.setOnMouseClicked((MouseEvent event) ->
if (event.getButton().equals(MouseButton.PRIMARY) && event.getClickCount() == 2)
System.out.println(table.getSelectionModel().getSelectedItem());
);
【讨论】:
【参考方案3】:TableView<MyType> table = new TableView<>();
//...
table.setRowFactory( tv ->
TableRow<MyType> row = new TableRow<>();
row.setOnMouseClicked(event ->
if (event.getClickCount() == 2 && (! row.isEmpty()) )
MyType rowData = row.getItem();
System.out.println(rowData);
);
return row ;
);
这是一个完整的工作示例:
import java.util.Random;
import java.util.function.Function;
import javafx.application.Application;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ObservableValue;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableRow;
import javafx.scene.control.TableView;
import javafx.stage.Stage;
public class TableViewDoubleClickOnRow extends Application
@Override
public void start(Stage primaryStage)
TableView<Item> table = new TableView<>();
table.setRowFactory(tv ->
TableRow<Item> row = new TableRow<>();
row.setOnMouseClicked(event ->
if (event.getClickCount() == 2 && (! row.isEmpty()) )
Item rowData = row.getItem();
System.out.println("Double click on: "+rowData.getName());
);
return row ;
);
table.getColumns().add(column("Item", Item::nameProperty));
table.getColumns().add(column("Value", Item::valueProperty));
Random rng = new Random();
for (int i = 1 ; i <= 50 ; i++)
table.getItems().add(new Item("Item "+i, rng.nextInt(1000)));
Scene scene = new Scene(table);
primaryStage.setScene(scene);
primaryStage.show();
private static <S,T> TableColumn<S,T> column(String title, Function<S, ObservableValue<T>> property)
TableColumn<S,T> col = new TableColumn<>(title);
col.setCellValueFactory(cellData -> property.apply(cellData.getValue()));
return col ;
public static class Item
private final StringProperty name = new SimpleStringProperty();
private final IntegerProperty value = new SimpleIntegerProperty();
public Item(String name, int value)
setName(name);
setValue(value);
public StringProperty nameProperty()
return name ;
public final String getName()
return nameProperty().get();
public final void setName(String name)
nameProperty().set(name);
public IntegerProperty valueProperty()
return value ;
public final int getValue()
return valueProperty().get();
public final void setValue(int value)
valueProperty().set(value);
public static void main(String[] args)
launch(args);
【讨论】:
@Aubin 我认为既然这个答案被接受并且有 80 多票赞成票,那么可以合理地假设如果它不适合你,那么你实现这个的方式就有问题。使用minimal reproducible example 发布您自己的问题。 如果我想改用细胞工厂怎么办?我已经有为每个字段使用PropertyValueFactory
的代码,如何扩展您的方法来监听双击?另外,我不明白你的行工厂的这一部分:你创建一个新的TableRow
,在上面调用getItem
,然后打印这个项目的名称?何时涉及实际数据?
@Arno A PropertyValueFactory
用于cellValueFactory
,而不是cellFactory
。您的TableColumn
s 上始终需要cellValueFactory
(请注意,表中的两列也都定义了cellValueFactory
s)。如果需要,您可以在部分或全部列上另外定义cellFactory
s;他们独立于此。不确定我是否理解您的最后一个问题;您所指的代码在鼠标处理程序中。因此,当鼠标双击该行时,处理程序会检索该行的值并显示其名称。
我刚刚明白ValueFactory
和CellFactory
之间的区别,谢谢。至于我的第二个问题,我只是错过了上下文,我现在明白了。【参考方案4】:
这个答案已经过测试:
table.setOnMouseClicked( event ->
if( event.getClickCount() == 2 )
System.out.println( table.getSelectionModel().getSelectedItem());
);
table.getSelectionModel().getSelectedItem()
可以使用,因为我们双击。第一次单击选择移动,第二次执行此处理程序。
【讨论】:
【参考方案5】:如果您使用SceneBuilder
,您可以将您的表的OnMouseClicked
设置为handleRowSelect()
方法,如下所示:
MyType temp;
Date lastClickTime;
@FXML
private void handleRowSelect()
MyType row = myTableView.getSelectionModel().getSelectedItem();
if (row == null) return;
if(row != temp)
temp = row;
lastClickTime = new Date();
else if(row == temp)
Date now = new Date();
long diff = now.getTime() - lastClickTime.getTime();
if (diff < 300) //another click registered in 300 millis
System.out.println("Edit dialog");
else
lastClickTime = new Date();
【讨论】:
您可以获取事件handleRowSelect(MouseEvent event)
来检测与@Abdul.Moqueet 回答中的主要鼠标按钮的双击【参考方案6】:
例子:
table.setOnMousePressed(new EventHandler<MouseEvent>()
@Override
public void handle(MouseEvent event)
if (event.isPrimaryButtonDown() && event.getClickCount() == 2)
System.out.println(table.getSelectionModel().getSelectedItem());
);
如果您使用自定义选择模型,则可以从事件中获取行,例如:
table.setOnMousePressed(new EventHandler<MouseEvent>()
@Override
public void handle(MouseEvent event)
if (event.isPrimaryButtonDown() && event.getClickCount() == 2)
Node node = ((Node) event.getTarget()).getParent();
TableRow row;
if (node instanceof TableRow)
row = (TableRow) node;
else
// clicking on text part
row = (TableRow) node.getParent();
System.out.println(row.getItem());
);
【讨论】:
虽然这行得通(因为双击的第一次单击选择了行),选择在语义上是不同的,将鼠标处理程序附加到行。如果您出于某种原因需要使用自定义选择模型,则可能会破坏此代码。 @James_D 在问题中没有写下自定义选择模型案例,但也针对此案例调整了答案。 这依赖于特定的节点层次结构(这是未记录的,并且故意如此)。如果在 JavaFX 的未来版本中表视图布局机制的实现发生了变化怎么办?只需在创建时将侦听器直接附加到表行即可。 你也有点误解了我的意思。问题不在于您的代码是否支持自定义选择模型,而实际上“选择”和“注册鼠标侦听器”是两个独立的东西。使用“选择了什么”作为一种机制来确定单击鼠标的节点会在 API 的两个部分之间引入以前不存在的耦合(依赖性)。 谢谢,但我必须使用event.getButton().equals(MouseButton.PRIMARY)
而不是 event.isPrimaryButtonDown()
才能让我的工作。以上是关于检测 TableView JavaFX 行上的双击的主要内容,如果未能解决你的问题,请参考以下文章
如何在 UICollectionView 中检测“仅单指”单元格上的双击?