我为我遇到的问题做了一个小的工作示例程序。请记住,我的真实程序更复杂,所有这些类都是必需的,即使它在这个小样本中看起来过于庞大
主类:
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 Ping {
private int difference;
private int time;
private final String url;
public Ping(String url,int time) {
this.url = url;
this.time = time;
difference = 0;
}
public int getDifference() {
return difference;
}
public int getTime() {
return time;
}
public void setTime(int time) {
difference = time - this.time;
this.time = time;
}
public String getUrl() {
return url;
}
}
线程
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;
}
}
在我的更大实现中,GUI表没有更新为新值,就像在这个小例子中一样。将值绑定到TableView时我做错了什么?
答案 0 :(得分:0)
此代码存在许多问题。
最直接的是呼叫
FXCollections.observableArrayList(Pings.getPings().entrySet());
创建一个新的可观察列表,并将Pings.getPings().entrySet()
中的所有内容添加到其中。但随后修改用于构造它的集合将不会修改可观察列表,因此表格不会更改。您需要将可观察列表存储在模型(Pings
)中并直接更新。
您还需要在FX应用程序线程上进行更新,并且您需要在Ping
类中使用JavaFX属性,以便表格可以观察到这些值的更改。
所以:
public class Ping {
private final ReadOnlyIntegerWrapper difference = new ReadOnlyIntegerWrapper();
private final ReadOnlyIntegerWrapper time = new ReadOnlyIntegerWrapper();
private final String url;
public Ping(String url,int time) {
this.url = url;
setTime(time);
difference.set(0);
}
public ReadOnlyIntegerProperty differenceProperty() {
return difference.getReadOnlyProperty() ;
}
public final int getDifference() {
return differenceProperty().get();
}
public ReadOnlyIntegerProperty timeProperty() {
return time ;
}
public final int getTime() {
return timeProperty().get();
}
public void setTime(int time) {
difference.set(time - getTime());
this.time.set(time);
}
public String getUrl() {
return url;
}
}
必须在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;
}
}
现在线程确实:
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());