简体   繁体   中英

Adding children to JavaFX Control/Parent classes

Added children used to be visible in all my subclasses, like in the example here.

Due to some recent changes I made (in a big porting of very old Java SWING code) children are still visible in TextField or TextArea , for example, but not in Button (ish) controls, even though additions are in the list.

Obviously, I don't understand the policy governing the addition of children. Any ideas?

public class QButton extends Button  {
    ...
    public QButton(String str) {
        ...
        ObservableList<Node> children = getChildren();
        System.out.println("Children: " + children);

        Rectangle rect = new Rectangle(0., 0., 200., 200.);
        rect.setStroke(Color.RED);
        rect.setFill(Color.TRANSPARENT);
        rect.setStrokeWidth(2);
        getChildren().add(rect);
        rect.setVisible(true);

        children = getChildren();
        System.out.println("Children: " + children);
    }
    ...

In JavaFX, UI Controls use the MVC (Model/View/Controller) pattern. The Control itself (eg a Button ) is the Model, and rendering is delegated to the View which is called Skin in JavaFX. The node graph of the Control is maintained by the View (the Skin), hence it is not possible to simply modify the children of the Control. See https://wiki.openjdk.java.net/display/OpenJFX/UI+Controls+Architecture for a good overview of the architecture.

One alternative might be to put the Button and the Rectangle into a Group so that the Rectangle overlays the Button , and then use the Group in your application's scene graph.

Otherwise, if you really want to subclass Button and add the Rectangle there, you need to create a custom skin for your Button . The following example shows how this can be done - one drawback is that the base skin class for Buttons ( ButtonSkin ) is not public, hence you need to extend a non-public class (which you normally should NEVER do, but I currently do not see an alternative besides duplicating a whole bunch of code from com.sun.javafx ). In Java 9, the skin classes will be made public in the javafx.scene.control.skin package (see http://download.java.net/jdk9/jfxdocs/javafx/scene/control/skin/ButtonSkin.html for the ButtonSkin ).

The following code shows how it could be done:

package com.example;

import javafx.scene.control.Button;
import javafx.scene.control.Skin;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;

// DO NOT DO THIS - com.sun is not public!
// (However, it seems that there is currently no alternative besides duplicating the code)
// With Java 9, change to javafx.scene.control.skin.ButtonSkin
class QButtonSkin extends com.sun.javafx.scene.control.skin.ButtonSkin {

    private Rectangle rect = null;

    public QButtonSkin(Button button) {
        super(button);
    }

    @Override
    protected void updateChildren() {
        super.updateChildren();

        if (rect == null) {
            rect = new Rectangle(0., 0., 200., 200.);
            rect.setStroke(Color.RED);
            rect.setFill(Color.TRANSPARENT);
            rect.setStrokeWidth(2);
        }
        getChildren().add(rect);
    }
}

public class QButton extends Button {
    public QButton(String str) {
        super(str);
    }

    @Override
    protected Skin<?> createDefaultSkin() {
        Skin<?> result = new QButtonSkin(this);
        return result;
    }
}

Essentially, QButton creates a new default skin (you could also do that in CSS). The new Skin overrides updateChildren() to add the rectangle to the control's child nodes. Here we need to consider the calling sequence - the super class's constructor calls updateChildren() itself, so we can not create the Rectangle in our Skin's constructor.

Depending on your use case, you might need to add some additional code like managing the bounds and geometry of QButtonSkin .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM