JavaFX透明窗口仅接收绘制像素上的鼠标事件

我想要一个与屏幕大小相同的舞台,它是完全透明的,可以在任何地方接收鼠标事件。 在下面的示例中,仅当鼠标位于圆圈上时才会收到鼠标事件。 我在使用Java 8u11的Windows XP和Windows 7上都看到了这个问题

import javafx.application.Application; import javafx.geometry.Rectangle2D; import javafx.scene.Scene; import javafx.scene.layout.StackPane; import javafx.scene.paint.Color; import javafx.scene.shape.Circle; import javafx.scene.shape.Rectangle; import javafx.stage.Screen; import javafx.stage.Stage; import javafx.stage.StageStyle; public class TransparentTest extends Application { public static void main(String[] args) { launch(args); } @Override public void start(Stage ignored) throws Exception { Stage stage = new Stage(StageStyle.TRANSPARENT); stage.setTitle("Transparent app test"); Rectangle2D screenBounds = Screen.getPrimary().getBounds(); stage.setX(0); stage.setY(0); stage.setWidth(screenBounds.getWidth()); stage.setHeight(screenBounds.getHeight()); Circle circle = new Circle(100); circle.setFill(Color.RED); Rectangle rectangle = new Rectangle(screenBounds.getWidth(), screenBounds.getHeight()); rectangle.setFill(Color.TRANSPARENT); Scene scene = new Scene(new StackPane(circle, rectangle)); scene.setFill(null); stage.setScene(scene); scene.setOnMouseMoved((e) -> { System.out.println("Mouse over rectangle " + e); }); stage.show(); } } 

有趣的是,如果我将填充颜色的alpha部分设置为绝对最小值,那么我会得到鼠标事件。 但是,我不想使用这种解决方法,实际上是问题的根源。 我的结论是在JavaFX或Windows库中的某处,有一些命中检测代码根据鼠标事件的像素值过滤鼠标事件。

  rectangle.setFill(Color.rgb(0, 0, 0, 1d / 255d)); // receives mouse events rectangle.setFill(Color.rgb(0, 0, 0, 0)); // does not receive mouse events 

研究

  • JavaFx透明窗口 – 是的请。 鼠标透明 – 不用感谢描述类似的问题,但它没有解决完全透明区域中鼠标事件的问题
  • 调试 – 在setOnMouseMoved()中使用断点我检查了前面的堆栈帧,试图找到命中检测代码。
  • 使用JNA测试不同的样式,例如WS_EX_TRANSPARENT和WS_EX_LAYERED。 有趣的是,WS_EX_TRANSPARENT使窗口完全是鼠标透明的 – 在绘制的像素上没有鼠标事件。
  • 尝试将鼠标监听器放在矩形/ StackPane上 – 没有区别
  • MSDN文章分层Windows提示此function是Windows的一部分,而不是JavaFX。 如果这是真的有任何解决方法吗?

分层窗口的命中测试基于窗口的形状和透明度。 这意味着窗口中的颜色键或其alpha值为零的区域将允许鼠标消息通过。 如果分层窗口具有WS_EX_TRANSPARENT扩展窗口样式,则将忽略分层窗口的形状,并将鼠标事件传递到分层窗口下的其他窗口。

总之,只有已知的解决方案是将背景设置为“不完全”透明,以便将JavaFX欺骗为发送事件。

 rectangle.setFill(Color.rgb(0, 0, 0, 1d / 255d)); // receives mouse events