JavaFX ListView in Kombination mit TextField

BigMemo007

Aktives Mitglied
Hallo Comunity,

habe folgenden Codes:

In der Gui:

Java:
Button addItem = new Button();
ListView<TextField> lv = new ListView<>();

addItem.setOnAction(new EventHandler<ActionEvent>() {

            @Override
            public void handle(ActionEvent arg0) {
                
                lv.getItems.add(new MyTF);

            }
        });

Im MyTF

Java:
public class MyTF{
    
     public MyTF(){
        setPromptText("Wie soll der Eintrag heißen");
        setEditable(true);
        
         //Der Code hier bewirkt, wenn auf Enter gedrückt wird dass der Text sozusagen
         //festgehalten wird, in dem editable auf false gesetzt wird
        setOnAction(new EventHandler<ActionEvent>() {

            @Override
            public void handle(ActionEvent arg0) {

                setEditable(false);

            }
        });
        
     }
 }


So, damit kann ich schon mit addItem in meiner ListView ein leeres TextField generieren, das beschreiben (Name des Items) und mit Enter quasi Namen akteptieren.

Soweit so gut, aber das ganze ist noch nicht perfekt.

1. Wenn man die ListView, nicht ein Item in der ListView, anklickt, bekommt es einen blauen Rahmen. Kann ich den wegmachen? Ich hab keine Möglichkeit gefunden bis jetzt, nur auf diesen Rahmen zugreifen zu können.

2. Wenn ein Item angeklickt wird, soll die Celle einen blauen Hintergrund bekommen, so dass die Markierung viel deutlicher ausfällt. Alternativ kann auch das Textfeld einen blauen Hintergrund bekommen. Wenn aber die Markierung weg ist ( der User hat woanders gecklickt), soll der blaue Hintergrund wieder weg.

3. Wenn User nach Texteingabe im neuen TextFeld woandershin mit der Maus klickt, also nicht auf Enter drückt, soll trotzdem der Text akzeptiert werden, quasi das Textfeld auf setEditable = false gesetzt werden.


Ich habe verdammt viele wege probiert, hat aber alles nicht so geklappt, wie es sein soll/muss. Jetzt habe ich Kopfvoll... 🙁((
 
Ich habe alle meine Probleme nach einmal drüber schlafen gelöst 🙂))

Folgende Testklasse habe ich geschrieben, wo alles super gelöst ist. Das kann ich in meine Programm so integrieren.


[CODE lang="java" highlight="37,"]public class Main extends Application {


@Override
public void start(Stage primaryStage) {
try {
BorderPane root = new BorderPane();

ListView<Object> lv = new ListView<Object>();
root.setCenter(lv);

Button btn = new Button("Eintrag hinzufügen");
BorderPane.setAlignment(btn, Pos.CENTER);
root.setBottom(btn);

btn.setOnAction(new EventHandler<ActionEvent>() {

@Override
public void handle(ActionEvent arg0) {
HBox hbox = new HBox(20);
TextField tf = new TextField();
Button ok = new Button("OK");
Button edit = new Button("umb");
edit.setVisible(false);

hbox.getChildren().addAll(tf, ok, edit);

lv.getItems().add(hbox);

tf.setOnMouseClicked(new EventHandler<MouseEvent>() {

@Override
public void handle(MouseEvent arg0) {
if (arg0.getButton() == MouseButton.PRIMARY) {
//wenn auf Textfeld gecklickt wird, wird entsprechende Zeile ausgewählt / markeirt
int index = lv.getItems().indexOf(hbox);
lv.getSelectionModel().select(index);

System.out.println(tf.getText());
}
}
});

ok.setOnAction(new EventHandler<ActionEvent>() {

@Override
public void handle(ActionEvent arg0) {
tf.setEditable(false);
ok.setVisible(false);
edit.setVisible(true);

edit.setOnAction(new EventHandler<ActionEvent>() {

@Override
public void handle(ActionEvent arg0) {
tf.setEditable(true);
edit.setVisible(false);
ok.setVisible(true);

}
});
}
});

}
});


Scene scene = new Scene(root,400,400);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}

public static void main(String[] args) {
launch(args);
}
}
[/CODE]

Kann man diesen Code noch kompakter gestatlten (meine jetzt nicht Lambda-Ausdrücke)? D.h. Methoden die ich noch nicht kenne, aber meine Listview genauso gestalten? Naja, blöde Frage ich weiß. Aber es sind wohl gerade die Glücksgefühle die mich überwältigen, weil ich diesen (für Profis pipifix) Code hinbekommen habe 🙂🙂😎😎😛😛
 
Erst einmal: Glückwunsch, dass du es geschafft hast. Hier kurz meine Verbesserungsvorschläge:
  • Nutze Lambdas anstelle von anonymen Klassen
    Java:
    button.setOnAction(EventHandler<ActionEvent>() { @Override
        public void handle(ActionEvent e) { /* do something */}
    });
    
    button.setOnAction(e -> { /* do something */});
  • Setze den edit-Handler nicht im EventHandler des ok-Buttons.
  • Deinen Code könnte man z.B. durch so ein Konstrukt hier verkürzen:
    Java:
    Consumer<Boolean> function = onOk -> {
        tf.setEditable(!onOk);
        ok.setVisible(!onOk);
        edit.setVisible(onOk);
    };
    ok.setOnAction(e -> function.accept(true));
    edit.setOnAction(e -> function.accept(false));
Das wär erst mal alles.

#Edit: den Teil mit dem MouseClicked-Listener habe ich mir jetzt nicht im Detail angeschaut. Aber auch hier kannst du ein Lambda nehmen.
 
Erst einmal: Glückwunsch, dass du es geschafft hast. Hier kurz meine Verbesserungsvorschläge:
  • Nutze Lambdas anstelle von anonymen Klassen
    Java:
    button.setOnAction(EventHandler<ActionEvent>() { @Override
    public void handle(ActionEvent e) { /* do something */}
    });
    
    button.setOnAction(e -> { /* do something */});
  • Setze den edit-Handler nicht im EventHandler des ok-Buttons.
  • Deinen Code könnte man z.B. durch so ein Konstrukt hier verkürzen:
    Java:
    Consumer<Boolean> function = onOk -> {
    tf.setEditable(!onOk);
    ok.setVisible(!onOk);
    edit.setVisible(onOk);
    };
    ok.setOnAction(e -> function.accept(true));
    edit.setOnAction(e -> function.accept(false));
Das wär erst mal alles.

#Edit: den Teil mit dem MouseClicked-Listener habe ich mir jetzt nicht im Detail angeschaut. Aber auch hier kannst du ein Lambda nehmen.

@dzim Danke für die Tipps. Habe die Lambdas umgesetzt. Das Functional Interface Consumer noch nicht, werde es aber bei Gelegenheit noch machen. Es wäre für mich al Neuling im Funcitonal Interfaces erstmal verwirrend.

Ich habe noch Code für das Speichern meiner ListView Inhalte geschrieben. Die Klasse ist irgendwie mMn unübersichtlich geworden, wenn ich Code von Profis vergleiche. Aber vielleicht ist es ja noch im Rahmen. Ich weiß es halt nicht. Deswegen werde ich ein neues Thread aufmachen und mal euch fragen, wie ihr den Code so findet.
 
Also zum Thema unübersichtlich: Ich habe manche Klassen, oder in Kotlin auch Files, mit weit über 1000 Zeilen.
In bestimmten Situationen (bei mir z.B. eine "Domain Specific Language") kannst du es gar nicht verhindern. Mach dir darum erst mal nicht den Kopf. Und ich habe auch Jahre gebraucht, bis ich wirklich so viel Disziplin erlangt habe, Code zu trennen und, wenn möglich, zu refaktorisieren, wenn es sinnvoll ist.

Glaub mir einfach: Das kommt mit der Zeit. Und - sofern möglich - werden wir dir Tipps geben, was du verbessern kannst, oder wo du recherchieren solltest. Oder Code-Schnipsel liefern, die dir hoffentlich helfen.

In meiner Erfahrung sind die meisten Entwickler recht sozial, wenn es um das Teilen von Erfahrungen und Tipps geht, auch wenn einige es schon wieder fast religiös betrachten, wie Code geschrieben werden müsste.
 

Zurück
Oben