javafx 8 链接效果
javafx 8 chaining effects
使用 .setInput() 在 JavaFX 中链接两个效果很容易
if (isDropShadowEnabled)
innerShadow.setInput(dropShadow);
content.setEffect(innerShadow);
但是当其中任何一种效果可能未启用时,我如何链接多个效果?
假设第三个效果是绽放。所以我想要一个 Dropshadow、InnerShadow 和 Bloom,但在其他时候只是一个 DropShadow 和 Bloom 而没有 InnerShadow。我试图避免大量的“如果”,并且我一直在寻找类似于 effect.getChildren().add('lots of effects') 的东西。但是经过几个小时的谷歌搜索,什么也没有跳出来。
也许您可以使用这段代码中的一些想法。抱歉有点复杂,我现在没时间解释。
import javafx.application.Application;
import javafx.beans.property.*;
import javafx.geometry.*;
import javafx.scene.Scene;
import javafx.scene.control.CheckBox;
import javafx.scene.effect.*;
import javafx.scene.image.*;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
public class Effector extends Application{
@Override
public void start(Stage stage) throws Exception {
ImageView imageView = new ImageView(
new Image(
"http://icons.iconarchive.com/icons/designbolts/smurfs-movie/128/smurfette-icon.png"
)
);
VBox effectControls = new VBox(5);
effectControls.setPadding(new Insets(5));
effectControls.getChildren().setAll(
new EffectController(
"Drop Shadow",
new DropShadow()
),
new EffectController(
"Inner Shadow",
new InnerShadow()
),
new EffectController(
"Bloom",
new Bloom()
)
);
EffectPipeline pipeline = new EffectPipeline(
effectControls.getChildren().stream().map(
node -> ((EffectController) node).getChainableEffect()
).toArray(ChainableEffect[]::new)
);
imageView.effectProperty().bind(
pipeline.chainedEffectProperty()
);
VBox layout = new VBox(
5,
effectControls,
imageView
);
layout.setPadding(new Insets(5));
layout.setAlignment(
Pos.CENTER
);
stage.setScene(
new Scene(
layout
)
);
stage.setResizable(false);
stage.show();
}
class EffectController extends CheckBox {
private final ChainableEffect chainableEffect;
public EffectController(
String text,
Effect effect
) {
super(text);
chainableEffect = new ChainableEffect(
effect
);
this.setSelected(!chainableEffect.isDisabled());
this.selectedProperty().addListener(
(observable, oldValue, newValue) -> {
chainableEffect.disabledProperty().set(!newValue);
}
);
}
public ChainableEffect getChainableEffect() {
return chainableEffect;
}
}
class EffectPipeline {
private List<ChainableEffect> effects;
private ReadOnlyObjectWrapper<Effect> chainedEffect = new ReadOnlyObjectWrapper<>();
public EffectPipeline(ChainableEffect... effects) {
this.effects = Arrays.asList(effects);
for (ChainableEffect chainableEffect: effects) {
chainableEffect.disabledProperty().addListener((observable, oldValue, newValue) -> {
refreshChainedEffect();
});
}
refreshChainedEffect();
}
public void refreshChainedEffect() {
ChainableEffect firstEffect = null, lastEffect = null;
for (ChainableEffect nextEffect : effects) {
nextEffect.setInput(null);
if (nextEffect.isDisabled()) {
continue;
}
if (firstEffect == null) {
firstEffect = nextEffect;
lastEffect = firstEffect;
continue;
}
lastEffect.setInput(nextEffect);
lastEffect = nextEffect;
}
chainedEffect.setValue(
firstEffect == null
? null
: firstEffect.getEffect()
);
}
public Effect getChainedEffect() {
return chainedEffect.get();
}
public ReadOnlyObjectProperty<Effect> chainedEffectProperty() {
return chainedEffect.getReadOnlyProperty();
}
}
class ChainableEffect {
private final Effect effect;
private final Method inputMethod;
private final BooleanProperty disabled = new SimpleBooleanProperty(
false
);
public ChainableEffect(Effect effect) {
if (effect == null) {
throw new IllegalArgumentException("Effect for chaining must not be null");
}
this.effect = effect;
try {
inputMethod = effect.getClass().getMethod(
"setInput",
Effect.class
);
} catch (NoSuchMethodException e) {
throw new IllegalArgumentException("Effect for chaining must implement the setInput method", e);
} catch (SecurityException e) {
throw new IllegalStateException("Creating chainable effects requires a reflection capable security environment", e);
}
}
public ChainableEffect setInput(ChainableEffect chainableEffect) {
try {
inputMethod.invoke(
this.getEffect(),
chainableEffect != null
? chainableEffect.getEffect()
: null
);
return this;
} catch (IllegalAccessException e) {
throw new IllegalStateException("Chainable effect does not support access rights for setInput", e);
} catch (InvocationTargetException e) {
throw new IllegalStateException("Unable to set the input for a chainable effect", e);
}
}
public Effect getEffect() {
return effect;
}
public boolean isDisabled() {
return disabled.get();
}
public BooleanProperty disabledProperty() {
return disabled;
}
public void setDisabled(boolean disabled) {
this.disabled.set(disabled);
}
}
public static void main(String[] args) {
launch(args);
}
}
使用 .setInput() 在 JavaFX 中链接两个效果很容易
if (isDropShadowEnabled)
innerShadow.setInput(dropShadow);
content.setEffect(innerShadow);
但是当其中任何一种效果可能未启用时,我如何链接多个效果?
假设第三个效果是绽放。所以我想要一个 Dropshadow、InnerShadow 和 Bloom,但在其他时候只是一个 DropShadow 和 Bloom 而没有 InnerShadow。我试图避免大量的“如果”,并且我一直在寻找类似于 effect.getChildren().add('lots of effects') 的东西。但是经过几个小时的谷歌搜索,什么也没有跳出来。
也许您可以使用这段代码中的一些想法。抱歉有点复杂,我现在没时间解释。
import javafx.application.Application;
import javafx.beans.property.*;
import javafx.geometry.*;
import javafx.scene.Scene;
import javafx.scene.control.CheckBox;
import javafx.scene.effect.*;
import javafx.scene.image.*;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
public class Effector extends Application{
@Override
public void start(Stage stage) throws Exception {
ImageView imageView = new ImageView(
new Image(
"http://icons.iconarchive.com/icons/designbolts/smurfs-movie/128/smurfette-icon.png"
)
);
VBox effectControls = new VBox(5);
effectControls.setPadding(new Insets(5));
effectControls.getChildren().setAll(
new EffectController(
"Drop Shadow",
new DropShadow()
),
new EffectController(
"Inner Shadow",
new InnerShadow()
),
new EffectController(
"Bloom",
new Bloom()
)
);
EffectPipeline pipeline = new EffectPipeline(
effectControls.getChildren().stream().map(
node -> ((EffectController) node).getChainableEffect()
).toArray(ChainableEffect[]::new)
);
imageView.effectProperty().bind(
pipeline.chainedEffectProperty()
);
VBox layout = new VBox(
5,
effectControls,
imageView
);
layout.setPadding(new Insets(5));
layout.setAlignment(
Pos.CENTER
);
stage.setScene(
new Scene(
layout
)
);
stage.setResizable(false);
stage.show();
}
class EffectController extends CheckBox {
private final ChainableEffect chainableEffect;
public EffectController(
String text,
Effect effect
) {
super(text);
chainableEffect = new ChainableEffect(
effect
);
this.setSelected(!chainableEffect.isDisabled());
this.selectedProperty().addListener(
(observable, oldValue, newValue) -> {
chainableEffect.disabledProperty().set(!newValue);
}
);
}
public ChainableEffect getChainableEffect() {
return chainableEffect;
}
}
class EffectPipeline {
private List<ChainableEffect> effects;
private ReadOnlyObjectWrapper<Effect> chainedEffect = new ReadOnlyObjectWrapper<>();
public EffectPipeline(ChainableEffect... effects) {
this.effects = Arrays.asList(effects);
for (ChainableEffect chainableEffect: effects) {
chainableEffect.disabledProperty().addListener((observable, oldValue, newValue) -> {
refreshChainedEffect();
});
}
refreshChainedEffect();
}
public void refreshChainedEffect() {
ChainableEffect firstEffect = null, lastEffect = null;
for (ChainableEffect nextEffect : effects) {
nextEffect.setInput(null);
if (nextEffect.isDisabled()) {
continue;
}
if (firstEffect == null) {
firstEffect = nextEffect;
lastEffect = firstEffect;
continue;
}
lastEffect.setInput(nextEffect);
lastEffect = nextEffect;
}
chainedEffect.setValue(
firstEffect == null
? null
: firstEffect.getEffect()
);
}
public Effect getChainedEffect() {
return chainedEffect.get();
}
public ReadOnlyObjectProperty<Effect> chainedEffectProperty() {
return chainedEffect.getReadOnlyProperty();
}
}
class ChainableEffect {
private final Effect effect;
private final Method inputMethod;
private final BooleanProperty disabled = new SimpleBooleanProperty(
false
);
public ChainableEffect(Effect effect) {
if (effect == null) {
throw new IllegalArgumentException("Effect for chaining must not be null");
}
this.effect = effect;
try {
inputMethod = effect.getClass().getMethod(
"setInput",
Effect.class
);
} catch (NoSuchMethodException e) {
throw new IllegalArgumentException("Effect for chaining must implement the setInput method", e);
} catch (SecurityException e) {
throw new IllegalStateException("Creating chainable effects requires a reflection capable security environment", e);
}
}
public ChainableEffect setInput(ChainableEffect chainableEffect) {
try {
inputMethod.invoke(
this.getEffect(),
chainableEffect != null
? chainableEffect.getEffect()
: null
);
return this;
} catch (IllegalAccessException e) {
throw new IllegalStateException("Chainable effect does not support access rights for setInput", e);
} catch (InvocationTargetException e) {
throw new IllegalStateException("Unable to set the input for a chainable effect", e);
}
}
public Effect getEffect() {
return effect;
}
public boolean isDisabled() {
return disabled.get();
}
public BooleanProperty disabledProperty() {
return disabled;
}
public void setDisabled(boolean disabled) {
this.disabled.set(disabled);
}
}
public static void main(String[] args) {
launch(args);
}
}