JavaFX Nodes platzieren

White_Fox

Top Contributor
Moin allerseits

Ein ähnliches Theater wie ich es neulich mit Swing hatte (und ihr mir so toll geholfen habt) verfolgt mich nun mit JavaFX: Wie platziere ich Nodes vernünftig?

Das, was ich vorhabe, soll mal eine tabellenartige Übersicht werden, zunächst will ich aber erstmal eine Art Spaltenheader dafür bauen. Etwas ganz einfaches, eigentlich nur ein Rechteck mit Text, zentriert. Also ein Region-Objekt erstellt, Hintergrund gesetzt, und dann ein Textobjekt eingefügt. Hier erstmal Code und CSS:

Java:
class StamptableHeader extends Region {

    StamptableHeader(String text) {
        super();
        getStylesheets().add(getClass().getResource("centerviewstamptable.css").toExternalForm());
        getStyleClass().add("stamptable-header");
        initGraphics(text);
    }

    private void initGraphics(String text) {
        Text headerText = new Text(text);

        layoutInArea(headerText,
                0, 0,
                headerText.getLayoutBounds().getWidth(),
                headerText.getLayoutBounds().getHeight(),
                0,
                HPos.CENTER,
                VPos.CENTER);

        getChildren().addAll(headerText);
    }
}

CSS:
.stamptable-header {
    -fx-background-color: -fx-box-border, lightgray;
    -fx-border-color: black;
    -fx-font-weight: bold;
    -fx-padding: 0 0 0 10; /* bzw. -fx-padding: 0 10 0 10; */
}

StamptableHeader>Text {
    -fx-font-weight: bold;
    -fx-text-alignment: center;
}

Ein Region-Objekt hat eine Contentarea. Diese wird, so verstehe ich das zumindest, von meinem Textobjekt ausgefüllt. Irgendwo in der Doku habe ich gelesen, das der Inhalt auch aus der Contentarea hinaus gehen kann. Um die Contentarea herum gibt es die Paddingarea, um einen Rand um die Contentarea definieren zu können. Erklärt hier:

Jetzt will ich in meinem CSS das Padding einstellen. Aber egal was ich da mache: Ich bekomme seitliches Padding stets immer nur auf der rechten Seite. Ich mache mal zwei Bilder und schreibe dazu, was ich im CSS eingestellt habe:

-fx-padding: 0 0 0 10; (soll eigentlich Padding auf der linken Seite liefern, ist aber stattdessen rechts):
padding1.png


-fx-padding: 0 10 0 10; (soll eigentlich Padding auf der linken und der rechten Seite liefern, aber stattdessen ist es rechts nun noch breiter):
padding2.png

Ich habe nun ziemlich viel ausprobiert, aber ich bekomme das Padding absolut nicht sauber links und rechts verteilt. Was ich machen kann, ist, das Textobjekt in der layoutInArea()-Methode weiter rechts zu platzieren. Das verschafft mir auf der linken Seite zwar scheinbar Abstand, hat mit Padding aber nix zu tun: die rechte Seite verhält sich unabhängig davon exakt gleich und summiert die Paddingabstände für links und rechts dort.

Ich habe auch probiert, einen LayoutManager dazuwischenzuschalten und diesen die Platzierung zu überlassen, aber das hat auch nicht funktioniert. Außerdem würde ich das auch deshalb gerne selber machen um das mal zu lernen.

Sieht vielleicht jemand, was ich da falsch mache?
 

White_Fox

Top Contributor
So...ich denke, ich habe eine Lösung gefunden. Ob es DIE Lösung ist werde ich in der Zukunft sehen.

Zuerst einmal:
Wird die Methode initGraphics() aufgerufen, sind noch keinerlei CSS-Eigenschaften geladen. Wenn ich mit dem Debugger in dieser Methode angehalten habe, haben z.B. getPadding().getLeft() nur 0.0 zurückgeliefert, völlig egal was ich in der CSS zu stehen habe.

Um das Objekt zu layouten – und das will ich hier ja –, bringt die Klasse Region eine Methode mit, die muß jedoch überschrieben werden, und zwar protected void layoutChildren(){}. Also:

Java:
@Override
    protected void layoutChildren() {
        layoutInArea(headerText,
                getPadding().getLeft(), 0,
                headerText.getLayoutBounds().getWidth(),
                headerText.getLayoutBounds().getHeight(),
                0,
                HPos.CENTER,
                VPos.CENTER);
    }

Man sollte meinen daß jetzt alles gut ist, aber Pustekuchen - das ganze Region ist immer noch zu lang und hat rechts zuviel Abstand, völlig egal was ich in die CSS schreibe. getPadding().getLeft() und auch getPadding().getRight() liefern zwar nun das, was in der CSS steht, trotzdem ist auf der rechten Seite mehr Abstand als ich will.

Das wird erst besser, wenn ich wenigstens die bevorzugte Weite angebe, die gesamte Methode also lautet:
Java:
    @Override
    protected void layoutChildren() {
        setPrefWidth(getPadding().getLeft() + headerText.getLayoutBounds().getWidth() + getPadding().getRight());
        
        layoutInArea(headerText,
                getPadding().getLeft(), 0,
                headerText.getLayoutBounds().getWidth(),
                headerText.getLayoutBounds().getHeight(),
                0,
                HPos.CENTER,
                VPos.CENTER);
    }

Das wird vermutlich auch erstmal nur vorläufig sein, sehr wahrscheinlich werde ich mit dem Layout noch viel "Spaß" haben. Aber zumindest funktioniert es jetzt so, wie es für den ersten Schuß geplant habe.
 

Robert Zenz

Top Contributor
Nur so als Anmerkung, es gibt (gab?) JVx-JavaFX, das hat ebenfalls eine solche Erweiterungsschicht wie fuer Swing. Da gibt es unter anderem auch die FXFormPane welche gleich wie das Swing FormLayout funktioniert.

Um auf dein Problem zurueck zu kommen, ich glaube die Region hat keine Ahnung von Padding und aehnliches, und klatscht die Kinder einfach so auf 0/0. Du brauchst einen Container welche auch auf das Padding achtet...aber frag' mich bitte nicht welche das sind. Vermutlich wird eine einfache Pane aber schon reichen.
 

White_Fox

Top Contributor
Um auf dein Problem zurueck zu kommen, ich glaube die Region hat keine Ahnung von Padding und aehnliches, und klatscht die Kinder einfach so auf 0/0. Du brauchst einen Container welche auch auf das Padding achtet...aber frag' mich bitte nicht welche das sind.
Die Region hat auf jeden Fall die Eigenschaft Padding. Aber sie scheint es nicht weiter zu verwalten. Das Koordinatensystem ignoriert das Padding jedenfalls, das muß man selber einhalten.

So jedenfalls mein Kenntnisstand nach meinen bisherigen Versuchen.

Ich will da eigentlich auch gar nicht groß herumlayouten, das sollen später mal Spaltenheader werden. Evt. soll der Benutzer die Spaltengröße auch mal ändern können, aber für den Anfang verzichte ich auch darauf.

PS: Danke für den Hinweis mit JVx. Ich wußte gar nicht daß es das auch für JavaFX gibt.

PPS: Es gibt übrigens, sicher interessant für den ein oder anderen, in JavaFX auch ein SwingNode. Um Swingkram in JavaFX anzeigen zu können.
 

Robert Zenz

Top Contributor
PS: Danke für den Hinweis mit JVx. Ich wußte gar nicht daß es das auch für JavaFX gibt.
Es gab irgendwo auch noch eine Vaadin Anbindung, aber die war damals fuer Vaadin 8, keine Ahnung ob das jemals aktualisiert wurde. Ich finde, ehrlich gesagt, auch gerade das Projekt dazu nicht mehr. Kann gut sein dass es schon immer Teil von VisionX, also dem kommerziellen Produkt, war.

JVx selbst ist GUI-Framework unabhaengig konzipiert, und zumindest schein es noch eine ReactUI und Flutter Anbindung zu geben, aber da bin ich schon lange raus.

PPS: Es gibt übrigens, sicher interessant für den ein oder anderen, in JavaFX auch ein SwingNode. Um Swingkram in JavaFX anzeigen zu können.
Ich kann mir erinnern, man konnte JavaFX in Swing einbetten und auch umgekehrt. Das ist natuerlich praktisch wenn man etwas was nur in dem einen laeuft aber man gerade eine Applikation in dem anderen baut.

Die Region hat auf jeden Fall die Eigenschaft Padding. Aber sie scheint es nicht weiter zu verwalten. Das Koordinatensystem ignoriert das Padding jedenfalls, das muß man selber einhalten.
Ja, das ist auch mein Gedanke. Ein Pane beachtet diese eventuell schon, bin ich mir aber auch nicht sicher.
 

White_Fox

Top Contributor
So langsam verstehe ich, wie JavaFX funktioniert. Eigentlich ist es wirklich gar nicht so schwer.

Neben protected void layoutChildren() sollten auch noch die Methoden rotected double computePrefHeight(double width) und protected double computePrefWidth(double height) überschrieben werden. Diese werden zu gegebener Zeit vom JavaFX Scenegraph aufgerufen.

Was die Methoden machen ist selbsterklärend. In protected void layoutChildren() legt man fest, welche Kindernodes man wo haben will und wie groß diese sein sollen. Welchen Platz man dafür in Höhe und Breite hat kann man mit getWidth() ganz einfach feststellen, man beachte daß es kein Gegenstück wie setWidth() oder so gibt.

Mit diesem Wissen (zuzüglich etwas Stylingkram mit CSS) wäre es kein Problem, die Tastatur von hier in JavaFX nachzubauen:

Und bei meinem anderen Projekt, für das ich den Aufriss mache, reicht es schon um Tabellenspalten anzuzeigen.
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
G JavaFX - bugs bei der ermittlung der breite der nodes AWT, Swing, JavaFX & SWT 3
krgewb Swing JTree - Farbe von nodes ändern AWT, Swing, JavaFX & SWT 4
C JavaFX Auf Nodes einer FXML-Datei in start Methode zugreifen AWT, Swing, JavaFX & SWT 5
G JavaFX Width von Nodes einer HBox an Tab width anpassen AWT, Swing, JavaFX & SWT 3
F Swing JTree + DiffUtils // Markierung Nodes aufheben AWT, Swing, JavaFX & SWT 2
M Nodes in JTree nicht anzeigen AWT, Swing, JavaFX & SWT 0
A Swing JTree - Nodes expanden AWT, Swing, JavaFX & SWT 2
1 Swing JTree collapse child nodes AWT, Swing, JavaFX & SWT 4
G JTree entfernt Nodes nicht AWT, Swing, JavaFX & SWT 12
L Swing [JTree] Selektierte Nodes nummerieren AWT, Swing, JavaFX & SWT 6
D Nodes eines statischen JTrees sollen auf Anker (Textmarken) in einer HTML-Datei zeigen AWT, Swing, JavaFX & SWT 8
A Swing JTree Editable einzelne Nodes editierbar machen! AWT, Swing, JavaFX & SWT 2
T JTree - alle Nodes entfernen AWT, Swing, JavaFX & SWT 8
D JTree programmtechnisch mehrere Nodes auswählen. AWT, Swing, JavaFX & SWT 2
D JTree - Zugriff auf Nodes mit Object AWT, Swing, JavaFX & SWT 6
P [JTree] Icon für Nodes und Leafs ändern bzw. löschen AWT, Swing, JavaFX & SWT 2
J JTree - Farbe von nodes ändern AWT, Swing, JavaFX & SWT 2
N JTree Nodes durchsuchen AWT, Swing, JavaFX & SWT 3
M JTree nodes nicht selektierbar AWT, Swing, JavaFX & SWT 2
K Probleme mit der Anzeige eines einzigen Nodes in einem JTree AWT, Swing, JavaFX & SWT 9
T JTree alle nodes expanden AWT, Swing, JavaFX & SWT 4
B JTree - Reihenfolge der Nodes verändern AWT, Swing, JavaFX & SWT 3
P JTree -> nodes ausblenden bzw nicht anzeigen AWT, Swing, JavaFX & SWT 7
W Swing GUI - Komponenten platzieren AWT, Swing, JavaFX & SWT 15
B 2D-Grafik String drehen/platzieren/formatieren in bestimmten Bereich AWT, Swing, JavaFX & SWT 1
B GUI: SWING-Steuerelemente freihand platzieren AWT, Swing, JavaFX & SWT 2
G Swing Buttons in Layouts frei platzieren AWT, Swing, JavaFX & SWT 7
J Swing Componenten übereinander platzieren. AWT, Swing, JavaFX & SWT 17
J LayoutManager BorderLayout - 2 Buttons in SOUTH nebeneinander platzieren? AWT, Swing, JavaFX & SWT 3
D LayoutManager JPanels ohne LayoutManager platzieren AWT, Swing, JavaFX & SWT 6
O Swing JFrame auf Monitor platzieren AWT, Swing, JavaFX & SWT 3
M Elemente in JTabbedPane platzieren AWT, Swing, JavaFX & SWT 7
B Komponenten übereinander platzieren AWT, Swing, JavaFX & SWT 2
G Fenster auf zweitem Monitor platzieren AWT, Swing, JavaFX & SWT 5
R Kleine Panels auf einem großen Panel frei platzieren AWT, Swing, JavaFX & SWT 11
T Markierten Mausbereich erfassen, Text beim Cursor platzieren AWT, Swing, JavaFX & SWT 6
C JLabel in JMenuBar frei platzieren AWT, Swing, JavaFX & SWT 2
O JList platzieren AWT, Swing, JavaFX & SWT 4
S Bild auf JWindow platzieren AWT, Swing, JavaFX & SWT 4
M JFrame in der Mitte platzieren. AWT, Swing, JavaFX & SWT 6
B Zwei "gleiche" Objekte auf einem Frame platzieren AWT, Swing, JavaFX & SWT 2

Ähnliche Java Themen


Oben