Hallo Liebe byte-welt Community :),
ich bin in meinem JavaFX Projekt auf ein Problem gestoßen.
Und zwar habe ich eine Klasse FavString, sie stellt bspw. eine Kategorie mit dem namen text dar, isFavorite enthält die Information ob es als Favorit gespeichert wurde… Logisch
public class FavString
{
private BooleanProperty isFavorite;
private StringProperty text;
}```
Nun möchte ich aber wenn jemand die Favoriten in der GUI bearbeitet die Datenbank aktualisieren.
Der Benutzer kann beide Properties ändern, also text und isFavorite.
Ich habe mir auch schon überlegt auf beiden Properties jeweils einen ChangeListener zuzuweisen, doch muss innerhalb des Listeners immer der Inhalt von text immer bekannt sein (sonst kann DB nicht aktualisiert werden).
Das ist nur möglich wenn ich die ChangeListener als Inner-classes definiere (da ich sonst keinen Zugriff auf text habe), nicht wahr?
Dann müsste ich aber auch jedem FavString eine Referenz auf mein "Backend-Objekt" (bietet Datenbank Zugriff) übergeben..
Ich weiß nicht wie "sauber" das dann ist..
Ich habe das "gelöst" indem ich für FavString selbst einen ChangeListener erlaube/erstelle, was wiederum mindestens genauso unsauber auf mich wirkt und ein weiteres Problem hat:
Es werden bei jeder Änderung 2 neue FavStrings erzeugt. (Soll das mich überhaupt interessieren? Eine Änderung wird vom Benutzer in der GUI gemacht und keine 100 Änderungen/Sekunde)
Der FavString changeListener wird in einer anderen Klasse, welche ObservableLists mit FavStrings enthält, dem Favstring hinzugefügt.
FavString:
```/*
* Unwichtige Methoden wie getter, toString
* und konstruktoren zur besseren Lesbarkeit gelöscht konstruktoren haben nur übergebene Werte gesetzt..)
*/
public class FavString
{
private BiConsumer<FavString, FavString> changeListener; //Der "ChangeListener" bzw genauer FavStringChangeListener
private final StringProperty text = new SimpleStringProperty();
private final BooleanProperty isFavorite = new SimpleBooleanProperty(false);
private void fireChangeEvent(FavString oldVal, FavString newVal)
{
if (changeListener == null)
return;
changeListener.accept(oldVal, newVal);
}
//ChangeListener auf beide Properties setzen damit sie den übergebenen listener aufrufen..
//Die Listener erstellen neue FavStrings damit der "neue" Listener Zugriff auf Informationen beider Properties hat..
public void setChangeListener(BiConsumer<FavString, FavString> listener)
{
isFavorite.addListener((ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) ->
{
FavString oldStr = new FavString(oldValue, this.text.getValue());
FavString newStr = new FavString(newValue, this.text.getValue());
fireChangeEvent(oldStr, newStr);
});
text.addListener((ObservableValue<? extends String> observable, String oldValue, String newValue) ->
{
FavString oldStr = new FavString(isFavorite.getValue(), oldValue);
FavString newStr = new FavString(isFavorite.getValue(), newValue);
fireChangeEvent(oldStr, newStr);
});
this.changeListener = listener;
}
}```
FavStringChangeListener:
```public class FavStringChangeListener implements BiConsumer<FavString, FavString>
{
private final TablePTC table; //Identifiziert Datenbanktabelle
private final PTCAccessor ptc; //bietet Zugriff auf Datenbank
public FavStringChangeListener(TablePTC tbl, PTCAccessor ptca)
{
this.table = tbl;
this.ptc = ptca;
}
/*
* Keiner der übergebenen Parameter ist der Originale Favstring
* Original könnte ich im Konstruktor übergeben, aber.. siehe Problem unten
*/
@Override
public void accept(FavString oldVal, FavString newVal)
{
boolean oldIsFavorite = oldVal.getBooleanProperty().get();
boolean newIsFavorite = newVal.getBooleanProperty().get();
String oldText = oldVal.getStringProperty().get();
String newText = newVal.getStringProperty().get();
try
{
//isFavorite status changed
if (oldIsFavorite != newIsFavorite)
ptc.setFavoritePC(table, newIsFavorite, newText);
else if(!oldText.equals(newText)) //text changed
ptc.updatePTC(table, oldText, newText);
}
catch (SQLException ex)
{
//Fehlernachricht anzeigen
//Werte von Original zurücksetzen
}
}
}
Bei beiden Ansätzen ergibt sich jedoch ein noch Problem, das weswegen ich überhaupt Frage:
Wenn eine Exception bei der Aktualisierung der Datenbank auftritt sollen die Daten des FavStrings zurückgesetzt werden.
Das kann ich im ChangeListener machen klar, aber wenn ich die Daten zurücksetzen will (also wieder verändern) wird wieder der ChangeListener aufgerufen was wohl zu einem undefinierbaren Problem führen kann…
Wie kann ich das umgehen?
Eine extra Methode erstellen um die Daten zu verändern ohne den Listener aufzurufen (Listener löschen, Daten ändern, Listener hinzufügen)?
Ist das überhaupt eine kluge Idee die Datenbank über den ChangeListener zu aktualisieren?
Wie kann ich das sonst machen? Der Controller-Klasse der Oberfläche das Backend-Objekt übergeben und die Datenbank von dort aus aktualisieren?
Bin über jede Hilfe, Kritik und Denkanstöße dankbar
- Beliar