Přidat otázku mezi oblíbenéZasílat nové odpovědi e-mailemVyřešeno Java - Jak projít v Timeline celé pole?

Dobrý den,

Potřebuji upravit tento kód

import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.util.Duration;

public class Example extends javafx.application.Application {
    
    int index = 0;

    @Override
    public void start(Stage primaryStage) {
        var rectangle = new Rectangle(200, 200, Color.BLACK);
        var list_of_color = new Color[]{Color.PINK, Color.MAGENTA, Color.RED, Color.GREEN, Color.YELLOW, Color.TURQUOISE, Color.BLUE, Color.ORANGE};
        rectangle.setOnMouseClicked((t) -> {
            var timeline = new Timeline(new KeyFrame(Duration.millis(400), (event) -> {
                rectangle.setFill(list_of_color[index]);
                index += 1;
            }));
            timeline.setCycleCount(list_of_color.length);
            timeline.play();
        });
        primaryStage.setTitle("Example!");
        primaryStage.setScene(new Scene(new Pane(rectangle)));
        primaryStage.show();
    }

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

Jde o to, že musím vytvořit řídící proměnou, abych mohl v timeline projít postupně všechny prvky pole.
A problémem je, že v lambda výrazu nelze používat local variable (local variable referenced from a lambda expression must be final or effectively final), proto jsem musel použít global variable.

Nevíte, prosím Vás, jak to upravit, abych globální proměnou nemusel použít?

Děkuji

Jsou zobrazeny jen nové odpovědi. Zobrazit všechny
Předmět Autor Datum
Otázka je, čo vlastne chceš dosiahnuť. S JavaFX nemám skúsenosti, ale ak sa má po každom kliknutí sp…
moose 22.04.2020 07:33
moose
Napadlo mě nevytvářet Rectangle, ale objekt vlastní třídy extend Rectangle, který by měl navíc field…
MichalDM 22.04.2020 23:37
MichalDM
Po prečítaní dokumentácie to vyzerá tak, že prvý parameter KeyFrame je čas, v ktorom má daná zmena n… nový
moose 23.04.2020 00:20
moose
Ano, vím o FillTransition. Šlo mi pouze o znázornění mého problému. Každopádně perfektní. Už to fung… poslední
MichalDM 23.04.2020 23:18
MichalDM

Otázka je, čo vlastne chceš dosiahnuť. S JavaFX nemám skúsenosti, ale ak sa má po každom kliknutí spustiť animácia s nasledujúcou farbou, tak si stav niekde musíš pamätať. To, čo máš, by mohlo fungovať. Inak ak chceš meniť stav v lambde, tak môžeš použiť wrapper, ktorý bude final, ako napr. AtomicInteger.

Ak chceš na jedno kliknutie prejsť všetky farby, tak v tom prípade to bude vyzerať nejako takto:

rectangle.setOnMouseClicked(mouseEvent -> {
    final var timeline = new Timeline();
    Arrays.stream(COLORS)
            .map(color -> new KeyFrame(Duration.millis(400), event -> { rectangle.setFill(color); }))
            .forEach(timeline.getKeyFrames()::add);
    timeline.setCycleCount(COLORS.length);
    timeline.play();
});

Napadlo mě nevytvářet Rectangle, ale objekt vlastní třídy extend Rectangle, který by měl navíc field int. A s tím bych pracoval. Nicméně, lepší je použít AtomicInteger.

Děkuji. Nejslibněji vypadá Váš kód. Bohužel nefunguje (Rectangle se změní rovnou na poslední barvu v poli) a nepřišel jsem na to, jak to opravit. V čem je, prosím Vás, problém?

Po prečítaní dokumentácie to vyzerá tak, že prvý parameter KeyFrame je čas, v ktorom má daná zmena nastať (pôvodne som myslel, že je to doba trvania frame-u). Takže ju treba vypočítať podľa indexu, asi takto:

IntStream.range(0, COLORS.length)
        .mapToObj(index -> new KeyFrame(Duration.millis(index * 400), event -> { rectangle.setFill(COLORS[index]); }))
        .forEach(timeline.getKeyFrames()::add);

Ak má byť farebný prechod plynulý, tak by som si pozrel dokumentáciu k FillTransition.

Ano, vím o FillTransition. Šlo mi pouze o znázornění mého problému. Každopádně perfektní. Už to funguje. Děkuji

Výsledný kód teda vypadá:

import java.util.stream.IntStream;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.util.Duration;

public class Example extends javafx.application.Application {

    @Override
    public void start(Stage primaryStage) {
        var rectangle = new Rectangle(200, 200, Color.BLACK);
        var list_of_color = new Color[]{Color.PINK, Color.MAGENTA, Color.RED, Color.GREEN, Color.YELLOW, Color.TURQUOISE, Color.BLUE, Color.ORANGE};
        var timeline = new Timeline();
        rectangle.setOnMouseClicked((t) -> {
            IntStream
                    .range(0, list_of_color.length)
                    .mapToObj(
                            index -> new KeyFrame(
                              Duration.millis(index * 400), event -> {
                                rectangle.setFill(list_of_color[index]);
                              }
                            )
                    )
                    .forEach(timeline.getKeyFrames()::add);
            timeline.play();
        });
        primaryStage.setTitle("Example!");
        primaryStage.setScene(new Scene(new Pane(rectangle)));
        primaryStage.show();
    }

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

Zpět do poradny Odpovědět na původní otázku Nahoru