2016-10-19 147 views
0

我需要根据单击另一个表格上的元素(Person)在表格上显示元素。问题在于,使用服务时,如果用户非常快速地点击第一个表的两个元素,那么这两个元素的数据会显示在表中,而我只想显示最后一个点击的数据。希望您能够帮助我。单击另一个表格中的元素时更新表格

这里是我的代码:

personTable.getSelectionModel().selectedItemProperty().addListener(
      (observable, oldValue, newValue) -> { 
       try { 
        contactoTable.setPlaceholder(new Label("Cargando...")); 
        showPersonDetails(newValue); 
       } catch (SQLException ex) { 
        Logger.getLogger(PersonOverviewController.class.getName()).log(Level.SEVERE, null, ex); 
       } 
      }); 

而且showPersonDatails:

contactoTable.setVisible(true); 
     contactoTable.getItems().clear(); 

     firstNameLabel.setText(person.getFirstName()); 
     lastNameLabel.setText(person.getLastName()); 
     mailLabel.setText(person.getMail()); 
     phoneLabel.setText(person.getPhone()); 
     descriptionLabel.setText(person.getDescription()); 

     service = new Service<Void>() { 
      @Override 
      protected Task<Void> createTask() { 
       return new Task<Void>() { 
        @Override 
        protected Void call() throws Exception { 
         //Background work 
         DBManager db = new DBManager(); 
         String query = "SELECT * FROM eventos"; 
         ResultSet r = db.executeSelect(query); 
         contactoTable.getItems().clear(); 
         contactoData.clear(); 

         while (r.next()) { 
          String q = "SELECT * FROM " + r.getString("Nombre").replace(" ", "_") + " WHERE Nombre = '" + person.getFirstName() + "' AND Apellidos = '" + person.getLastName() + "' AND Correo = '" + person.getMail() + "'"; 
          ResultSet result = db.executeSelect(q); 

          while (result.next()) { 
           contactoData.add(new Row(r.getString("Nombre"), result.getString("Asistencia"))); 
          } 
         } 

         final CountDownLatch latch = new CountDownLatch(1); 
         Platform.runLater(() -> { 
          try { 
           //FX Stuff done here 
           contactoTable.setPlaceholder(new Label("No invitado a ningún evento")); 
           contactoTable.setItems(contactoData); 

          } finally { 
           latch.countDown(); 

          } 
         }); 
         latch.await(); 
         //Keep with the background work 
         return null; 
        } 
       }; 
      } 
     }; 

     service.start(); 
+1

请创建一个不会与数据库对话的SSCCE –

+0

使任务等待UI更新的目的是什么?这似乎是多余的,尤其是因为任务没有更多的工作要做,并且将要退出。 –

+0

以前我在那里有代码。但它不会影响任务功能。我的意思是,该程序也一样。 –

回答

0

你引用从多个线程相同的数据列表(contactoData),与名单上显然没有同步。如果用户快速连续选择两个不同的项目,则为每个项目启动一项服务,每项服务在不同的线程中运行其任务。因此,您无法控制两个不同线程在contactoData上执行其(多个)操作的顺序。例如,有可能(甚至是可能的),对于异步执行两个服务的顺序是:

  1. 服务第一清除列表
  2. 第二业务清除列表
  3. 服务第一添加元素到列表中
  4. 第二业务将元素加到列表

,并在这种情况下,列表包含两种服务,而不仅仅是其中一个生成的元素。

所以你应该让你的任务运行并返回一个他们创建的新列表。然后在FX应用程序线程上处理该列表。

目前还不清楚为什么你需要在这里的服务,因为你似乎只使用每个服务一次。你也可以直接使用任务。

您也可能想确保最后一个选择是显示的选择。由于这些任务是异步运行的,因此如果两个任务快速连续启动,第二个任务可能会在第一个任务之前完成。这会导致显示第二个选择,然后第一个选择将替换它。您可以通过在onSucceeded处理程序中执行UI更新并在开始新任务时取消任何当前任务(从而防止当前正在执行的任务调用其onSucceeded处理程序)来避免此问题。

最后,我真的不清楚为什么你要让任务等到UI更新。

这里是你的代码的更新版本:

private Task<List<Row>> updateContactTableTask ; 

// ... 

private void showPersonDetails(Person person) { 

    contactoTable.getItems().clear(); 

    firstNameLabel.setText(person.getFirstName()); 
    lastNameLabel.setText(person.getLastName()); 
    mailLabel.setText(person.getMail()); 
    phoneLabel.setText(person.getPhone()); 
    descriptionLabel.setText(person.getDescription()); 


    if (updateContactTableTask != null && updateContactTableTask.isRunning()) { 
     updateContactTableTask.cancel(); 
    } 

    updateContactTableTask = new Task<List<Row>>() { 
     @Override 
     protected List<Row> call() throws Exception { 

      List<Row> resultList = new ArrayList<>() ; 

      //Background work 
      DBManager db = new DBManager(); 
      String query = "SELECT * FROM eventos"; 
      ResultSet r = db.executeSelect(query); 

      // quit if we got canceled here... 
      if (isCancelled()) { 
       return resultList; 
      } 

      while (r.next() && ! isCancelled()) { 

       // Note: building a query like this is inherently unsafe 
       // You should use a PreparedStatement in your DBManager class instead 
       String q = "SELECT * FROM " + r.getString("Nombre").replace(" ", "_") + " WHERE Nombre = '" + person.getFirstName() + "' AND Apellidos = '" + person.getLastName() + "' AND Correo = '" + person.getMail() + "'"; 
       ResultSet result = db.executeSelect(q); 

       while (result.next()) { 
        resultList.add(new Row(r.getString("Nombre"), result.getString("Asistencia"))); 
       } 

      } 

      return resultList ; 
     } 
    }; 

    updateContactTableTask.setOnSucceeded(e -> { 
     // not really clear you still need contactoData, but if you do: 
     contactoData.setAll(updateContactTableTask.getValue()); 
     contactoTable.setPlaceholder(new Label("No invitado a ningún evento")); 
     contactoTable.setItems(contactoData); 
    }); 

    updateContactTableTask.setOnFailed(e -> { 
     // handle database errors here... 
    }); 

    new Thread(updateContactTableTask).start(); 
} 

顺便说一句,这不是我清楚,如果,如果是这样,怎么样,你是关闭您的数据库资源。例如。结果集似乎从未关闭。这可能会导致资源泄漏。然而,这是偶然的(并且知道你的DBManager类是如何实现的),所以我不会在这里解决它。

+0

谢谢!它非常完美! –

相关问题