本文介绍了使用WritableImage的JavaFX透明光标的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

您可以查看 Fabian的回答以及此库(

解决方案

您只能根据循环将每个像素的不透明度设置为一个值变量在这里:

  color = new Color(color.getRed(),color.getGreen(),color.getBlue(), counter / 10.00); 

对于透明像素(不透明度= 0),您实际上增加不透明度存储在其他通道中的值(在这种情况下为0 /黑色)可见。你需要确保透明像素保持透明,通常这样做:

  color = new Color(color.getRed( ),color.getGreen(),color.getBlue(),(counter / 10.00)* color.getOpacity()); 

或者你可以使用 deriveColor

  color = color.deriveColor(0,1,1,counter / 10d); 

修改



出于某种原因 ImageCursor 似乎不喜欢完全透明的图像。你可以通过添加

  pixelWriter.setColor(0,0, new Color(0,0,0,0.01)); 

写入图像的for循环后。



要解决此问题,您只需使用 Cursor.NONE 而不是 ImageCursor ,并使用完全透明的图像:

  for(; counter> = 1; counter--){
...
}
Platform.runLater(() - > scene.setCursor(Cursor.NONE));

 



无需任何选择重新创建图像/光标



您可以通过移动图像来自己模拟光标场景的根 。这不会使图像显示超出场景的范围,但您可以将动画应用于 ImageView 用于淡化而不是手动修改每个像素的不透明度...

  public class CursorSimulator {

私人决赛FadeTransition褪色;

public CursorSimulator(Image image,Scene scene,ObservableList< Node> rootChildrenWriteable,double hotspotX,double hotspotY){
ImageView imageView = new ImageView(image);
imageView.setManaged(false);
imageView.setMouseTransparent(true);

fade = new FadeTransition(Duration.seconds(2),imageView);
fade.setFromValue(0);
fade.setToValue(1);

//将图像保持在最高
rootChildrenWriteable.addListener((Observable o) - > {
if(imageView.getParent()!= null
& & rootChildrenWriteable.get(rootChildrenWriteable.size() - 1)!= imageView){
//在完成更改后将图片移至顶部...
Platform.runLater(() - > imageView.toFront());
}
});
scene.addEventFilter(MouseEvent.MOUSE_ENTERED,evt - > {
rootChildrenWriteable.add(imageView);
});
scene.addEventFilter(MouseEvent.MOUSE_EXITED,evt - > {
rootChildrenWriteable.remove(imageView);
});
scene.addEventFilter(MouseEvent.MOUSE_MOVED,evt - > {
imageView.setLayoutX(evt.getX() - hotspotX);
imageView.setLayoutY(evt.getY() - hotspotY) ;
});
scene.setCursor(Cursor.NONE);
}

public void fadeOut(){
fade.setRate(-1);
if(fade.getStatus()!= Animation.Status.RUNNING){
fade.playFrom(fade.getTotalDuration());
}
}

public void fadeIn(){
fade.setRate(1);
if(fade.getStatus()!= Animation.Status.RUNNING){
fade.playFromStart();
}
}

}





  @Override 
public void start(Stage primaryStage){
Button btn = new Button(Say'Hello World');
btn.setOnAction((ActionEvent event) - > {
System.out.println(Hello World!);
});

StackPane root = new StackPane();
root.getChildren()。add(btn);

场景场景=新场景(root,500,500);

图片图片=新图片(http://i.stack.imgur.com/OHj1R.png);
CursorSimulator simulator = new CursorSimulator(image,scene,root.getChildren(),32,50);
scene.setOnMouseClicked(new EventHandler< MouseEvent>(){

private boolean fadeOut = true;

@Override
public void handle(MouseEvent事件) ){
if(fadeOut){
simulator.fadeOut();
} else {
simulator.fadeIn();
}
fadeOut =! fadeOut;
}
});

primaryStage.setScene(scene);
primaryStage.show();
}


You can check Fabian's answer and also this library (https://github.com/goxr3plus/JFXCustomCursor)

I want to create a cursor which is fading out in JavaFX so for that i am using a WritableImage and i am continuously reading pixels from the original Image and writing them to a new WritableImage.Then i set a custom cursor to the Scene using ImageCursor(writableImage),below is the full code(give it a try).

The problem is that a get black pixels where transparent pixels are expected.

package sample;

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.FlowPane;
import javafx.stage.Stage;

public class Main extends Application {

    FadingCursor fade = new FadingCursor();

    @Override
    public void start(Stage primaryStage) throws Exception {

        primaryStage.setWidth(300);
        primaryStage.setHeight(300);

        Scene scene = new Scene(new FlowPane());

        primaryStage.setScene(scene);

        fade.startFade(scene,100);

        primaryStage.show();
    }

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

}
package sample;

import java.util.concurrent.CountDownLatch;

import javafx.application.Platform;
import javafx.scene.ImageCursor;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.PixelReader;
import javafx.scene.image.PixelWriter;
import javafx.scene.image.WritableImage;
import javafx.scene.paint.Color;

public class FadingCursor {

    private int counter;
    private Image cursorImage;

    /**
     * Change the image of the Cursor
     *
     * @param image
     */
    public void setCursorImage(Image image) {
        this.cursorImage = image;
    }

    /**
     * Start fading the Cursor
     *
     * @param scene
     */
    public void startFade(Scene scene, int millisecondsDelay) {

        // Create a Thread
        new Thread(() -> {

            // Keep the original image stored here
            Image image = new Image(getClass().getResourceAsStream("fire.png"), 64, 64, true, true);
            PixelReader pixelReader = image.getPixelReader();

            // Let's go
            counter = 10;
            for (; counter >= 0; counter--) {
                CountDownLatch count = new CountDownLatch(1);
                Platform.runLater(() -> {

                    // Create the fading image
                    WritableImage writable = new WritableImage(64, 64);
                    PixelWriter pixelWriter = writable.getPixelWriter();

                    // Fade out the image
                    for (int readY = 0; readY < image.getHeight(); readY++) {
                        for (int readX = 0; readX < image.getWidth(); readX++) {
                            Color color = pixelReader.getColor(readX, readY);

                            // Now write a brighter color to the PixelWriter.

                            // -------------------------Here some way happens
                            // the problem------------------
                            color = new Color(color.getRed(), color.getGreen(), color.getBlue(), (counter / 10.00) * color.getOpacity());
                            pixelWriter.setColor(readX, readY, color);
                        }
                    }

                    System.out.println("With counter:"+counter+" opacity is:" + writable.getPixelReader().getColor(32, 32).getOpacity());


                    scene.setCursor(new ImageCursor(writable));
                    count.countDown();
                });
                try {
                    // Wait JavaFX Thread to change the cursor
                    count.await();
                    // Sleep some time
                    Thread.sleep(millisecondsDelay);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }

        }).start();

    }

}
解决方案

You set the opacity of every pixel to a value only depending on the loop variable here:

color = new Color(color.getRed(), color.getGreen(), color.getBlue(), counter / 10.00);

For transparent pixels (opacity = 0) you actually increase the opacity making the values stored in the other channels (in this case 0 / black) visible. You need to make sure transparent pixels remain transparent, which usually is done like this:

color = new Color(color.getRed(), color.getGreen(), color.getBlue(), (counter / 10.00) * color.getOpacity());

Alternatively you could use deriveColor:

color = color.deriveColor(0, 1, 1, counter / 10d);

Edit

For some reason ImageCursor doesn't seem to like a completely transparent image. You can check that this works, if at least one pixel is not completely transparent by adding

pixelWriter.setColor(0, 0, new Color(0, 0, 0, 0.01));

After the for loops writing the image.

To fix this you could simply use Cursor.NONE instead of an ImageCursor with a fully transparent image:

for (; counter >= 1; counter--) {
    ...
}
Platform.runLater(() -> scene.setCursor(Cursor.NONE));

Alternative without the need to recreate the image/cursor

You could simulate the cursor yourself by moving a image Across the root of the Scene. This won't make the image show up beyond the bounds of the Scene, but you can apply animations to the ImageView for fading instead of modifying the opacity of each pixel manually...

public class CursorSimulator {

    private final FadeTransition fade;

    public CursorSimulator(Image image, Scene scene, ObservableList<Node> rootChildrenWriteable, double hotspotX, double hotspotY) {
        ImageView imageView = new ImageView(image);
        imageView.setManaged(false);
        imageView.setMouseTransparent(true);

        fade = new FadeTransition(Duration.seconds(2), imageView);
        fade.setFromValue(0);
        fade.setToValue(1);

        // keep image on top
        rootChildrenWriteable.addListener((Observable o) -> {
            if (imageView.getParent() != null
                    && rootChildrenWriteable.get(rootChildrenWriteable.size() - 1) != imageView) {
                // move image to top, after changes are done...
                Platform.runLater(() -> imageView.toFront());
            }
        });
        scene.addEventFilter(MouseEvent.MOUSE_ENTERED, evt -> {
            rootChildrenWriteable.add(imageView);
        });
        scene.addEventFilter(MouseEvent.MOUSE_EXITED, evt -> {
            rootChildrenWriteable.remove(imageView);
        });
        scene.addEventFilter(MouseEvent.MOUSE_MOVED, evt -> {
            imageView.setLayoutX(evt.getX() - hotspotX);
            imageView.setLayoutY(evt.getY() - hotspotY);
        });
        scene.setCursor(Cursor.NONE);
    }

    public void fadeOut() {
        fade.setRate(-1);
        if (fade.getStatus() != Animation.Status.RUNNING) {
            fade.playFrom(fade.getTotalDuration());
        }
    }

    public void fadeIn() {
        fade.setRate(1);
        if (fade.getStatus() != Animation.Status.RUNNING) {
            fade.playFromStart();
        }
    }

}
@Override
public void start(Stage primaryStage) {
    Button btn = new Button("Say 'Hello World'");
    btn.setOnAction((ActionEvent event) -> {
        System.out.println("Hello World!");
    });

    StackPane root = new StackPane();
    root.getChildren().add(btn);

    Scene scene = new Scene(root, 500, 500);

    Image image = new Image("http://i.stack.imgur.com/OHj1R.png");
    CursorSimulator simulator = new CursorSimulator(image, scene, root.getChildren(), 32, 50);
    scene.setOnMouseClicked(new EventHandler<MouseEvent>() {

        private boolean fadeOut = true;

        @Override
        public void handle(MouseEvent event) {
            if (fadeOut) {
                simulator.fadeOut();
            } else {
                simulator.fadeIn();
            }
            fadeOut = !fadeOut;
        }
    });

    primaryStage.setScene(scene);
    primaryStage.show();
}

这篇关于使用WritableImage的JavaFX透明光标的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-05 14:13
查看更多