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
相关产品推荐
相关产品推荐

