向JavaFX控件/父类添加子类

向JavaFX控件/父类添加子类,java,javafx,Java,Javafx,添加的子类以前在我的所有子类中都是可见的,如这里的示例所示 由于我最近做了一些更改(在一个非常旧的Java SWING代码的大移植中),例如,在TextField或TextArea中仍然可以看到子项,但在按钮(ish)控件中却看不到,即使列表中有添加项 很明显,我不理解关于增加儿童的政策。有什么想法吗 public class QButton extends Button { ... public QButton(String str) { ...

添加的子类以前在我的所有子类中都是可见的,如这里的示例所示

由于我最近做了一些更改(在一个非常旧的Java SWING代码的大移植中),例如,在
TextField
TextArea
中仍然可以看到子项,但在
按钮(ish)控件中却看不到,即使列表中有添加项

很明显,我不理解关于增加儿童的政策。有什么想法吗

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);
    }
    ...
公共类QButton扩展按钮{
...
公共QButton(字符串str){
...
ObservableList children=getChildren();
System.out.println(“Children:+Children”);
矩形rect=新矩形(0,0,200,200.);
直接设定行程(颜色为红色);
矩形设置填充(彩色透明);
直接设定行程宽度(2);
getChildren().add(rect);
rect.setVisible(true);
children=getChildren();
System.out.println(“Children:+Children”);
}
...

在JavaFX中,UI控件使用MVC(模型/视图/控制器)模式。控件本身(例如
按钮
)就是模型,呈现委托给JavaFX中称为外观的视图。控件的节点图由视图(外观)维护,因此不可能简单地修改控件的子级。有关该体系结构的详细概述,请参阅

一种替代方法是将
按钮
矩形
放入
,以便
矩形
覆盖
按钮
,然后在应用程序的场景图中使用

否则,如果您真的想对
按钮
进行子类化并在那里添加
矩形
,则需要为
按钮
创建自定义蒙皮。下面的示例说明了如何实现这一点-一个缺点是按钮的基本蒙皮类(
按钮蒙皮
)不是公共的,因此您需要扩展一个非公共类(您通常不应该这样做,但除了从
com.sun.javafx
复制一大堆代码之外,我目前没有其他选择)。在Java 9中,皮肤类将在
javafx.scene.control.skin
包中公开(请参见 对于
按钮皮肤

以下代码显示了如何执行此操作:

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;
    }
}
package.com.example;
导入javafx.scene.control.Button;
导入javafx.scene.control.Skin;
导入javafx.scene.paint.Color;
导入javafx.scene.shape.Rectangle;
//不要这样做-com.sun不是公共的!
//(然而,除了复制代码外,目前似乎没有其他选择)
//使用Java 9,更改为javafx.scene.control.skin.ButtonSkin
类QButtonSkin扩展com.sun.javafx.scene.control.skin.ButtonSkin{
私有矩形rect=null;
公共QButtonSkin(按钮){
超级(按钮);
}
@凌驾
受保护的void updateChildren(){
super.updateChildren();
if(rect==null){
矩形=新矩形(0,0,200,200.);
直接设定行程(颜色为红色);
矩形设置填充(彩色透明);
直接设定行程宽度(2);
}
getChildren().add(rect);
}
}
公共类QButton扩展按钮{
公共QButton(字符串str){
超级(str);
}
@凌驾
受保护的皮肤createDefaultSkin(){
皮肤结果=新的QButtonSkin(此);
返回结果;
}
}

基本上,<代码> QButton <代码>创建一个新的默认皮肤(您也可以在CSS中这样做)。新的皮肤覆盖<代码> UpDeDeCube()/Cuffer >将矩形添加到控件的子节点。这里我们需要考虑调用序列——超级类的构造函数调用<代码> UpDeaEdvEnter()

本身,因此我们无法在皮肤的构造函数中创建
矩形


根据您的用例,您可能需要添加一些额外的代码,例如管理
QButtonSkin

的边界和几何图形。添加的子节点过去在我的所有子类中都是可见的,就像在这里的示例中一样。
-所以您的意思是上面的示例在前面已经起作用了,您可以将子节点添加到
但是ton
?是的,过去我会看到这个rect in/around按钮,现在我再也看不到了。在TextField中我仍然看到它。它在子项列表中,显式地将其“管理”也没有帮助。将其放入按钮中也没有帮助。这很奇怪,因为我希望它根本不起作用:
Control
(包括
按钮
)在内的所有UI控件的基类通常通过委托给单独的皮肤对象来呈现,即使这是
按钮
本身,皮肤在设置按钮后也会更改按钮的子节点。尝试向按钮添加一个事件侦听器,该按钮不会
System.err.println(button.getChildrenUnmodifiable())
您将看到您在构造函数中添加的子级不再存在。相反,现在只有一个
Text
节点作为childTrue,谢谢Andreas。我的子级位于构造函数末尾,但在构造之后它们消失了:)请注意,这些皮肤类在Java 9中是公开的,但具有不同的包名。很高兴知道-我已经希望如此…(与Java 8中的
SkinBase
类似…)现在可以工作了,谢谢大家!updateChildren做到了这一点。尽管我一直都有皮肤,但我从未拥有过它(基本上什么都不做)。将更新所有代码,但:textfield现在可以在没有皮肤的情况下工作,而且直到几天前按钮也可以工作。唯一的区别是,我现在使用的是SDK/JRE的更新版本,尽管更新不了多少