gpt4 book ai didi

使用 WritableImage 的 JavaFX 透明光标

转载 作者:行者123 更新时间:2023-12-01 09:27:53 26 4
gpt4 key购买 nike

Edit-Answer:

您可以查看Fabian 的回答 以及这个库 ( https://github.com/goxr3plus/JFXCustomCursor )

Actual Question

我想在 JavaFX 中创建一个淡出的光标,因此我使用 WritableImage 并且连续读取像素从原始的Image并将它们写入新的WritableImage。然后我使用ImageCursor(writableImage)将自定义光标设置到Scene ,下面是完整的代码(尝试一下)。

问题在于,在预期透明像素的地方却得到了黑色像素。

Note that all the below classes have to be in package sample.

Code(Main):

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);
}

}

Code(FadingCursor)(Edited):

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();

}

}

The image(needs to be downloaded)(Right Click ->Save Image as...):

enter image description here

最佳答案

您将每个像素的不透明度设置为仅取决于此处循环变量的值:

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

对于透明像素(不透明度= 0),您实际上增加不透明度,使存储在其他 channel 中的值(在本例中为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));

 

无需重新创建图像/光标的替代方案

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

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("/image/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 透明光标,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39692625/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com