如何在JavaFX中制作鼠标透明舞台

问题描述 投票:0回答:1

我想制作一个在屏幕中间显示十字准线的 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;");
    }
java javafx mouseevent transparent stage
1个回答
0
投票

这是一个仅限 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>
© www.soinside.com 2019 - 2024. All rights reserved.