JavaFX TableView未触发选择回调
我对JavaFXTableView没有触发选择回调有问题。我设置了以下两个回调:JavaFX TableView未触发选择回调,java,events,javafx,tableview,Java,Events,Javafx,Tableview,我对JavaFXTableView没有触发选择回调有问题。我设置了以下两个回调: tableView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE); tableView.getSelectionModel().selectedItemProperty().addListener((observable) -> { System.out.println(LocalDateTime.now() + " Item
tableView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
tableView.getSelectionModel().selectedItemProperty().addListener((observable) -> {
System.out.println(LocalDateTime.now() + " Item selection changed.");
});
tableView.getSelectionModel().selectedIndexProperty().addListener(observable -> {
System.out.println(LocalDateTime.now() + " Item index changed.");
});
有一件事我感到困惑。选择更改事件仅在第一次选择和启动多重选择时触发。索引变化似乎发生在每一次变化上。为什么呢
然而,我最大的问题是,当我选择多个条目,然后选择我单击的最后一个条目时,因此,撤消多个选择但不更改焦点中的条目,不会触发任何事件。希望这能说明:
知道为什么会这样吗?我怎么知道选择是什么时候改变的
我的最小示例是四个文件:
Main.java:
package sample;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Main extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
primaryStage.setTitle("Hello World");
primaryStage.setScene(new Scene(root, 300, 275));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Record.java
package sample;
import javafx.beans.property.SimpleStringProperty;
public class Record {
private SimpleStringProperty c1 = new SimpleStringProperty();
private SimpleStringProperty c2 = new SimpleStringProperty();
public Record(String c1, String c2) {
this.c1.setValue(c1);
this.c2.setValue(c2);
}
public String getC1() {
return c1.get();
}
public SimpleStringProperty c1Property() {
return c1;
}
public void setC1(String c1) {
this.c1.set(c1);
}
public String getC2() {
return c2.get();
}
public SimpleStringProperty c2Property() {
return c2;
}
public void setC2(String c2) {
this.c2.set(c2);
}
@Override
public String toString() {
return String.format("Record{c1=%s, c2=%s}", c1, c2);
}
}
Controller.java
package sample;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.SelectionMode;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import java.time.LocalDateTime;
public class Controller {
private ObservableList<Record> records = FXCollections.observableArrayList();
@FXML
private TableView<Record> tableView;
@FXML
private TableColumn<Record, String> c1Column;
@FXML
private TableColumn<Record, String> c2Column;
@FXML
private void initialize() {
records.add(new Record("c1 - 1", "c2 - 1"));
records.add(new Record("c1 - 2", "c2 - 2"));
records.add(new Record("c1 - 3", "c2 - 3"));
records.add(new Record("c1 - 4", "c2 - 4"));
records.add(new Record("c1 - 5", "c2 - 5"));
tableView.setItems(records);
c1Column.setCellValueFactory(new PropertyValueFactory<>("c1"));
c2Column.setCellValueFactory(new PropertyValueFactory<>("c2"));
tableView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
tableView.getSelectionModel().selectedItemProperty().addListener((observable) -> {
System.out.println(LocalDateTime.now() + " Item selection changed.");
});
tableView.getSelectionModel().selectedIndexProperty().addListener(observable -> {
System.out.println(LocalDateTime.now() + " Item index changed.");
});
}
}
包装样品;
导入javafx.collections.FXCollections;
导入javafx.collections.ObservableList;
导入javafx.fxml.fxml;
导入javafx.scene.control.SelectionMode;
导入javafx.scene.control.TableColumn;
导入javafx.scene.control.TableView;
导入javafx.scene.control.cell.PropertyValueFactory;
导入java.time.LocalDateTime;
公共类控制器{
私有ObservableList记录=FXCollections.observableArrayList();
@FXML
私有TableView TableView;
@FXML
私有表列;
@FXML
私有表列;
@FXML
私有void初始化(){
增加(新记录(“c1-1”、“c2-1”);
增加(新记录(“c1-2”、“c2-2”);
增加(新记录(“c1-3”、“c2-3”);
增加(新记录(“c1-4”、“c2-4”);
增加(新记录(“c1-5”、“c2-5”);
tableView.setItems(记录);
c1Column.setCellValueFactory(新属性ValueFactory(“c1”));
c2Column.setCellValueFactory(新属性ValueFactory(“c2”);
tableView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
tableView.getSelectionModel().SelectEditeProperty().addListener((可观察)->{
System.out.println(LocalDateTime.now()+“项目选择已更改”);
});
tableView.getSelectionModel().selectedIndexProperty().addListener(可观察->{
System.out.println(LocalDateTime.now()+“项索引已更改”);
});
}
}
和sample.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.layout.StackPane?>
<StackPane xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="sample.Controller">
<TableView fx:id="tableView" prefHeight="200.0" prefWidth="200.0">
<columns>
<TableColumn fx:id="c1Column" prefWidth="75.0" text="C1"/>
<TableColumn fx:id="c2Column" prefWidth="75.0" text="C2"/>
</columns>
</TableView>
</StackPane>
问题在于您使用的是
invalizationlistener
s。这些侦听器在可观察值无效时被触发:也就是说,最后计算的值可能不是最新的
JavaFX属性可以惰性地进行评估。如果它们变得无效,则会通知无效侦听器,但不一定计算它们的新值。如果它们所依赖的值在重新计算之前再次更改,则它们已经无效,因此不会再次通知无效侦听器。如果在中间时间内重新计算,则它们将在重新计算后生效,并再次通知无效侦听器
此机制是出于性能原因而设计的:您可以想象,例如,一个大窗格的布局取决于其中许多项目的大小和位置;但您不希望在每次更改时都重新计算它:您只需要知道它何时需要重新计算(当它无效时)
从您的代码来看,其工作方式似乎是selectedItem
声明了对selectedIndex
的依赖关系。当用户选择某项内容时,直接设置selectedIndex
(使其无效并更改),这会导致selectedItem
无效。但是,selectedItem
在重新计算之前不会显式更改
如果您实际在侦听器中重新计算值,则可以看到所有这些:
tableView.getSelectionModel().selectedItemProperty().addListener((observable) -> {
System.out.println(LocalDateTime.now() + " Item selection changed: "+tableView.getSelectionModel().getSelectedItem());
});
tableView.getSelectionModel().selectedIndexProperty().addListener((observable) -> {
System.out.println(LocalDateTime.now() + " Item index changed: " + tableView.getSelectionModel().getSelectedIndex());
});
典型的用法是使用这些属性注册changelister
s,而不是invalizationlistener
sChangeListener
s通知属性的先前值和新值,因此它们强制重新计算该值:
tableView.getSelectionModel().selectedItemProperty().addListener((observable, oldItem, newItem) -> {
System.out.println(LocalDateTime.now() + " Item selection changed: "+ oldItem + " -> " + newItem);
});
tableView.getSelectionModel().selectedIndexProperty().addListener((observable, oldIndex, newInde) -> {
System.out.println(LocalDateTime.now() + " Item index changed: " + oldIndex + " -> " + newIndex);
});
最后,请注意,对于多个选择,和属性仅引用最后一个选择。可以在不更改上次选择的情况下更改所选项目的列表。在这种情况下,属性根本不会更改,因此不会通知更改侦听器或无效侦听器。因此,对于多重选择,在项目(或索引)列表上使用侦听器比在项目或索引本身上使用侦听器更为自然:
tableView.getSelectionModel().getSelectedItems().addListener((Change<? extends Record> c) -> {
System.out.println("Selected items: "+tableView.getSelectionModel().getSelectedItems());
});
tableView.getSelectionModel().getSelectedItems().addListener((ChangeThank you@James_D.最后一点确实有用,因为我所描述的问题最大的行为发生在SelectEditProperty()上的两种类型的侦听器上)
@PabloselectedItem
和selectedIndex
属性只引用最后一个选中的项目:因此在某些情况下,您可以更改选中项目的列表而不更改最后一个选择:在这种情况下,这两个属性不会更改(因此不会对它们触发侦听器).我会在回答中加上一条评论。