2016-10-19 256 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

謝謝!它非常完美! –

相關問題