2016-06-14 4 views
-1

Я пытаюсь сделать анимированную кнопку, постепенно меняя ее стиль с помощью файла CSS.Использование StringProperty в качестве параметра метода KeyValue

Я исследовал об этом, и я добрался до this. Я видел принятый ответ, и я попытался реализовать решение, которое дал этот человек.

Что я сделал, в основном создаю класс CustomButton, который расширяет Button, а затем настраивает StringProperties, значения которого изменяются в зависимости от того, нажата ли кнопка или нет; то каждый StringProperty объединяется, поэтому они работают как альтернатива CSS-файлу, применяемые в качестве стиля к кнопке.

Я думаю, что все кодируется в порядке, проблема в том, что я не могу создать анимацию, которая должна воспроизводиться при нажатии на кнопку, потому что для этого я должен был бы создать Timeline которого Keyframe «s KeyValue s указать значение каждого из компонентов, которые соответствуют анимации, и оказывается, что StringProperties не могут работать как параметры для метода KeyValue.

Это класс CustomButton:

public class CustomButton extends Button{ 


BooleanProperty clicked = new SimpleBooleanProperty(false); // Its value changes each time the button is clicked. 

StringProperty oldRotationValue = new SimpleStringProperty("-fx-rotate: -360;"); // Stores the last value of rotationStringProperty, so 
                       // then it can be used as the first frame of an animation. 

StringProperty oldColorValue = new SimpleStringProperty("#E74C3C;"); // Stores the last value of colorStringProperty, so 
                    // then it can be used as the first frame of an animation. 

StringProperty oldSizeValue = new SimpleStringProperty("-fx-size: " + "180px;"); // Stores the last value of sizeStringProperty, so 
                       // then it can be used as the first frame of an animation. 
public CustomButton(){ 
    Button button = createButton(rotationStringProperty, colorStringProperty, sizeStringProperty); 
} //CustomButton constructor 

StringProperty rotationStringProperty = new SimpleStringProperty(); // Creates the rotationStringProperty. 
StringProperty colorStringProperty = new SimpleStringProperty(); // Creates the colorStringProperty. 
StringProperty sizeStringProperty = new SimpleStringProperty(); // Creates the sizeStringProperty. 

private void setRotationStringProperty() { // Method that sets the rotation value depending on whether the button was pressed or not. 

    if (!clicked.getValue()) { // If the button wasn't clicked. 
     oldRotationValue.set("-fx-rotate: " + "-360;"); 
     rotationStringProperty.set("-fx-rotate: " + "360;"); 
    } else { // If the button was clicked. 
     oldRotationValue.set("-fx-rotate: " + "360;"); 
     rotationStringProperty.set("-fx-rotate: " + "-360;"); 
    } 
} 

private StringProperty setColorStringProperty() { // Method that sets the color depending on whether the button was pressed or not. 
    if (!clicked.getValue()) { // If the button wasn't clicked. 
     oldColorValue.set("#EA6153;"); 
     colorStringProperty.set("#E74C3C;"); 
    } else { // If the button was clicked. 
     oldColorValue.set("#E74C3C;"); 
     colorStringProperty.set("#EA6153;"); 
    } 
} 

private StringProperty setSizeStringProperty() { // Method that sets the size depending on whether the button was pressed or not. 
    if (!clicked.getValue()) { // If the button wasn't pressed 
     oldSizeValue.set("-fx-size: " + "200px;"); 
     sizeStringProperty.set("-fx-size: " + "180px;"); 
    } else { // If the button was pressed. 
     oldSizeValue.set("-fx-size: " + "180px;"); 
     sizeStringProperty.set("-fx-size: " + "200px;"); 
    } 
} 

private void setSizeStringMediumProperty(){ // Sets the size that the button must have in the middle of the animation. 
    if(!clicked.getValue()){ // If the button wasn't pressed. 
     sizeStringProperty.set("-fx-size: " + "170px;"); 
    }else{ // If the button was pressed. 
     sizeStringProperty.set("-fx-size: " + "210px;"); 
    } 
} 

private Button createButton(StringProperty rotationStringProperty, //Method that creates a button and defines the its rotation, 
                    // color, size, and how these has to be animated. 
                    // Once everything is done, it returns the customized button. 
          StringProperty colorStringProperty, 
          StringProperty sizeStringProperty) { 

    Button button = new Button(); // Creates a normal JavaFX Button so then it can be modified. 

    buttonSetOnAction(button); // Sets the action that the button must perform when it's clicked. 

    setRotationStringProperty(); // Sets the rotationStringProperty. 
    setColorStringProperty(); // Sets the colorStringProperty. 
    setSizeStringProperty(); // Sets the sizeStringProperty. 

    button.styleProperty().bind(new SimpleStringProperty("-fx-background-color: ") // Set's the style of the button. 
           .concat(colorStringProperty) 
           .concat(sizeStringProperty) 
           .concat(rotationStringProperty) 
           .concat("fx-border-color; #c0392b;") 
           .concat("-fx-border-width: 15px;")); 
    return button; // Returns the button. 
} 

private void buttonSetOnAction(Button button){ // Definition of a method that sets the actions that the button must perform when it's clicked. 
    button.setOnAction(e -> { 
     clicked.set(!clicked.getValue()); // The value of clicked is set to its opposite. 
     Timeline animation = new Timeline(//Defines an animation 
       new KeyFrame(Duration.seconds(0), new KeyValue(oldRotationValue, oldColorValue, oldSizeValue)); 
       setSizeStringMediumProperty(); // Sets the size that the button must have at the middle of the animation. 
       new KeyFrame(Duration.seconds(0.25), new KeyValue(sizeStringProperty)); 
       setSizeStringProperty(); // Sets the size that the button must have at the end of the animation. 
       new KeyFrame(Duration.seconds(0.50), new KeyValue(rotationStringProperty, colorStringProperty, sizeStringProperty)); 
       ); 
     animation.play(); // Plays the animation; 
    }); 
} 
} 

Может кто-нибудь придумать альтернативу использованию StringProperties?

ПРИМЕЧАНИЕ: Я знаю, что "-fx-size: " ничего не делает, но я не знаю, как изменить размер кнопки в CSS. Я спрошу об этом в другом вопросе, когда я смогу решить проблему анимации.

UPDATE: Я только что редактировали код путем внедрения альтернативных @James_D «S:

import javafx.animation.Animation; 
import javafx.animation.KeyFrame; 
import javafx.animation.KeyValue; 
import javafx.animation.Timeline; 
import javafx.beans.binding.Bindings; 
import javafx.beans.property.BooleanProperty; 
import javafx.beans.property.IntegerProperty; 
import javafx.beans.property.SimpleBooleanProperty; 
import javafx.beans.property.SimpleIntegerProperty; 
import javafx.scene.control.Button; 
import javafx.util.Duration; 

public class CustomButton extends Button{ 


    BooleanProperty clicked = new SimpleBooleanProperty(false); // Its value changes each time the button is clicked. 

    IntegerProperty oldRotationValue = new SimpleIntegerProperty(-360); // Stores the last value of rotationIntegerProperty, so 
                     // then it can be used as the first frame of an animation. 

    IntegerProperty oldColorValue = new SimpleIntegerProperty(Integer.decode("E74C3C")); // Stores the last value of colorIntegerProperty, so 
                          // then it can be used as the first frame of an animation. 

    IntegerProperty oldSizeValue = new SimpleIntegerProperty(180); // Stores the last value of sizeIntegerProperty, so 
                    // then it can be used as the first frame of an animation. 
    public CustomButton(){ //CustomButton constructor 
     Button button = createButton(rotationIntegerProperty, colorIntegerProperty, sizeIntegerProperty); 

    } 

    IntegerProperty rotationIntegerProperty = new SimpleIntegerProperty(); // Creates the rotationIntegerProperty. 
    IntegerProperty colorIntegerProperty = new SimpleIntegerProperty(); // Creates the rotationIntegerProperty. 
    IntegerProperty sizeIntegerProperty = new SimpleIntegerProperty(); // Creates the sizeIntegerProperty. 

    private IntegerProperty setRotationIntegerProperty() { // Method that sets the rotation value depending on whether the button was pressed or not. 

     IntegerProperty newRotationIntegerProperty = new SimpleIntegerProperty(); 

     if (!clicked.getValue()) { // If the button wasn't clicked. 
      oldRotationValue.set(-360); 
      rotationIntegerProperty.set(360); 
     } else { // If the button was clicked. 
      oldRotationValue.set(260); 
      rotationIntegerProperty.set(-360); 
     } 

     return newRotationIntegerProperty; 

    } 

    private IntegerProperty setColorIntegerProperty() { // Method that sets the color depending on whether the button was pressed or not. 

     IntegerProperty newColorIntegerProperty = new SimpleIntegerProperty(); 

     if (!clicked.getValue()) { // If the button wasn't clicked. 
      oldColorValue.set(Integer.decode("EA6153")); // oldColorValue.set("#EA6153;"); 
      colorIntegerProperty.set(Integer.decode("E74C3C")); 
     } else { // If the button was clicked. 
      oldColorValue.set(Integer.decode("E74C3C")); 
      colorIntegerProperty.set(Integer.decode("EA6153")); 
     } 

     return newColorIntegerProperty; 

    } 

    private IntegerProperty setSizeIntegerProperty() { // Method that sets the size depending on whether the button was pressed or not. 

     IntegerProperty newSizeIntegerProperty = new SimpleIntegerProperty(); 

     if (!clicked.getValue()) { // If the button wasn't pressed 
      oldSizeValue.set(200); 
      sizeIntegerProperty.set(180); 
     } else { // If the button was pressed. 
      oldSizeValue.set(180); 
      sizeIntegerProperty.set(200); 
     } 

     return newSizeIntegerProperty; 

    } 

    private IntegerProperty setSizeIntegerMediumProperty(){ // Sets the size that the button must have in the middle of the animation. 

     IntegerProperty newSizeIntegerMediumProperty = new SimpleIntegerProperty(); 

     if(!clicked.getValue()){ // If the button wasn't pressed. 
      sizeIntegerProperty.set(180); 
     }else{ // If the button was pressed. 
      sizeIntegerProperty.set(180); 
     } 

     return newSizeIntegerMediumProperty; 

    } 

    private Button createButton(IntegerProperty rotationIntegerProperty, //Method that creates a button and defines the its rotation, 
                     // color, size, and how these has to be animated. 
                     // Once everything is done, it returns the customized button. 
           IntegerProperty colorIntegerProperty, 
           IntegerProperty sizeIntegerProperty) { 

     Button button = new Button(); // Creates a normal JavaFX Button so then it can be modified. 

     buttonSetOnAction(button); // Sets the action that the button must perform when it's clicked. 

     setRotationIntegerProperty(); // Sets the rotationIntegerProperty. 
     setRotationIntegerProperty(); // Sets the colorIntegerProperty. 
     setSizeIntegerProperty(); // Sets the sizeIntegerProperty. 

     button.styleProperty().bind(Bindings.format(// Set's the style of the button. 
           "-fx-pref-width: #%f;" 
           + "-fx-pref-height: #%f;" 
           + "-fx-rotate: %f;" 
           + "-fx-background-color: #%s;" 
           + "-fx-border-color: #c0392b;" 
           + "-fx-border-width: 15px;", 
           sizeIntegerProperty, sizeIntegerProperty, rotationIntegerProperty, colorIntegerProperty)); 
     return button; // Returns the button. 
    } 

    private void buttonSetOnAction(Button button){ // Definition of a method that sets the actions that the button must perform when it's clicked. 

     Timeline animation = new Timeline(); 

     button.setOnAction(e -> { 

      clicked.set(!clicked.getValue()); // The value of clicked is set to its opposite. 

      animation.getKeyFrames().clear(); 

       animation.getKeyFrames().addAll(new KeyFrame(Duration.seconds(0), 
         new KeyValue (rotationIntegerProperty, oldRotationValue.getValue()), 
         new KeyValue (colorIntegerProperty, oldColorValue.getValue()), 
         new KeyValue (sizeIntegerProperty, oldSizeValue.getValue())), 
              new KeyFrame(Duration.seconds(0.25), 
         new KeyValue (sizeIntegerProperty, setSizeIntegerMediumProperty().getValue())), 
              new KeyFrame(Duration.seconds(0.25), 
         new KeyValue (sizeIntegerProperty, setSizeIntegerProperty().getValue()), 
         new KeyValue (rotationIntegerProperty, setRotationIntegerProperty().getValue()), 
         new KeyValue (colorIntegerProperty, setColorIntegerProperty().getValue()))); 

       animation.play(); // Plays the animation; 

       button.disableProperty().bind(animation.statusProperty().isEqualTo(Animation.Status.RUNNING)); 


     }); 
    } 
} 

Все кажется хорошо, пока я не выполнить код, и консоль печатает это:

Exception in Application start method 
java.lang.reflect.InvocationTargetException 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) 
    at java.lang.reflect.Method.invoke(Unknown Source) 
    at com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(Unknown Source) 
    at com.sun.javafx.application.LauncherImpl.launchApplication(Unknown Source) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) 
    at java.lang.reflect.Method.invoke(Unknown Source) 
    at sun.launcher.LauncherHelper$FXHelper.main(Unknown Source) 
Caused by: java.lang.RuntimeException: Exception in Application start method 
    at com.sun.javafx.application.LauncherImpl.launchApplication1(Unknown Source) 
    at com.sun.javafx.application.LauncherImpl.lambda$launchApplication$155(Unknown Source) 
    at java.lang.Thread.run(Unknown Source) 
Caused by: java.util.IllegalFormatConversionException: f != java.lang.Integer 
    at java.util.Formatter$FormatSpecifier.failConversion(Unknown Source) 
    at java.util.Formatter$FormatSpecifier.printFloat(Unknown Source) 
    at java.util.Formatter$FormatSpecifier.print(Unknown Source) 
    at java.util.Formatter.format(Unknown Source) 
    at java.util.Formatter.format(Unknown Source) 
    at java.lang.String.format(Unknown Source) 
    at com.sun.javafx.binding.StringFormatter$4.computeValue(Unknown Source) 
    at javafx.beans.binding.StringBinding.get(Unknown Source) 
    at com.sun.javafx.binding.StringFormatter.format(Unknown Source) 
    at javafx.beans.binding.Bindings.format(Unknown Source) 
    at CustomButton.createButton(CustomButton.java:109) 
    at CustomButton.<init>(CustomButton.java:26) 
    at StartingPoint.start(StartingPoint.java:15) 
    at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$162(Unknown Source) 
    at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$175(Unknown Source) 
    at com.sun.javafx.application.PlatformImpl.lambda$null$173(Unknown Source) 
    at java.security.AccessController.doPrivileged(Native Method) 
    at com.sun.javafx.application.PlatformImpl.lambda$runLater$174(Unknown Source) 
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(Unknown Source) 
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method) 
    at com.sun.glass.ui.win.WinApplication.lambda$null$148(Unknown Source) 
    ... 1 more 
Exception running application StartingPoint 

Насколько я понимаю, это связано с тем, что в 109-й строке класса CustomButton есть проблема:

button.styleProperty().bind(Bindings.format(// Set's the style of the button. 

В чем проблема?

Заранее благодарен!

+0

Метод 'buttonSetOnAction' вызывается в 105-й строке класса CustomButton. – SpaceCore186

+0

Единственная точка с запятой, которую я вижу в вызове конструктора 'Timeline', находится в конце. – SpaceCore186

+0

@JavaNoob В конце каждой строки есть точки с запятой, которые составляют вызов конструктора 'Timeline'. Что касается ошибки, сообщение об ошибке сообщает вам о проблеме: формат ожидает целое число для одного из аргументов и получает что-то другое. Я рекомендую прочитать документацию для [этого метода] (http://docs.oracle.com/javase/8/javafx/api/javafx/beans/binding/Bindings.html # format-java.lang.String-java.lang.Object ...-) и для ['Formatter'] (http: // docs.oracle.com/javase/8/docs/api/java/util/Formatter.html) –

ответ

0

Вы можете использовать числовые (или другие интерполяционные типы, такие как цвет) в значениях ключа, и привязать свойство строки к их значениям. Посмотрите на этот пример:

import javafx.animation.Animation; 
import javafx.animation.KeyFrame; 
import javafx.animation.KeyValue; 
import javafx.animation.Timeline; 
import javafx.application.Application; 
import javafx.beans.binding.Bindings; 
import javafx.beans.property.BooleanProperty; 
import javafx.beans.property.DoubleProperty; 
import javafx.beans.property.ObjectProperty; 
import javafx.beans.property.SimpleBooleanProperty; 
import javafx.beans.property.SimpleDoubleProperty; 
import javafx.beans.property.SimpleObjectProperty; 
import javafx.beans.property.SimpleStringProperty; 
import javafx.beans.property.StringProperty; 
import javafx.scene.Scene; 
import javafx.scene.control.Button; 
import javafx.scene.layout.StackPane; 
import javafx.scene.paint.Color; 
import javafx.stage.Stage; 
import javafx.util.Duration; 

public class AnimatedStyleButton extends Application { 

    @Override 
    public void start(Stage primaryStage) { 
     Button button = new Button("Grow"); 
     ObjectProperty<Color> color = new SimpleObjectProperty<>(Color.RED); 
     DoubleProperty size = new SimpleDoubleProperty(50); 
     DoubleProperty fontSize = new SimpleDoubleProperty(12); 
     DoubleProperty rotate = new SimpleDoubleProperty(0); 
     StringProperty text = button.textProperty(); 
     BooleanProperty large = new SimpleBooleanProperty(false); 

     Timeline timeline = new Timeline(); 

     button.setOnAction(e -> { 

      timeline.getKeyFrames().clear(); 

      if (large.get()) { 
       timeline.getKeyFrames().add(new KeyFrame(Duration.seconds(1), 
         new KeyValue(text, "Grow"), 
         new KeyValue(size, 80), 
         new KeyValue(large, false), 
         new KeyValue(rotate, 0), 
         new KeyValue(color, Color.RED), 
         new KeyValue(fontSize, 12) 
       )); 
      } else { 
       timeline.getKeyFrames().add(new KeyFrame(Duration.seconds(1), 
         new KeyValue(text, "Shrink"), 
         new KeyValue(size, 200), 
         new KeyValue(large, true), 
         new KeyValue(rotate, 360), 
         new KeyValue(color, Color.BLUE), 
         new KeyValue(fontSize, 24) 
       )); 
      } 

      timeline.play(); 
     }); 

     StringProperty colorAsString = new SimpleStringProperty(); 
     colorAsString.bind(Bindings.createStringBinding(() -> toWebColor(color.get()), color)); 

     button.styleProperty().bind(Bindings.format(
       "-fx-pref-width: %f;" 
       + "-fx-pref-height: %f;" 
       + "-fx-rotate: %f;" 
       + "-fx-font-size: %f;" 
       + "-fx-base: %s", 
       size, size, rotate, fontSize, colorAsString)); 

     button.disableProperty().bind(timeline.statusProperty().isEqualTo(Animation.Status.RUNNING)); 

     StackPane root = new StackPane(button); 
     Scene scene = new Scene(root, 400, 400); 
     primaryStage.setScene(scene); 
     primaryStage.show(); 

    } 

    private String toWebColor(Color c) { 
     return String.format("#%02x%02x%02x", 
      (int) (c.getRed() * 255), 
      (int) (c.getGreen() * 255), 
      (int) (c.getBlue() * 255) 
     ); 
    } 

    public static void main(String[] args) { 
     launch(args); 
    } 
} 

Edit: я, вероятно, следовало бы посмотрел на linked question, так как это решение очень похоже на то. Возможно, это будет полезно в любом случае.

+0

Привет. Спасибо за Ваш ответ. Я просто удалил код, выполнив ваше решение, но теперь я получаю сообщение об ошибке в 109-й строке класса CustomButton. Я просто обновил вопрос. – SpaceCore186

Смежные вопросы