Этот вопрос касается поведения мыши в операционных системах; в частности, мой код работает в Windows и Mac OS X, но не в Ubuntu.
В конечном итоге я пытаюсь создать специальный подкласс Pane («ConvertiblePane»), который существует в родительской панели на главной сцене / сцене, но волшебным образом переносится на собственную временную сцену / сцену при перетаскивании, таким образом становясь независимый и может быть размещен в любом месте на экране. Когда пользователь отпускает кнопку мыши, ConvertiblePane должен вернуться на исходную родительскую панель и потерять временную стадию. (В моей полной программе исходная родительская сцена изменяет размеры / перемещает себя, чтобы приспособить конвертируемую панель везде, где она была отброшена.)
Это подводит меня к моей проблеме. Когда я нажимаю мышь на ConvertiblePane, он запускает MousePress в главной сцене, как и ожидалось, и в этот момент ConvertiblePane перемещается на временную стадию. Когда я перетаскиваю мышь, она вызывает MouseDrag во временной сцене и перемещает временную сцену. Хорошо, отлично.
Однако, когда я отпускаю кнопку мыши, в разных операционных системах у меня разное поведение. В Windows (7) и Mac OS X (10.12.6) в временной сцене происходит MouseRelease, отправляя панель обратно своему первоначальному родительскому элементу на основной стадии, как и ожидалось. Однако в 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 () выводят «Передано в TEMP». и "Переведено в ГЛАВНУЮ". соответственно.
Если я щелкну мышью на ConvertiblePane, перетащу несколько пикселей и отпущу, это будет вывод:
(on Windows or Mac OS X)
Pressed as Child
Transferred to TEMP.
Dragged as Independent
Dragged as Independent
Dragged as Independent
Released as Independent
Transferred to MAIN.
(on Ubuntu)
Pressed as Child
Transferred to TEMP.
Dragged as Independent
Dragged as Independent
Dragged as Independent
Я также попытался добавить фильтры событий к двум сценам; но результат тот же: MouseRelease происходит на Win / Mac, но не на Ubuntu.
Если кто-то может объяснить это поведение или предложить что-то, это было бы здорово. В качестве альтернативы ... есть ли какое-нибудь глобальное (до сцены) создание MouseEvents, которое я мог бы поймать? Я имею в виду, меня не волнуют детали выпуска мыши; Я просто хочу, чтобы событие сообщило мне, когда добавить ConvertiblePane обратно на главную сцену.
Спасибо!