Zuerst müssen wir identifizieren, welche Probleme wir lösen wollen. Das größte Problem ist die Erstellung einfacher Event-Bindings, die in früheren Java-Versionen die Verwendung von inneren Klassen benötigten. Dies kann in den meisten Fällen durch einen Lambda-Ausdruck für Single-Method-Listener-Interfaces ersetzt werden, für Multi-Method-Interfaces benötigen Sie Adapter, wie in this oder that Q & A beschrieben, aber dies muss nur einmal gemacht werden.
Das andere Problem ist die Struktur des Initialisierungscodes. Prinzipiell funktioniert imperativer Code gut. Wenn Sie jedoch einige Eigenschaften einer Komponente ändern möchten, die Sie einem Container hinzufügen möchten, müssen Sie container.add(new ComponentType());
ändern, um eine neue lokale Variable einzufügen, die von den nachfolgenden Anweisungen verwendet werden kann. Das Hinzufügen zu einem Container selbst erfordert auch das Speichern in einer Variablen. Während Java es erlaubt, den Geltungsbereich lokaler Variablen durch geschweifte Klammern zu begrenzen, ist das Ergebnis immer noch schwerfällig.
Dies ist der beste Ausgangspunkt. Wenn wir z.B.
public class SwingBuilder {
public static <T> T build(T instance, Consumer<T> prepare) {
prepare.accept(instance);
return instance;
}
public static <T extends Container> T build(
T instance, Consumer<T> prepare, Component... ch) {
return build(build(instance, prepare), ch);
}
public static <T extends Container> T build(T instance, Component... ch) {
for(Component c: ch) instance.add(c);
return instance;
}
}
Diese einfachen generischen Methoden sind bereits leise, weil sie miteinander kombiniert werden können. Mit import static
kann eine Verwendung Website aussehen
JFrame frame = build(new JFrame("Example"),
f -> {
f.getContentPane().setLayout(
new BoxLayout(f.getContentPane(), BoxLayout.LINE_AXIS));
f.setResizable(false);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
},
build(new JLabel("\u263A"), l -> l.setFont(l.getFont().deriveFont(36f))),
Box.createHorizontalStrut(16),
build(new JPanel(new GridLayout(0, 1, 0, 5)),
new JLabel("Hello World"),
build(new JButton("Close"), b -> {
b.addActionListener(ev -> System.exit(0));
})
)
);
frame.pack();
frame.setVisible(true);
Im Vergleich zu Groovy, müssen wir noch eine Variable verwenden, das Ziel des Verfahrens Anrufungen auszudrücken Eigenschaften zu ändern, aber diese Variable kann so einfach wie name ->
deklariert werden Typ verwendet Rückschluss bei der Implementierung der Consumer
über Lambda-Ausdruck. Außerdem ist der Gültigkeitsbereich der Variablen automatisch auf die Dauer der Initialisierung beschränkt.
Mit diesem Startpunkt können Sie spezielle Methoden für häufig verwendete Komponenten und/oder häufig verwendete Eigenschaften sowie die bereits erwähnten Factory-Methoden für Listener mit mehreren Methoden hinzufügen. Z.B.
public static JFrame frame(String title, Consumer<WindowEvent> closingAction,
Consumer<? super JFrame> prepare, Component... contents) {
JFrame f = new JFrame(title);
if(closingAction!=null) f.addWindowListener(new WindowAdapter() {
@Override public void windowClosing(WindowEvent e) {
closingAction.accept(e);
}
});
if(prepare!=null) prepare.accept(f);
final Container target = f.getContentPane();
if(contents.length==1) target.add(contents[0], BorderLayout.CENTER);
else {
target.setLayout(new BoxLayout(target, BoxLayout.PAGE_AXIS));
for(Component c: contents) target.add(c);
}
return f;
}
Aber ich denke, das Bild ist klar.
Sollte es möglich sein, in die Nähe zu kommen, werden Sie nicht die Nettigkeit des missingProperty Zeugs bekommen, um eine Kontrolle über den Namen zu bekommen ... Ich würde jedoch JavaFX als Ziel haben, da Swing auf dem Weg zur Tür ist –