在JavaFX中自动更新Tableview

在JavaFX中自动更新Tableview,java,tableview,javafx-8,Java,Tableview,Javafx 8,在我的项目中,当客户端断开连接时,服务器将从可观察列表中删除该名称,tableview将停止显示该名称。但是tableview没有更新。 控制器类 public class Controller { @FXML public TableView tableView; @FXML private TableColumn<clientLoginData,String> client; @FXML private TableColumn<clientLoginData,Strin

在我的项目中,当客户端断开连接时,服务器将从可观察列表中删除该名称,tableview将停止显示该名称。但是tableview没有更新。 控制器类

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);

}

}
公共类控制器{
@FXML
公共桌面视图桌面视图;
@FXML
私有表列客户端;
@FXML
私有表列活动时间;
无效初始化(可观察列表数据)
{
client.setCellValueFactory(新的PropertyValueFactory(“clientName”);
setCellFactory(TextFieldTableCell.forTableColumn());
setCellValueFactory(新属性ValueFactory(“时间”));
setCellFactory(TextFieldTableCell.forTableColumn());
tableView.setItems(数据);
tableView.setEditable(true);
}
}
主类

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);
}
}
public类主扩展应用程序{
volatile public ObservableList data=FXCollections.observableAryList();
公共控制器;
@凌驾
public void start(Stage primaryStage)引发异常{
FXMLLoader=新的FXMLLoader();
setLocation(getClass().getResource(“server.fxml”);
父根=loader.load();
addAll(新的clientLoginData((新的SimpleStringProperty(“john”)),新的SimpleStringProperty(ZonedDateTime.now().getHour()+”:“+ZonedDateTime.now().getMinute()));
controller=loader.getController();
控制器初始化(数据);
primaryStage.setTitle(“服务器”);
原始阶段。设置场景(新场景(根,600400));
primaryStage.show();
线程t=新线程(新信使服务器(this));
t、 start();
}
公共静态void main(字符串[]args){
发射(args);
}
}
更新类

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();
}
}
公共类messengerReadThread实现可运行{
私有线程thr;
专用网络;
公共哈希表;
SimpleStringProperty oldName;
主要的;
public Messenger ReadThread(NetworkUtil nc、哈希表、SimpleStringProperty s、Main){
this.nc=nc;
this.thr=新螺纹(this);
thr.start();
这个表=表;
oldName=s;
this.main=main;
}
公开募捐{
试一试{
while(true){
字符串s1=(字符串)nc.read();
StringTokenizer st=新的StringTokenizer(s1);
如果(st.nextToken().equals(“Name”))
{
字符串sn=s1.子字符串(5,s1.length());
NetworkUtil n1=table.get(oldName);
表.删除(旧名称);
oldName=新的SimpleStringProperty(序列号);
表.put(旧名称,n1);
main.data.add(新的clientLoginData(旧名称,新的SimpleStringProperty(ZonedDateTime.now().getHour()+”:“+ZonedDateTime.now().getMinute()));
}
其他的
{
System.out.println(“这里是”+s1);
}
}
}捕获(例外e){
System.out.println(“断开连接”+oldName.toString());
main.data.remove(旧名称);
//System.out.println(main.data.contains(oldName));
main.controller.tableView.refresh();//tableView应该更新
}
nc.closeConnection();
}
}

我应该对该代码进行一些修改,比如通过定义ObservableList并将更新代码移到控制器中,避免使用那些“静态引用”,这样您就可以有一个2类代码,主类和控制器。。。但我会尽量保持简单

首先,您需要在控制器内定义ObservableList

然后将“更新”代码放在方法中的控制器内。我建议您在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();
}
@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所指出的,这是一个肮脏的黑客行为,我将把它装饰成一个肮脏的黑客行为。 ****************************肮脏的黑客*****************************************
尝试隐藏列并再次显示,您的tableview应该会刷新您的main.data.remove调用,因为您正试图从
列表中删除StringProperty,所以该调用永远不会有任何效果。此外,所有可观察对象的修改都需要在应用程序线程上完成。这意味着必须在调用内部调用
main.data.add
main.data.remove
。无需恶意攻击:如果所有协作者都正确连接,则将进行更新automagically@kleopatra我一直在和oracle讨论这个问题,表视图也会导致内存泄漏。他们还没有解决这个问题。除非有与之相关的事件,否则我无法在没有恶意攻击的情况下更新表。event.getTableView().getItems().get(event.getTablePosition().getRow()).setSomething(event.getNewValue().trim());想想看,您可能会生成自己的事件来更新表。在99.999%的tableView中,更改数据时不更新,数据设置有问题。剩下的是
tableView.refresh()
@kleopatra,我们按照oracle在其示例中所描述的实现进行了跟踪。它在99.99%的时间里对我们不起作用。tableview.refresh()没有为我们做任何事情。oracle在上提交并接受了一些bug。更新60中修复了堆栈上的post溢出