gpt4 book ai didi

java - 当目标节点改变场景时,Ubuntu 上不会发生鼠标释放事件?

转载 作者:太空宇宙 更新时间:2023-11-03 17:07:05 26 4
gpt4 key购买 nike

这个问题涉及跨操作系统的鼠标行为;具体来说,我的代码适用于 Windows 和 Mac OS X,但不适用于 Ubuntu。

最终我想做的是制作一个特殊的 Pane 子类(“ConvertiblePane”),它存在于主舞台/场景的父 Pane 中,但在拖动时神奇地转移到它自己的临时舞台/场景中,从而成为独立且能够放置在屏幕上的任何位置。当用户释放鼠标按钮时,ConvertiblePane 应该回到其原始父 Pane 并失去临时舞台。 (在我的完整程序中,原始父 Stage 会自行调整大小/重新定位以适应 ConvertiblePane 的放置位置。)

这让我想到了我的问题。当我在 ConvertiblePane 上按下鼠标时,它会按预期在主场景中触发 MousePress,此时 ConvertiblePane 将移至临时舞台。当我拖动鼠标时,它会在临时场景中触发 MouseDrag 并移动临时舞台。好的,太好了。

但是,当我释放鼠标按钮时,我会在不同的操作系统上遇到不同的行为。在 Windows (7) 和 Mac OS X (10.12.6) 上,在临时场景中发生 MouseRelease,按预期将 Pane 发送回其在主舞台中的原始父级。然而,在 Ubuntu 上,似乎在主场景或临时场景中都没有生成 MouseRelease。

这是作为 MCV 示例的相关代码:

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Point2D;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.CornerRadii;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javafx.stage.StageStyle;

public class ConvertibleTest extends Application {

@Override
public void start(Stage primaryStage) {

// Set up the main stage and scene with a
// Pane as root and a ConvertiblePane child:
primaryStage.initStyle(StageStyle.TRANSPARENT);
Pane root = new Pane();
ConvertiblePane conv = new ConvertiblePane();
root.getChildren().add(conv);
Scene scene = new Scene(root, 400, 400, Color.PINK);
primaryStage.setTitle("Convertible Test");
primaryStage.setScene(scene);
primaryStage.show();
}

public static void main(String[] args) {
launch(args);
}
}

class ConvertiblePane extends Pane
{
private final Group TEMP_ROOT = new Group();
private final Stage TEMP_STAGE = new Stage(StageStyle.TRANSPARENT);
private final Scene TEMP_SCENE = new Scene(TEMP_ROOT);
private Pane originalParent = null;
private double deltaX = 0.0;
private double deltaY = 0.0;
private String name = null;

public void onMousePress(MouseEvent event)
{
// Save deltaX/Y for later:
Point2D delta = this.sceneToLocal(event.getX(), event.getY());
deltaX = delta.getX();
deltaY = delta.getY();

if (!isIndependent())
{
makeIndependent();
}
}

public void onMouseDrag(MouseEvent event)
{
// Keep the TEMP_STAGE relative to the original click point:
TEMP_STAGE.setX(event.getScreenX()-deltaX);
TEMP_STAGE.setY(event.getScreenY()-deltaY);
}

public void onMouseRelease(MouseEvent event)
{
if (isIndependent())
{
returnToParent();
}
}

public ConvertiblePane()
{
this.setPrefSize(100, 100);
this.setBackground(new Background(new BackgroundFill(Color.GREEN, new CornerRadii(10), Insets.EMPTY)));
this.setVisible(true);

// Attach event code and report to System.out what is happening:
this.setOnMousePressed((MouseEvent event) -> {
if (this.getScene() == TEMP_SCENE)
System.out.println("Pressed as Independent");
else
System.out.println("Pressed as Child");
onMousePress(event);
});
this.setOnMouseDragged((MouseEvent event) -> {
if (this.getScene() == TEMP_SCENE)
System.out.println("Dragged as Independent");
else
System.out.println("Dragged as Child");
onMouseDrag(event);
});
this.setOnMouseReleased((MouseEvent event) -> {
if (this.getScene() == TEMP_SCENE)
System.out.println("Released as Independent");
else
System.out.println("Released as Child");
onMouseRelease(event);
});
}

public boolean isIndependent()
{
// Return whether this ConvertiblePane is "independent" (exists in its own temp scene)
return this.getScene() == TEMP_SCENE;
}

public void makeIndependent()
{
// Get the point where this ConvertiblePane appears on screen:
Point2D screenPt = this.localToScreen(0, 0);

// Save the originaParent of this ConvertiblePane; we will return to it later:
originalParent = (Pane)getParent();

// Remove this ConvertiblePane from its originalParent:
originalParent.getChildren().remove(this);

// Set this ConvertiblePane as the root of the TEMP_SCENE on the TEMP_STAGE:
TEMP_SCENE.setRoot(this);
TEMP_STAGE.setScene(TEMP_SCENE);
System.out.println("Transferred to TEMP.");
this.relocate(0, 0);

// Show the TEMP_STAGE in the same location on screen where this ConvertiblePane originally was:
TEMP_STAGE.setX(screenPt.getX());
TEMP_STAGE.setY(screenPt.getY());
TEMP_STAGE.show();
}

public void returnToParent()
{
// Reset deltas:
deltaX = 0;
deltaY = 0;

// Get the location of this ConvertiblePane on screen:
Point2D screenPt = this.localToScreen(0, 0);

// Set TEMP_ROOT as the root of TEMP_SCENE; this will allow us to detach
// this ConvertiblePane from being the scene root (since root cannot == null).
TEMP_SCENE.setRoot(TEMP_ROOT);

// Hide the TEMP_STAGE:
TEMP_STAGE.hide();

// Add this ConvertiblePane back to the originalParent:
originalParent.getChildren().add(this);
System.out.println("Transferred to MAIN.");

// Relocate this ConvertiblePane within the originalParent to maintain its position on screen
Point2D parentPt = originalParent.screenToLocal(screenPt);
this.relocate(parentPt.getX(), parentPt.getY());
}
}

如您所见,事件处理方法中有一些基本的报告; makeIndependent() 和 returnToParent() 方法输出“Transferred to TEMP”。和“转移到 MAIN”。分别。

如果我在 ConvertiblePane 上单击鼠标,拖动几个像素,然后松开,这就是输出:

(在 Windows 或 Mac OS X 上)
孩提时代的压力
转移到 TEMP。
拖动为独立
拖动为独立
拖动为独立
作为独立发布
转移到 MAIN。

(在 Ubuntu 上)
孩提时代的压力
转移到 TEMP。
拖动为独立
拖动为独立
拖动为独立

我也试过为两个场景添加事件过滤器;但结果是一样的:MouseRelease 出现在 Win/Mac 上,但不是 Ubuntu。

如果有人能解释这种行为或提出建议,那就太好了。或者...是否有任何我可以捕获的 MouseEvents 的“全局”(场景前)创建?我的意思是,我真的不关心鼠标释放的细节;我只想要一个事件来告诉我何时将 ConvertiblePane 添加回主舞台。

谢谢!

最佳答案

在这方面花了几个星期之后,我找不到一种方法来针对这种情况在 Ubuntu 上触发适当的 MouseReleased 事件;但是,我确实想出了一个可以很好地完成工作的 hack。基本上,我不会在 MouseReleased 发生时收到通知,而是每 10 毫秒检查一次鼠标按钮是否不再按下。

解释:当节点转移到临时场景时,时间轴开始每10毫秒将鼠标指针“移动”到位。这会触发 MouseDragged 事件(如果鼠标按钮仍然按下)或 MouseMoved 事件(如果鼠标按钮向上);这样我就可以模拟 MouseReleased 事件并调用我的过程来将节点添加回主舞台。那时,当然,我也停止了时间线。

下面是相关代码来演示这一点;也许它对其他人也有用。

// The robot is needed to "move" the mouse in place,
// triggering a MOUSE_MOVED event.
private static Robot robot = null;
static {
try {
robot = new Robot();
} catch (AWTException ex) {
Logger.getLogger(ConvertiblePane.class.getName()).log(Level.SEVERE, null, ex);
}
}

// clickWaiter will move the mouse in place every 10 milliseconds,
// triggering a MOUSE_MOVED event if the mouse is no longer pressed.
private final Timeline clickWaiter = new Timeline(new KeyFrame(Duration.millis(10), (ActionEvent event) -> {
// Get the mouse position from MouseInfo class.
Point mouse = MouseInfo.getPointerInfo().getLocation();
// "Move" the mouse in place to trigger a mouseMove or mouseDrag event.
robot.mouseMove(mouse.x, mouse.y);
}));

public ConvertiblePane()
{
...

// MOUSE_MOVED will be triggered by the robot when the mouse button is no longer pressed:
TEMP_SCENE.addEventFilter(MouseEvent.MOUSE_MOVED, (MouseEvent event) ->
{
if (!event.isPrimaryButtonDown())
{
System.out.println("Temp.release (sim)");
clickWaiter.stop();
// Simulate MOUSE_RELEASED event.
}
});
}

public void makeIndependent()
{
...

// Start the clickWaiter, part of the Linux hack:
clickWaiter.playFromStart();
}

关于java - 当目标节点改变场景时,Ubuntu 上不会发生鼠标释放事件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50240054/

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