2016-12-28 153 views
1

我在學習JavafX,因此如何用屬性來思考。ChangeListener在Javafx中不觸發

我有一顆豆,我用它來更新的TableView,像這樣:

public class DDTTabController extends DefaultTabController implements Initializable { 
    .... 
    @FXML 
    private TableView<DDTTableView> ddtTable; 
    .... 
    @FXML 
    private TableColumn<DDTTableView, String> rifColumn; 
    .... 
} 

等。我初始化我的控制器是這樣的:

@Override 
public void initialize(URL url, ResourceBundle rb) { 
.... 
    rifColumn.setCellValueFactory(cellData -> cellData.getValue().getRifProperty()); 
.... 
} 

這是我使用的瀏覽豆:

private class DDTTableView { 

    private ObjectProperty<DDT> ddt; 
    private ObjectProperty<Contact> contact; 
    private StringProperty rif; 

    public DDTTableView() { 
     this.ddt = new SimpleObjectProperty<>(); 
     this.contact = new SimpleObjectProperty<>(); 
     this.rif = new SimpleStringProperty(""); 
    } 

    public DDTTableView(DDT o) { 
     this(); 

     this.setDdt(o); 
     this.setContact(dataManager.getContactForCodeType(o.getAnaTipe(), o.getAnaCode().trim())); 

     this.ddt.get().getRowsProperty().addListener(new ChangeListener() { 
      @Override 
      public void changed(ObservableValue observable, Object oldValue, Object newValue) { 
       System.out.println("bip!"); 
       rif.set(...... buildString ......); 
      } 
     }); 

    } 

    public StringProperty getRifProperty() { 
     return this.rif; 
    } 

    public String getRif() { 
     return this.rif.get(); 
    } 

    public void setRif(String r) { 
     this.rif.set(r); 
    } 

    public ObjectProperty<DDT> getDdtProperty() { 
     return ddt; 
    } 

    public DDT getDdt() { 
     return ddt.get(); 
    } 

    public void setDdt(DDT ddt) { 
     this.ddt.set(ddt); 
    } 

    public ObjectProperty<Contact> getContactProperty() { 
     return contact; 
    } 

    public Contact getContact() { 
     return contact.get(); 
    } 

    public void setContact(Contact contact) { 
     this.contact.set(contact); 
    } 

    @Override 
    public int hashCode() { 
     int hash = 5; 
     hash = 89 * hash + Objects.hashCode(this.ddt); 
     return hash; 
    } 

    @Override 
    public boolean equals(Object obj) { 
     if (this == obj) { 
      return true; 
     } 
     if (obj == null) { 
      return false; 
     } 
     if (getClass() != obj.getClass()) { 
      return false; 
     } 
     final DDTTableView other = (DDTTableView) obj; 
     if (!Objects.equals(this.ddt, other.ddt)) { 
      return false; 
     } 
     return true; 
    } 
} 

的DDT豆:

public class DDT { 
.... 
    private ObjectProperty<ObservableList<DDTItem>> rows; 
.... 
} 

public DDT() { 
.... 
    this.rows = new SimpleObjectProperty<>(FXCollections.observableArrayList()); 
.... 
} 

    public ObjectProperty<ObservableList<DDTItem>> getRowsProperty() { 
     return rows; 
    } 

    public ObservableList<DDTItem> getRows() { 
     return rows.get(); 
    } 

    public void setRighe(ObservableList<DDTItem> r) { 
     this.rows.set(r); 
    } 
.... 
} 

最後的入口點中,我將我的數據傳遞給控制器​​:

public void setMainApp(AppWindow mainApp, MDIWindow win, MDICanvas can) { 
    super.setMainApp(mainApp, win, can); 

    dataManager.getDDT().stream().forEach((ddt) -> { 
     actualDDT.add(new DDTTableView(ddt)); 
    }); 
} 

你可以看到我只使用第二個構造函數(帶參數的那個)。

現在的問題是,即使在DDT bean中更新了Rows屬性,Rif屬性也不會被重建,因爲ChangeListener不會觸發,我不明白爲什麼。

任何人都可以請一些光?

謝謝。

+0

你的意思是你更新調用'setRighe()'的行屬性嗎?這實際上應該工作。當更改監聽器沒有觸發時,通常情況下,由於引用較弱,該屬性會收集垃圾。但是因爲你的所有屬性都存儲在字段中,所以這不應該成爲問題。 – Calculator

回答

1

DDTTableView構造函數中,您將ddt屬性作爲參數傳遞的值的值,然後添加一個監聽器的ddt電流值的rowsProperty

this.ddt.get().getRowsProperty().addListener(new ChangeListener() { 
    @Override 
    public void changed(ObservableValue observable, Object oldValue, Object newValue) { 
     System.out.println("bip!"); 
     rif.set(...... buildString ......); 
    } 
}); 

有三個問題,我可以在這裏看到:

  1. ddt是可變的(可以設置爲一個新的值),如果它被改變時,李stener仍然會附加原始rowsProperty值,而不是當前值。
  2. 您只是在監聽對整個行列表的更改。即您的聽衆將回應ddt.setRows(/* another entire list of DDTItems */),但不會響應對當前列表的更改。所以它不會響應ddt.getRows().add(/* some DDTItem */);
  3. 您的默認DDTTableView構造函數不會添加偵聽器(只有構造函數帶參數)。

對於第一個問題,您需要觀察ddt屬性,並在偵聽器的值更改時移動該偵聽器。

對於第二個問題,我建議不要讓列表變爲可變的,而只是可修改的。而不是ddt.setRows(someOtherList)(如果你需要它),你總是可以做ddt.getRows().setAll(someOtherList),它基本上具有相同的效果。然後只需註冊一個ListChangeListener將名單。

第三個問題很容易通過將附加偵聽器的代碼移動到默認構造函數(由其他構造函數調用)來修復。

您還應該修復方法名稱,使其與JavaFX properties pattern匹配。

即:

public class DDT { 

    //... 

    private final ObservableList<DDTItem> rows; 

    // ... 


    public DDT() { 

     // ... 

     this.rows = FXCollections.observableArrayList(); 

     // ... 
    } 


    public ObservableList<DDTItem> getRows() { 
     return rows.get(); 
    } 

    // ... 
} 

現在

private class DDTTableView { 

    private ObjectProperty<DDT> ddt; 
    private ObjectProperty<Contact> contact; 
    private StringProperty rif; 

    public DDTTableView() { 
     this.ddt = new SimpleObjectProperty<>(); 
     this.contact = new SimpleObjectProperty<>(); 
     this.rif = new SimpleStringProperty(""); 

     this.setContact(dataManager.getContactForCodeType(o.getAnaTipe(), o.getAnaCode().trim())); 

     ListChangeListener<DDTItem> rowsListener = (ListChangeListener.Change<? extends DDTItem> change) -> { 
      rif.set(/* buildString */); 
     }; 

     this.ddt.addListener((obs, oldDdt, newDdt) -> { 
      if (oldDdt != null) { 
       oldDdt.getRows().removeListener(rowsListener); 
      } 
      if (newDdt != null) { 
       newDdt.getRows().addListener(rowsListener); 
      } 
     }); 


    } 

    public DDTTableView(DDT o) { 
     this(); 

     this.setDdt(o); 

    } 

    public StringProperty rifProperty() { 
     return this.rif; 
    } 

    public String getRif() { 
     return this.rif.get(); 
    } 

    public void setRif(String r) { 
     this.rif.set(r); 
    } 

    public ObjectProperty<DDT> ddtProperty() { 
     return ddt; 
    } 

    public DDT getDdt() { 
     return ddt.get(); 
    } 

    public void setDdt(DDT ddt) { 
     this.ddt.set(ddt); 
    } 

    public ObjectProperty<Contact> contactProperty() { 
     return contact; 
    } 

    public Contact getContact() { 
     return contact.get(); 
    } 

    public void setContact(Contact contact) { 
     this.contact.set(contact); 
    } 

    @Override 
    public int hashCode() { 
     int hash = 5; 
     hash = 89 * hash + Objects.hashCode(this.ddt); 
     return hash; 
    } 

    @Override 
    public boolean equals(Object obj) { 
     if (this == obj) { 
      return true; 
     } 
     if (obj == null) { 
      return false; 
     } 
     if (getClass() != obj.getClass()) { 
      return false; 
     } 
     final DDTTableView other = (DDTTableView) obj; 
     if (!Objects.equals(this.ddt, other.ddt)) { 
      return false; 
     } 
     return true; 
    } 
} 

如果你真的需要功能setRows(...),您可以使用ListProperty<DDTItem>代替ObjectProperty<ObservableList<DDTItem>>。如果通過setRows(...)更改了基礎列表,或者通過getRows().add(...)等修改了當前列表,則會通知ListChangeListener s。但是,這種情況的用例非常少見,通常只需要具有不可修改的可修改列表即可上面的代碼。

相關問題