2017-06-01 13 views
0

私は問題のために小さな実例プログラムを作った。ThreadViewからの新しい情報でTableViewが更新されない

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

このコードには多くの問題があります。

最も直接的には

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()); 
+0

総合的な説明をいただきありがとうございます – chenino

関連する問題