无法一点一点地修改图像:线程被卡住了

时间:2016-08-11 15:43:58

标签: javafx task

我有一张图片,我想反转它。我写了算法,它工作正常。 但是我想逐渐显示反转(显示第1列的像素,然后显示第2列的像素等),因为它更好!

所以我使用ServiceTask类来使包含此算法的类(GraphicEngine)成为一个线程。后者将由另一个类(Gui)启动,这是GUI。在JavaFX中这样做是很常见的。

问题在于反转的显示卡在图像的开头或中间......它是随机的。我不知道为什么。

以下是源代码:

启动器类:

import javafx.application.Application;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;

public class Launcher extends Application {

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

    public void start(Stage stage) {
        stage.setWidth(700);
        stage.setHeight(700);
        stage.setMaximized(true);

        Gui gui = new Gui(stage, new BorderPane(), 700, 500);
        gui.fill();

        stage.setScene(gui);
        stage.show();
    }

}

在Gui.java中(扩展场景):

    this.button_reverse_image.setOnAction(button -> {
        this.graphic_engine.restart();
    });

在GraphicEngine.java中:

public class GraphicEngine extends Service<Void> {
    private WritableImage writable_image;
    private PixelReader writable_pixel_reader;
    private PixelWriter writable_pixel_writer;

    public Task<Void> createTask() {
        return new Task<Void>() {

            protected Void call() {
                double r, g, b;
                for(int x = 0; x < writable_image.getWidth(); x++) {
                    for(int y = 0; y < writable_image.getHeight(); y++) {
                        r = writable_pixel_reader.getColor(x, y).getRed()*255;
                        g = writable_pixel_reader.getColor(x, y).getGreen()*255;
                        b = writable_pixel_reader.getColor(x, y).getBlue()*255;
                        writable_pixel_writer.setColor(x, y, Color.rgb((int) (255 - r), (int) (255 - g), (int) (255 - b)));
                    }
                }
                return null;
            }
        };
    }

1 个答案:

答案 0 :(得分:1)

您无法从后台线程修改UI。相反,你应该使用动画(因为动画新图像实际上就是你正在做的事情)。

E.g。

private void progressivelyWriteImage(PixelReader source, WritableImage target) {

    Duration animationDuration = Duration.seconds(1);

    int width = target.getWidth();
    int height = target.getHeight();

    PixelWriter pixelWriter = target.getPixelWriter();

    IntegerProperty columnProgression = new SimpleIntegerProperty(0);
    columnProgression.addListener((obs, oldX, newX) -> {
        int progWidth = newX.intValue() - oldX.intValue();
        int[] pixels = new int[progWidth*height];
        source.getPixels(oldX.intValue(), 0, progWidth, height,
            PixelFormat.getIntArgbInstance(),
            pixels, 0, progWidth);
        int[] newPixels = new int[pixels.length];
        for (int i = 0; i < pixels.length ; i++) {
            int a = pixels[i] & 0xFF000000 ;
            int rgb = 0xFFFFFF - (pixels[i] & 0xFFFFFF) ;
            newPixels[i] = a | rgb ;
        }
        pixelWriter.setPixels(oldX.intValue(), 0, progWidth, height,
            PixelFormat.getIntArgbInstance(),
            newPixels, 0, progWidth);
    });

    Timeline timeline = new Timeline(new KeyFrame(animationDuration,
        new KeyValue(columnProgression, width)));
    timeline.play();
}

这是一个SSCCE:

import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.scene.image.PixelFormat;
import javafx.scene.image.PixelWriter;
import javafx.util.Duration;

public class GraphicEngine() {

    public negateImage(PixelReader source, WritableImage target) {

        Duration animationDuration = Duration.seconds(1);

        int width = (int) target.getWidth();
        int height = (int) target.getHeight();

        PixelWriter pixelWriter = target.getPixelWriter();

        IntegerProperty columnProgression = new SimpleIntegerProperty(0);
        columnProgression.addListener((obs, oldX, newX) -> {
            int progWidth = newX.intValue() - oldX.intValue();
            int[] pixels = new int[progWidth*height];
            source.getPixels(oldX.intValue(), 0, progWidth, height,
                PixelFormat.getIntArgbInstance(),
                pixels, 0, progWidth);
            int[] newPixels = new int[pixels.length];
            for (int i = 0; i < pixels.length ; i++) {
                int a = pixels[i] & 0xFF000000 ;
                int rgb = 0xFFFFFF - (pixels[i] & 0xFFFFFF) ;
                newPixels[i] = a | rgb ;
            }
            pixelWriter.setPixels(oldX.intValue(), 0, progWidth, height,
                PixelFormat.getIntArgbInstance(),
                newPixels, 0, progWidth);
        });

        Timeline timeline = new Timeline(new KeyFrame(animationDuration,
            new KeyValue(columnProgression, width)));
        timeline.play();
    }
}
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.image.PixelFormat;
import javafx.scene.image.PixelWriter;
import javafx.scene.image.WritableImage;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Duration;

public class ImageModifyDemo extends Application {

    @Override
    public void start(Stage primaryStage) {

        GraphicEngine engine = new GraphicEngine();
        Image initialImage = createImage();

        int width = (int) initialImage.getWidth();
        int height = (int) initialImage.getHeight();
        WritableImage target = new WritableImage(width, height);

        Button demoChange = new Button("Run demo");
        demoChange.setOnAction(e -> {
            target.getPixelWriter().setPixels(0, 0, width, height, PixelFormat.getIntArgbInstance(), new int[width], 0, 0);
            engine.negateImage(initialImage.getPixelReader(), target);
        });

        VBox root = new VBox(10, new ImageView(initialImage), new ImageView(target), demoChange);
        root.setPadding(new Insets(10));
        primaryStage.setScene(new Scene(root));
        primaryStage.show();
    }


    private Image createImage() {
        Label label = new Label("Hello world");
        label.setStyle("-fx-background-color: -fx-background; -fx-background: salmon; -fx-font-size:72;");
        new Scene(label);
        return label.snapshot(null, null);

    }

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