问题描述
您可以查看 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透明光标的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!