Проблемы с обнаружением событий после использования контекстного меню в JavaFX (Linux)Linux

Ответить
Anonymous
 Проблемы с обнаружением событий после использования контекстного меню в JavaFX (Linux)

Сообщение Anonymous »

Я столкнулся со странным поведением приложения JavaFX, работающего в Linux.
Приложение представляет собой простой графический редактор. Его основная область представлена ​​ScrollPane с двумя полосами прокрутки и содержимым панели прокрутки AnchorPane, дочерними элементами которой являются два слоя - графический слой (где размещаются все объекты) и слой выбора (для реализации рамки выбора).
Графический слой также имеет контекст. меню.
Рамка выбора реализуется путем обнаружения событий перетаскивания. Вы нажимаете кнопку мыши, и создается рамка выделения, затем вы перемещаете мышь и прямоугольник перерисовывается в соответствии с координатами X и Y мыши. Когда вы отпускаете кнопку, все объекты внутри прямоугольника выбираются, а затем прямоугольник удаляется. Ключевым моментом этого поведения является то, что всякий раз, когда я перетаскиваю мышь за пределы сцены, события перетаскивания мышью по-прежнему обнаруживаются, поэтому размер прямоугольника увеличивается, а полосы прокрутки соответственно уменьшаются, показывая, что общий размер графической области увеличивается. Это нормальное поведение.
Проблема в том, что после открытия контекстного меню, когда я пытаюсь выбрать объекты с помощью рамки выбора, рамка выбора не может выйти за пределы видимой области панели прокрутки, что приводит к перетаскиванию. события больше не обнаруживаются за пределами сцены. Нажатие мыши обнаруживается, перетаскивание мыши обнаруживается только внутри видимой области панели прокрутки. Но если я открываю контекстное меню, ЗАТЕМ нажимаю кнопку мыши на графическом слое и ПОСЛЕ этого использую рамку выделения, то все работает правильно. Другой способ вернуться к нормальному поведению - нажать клавишу ESC.
Эта проблема существует только в Linux, в Windows все работает отлично. Также эта проблема появилась после перехода с Java 8 со встроенным JavaFX на Java 17 с JavaFX 21.
Я придумал несколько обходных путей этой проблемы, например, используя Robot API для нажатия ESC. клавиша, когда контекстное меню скрыто, но я хотел бы решить эту проблему более чистым и подходящим способом.
Буду признателен за любую помощь.
Минимальный воспроизводимый пример

Код: Выделить всё

package org.example;

import javafx.application.Application;
import javafx.geometry.Point2D;
import javafx.scene.Scene;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuItem;
import javafx.scene.control.ScrollPane;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import org.controlsfx.control.NotificationPane;

public class Main extends Application {
public static void main(String[] args) {
launch(args);
}

public void start(Stage primaryStage) {
AnchorPane mainPane = new AnchorPane();

//Creating scroll pane
ScrollPane scroll = new ScrollPane();
scroll.setContent(mainPane);
scroll.setHbarPolicy(ScrollPane.ScrollBarPolicy.ALWAYS);
scroll.setVbarPolicy(ScrollPane.ScrollBarPolicy.ALWAYS);
scroll.setPrefWidth(1024);
scroll.setPrefHeight(768);

//Creating selection layer to place selection frame
AnchorPane selectionLayer = new AnchorPane();
selectionLayer.setMouseTransparent(true);

//Creating graphic layer
NotificationPane graphicLayer = new NotificationPane();
graphicLayer.setMinHeight(768);
graphicLayer.setMinWidth(1024);
graphicLayer.setFocusTraversable(false);

//Creating context menu
ContextMenu contextMenu = new ContextMenu();
contextMenu.getItems().add(new MenuItem("test1"));
contextMenu.getItems().add(new MenuItem("test2"));

graphicLayer.setContextMenu(contextMenu);

SelectionController controller = new SelectionController(selectionLayer);

graphicLayer.setOnMousePressed(event -> {
System.err.println("PRESSED"); //added output to see which events are triggered
controller.startSelection(event);
});

graphicLayer.setOnMouseDragged(event -> {
System.err.println("DRAGGED");
controller.setPosition(event);
});

graphicLayer.setOnMouseReleased(event -> {
System.err.println("RELEASED");
controller.finishSelection(event);
});

mainPane.getChildren().addAll(graphicLayer, selectionLayer);

Scene scene = new Scene(scroll);
primaryStage.setScene(scene);

primaryStage.show();
}

class SelectionController {
AnchorPane selectionLayer;
Point2D startingPoint;
Rectangle selectionFrame;

SelectionController(AnchorPane selectionLayer) {
this.selectionLayer = selectionLayer;
}

void startSelection(MouseEvent event) {
startingPoint = new Point2D(event.getX(), event.getY());

selectionFrame = new Rectangle();
selectionFrame.setId("selection_frame");
selectionFrame.setFill(Color.TRANSPARENT);
selectionFrame.getStrokeDashArray().add(10.0);
selectionFrame.setStrokeWidth(2.0);
selectionFrame.setStroke(Color.LIGHTSKYBLUE);
selectionFrame.xProperty().set(startingPoint.getX());
selectionFrame.yProperty().set(startingPoint.getY());

selectionLayer.getChildren().add(selectionFrame);
}

void setPosition(MouseEvent event) {
double x = event.getX();
double y = event.getY();

if (x < startingPoint.getX()) {
selectionFrame.xProperty().set(x);
selectionFrame.widthProperty().set(startingPoint.getX() - x);
} else {
selectionFrame.widthProperty().set(x - startingPoint.getX());
}

if (y <  startingPoint.getY()) {
selectionFrame.yProperty().set(y);
selectionFrame.heightProperty().set(startingPoint.getY() - y);
} else {
selectionFrame.heightProperty().set(y - startingPoint.getY());
}
}

void finishSelection(MouseEvent event) {
// Do some logic to filter objects on graphic layer inside selection frame

selectionLayer.getChildren().clear();
}
}
}
Действия для воспроизведения:

[*]Запустить приложение
[*]Попробовать использовать выбор кадр, левый верхний угол внутри сцены, затем перетащите правый нижний угол за пределы видимых границ сцены. Вы увидите, что перетаскиваемые события все еще активируются.
[*]Нажмите правую кнопку, чтобы вызвать контекстное меню.
[*]Когда меню все еще отображается, попробуйте повторить шаг 2. Вы увидите, что рамка выделения не выходит за границы сцены, несмотря на то, что указатель мыши находится за пределами сцены. Также перетаскиваемые события не запускаются за пределами сцены.
[*]Повторите шаг 3. Теперь, если вы щелкнете внутри сцены или нажмете кнопку ESC перед созданием рамки выбора, рамка выбора будет вести себя так, как должна


Подробнее здесь: https://stackoverflow.com/questions/786 ... vafx-linux
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Linux»