Chciałbym wyświetlić listę osób (zakodowanych w POJOS i zawierających nazwę i właściwość nazwy) za pomocą formantu ListView JavaFX. Stworzyłem ListView i dodałem listę osób jako ObservableList. Wszystko działa poprawnie, jeśli usunę lub dodam nową osobę do obiektu ObservableList, ale zmiany w POJO nie powodują aktualizacji ListView. Muszę usunąć i dodać zmodyfikowane POJO z ObservableList, aby wywołać aktualizację ListView. Czy istnieje możliwość wyświetlenia zmian w POJOS bez obejścia opisanego powyżej?JavaFX: Aktualizacja ListView, jeśli element ObservableList zmienia się
Odpowiedz
ObservableList<String> items = FXCollections.observableArrayList();
ListView lv;
lv.setItems(items);
items.add();
items.remove;
spróbować
list.remove(POJO);
list.add(index,POJO);
nic nowego, prawda? Nawet OP już wspomniał o tym jako o obejściu ... – kleopatra
Istnieje kilka aspektów na swoje pytanie (i nie jestem do końca, który jest problem :-) będę zakładać, że jakoś POJO słuchaczy powiadamiania o zmianach, może być pełnoprawnym językiem JavaBean, który jest zgodny z jego umową powiadamiania poprzez wywoływanie zdarzeń propertyChange w razie potrzeby lub w inny sposób - w przeciwnym razie potrzebowałbyś ręcznego wypychania zmiany.
Podstawową metodą uczynienia obiektu FX-ObservableList powiadomieniem własnych odbiorców o mutacjach zawartych elementów jest skonfigurowanie go za pomocą niestandardowego wywołania zwrotnego, które zapewnia szereg obserwowanych obiektów. Jeśli elementy mają FX-właściwości byś zrobił coś takiego:
Callback<Person, Observable[]> extractor = new Callback<Person, Observable[]>() {
@Override
public Observable[] call(Person p) {
return new Observable[] {p.lastNameProperty(), p.firstNameProperty()};
}
};
ObservableList<Person> teamMembers = FXCollections.observableArrayList(extractor);
// fill list
Jeśli pojo oznacza pełnoprawnym rdzeń JavaBeans, jego właściwości muszą być dostosowane do FX-właściwościom f.i. za pomocą JavaBeanProperty:
Callback<PersonBean, Observable[]> extractor = new Callback<PersonBean, Observable[]>() {
List<Property> properties = new ArrayList<Property>();
@Override
public Observable[] call(PersonBean arg0) {
JavaBeanObjectProperty lastName = null;
JavaBeanObjectProperty age = null;
try {
lastName = JavaBeanObjectPropertyBuilder.create()
.bean(arg0).name("lastName").build();
age = JavaBeanObjectPropertyBuilder.create()
.bean(arg0).name("age").build();
// hack around loosing weak references ...
properties.add(age);
properties.add(lastName);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
return new Observable[] {lastName, age};
}
};
ObservableList<Person> teamMembers = FXCollections.observableArrayList(extractor);
// fill list
Uwaga uwaga: bez zachowania silnego odniesienia do dostosowanych właściwości gdzieś, będą szybko śmieci zgromadzone - pojawiają się, a potem nie mają żadnego wpływu na wszystko (znowu wpadania w pułapkę i znowu nie wiem, czy istnieje dobra strategia, aby tego uniknąć).
W przypadku innych sposobów powiadamiania (możliwie gruboziarnistego) można zaimplementować niestandardową kartę: adapter poniżej nasłuchuje wszystkich zmian właściwości fasoli, a słuchanie innych typów zdarzeń będzie zupełnie analogiczne.
/**
* Adapt a Pojo to an Observable.
* Note: extending ObservableValue is too much, but there is no ObservableBase ...
*
* @author Jeanette Winzenburg, Berlin
*/
public class PojoAdapter<T> extends ObservableValueBase<T> {
private T bean;
private PropertyChangeListener pojoListener;
public PojoAdapter(T pojo) {
this.bean = pojo;
installPojoListener(pojo);
}
/**
* Reflectively install a propertyChangeListener for the pojo, if available.
* Silently does nothing if it cant.
* @param item
*/
private void installPojoListener(T item) {
try {
Method method = item.getClass().getMethod("addPropertyChangeListener",
PropertyChangeListener.class);
method.invoke(item, getPojoListener());
} catch (NoSuchMethodException | SecurityException | IllegalAccessException |
IllegalArgumentException | InvocationTargetException e) {
e.printStackTrace();
}
}
/**
* Returns the propertyChangeListener to install on each item.
* Implemented to call notifyList.
*
* @return
*/
private PropertyChangeListener getPojoListener() {
if (pojoListener == null) {
pojoListener = new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
fireValueChangedEvent();
}
};
}
return pojoListener;
}
@Override
public T getValue() {
return bean;
}
}
To Wykorzystanie tak samo jak powyżej (coraz nudne, prawda :-)
Callback<PersonBean, Observable[]> extractor = new Callback<PersonBean, Observable[]>() {
@Override
public Observable[] call(PersonBean arg0) {
return new Observable[] {new PojoAdapter<PersonBean>(arg0)};
}
};
ObservableList<Person> teamMembers = FXCollections.observableArrayList(extractor);
// fill list
Niestety, automatyczne aktualizacje ListView z takim chłodnym liście nie będzie działać niezawodnie powodu a bug that's fixed only in jdk8. We wcześniejszych wersjach, jesteś z powrotem na placu 1 - jakoś słuchać zmiany, a następnie ręcznie zaktualizować listę:
protected void notifyList(Object changedItem) {
int index = list.indexOf(changedItem);
if (index >= 0) {
// hack around RT-28397
//https://javafx-jira.kenai.com/browse/RT-28397
list.set(index, null);
// good enough since jdk7u40 and jdk8
list.set(index, changedItem);
}
}
Dziękuję bardzo za zastrzeżenie, gdzie o tym przeczytałeś? Czy mógłbyś to udostępnić tutaj :) – TuanAnh207
Można ręcznie wyzwolić ListView.EditEvent
— co spowoduje ListView
zaktualizować — przez wywołanie metody ListView::fireEvent
odziedziczone po javafx.scene.Node
. Na przykład,
/**
* Informs the ListView that one of its items has been modified.
*
* @param listView The ListView to trigger.
* @param newValue The new value of the list item that changed.
* @param i The index of the list item that changed.
*/
public static <T> void triggerUpdate(ListView<T> listView, T newValue, int i) {
EventType<? extends ListView.EditEvent<T>> type = ListView.editCommitEvent();
Event event = new ListView.EditEvent<>(listView, type, newValue, i);
listView.fireEvent(event);
}
lub jako jedną wkładką,
listView.fireEvent(new ListView.EditEvent<>(listView, ListView.editCommitEvent(), newValue, i));
Oto przykładowa aplikacja wykazać jego wykorzystanie.
/**
* An example of triggering a JavaFX ListView when an item is modified.
*
* Displays a list of strings. It iterates through the strings adding
* exclamation marks with 2 second pauses in between. Each modification is
* accompanied by firing an event to indicate to the ListView that the value
* has been modified.
*
* @author Mark Fashing
*/
public class ListViewTest extends Application {
/**
* Informs the ListView that one of its items has been modified.
*
* @param listView The ListView to trigger.
* @param newValue The new value of the list item that changed.
* @param i The index of the list item that changed.
*/
public static <T> void triggerUpdate(ListView<T> listView, T newValue, int i) {
EventType<? extends ListView.EditEvent<T>> type = ListView.editCommitEvent();
Event event = new ListView.EditEvent<>(listView, type, newValue, i);
listView.fireEvent(event);
}
@Override
public void start(Stage primaryStage) {
// Create a list of mutable data. StringBuffer works nicely.
final List<StringBuffer> listData = Stream.of("Fee", "Fi", "Fo", "Fum")
.map(StringBuffer::new)
.collect(Collectors.toList());
final ListView<StringBuffer> listView = new ListView<>();
listView.getItems().addAll(listData);
final StackPane root = new StackPane();
root.getChildren().add(listView);
primaryStage.setScene(new Scene(root));
primaryStage.show();
// Modify an item in the list every 2 seconds.
new Thread(() -> {
IntStream.range(0, listData.size()).forEach(i -> {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(listData.get(i));
Platform.runLater(() -> {
// Where the magic happens.
listData.get(i).append("!");
triggerUpdate(listView, listData.get(i), i);
});
});
}).start();
}
public static void main(String[] args) {
launch(args);
}
}
Powinieneś zająć listę obserwowalną i zaktualizować obiekt używając list.set (selectedIndex, object); Mój przykład pokazuje przycisk z metodą uchwytu. W ten edytowany lista użytkowników w fx viewtable
Button commit = new Button("Commit");
commit.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent evt) {
int selectedIndex = tableView.getSelectionModel().getSelectedIndex();
User user = tableView.getSelectionModel().getSelectedItem();
user.setId(Integer.parseInt(idTF.getText()));
user.setName(nameCB.getValue());
user.setSurname(srnameTF.getText());
user.setAddress(addressTF.getText());
service.getUsers().set(selectedIndex, user);
tableView.toFront();
}
});
Korzystanie Francis pomysł robiłam:
list.set(list.indexOf(POJO), POJO);
nie może być najlepszym rozwiązaniem, ale działało.
Ponieważ Java 8u60 ListView oficjalnie obsługuje metodę refresh()
w celu ręcznej aktualizacji widoku. JavaDoc:
Jest to przydatne w przypadkach, gdy podstawowe źródło danych uległo zmianie w sposób, który nie jest obserwowany przez samą ListView.
Pomyślnie użyłem tej metody dla tego wydania, aby zaktualizować zawartość elementów w ListView.
- 1. JavaFX - ListView Element z przyciskiem obrazu
- 2. Odznacz element w javafx ListView na kliknij
- 3. JavaFX - CSS stylizacji ListView
- 4. JavaFX wybierz pozycję w ListView
- 5. Jak monitorować zmiany obiektów zawartych w obiekcie ObservableList JavaFX
- 6. Android ListView Live Aktualizacja
- 7. Wybierz element kombo w JavaFX 2
- 8. Aktualizacja układu UICollectionView - wielkość elementu nie zmienia się
- 9. Aktualizacja Android ListView za pomocą SimpleCursorAdapter
- 10. Android element ListView kulminacyjnym programowo
- 11. JavaFX TabPane: Jak słuchać wyboru zmienia
- 12. Xamarin.Forms - ListView nie aktualizuje gdy dane zmienia
- 13. Edytuj element w JavaFX TreeView
- 14. Android: jak ukryć element ListView?
- 15. Odznacz wybrany element w ListView
- 16. Aparat nie zastępuje starego obrazu, jeśli zmienia się orientacja
- 17. resetuje WPF ComboBox zaznaczony element, gdy element source zmienia
- 18. Jak znaleźć element o identyfikatorze w JavaFX?
- 19. Funkcja MySQL do wstawiania rekordów, jeśli aktualizacja się nie powiedzie?
- 20. Aktualizacja mysql ze jeśli warunek
- 21. Jak wypełnić okno listy w JavaFX przy użyciu obiektów niestandardowych?
- 22. Niestandardowy element listy do ListView android
- 23. JavaFX: Aktualizacja elementów interfejsu w klasie kontrolera z wątku
- 24. Wypełnianie Listview & Imagelist Wybrany element pomyłki C#
- 25. Jak ukryć element, jeśli istnieje inny element?
- 26. match_parent nie działa dla ListView, jeśli ListView jest wewnątrz NestedScrollView
- 27. Znajdź javascript, który zmienia element DOM
- 28. Animować każdy element Listview podczas wyświetlania
- 29. Javafx 2 TreeView - ukryj element root
- 30. ListView nie przewija się
czy możesz wysłać swoją klasę POJO? – invariant
Istnieje podejście opisane na forum Oracle [tutaj] (https://forums.oracle.com/thread/2244635), które opisuje rozwiązanie tego problemu. – ThomasMH
Podejście zaproponowane przez kleopatra jest najnowszym i najprostszym rozwiązaniem. Chcę tylko dodać, że 'ekstraktor' może zwrócić wszelkie obserwowalne obiekty, które chce. I że może być bardzo zwięźle napisane z lambdami. – HRJ