我想制作一个在屏幕中间显示十字准线的 JavaFX 应用程序,但每当我将鼠标悬停在 ImageView 上时,我都无法执行后台任务,就像它会阻止我的鼠标事件一样。
我尝试过使用
Node#setMouseTransparent
,但它并没有真正起作用,Scene.setFill(null)
也是如此
这是我现在拥有的代码:
private void setStageProperties() {
Screen screen = Screen.getPrimary();
Rectangle2D bounds = screen.getBounds();
stage.setWidth(bounds.getWidth());
stage.setHeight(bounds.getHeight());
Scene scene = new Scene(this);
scene.setFill(null);
stage.setScene(scene);
stage.setAlwaysOnTop(true);
this.primary = new Stage();
primary.initStyle(StageStyle.UTILITY);
primary.setOpacity(0);
primary.setHeight(0);
primary.setWidth(0);
primary.show();
stage.initOwner(primary);
stage.initStyle(StageStyle.TRANSPARENT);
double centerX = bounds.getMinX() + bounds.getWidth() / 2;
double centerY = bounds.getMinY() + bounds.getHeight() / 2;
stage.setX(centerX - stage.getWidth() / 2);
stage.setY(centerY - stage.getHeight() / 2);
}
public CrosshairScene() {
this.stage = new Stage();
this.crosshairImage = new ImageView("crosshair.png");
this.crosshairImage.setPickOnBounds(false);
this.setMouseTransparent(true);
this.setCenter(crosshairImage);
this.setStageProperties();
this.setStyle("-fx-background-color: null;");
}
这是一个仅限 Windows 的解决方案,基于以下想法:
使用虚拟机参数运行:
--add-opens javafx.graphics/javafx.stage=com.example --add-opens javafx.graphics/com.sun.javafx.tk.quantum=com.example
src/main/java/module-info.java
module com.example {
requires javafx.controls;
requires com.sun.jna;
requires com.sun.jna.platform;
exports com.example;
}
src/main/java/com/example/TransparentApplication.java
package com.example;
import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.User32;
import com.sun.jna.platform.win32.WinDef;
import com.sun.jna.platform.win32.WinUser;
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.layout.Background;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.SVGPath;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.stage.Window;
import java.io.IOException;
import java.lang.reflect.Method;
public class TransparentApplication extends Application {
private static final String CIRCLE_SVG_PATH =
"""
M 14,8 A 6,6 0 0 1 8,14 6,6 0 0 1 2,8 6,6 0 0 1 8,2 6,6 0 0 1 14,8 Z M 8 0 L 8 6.5 M 0 8 L 6.5 8 M 8 9.5 L 8 16 M 9.5 8 L 16 8
""";
@Override
public void start(Stage stage) throws IOException {
SVGPath path = new SVGPath();
path.setContent(CIRCLE_SVG_PATH);
path.setFill(Color.TRANSPARENT);
path.setStroke(
Color.BLUEVIOLET.deriveColor(
0, 1, 1, .6
)
);
path.setScaleX(10);
path.setScaleY(10);
StackPane layout = new StackPane(new Group(path));
layout.setBackground(Background.fill(Color.TRANSPARENT));
layout.setMouseTransparent(true);
Scene scene = new Scene(layout, Color.TRANSPARENT);
stage.setTitle("crosshair");
stage.initStyle(StageStyle.TRANSPARENT);
stage.setScene(scene);
stage.setAlwaysOnTop(true);
stage.show();
WinDef.HWND hwnd = getNativeHandleForStage(stage);
int wl = User32.INSTANCE.GetWindowLong(hwnd, WinUser.GWL_EXSTYLE);
wl = wl | WinUser.WS_EX_LAYERED | WinUser.WS_EX_TRANSPARENT;
User32.INSTANCE.SetWindowLong(hwnd, WinUser.GWL_EXSTYLE, wl);
}
private static WinDef.HWND getNativeHandleForStage(Stage stage) {
try {
final Method getPeer = Window.class.getDeclaredMethod("getPeer", null);
getPeer.setAccessible(true);
final Object tkStage = getPeer.invoke(stage);
final Method getRawHandle = tkStage.getClass().getMethod("getRawHandle");
getRawHandle.setAccessible(true);
final Pointer pointer = new Pointer((Long) getRawHandle.invoke(tkStage));
return new WinDef.HWND(pointer);
} catch (Exception ex) {
System.err.println("Unable to determine native handle for window");
return null;
}
}
public static void main(String[] args) {
launch();
}
}
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>TransparentApp</artifactId>
<version>1.0-SNAPSHOT</version>
<name>TransparentApp</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna-platform</artifactId>
<version>5.14.0</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>21.0.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<source>21</source>
<target>21</target>
</configuration>
</plugin>
</plugins>
</build>
</project>