2015-08-14 3 views
2

СЦЕПЛЕНИЕ двух эффектов в JavaFX легко с .setInput()JavaFX 8 цепные эффекты

if (isDropShadowEnabled) 
    innerShadow.setInput(dropShadow); 
content.setEffect(innerShadow); 

Но как я цепь несколько эффектов, когда какой-либо один из этих эффектов не может быть включен?

Скажем, третий эффект - это Блум. Поэтому я хочу Dropshadow, InnerShadow и Bloom, но в других случаях просто DropShadow и Bloom, а не InnerShadow. Я стараюсь избегать множества «if's», и я искал что-то по линии effect.getChildren(). Add («Множество эффектов»). Но ничто не выскочило после нескольких часов в Гуглинг.

ответ

4

Возможно, вы можете использовать некоторые идеи из этого кода. Извините, это немного сложно, и у меня нет времени объяснять это прямо сейчас.

s1 s2 s3 s4

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); 
    } 
} 
+0

Это будет нуждаться в какой-то серьезное исследование, так что это будет несколько часов, но спасибо! – Frank

+0

Отлично! Это хорошо работает. Я использую текст, а не изображение, и я также добавил освещение к тексту. Проблема с освещением заключается в том, что он не имеет метода setInput(), поэтому он не связан с цепью. Я решил эту проблему, наложив текст на себя и применив прикованные эффекты к нижнему тексту, а освещение - к верхнему тексту. Конечный результат фантастический. Спасибо jewelsea. – Frank