在 JAVA Fx 中自动更新 Tableview
Auto Updating Tableview in JAVA Fx
在我的项目中,当客户端断开连接时,服务器将从可观察列表中删除该名称,并且表视图应停止显示该名称。但是 tableview 没有更新。
控制器 class
public class Controller {
@FXML
public TableView tableView;
@FXML
private TableColumn<clientLoginData,String> client;
@FXML
private TableColumn<clientLoginData,String> activeTime;
void initialize(ObservableList<clientLoginData> data)
{
client.setCellValueFactory(new PropertyValueFactory<>("clientName"));
client.setCellFactory(TextFieldTableCell.<clientLoginData>forTableColumn());
activeTime.setCellValueFactory(new PropertyValueFactory<>("time"));
activeTime.setCellFactory(TextFieldTableCell.<clientLoginData>forTableColumn());
tableView.setItems(data);
tableView.setEditable(true);
}
}
主要class
public class Main extends Application{
volatile public ObservableList<clientLoginData> data= FXCollections.observableArrayList();
public Controller controller;
@Override
public void start(Stage primaryStage) throws Exception {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("server.fxml"));
Parent root = loader.load();
data.addAll(new clientLoginData((new SimpleStringProperty("john")),new SimpleStringProperty(ZonedDateTime.now().getHour()+":"+ZonedDateTime.now().getMinute())));
controller=loader.getController();
controller.initialize(data);
primaryStage.setTitle("Server");
primaryStage.setScene(new Scene(root, 600, 400));
primaryStage.show();
Thread t=new Thread(new messengerServer(this));
t.start();
}
public static void main(String[] args) {
launch(args);
}
}
正在更新class
public class messengerReadThread implements Runnable {
private Thread thr;
private NetworkUtil nc;
public Hashtable<SimpleStringProperty, NetworkUtil> table;
SimpleStringProperty oldName;
Main main;
public messengerReadThread(NetworkUtil nc, Hashtable<SimpleStringProperty, NetworkUtil> table, SimpleStringProperty s, Main main) {
this.nc = nc;
this.thr = new Thread(this);
thr.start();
this.table=table;
oldName=s;
this.main=main;
}
public void run() {
try {
while(true) {
String s1=(String)nc.read();
StringTokenizer st=new StringTokenizer(s1);
if(st.nextToken().equals("Name"))
{
String sn=s1.substring(5,s1.length());
NetworkUtil n1=table.get(oldName);
table.remove(oldName);
oldName=new SimpleStringProperty(sn);
table.put(oldName, n1);
main.data.add(new clientLoginData(oldName,new SimpleStringProperty(ZonedDateTime.now().getHour()+":"+ZonedDateTime.now().getMinute())));
}
else
{
System.out.println("here it is"+s1);
}
}
} catch(Exception e) {
System.out.println("disconnected "+oldName.toString());
main.data.remove(oldName);
//System.out.println(main.data.contains(oldName));
main.controller.tableView.refresh();//the tableview should update
}
nc.closeConnection();
}
}
我应该对该代码进行一些修改,比如避免使用那些 "static references",通过定义 ObservableList 并将您的更新代码移到 Controller 中,这样您就可以拥有 2 类 代码, Main Class 和你的控制器...但我会尽量保持简单。
首先,您需要在控制器中定义 ObservableList。
然后将您的 "updating" 代码放在控制器中的一个方法中。我建议您使用 Task<> 使您的控制器在 JavaFX 线程中保持更新。
尝试这样的事情:
private void updateTable(){
Task<Void> myUpdatingTask=new Task<Void>() {
@Override
protected Void call() throws Exception {
//Your Updating Code Here
}
}
//and then you run it like this:
Thread hilo=new Thread(myUpdatingTask);
hilo.setDaemon(true);
hilo.start();
}
然后,从您的 Initialize 方法中删除该参数,并使用 @FXML 注释将其定义为私有,如下所示:
@FXML
private void initialize(){
//Your Stuff to initialize
//here is were you fill your table like you did in the Main
//and don't forget to call you updateTable Method
this.updateTable();
}
由于@kleopatra 指出这是一个肮脏的 hack,我将把它装饰成一个肮脏的 hack。
****************************肮脏的黑客******************** ************************
尝试隐藏一列并再次显示它,您的 tableview 应该会刷新
在我的项目中,当客户端断开连接时,服务器将从可观察列表中删除该名称,并且表视图应停止显示该名称。但是 tableview 没有更新。 控制器 class
public class Controller {
@FXML
public TableView tableView;
@FXML
private TableColumn<clientLoginData,String> client;
@FXML
private TableColumn<clientLoginData,String> activeTime;
void initialize(ObservableList<clientLoginData> data)
{
client.setCellValueFactory(new PropertyValueFactory<>("clientName"));
client.setCellFactory(TextFieldTableCell.<clientLoginData>forTableColumn());
activeTime.setCellValueFactory(new PropertyValueFactory<>("time"));
activeTime.setCellFactory(TextFieldTableCell.<clientLoginData>forTableColumn());
tableView.setItems(data);
tableView.setEditable(true);
}
}
主要class
public class Main extends Application{
volatile public ObservableList<clientLoginData> data= FXCollections.observableArrayList();
public Controller controller;
@Override
public void start(Stage primaryStage) throws Exception {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("server.fxml"));
Parent root = loader.load();
data.addAll(new clientLoginData((new SimpleStringProperty("john")),new SimpleStringProperty(ZonedDateTime.now().getHour()+":"+ZonedDateTime.now().getMinute())));
controller=loader.getController();
controller.initialize(data);
primaryStage.setTitle("Server");
primaryStage.setScene(new Scene(root, 600, 400));
primaryStage.show();
Thread t=new Thread(new messengerServer(this));
t.start();
}
public static void main(String[] args) {
launch(args);
}
}
正在更新class
public class messengerReadThread implements Runnable {
private Thread thr;
private NetworkUtil nc;
public Hashtable<SimpleStringProperty, NetworkUtil> table;
SimpleStringProperty oldName;
Main main;
public messengerReadThread(NetworkUtil nc, Hashtable<SimpleStringProperty, NetworkUtil> table, SimpleStringProperty s, Main main) {
this.nc = nc;
this.thr = new Thread(this);
thr.start();
this.table=table;
oldName=s;
this.main=main;
}
public void run() {
try {
while(true) {
String s1=(String)nc.read();
StringTokenizer st=new StringTokenizer(s1);
if(st.nextToken().equals("Name"))
{
String sn=s1.substring(5,s1.length());
NetworkUtil n1=table.get(oldName);
table.remove(oldName);
oldName=new SimpleStringProperty(sn);
table.put(oldName, n1);
main.data.add(new clientLoginData(oldName,new SimpleStringProperty(ZonedDateTime.now().getHour()+":"+ZonedDateTime.now().getMinute())));
}
else
{
System.out.println("here it is"+s1);
}
}
} catch(Exception e) {
System.out.println("disconnected "+oldName.toString());
main.data.remove(oldName);
//System.out.println(main.data.contains(oldName));
main.controller.tableView.refresh();//the tableview should update
}
nc.closeConnection();
}
}
我应该对该代码进行一些修改,比如避免使用那些 "static references",通过定义 ObservableList 并将您的更新代码移到 Controller 中,这样您就可以拥有 2 类 代码, Main Class 和你的控制器...但我会尽量保持简单。
首先,您需要在控制器中定义 ObservableList。
然后将您的 "updating" 代码放在控制器中的一个方法中。我建议您使用 Task<> 使您的控制器在 JavaFX 线程中保持更新。
尝试这样的事情:
private void updateTable(){
Task<Void> myUpdatingTask=new Task<Void>() {
@Override
protected Void call() throws Exception {
//Your Updating Code Here
}
}
//and then you run it like this:
Thread hilo=new Thread(myUpdatingTask);
hilo.setDaemon(true);
hilo.start();
}
然后,从您的 Initialize 方法中删除该参数,并使用 @FXML 注释将其定义为私有,如下所示:
@FXML
private void initialize(){
//Your Stuff to initialize
//here is were you fill your table like you did in the Main
//and don't forget to call you updateTable Method
this.updateTable();
}
由于@kleopatra 指出这是一个肮脏的 hack,我将把它装饰成一个肮脏的 hack。 ****************************肮脏的黑客******************** ************************ 尝试隐藏一列并再次显示它,您的 tableview 应该会刷新