JavaFX Kontextmenü - wie am Besten?

Guten Morgen allerseits.

Ich will ein JavaFX-Kontextmenü erstellen. Ich habe das im ersten Anlauf wie in Tutorials gezeigt, als innere Klasse gebaut. Soweit, so gut.

Jetzt sitz ich aber vor dem Problem, daß meine Codemenge völlig ausufert. Die View selber ist schon einige hundert Zeilen lang, und das Kontextmenü erfordert auch einiges an Codeaufwand.
Jetzt hab ich überlegt, das Kontextmenü als normale Klasse ins gleiche Package zu legen und dabei festgestellt, daß es als innere Klasse doch recht praktisch ist. So kann ich auf Instanzvariablen der View gleich zugreifen, Methoden aufrufen, usw. Und rein von der Struktur her ist es als innere Klasse auch richtig, alleinstehend verliert die Klasse völlig ihren Sinn.

Aber: Es wird häßlich unübersichtlich. Ich bin jetzt schon bei fast 700 Codezeilen, dabei ist das noch nichtmal in der Nähe von fertig. Und es ist auch nur die erste Schmalspurversion dessen, was es am Ende mal sein soll, einfach nur um überhaupt erstmal mit einem funktionierenden Programm arbeiten zu können.

Ich bin auch kein großer Freund von Codefolds, da ich mich dabei schnell im Code verlaufe wenn auffällige "Wegmarken" (z.B. größere Ansammelungen von Variablendeklarationen oder längere Kommentare) plötzlich fehlen.

Frage: Wie macht ihr sowas? Meine View ist noch sehr, sehr einfach. Wie macht ihr das bei komplexeren Dingen?
 
K

kneitzel

Also in meinen Augen ist das Separat und gehört da auch nicht wirklich rein und führt doch auch zu einem relativ unsauberen Design weil Du da wild kreuz und Quer zugreifst. Du hast also stark gekoppelte Klassen und da macht es Sinn, dass diese Kopplung reduziert wird.

Ohne Deinen Code gesehen zu haben wäre meine Vermutung, dass eine Auftrennung etwas fehlt.
Ob nun MVC, MVVM, MVP, .... prinzipiell egal, aber eine sinnvolle Aufgliederung ist wichtig und die vereinfacht dann auch oft die weitere Trennung / Aufteilung.

Also evtl. diesbezüglich etwas schauen - bezüglich MVC mit javafx findet sich z.B. http://blog.axxg.de/model-view-controller-mit-javafx/
 
Hättest du eine Idee, wie ich die Kopplung reduzieren kann?

Ich meine, ich kann der Viewklasse einige Getter spendieren, schmeiße die (aktuell als innere Klasse) ausgeführte Kontextmenüklasse raus, und übergebe dieser im Konstruktor die Viewklasse um die Methodenaufrufe weiter ausführen zu können.

Ich sehe dabei aber nicht, wie die Kopplung reduziert wird. Zumindest die Kontextmenüklasse ist ohne View völlig nutzlos, da ich z.B. verschiedene MenuItems je nach aktuellem Zustand aktivieren und deaktivieren will. Das Kotextmenü soll schon so erscheinen, daß nicht gelöscht werden kann wo es nichts zu löschen gibt.

Oder verstehe ich den Begriff Kopplung einfach nur falsch?
 
K

kneitzel

Also arbeite gerne mit Model (Daten und Zustände), View (Anzeige der Daten vom Model, muss natürlich die View und den Controller kennen) und dann dem Controller (Der kennt das Model).

Die View zeigt also nur Dinge aus dem Model an. Ein Datensatz kann dann z.B. Informationen haben, ob diese Datensatz editiert oder gelöscht werden kann. Somit kann die View die Darstellung machen. Wenn aber nun etwas passiert, dann macht die View selbst nichts. Es wird nur die Aktion selbst erfasst und an den Controller gegeben.
Der Controller bekommt also dann die Aktion und führt diese aus um dann die View zu aktualisieren.

Und die einzelnen Komponenten kennen sich oft nicht im Detail, z.B.:
- Der Controller kennt keine Details der View. Aber natürlich kennt er die "View" und weiss: Eine View kann sich aktualisieren oder so .... Der Controller kennt auch keine Elemente der View. Daher bekommt der Controller auch kein "Contextmenü Löschen wurde angeklickt" sondern es kommt eine definierte Aktion "delete marked element". Dabei ist es egal, ob das über ein Kontextmenü ausgewählt wurde, einen Delete Knopf oder die Entfernen Taste.
- Die View kennt den Controller nicht im Detail. Aber es weiss: Der Controller implementiert ein Interface, das ihm erlaubt, bestimmte Events entgegen zu nehmen. (Also z.B. das delete marked element)

Das findet sich in den Prinzipien der Softwareentwicklung etwas wieder: "Man soll gegen Interfaces und nicht gegen Klassen entwickeln". (Wobei Interface nicht wortwörtlich zu nehmen ist, das kann auch eine abstrakte Klasse sein oder so ...

Bezüglich des Zugriffs auf das Model klappt es nicht, denn natürlich müssen View und Controller das Model recht gut kennen, denn es sollen ja die Daten dargestellt und Veränderungen durchgeführt werden.

Das ist halt die Theorie, die da etwas dahinter steckt. Aber ich habe da auch kein konkretes Beispiel. Man sieht es halt in Beispielen eigentlich fast immer alles vermengt.
 
So in etwa hab ich das auch gelöst:
-Das Model implementiert ein Interface für die View (ein paar Getter für Daten und Observer an/abmelden)
-View schickt ein Command-Objekt an den Controller (Controller implementiert auch ein Interface speziell für die View)
-Controller führt das Commandobjekt auf dem Model aus

Mir ging es speziell um die Beziehnung View <> Kontextmenü, alle anderen Klassen sollen nichts davon mitkriegen wo die Commandobjekte herkommen. Die View hält z.B. auch die letzten aktualisierten Daten. Es wäre zwar theoretisch kein Problem, die Daten an mehrere Beobachter (z.B. auch an das Kontextmenü) zu senden, ich es allerdings trotzdem gerne vermeiden. Ich möchte nachher nicht in das Problem reinlaufen, unnötig oft Daten aus dem Model zu holen.

Danke soweit...ich denke, ich weiß was ich als nächstes probieren werde. :)
 
Der Kontext ist eine Tabelle...;)

Aber das Problem hab ich schon abgefrühstückt, war einfacher als ich dachte. :) So in etwa sieht es jetzt aus:

Java:
class TableContextmenu extends ContextMenu implements EventHandler<Event>, ModelObservable{
    
    TableContextmenu(View view, Model model){
        //Melde das Kontextmenü als Observer beim Model an,
        //um abhängig vom Modelzustand bestimmte Einträge aus- oder einzublenden.
    }
    
    private MenuItem item;
    
    item = new MenuItem(lang.getString(2300));
    item.setOnAction(new EventHandler<ActionEvent>() {
        @Override
        public void handle(ActionEvent event) {
            view.callItemmethod(); //Methode in der View, die die entsprechende Aktion auslöst.
        }
    });
}

public class View view implements ModelObservable{
    private Model model;
    
    public View(Model model){
        this.model = model;
    }
    
    //...
    InitTable(){
        SpreadsheetView talbe = new SpreadsheetView();
        //...
        table.setContextMenu(new TableContextmenu(this, model));
        //...
    }
    
    callItemmethod(){
        //Mach irgendwas...
    }
}
So in etwa jedenfalls...ich find das praktisch, da ich später mal noch kurze Tastaturbefehle hinzufügen will. Ich liebe gute GUIs, aber ich hasse Mausschubserei.
 
Passende Stellenanzeigen aus deiner Region:

Neue Themen

Oben