Multithreading TableView未更新来自线程的新信息
我为我遇到的问题做了一个小的工作示例程序。请记住,我真正的程序更复杂,所有这些类都是必需的,即使在这个小样本中看起来尺寸过大 主要类别:Multithreading TableView未更新来自线程的新信息,multithreading,javafx,tableview,Multithreading,Javafx,Tableview,我为我遇到的问题做了一个小的工作示例程序。请记住,我真正的程序更复杂,所有这些类都是必需的,即使在这个小样本中看起来尺寸过大 主要类别: public class PingTest extends Application { private static final ArrayList<PingThread> THREADS = new ArrayList(); @Override public void start(Stage primaryStage) { Anch
public class PingTest extends Application {
private static final ArrayList<PingThread> THREADS = new ArrayList();
@Override
public void start(Stage primaryStage) {
AnchorPane root = new AnchorPane();
TableView<Map.Entry<String, Ping>> tblPing = new TableView();
TableColumn<Map.Entry<String, Ping>, String> colName = new TableColumn("Name");
TableColumn<Map.Entry<String, Ping>, String> colTime = new TableColumn("Time");
TableColumn<Map.Entry<String, Ping>, String> colDifference = new TableColumn("Difference");
colName.setCellValueFactory((TableColumn.CellDataFeatures<Map.Entry<String, Ping>, String> p) -> new SimpleStringProperty(p.getValue().getKey()));
colTime.setCellValueFactory((TableColumn.CellDataFeatures<Map.Entry<String, Ping>, String> p) -> new SimpleStringProperty(Integer.toString(p.getValue().getValue().getTime())));
colDifference.setCellValueFactory((TableColumn.CellDataFeatures<Map.Entry<String, Ping>, String> p) -> new SimpleStringProperty(Integer.toString(p.getValue().getValue().getDifference())));
ObservableList<Map.Entry<String, Ping>> items = FXCollections.observableArrayList(Pings.getPings().entrySet());
tblPing.setItems(items);
Scene scene = new Scene(root, 300, 750);
// Align to pane
AnchorPane.setTopAnchor(tblPing, 0.0);
AnchorPane.setLeftAnchor(tblPing, 0.0);
AnchorPane.setRightAnchor(tblPing, 0.0);
AnchorPane.setBottomAnchor(tblPing, 0.0);
tblPing.getColumns().addAll(colName, colTime, colDifference);
root.getChildren().add(tblPing);
// Setting primary Stage
primaryStage.setOnCloseRequest(e -> {
THREADS.forEach(t -> t.interrupt());
});
primaryStage.setTitle("Ping List");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
// Some examples
String[] servers = {"www.google.com", "www.bing.com", "www.yahoo.com", "www.stackoverflow.com"};
// Start Threads
for (String server : servers) {
PingThread pingThread = new PingThread(server);
pingThread.start();
THREADS.add(pingThread);
}
launch(args);
}
线程
public class PingThread extends Thread {
private final String SERVER;
private int ping = 0;
public PingThread(String server) {
SERVER = server;
}
@Override
public void run() {
try {
while (true) {
// Ping, update then sleep
ping();
Pings.update(SERVER, ping);
Thread.sleep(1000);
}
} catch (InterruptedException ex) {
// Used to end thread
}
}
public void ping() {
try {
// Sendinging request
InetAddress host = InetAddress.getByName(SERVER);
long tm = System.nanoTime();
Socket so = new Socket(host, 80);
so.close();
ping =(int)( (System.nanoTime() - tm) / 1000000L);
} catch (IOException ex) {
}
}
}
数据容器
public class Pings {
private static final ConcurrentHashMap<String,Ping> PINGS= new ConcurrentHashMap();
public static synchronized void update(String server, int time) {
if (PINGS.containsKey(server)) {
PINGS.get(server).setTime(time);
} else {
PINGS.put(server, new Ping(server,time));
}
}
public static synchronized ConcurrentHashMap<String,Ping> getPings(){
return PINGS;
}
}
公共类ping{
私有静态最终ConcurrentHashMap PINGS=新ConcurrentHashMap();
公共静态同步无效更新(字符串服务器,整数时间){
if(PINGS.containsKey(服务器)){
PINGS.get(服务器).setTime(时间);
}否则{
PINGS.put(服务器,新Ping(服务器,时间));
}
}
公共静态同步ConcurrentHashMap getPings(){
返回ping;
}
}
在我的大型实现中,GUI表没有更新为新的值,就像在这个小示例中一样。将值绑定到TableView有什么不对?此代码存在许多问题 最直接的是电话
FXCollections.observableArrayList(Pings.getPings().entrySet());
创建一个新的可观察列表,并将Pings.getPings().entrySet()中的所有内容添加到该列表中。但随后修改用于构建它的集合不会修改可观察列表,因此表不会更改。您需要将可观察列表存储在模型中(Pings
)并直接更新它
您还需要在FX应用程序线程上执行更新,并且需要在Ping
类中使用JavaFX属性,以便该表可以观察这些值的更改
因此:
必须在FX应用程序线程上更改数据,因此您的数据容器也可以是单线程:
public class Pings {
private static final Map<String,Ping> PINGS= new HashMap<>();
private static final ObservableList<Ping> pingList = FXCollections.observableArrayList();
public static void update(String server, int time) {
if (PINGS.containsKey(server)) {
PINGS.get(server).setTime(time);
} else {
Ping ping = new Ping(server, time);
pingList.add(ping);
PINGS.put(server, ping);
}
}
public static ObservableList<Ping> getPings(){
return pingList;
}
}
最后将表格设置为:
TableView<Ping> tblPing = new TableView<>();
TableColumn<Ping, String> colName = new TableColumn<>("Name");
TableColumn<Ping, Number> colTime = new TableColumn<>("Time");
TableColumn<Ping, Number> colDifference = new TableColumn<>("Difference");
colName.setCellValueFactory(p -> new SimpleStringProperty(p.getValue()));
colTime.setCellValueFactory(p -> p.getValue().timeProperty());
colDifference.setCellValueFactory(p -> p.getValue().differenceProperty());
tblPing.getColumns().addAll(colName, colTime, colDifference);
tblPing.setItems(Pings.getPings());
TableView tblPing=newtableview();
TableColumn colName=新的TableColumn(“名称”);
TableColumn colTime=新的TableColumn(“时间”);
TableColumn colDifference=新的TableColumn(“差异”);
setCellValueFactory(p->newSimpleStringProperty(p.getValue());
setCellValueFactory(p->p.getValue().timeProperty());
colDifference.setCellValueFactory(p->p.getValue().differenceProperty());
tblPing.getColumns().addAll(colName、colTime、colDifference);
tblPing.setItems(Pings.getPings());
非常感谢您的全面解释
public class Pings {
private static final Map<String,Ping> PINGS= new HashMap<>();
private static final ObservableList<Ping> pingList = FXCollections.observableArrayList();
public static void update(String server, int time) {
if (PINGS.containsKey(server)) {
PINGS.get(server).setTime(time);
} else {
Ping ping = new Ping(server, time);
pingList.add(ping);
PINGS.put(server, ping);
}
}
public static ObservableList<Ping> getPings(){
return pingList;
}
}
public class PingThread extends Thread {
private final String SERVER;
public PingThread(String server) {
SERVER = server;
}
@Override
public void run() {
try {
while (true) {
// Ping, update then sleep
final int ping = ping();
// again, not exactly sure how you want to handle exceptions...
if (ping >= 0) {
Platform.runLater(() -> Pings.update(SERVER, ping));
}
Thread.sleep(1000);
}
} catch (InterruptedException ex) {
// Used to end thread
}
}
public int ping() {
try {
// Sendinging request
InetAddress host = InetAddress.getByName(SERVER);
long tm = System.nanoTime();
Socket so = new Socket(host, 80);
so.close();
return (int)( (System.nanoTime() - tm) / 1000000L);
} catch (IOException ex) {
return -1 ; // or handle exception?
}
}
}
TableView<Ping> tblPing = new TableView<>();
TableColumn<Ping, String> colName = new TableColumn<>("Name");
TableColumn<Ping, Number> colTime = new TableColumn<>("Time");
TableColumn<Ping, Number> colDifference = new TableColumn<>("Difference");
colName.setCellValueFactory(p -> new SimpleStringProperty(p.getValue()));
colTime.setCellValueFactory(p -> p.getValue().timeProperty());
colDifference.setCellValueFactory(p -> p.getValue().differenceProperty());
tblPing.getColumns().addAll(colName, colTime, colDifference);
tblPing.setItems(Pings.getPings());