You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaFX 1.7:父Group的Lighting效果无法在子节点上覆盖或取消

解决JavaFX父Group效果继承问题

问题描述

我有一个包含多个子节点的父Group,给父Group添加Lighting效果后,所有子节点都继承了该效果。我希望取消子节点的继承效果,并为其应用不同颜色的Lighting效果。

尝试过的方案:

  • 将子节点的effect设为null,无效;
  • 在父Group下创建子Group,无效。

请问是否有方法为子节点应用Lighting效果以抵消父节点的效果?或者是否能阻止这种继承行为?

最小可复现代码:

import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.effect.ColorAdjust;
import javafx.scene.effect.Effect;
import javafx.scene.effect.Light;
import javafx.scene.effect.Lighting;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;

// Trying to override an effect applied at group level on a child in the group
public class TestHarnessMain extends Application
{
    public static Effect createFilteredEffect(final Color colour)
    {
        double LIGHT_ANGLE = 90.0;
        ColorAdjust GREY_EFFECT = new ColorAdjust(0.0, -1.0, 0.0, 0.0);

        final Light.Distant light = new Light.Distant();
        light.setElevation(LIGHT_ANGLE);
        light.setAzimuth(LIGHT_ANGLE);
        light.setColor(colour);
        final Lighting lighting = new Lighting();
        lighting.setLight(light);
        lighting.setSurfaceScale(0);
        lighting.setContentInput(GREY_EFFECT);
        return lighting;
    }

    @Override
    public void start(final Stage stage)
    {
        double ON_COLOUR_COMPONENT = 1.0;
        double OFF_COLOUR_COMPONENT = 0.1;
        double COLOUR_OPACITY = 1.0;

        Effect BLUE_EFFECT = createFilteredEffect(new Color(OFF_COLOUR_COMPONENT, OFF_COLOUR_COMPONENT, ON_COLOUR_COMPONENT, COLOUR_OPACITY));
        Effect RED_EFFECT = createFilteredEffect(new Color(ON_COLOUR_COMPONENT, OFF_COLOUR_COMPONENT, OFF_COLOUR_COMPONENT, COLOUR_OPACITY));

        stage.setTitle("Test Set Effect on Children");
        stage.setWidth(1200);
        stage.setHeight(800);

        // 2 green circles initially
        Circle circle1 = new Circle(50,50, 30);
        circle1.setFill(Color.GREEN);

        Circle circle2 = new Circle(100,100, 20);
        circle2.setFill(Color.GREEN);

        // Add circles to group
        Group group = new Group();
        group.getChildren().add(circle1);
        group.getChildren().add(circle2);

        // Set effect on group - sets both circles blue.
        group.setEffect(BLUE_EFFECT);    // Comment this line to see that circle2 will go to red

        // Try to override group effect on circle 2 (does not work)
        circle2.setEffect(null);
        circle2.setEffect(RED_EFFECT);

        Scene scene = new Scene(group, 500, 300);
        stage.setScene(scene);
        stage.show();
    }

    public static void main(final String... args)
    {
        Application.launch(args);
    }

}

解决方案

JavaFX中,父节点的效果会作用于整个子节点树,子节点设置的效果是叠加在父效果之上,而非替换。要彻底隔离父节点的效果,需要将目标子节点放入SubScene中——SubScene拥有独立的渲染上下文,不会继承父容器的效果。

修改后的代码

import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.SubScene;
import javafx.scene.effect.ColorAdjust;
import javafx.scene.effect.Effect;
import javafx.scene.effect.Light;
import javafx.scene.effect.Lighting;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;

public class TestHarnessMain extends Application
{
    public static Effect createFilteredEffect(final Color colour)
    {
        double LIGHT_ANGLE = 90.0;
        ColorAdjust GREY_EFFECT = new ColorAdjust(0.0, -1.0, 0.0, 0.0);

        final Light.Distant light = new Light.Distant();
        light.setElevation(LIGHT_ANGLE);
        light.setAzimuth(LIGHT_ANGLE);
        light.setColor(colour);
        final Lighting lighting = new Lighting();
        lighting.setLight(light);
        lighting.setSurfaceScale(0);
        lighting.setContentInput(GREY_EFFECT);
        return lighting;
    }

    @Override
    public void start(final Stage stage)
    {
        double ON_COLOUR_COMPONENT = 1.0;
        double OFF_COLOUR_COMPONENT = 0.1;
        double COLOUR_OPACITY = 1.0;

        Effect BLUE_EFFECT = createFilteredEffect(new Color(OFF_COLOUR_COMPONENT, OFF_COLOUR_COMPONENT, ON_COLOUR_COMPONENT, COLOUR_OPACITY));
        Effect RED_EFFECT = createFilteredEffect(new Color(ON_COLOUR_COMPONENT, OFF_COLOUR_COMPONENT, OFF_COLOUR_COMPONENT, COLOUR_OPACITY));

        stage.setTitle("Test Set Effect on Children");
        stage.setWidth(1200);
        stage.setHeight(800);

        // 2 green circles initially
        Circle circle1 = new Circle(50,50, 30);
        circle1.setFill(Color.GREEN);

        Circle circle2 = new Circle(100,100, 20);
        circle2.setFill(Color.GREEN);
        // 为circle2创建独立的SubScene
        Group circle2Group = new Group(circle2);
        SubScene subScene = new SubScene(circle2Group, 200, 200);
        // 给SubScene里的circle2设置独立效果
        circle2.setEffect(RED_EFFECT);

        // Add circles to group
        Group group = new Group();
        group.getChildren().add(circle1);
        group.getChildren().add(subScene);

        // Set effect on group - 仅作用于circle1
        group.setEffect(BLUE_EFFECT);

        Scene scene = new Scene(group, 500, 300);
        stage.setScene(scene);
        stage.show();
    }

    public static void main(final String... args)
    {
        Application.launch(args);
    }

}

说明

  • 把需要独立效果的circle2放到单独的Group中,再将这个Group作为SubScene的根节点。
  • SubScene的尺寸可以根据子节点的大小调整,确保完全显示目标节点。
  • 父Group的BLUE_EFFECT只会作用于circle1,而circle2会应用自己的RED_EFFECT,完全不受父效果影响。

内容的提问来源于stack exchange,提问作者NottmTony

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 04:19:58