Обнаружение простоя пользователя JavaFX 2
Я пытаюсь сделать простое приложение транзакций Java с JavaFX в качестве пользовательского интерфейса.
То, что я хочу сделать сейчас, - это определить состояние простоя пользователя из моего приложения, которое имеет 1 начальную стадию и множество сцен.
Пример: если пользователь простаивает 3 минуты, вернитесь в главное меню.
Я уже пробовал несколько примеров в Интернете о том, как обнаружить состояние простоя JavaFX, но я обнаружил, что всегда - обнаружение состояния простоя одной функции, которое происходит во всех сценах, - метод, который (я думаю) опасен для приложения транзакции (например: приложения обнаруживают) состояние бездействия в середине процесса транзакции).
Можно ли определить состояние простоя пользователя на каждой сцене? как?
Благодарю.
РЕДАКТИРОВАТЬ:
Примеры, которые я уже пробовал:
http://tomasmikula.github.io/blog/2014/06/04/timers-in-javafx-and-reactfx.html
а также
1 ответ
Я не совсем понимаю, что вы говорите о транзакционном поведении. Транзакции касаются гарантий данных, и ваше поведение транзакций должно определяться на уровне данных и не должно зависеть от того, что происходит в пользовательском интерфейсе. Другими словами, ваше атомарное поведение должно завершиться или выполнить откат, даже если пользовательский интерфейс сбрасывается из-за простоя пользователя.
Может быть, это поможет, хотя. (Обратите внимание, что я использовал код Java 8 в этих примерах, но вы можете довольно легко сделать его совместимым с JavaF 2.2, если вам нужно.) Это следует общему подходу Томаса Микулы в том, что он использует Timeline
реализовать проверку на холостом ходу. Я не использовал оболочку FX Timer от Tomas, но вы можете сделать это, если хотите. Этот класс инкапсулирует монитор для того, находится ли пользователь в режиме ожидания. Вы можете зарегистрировать любой узел (или сцену) и тип события: если событие этого типа происходит на этом узле (или сцене), то определяется, что пользователь не находится в режиме ожидания. Если указанное время истекает без каких-либо зарегистрированных событий, выполняется предоставленный исполняемый файл (в потоке приложений FX). Это дает вам возможность создавать несколько мониторов, если это необходимо, и регистрировать один или несколько узлов на каждом.
import javafx.animation.Animation;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.event.EventType;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.util.Duration;
public class IdleMonitor {
private final Timeline idleTimeline ;
private final EventHandler<Event> userEventHandler ;
public IdleMonitor(Duration idleTime, Runnable notifier, boolean startMonitoring) {
idleTimeline = new Timeline(new KeyFrame(idleTime, e -> notifier.run()));
idleTimeline.setCycleCount(Animation.INDEFINITE);
userEventHandler = e -> notIdle() ;
if (startMonitoring) {
startMonitoring();
}
}
public IdleMonitor(Duration idleTime, Runnable notifier) {
this(idleTime, notifier, false);
}
public void register(Scene scene, EventType<? extends Event> eventType) {
scene.addEventFilter(eventType, userEventHandler);
}
public void register(Node node, EventType<? extends Event> eventType) {
node.addEventFilter(eventType, userEventHandler);
}
public void unregister(Scene scene, EventType<? extends Event> eventType) {
scene.removeEventFilter(eventType, userEventHandler);
}
public void unregister(Node node, EventType<? extends Event> eventType) {
node.removeEventFilter(eventType, userEventHandler);
}
public void notIdle() {
if (idleTimeline.getStatus() == Animation.Status.RUNNING) {
idleTimeline.playFromStart();
}
}
public void startMonitoring() {
idleTimeline.playFromStart();
}
public void stopMonitoring() {
idleTimeline.stop();
}
}
Вот тест. Кнопки "Пуск", возможно, являются заменой для входа в систему. Основной интерфейс имеет панель вкладок с двумя вкладками: каждая отдельная вкладка начинается со своей собственной кнопки "Пуск", а затем основное содержимое имеет метку, текстовое поле и кнопку.,
С каждым содержимым вкладки связан (кратко, для тестирования) монитор простоя, связанный с ними. Любое событие в содержимом вкладки сбрасывает монитор простоя, но события вне содержимого вкладки не сбрасывают его. Есть также "глобальный" монитор простоя для всего окна, который сбрасывает весь интерфейс через 30 секунд.
Обратите внимание, что данные сохраняются: т. Е. При превышении времени ожидания из-за простоя любой текст, введенный в текстовое поле, сохраняется должным образом. Вот почему я думаю, что проблема с "транзакциями" не должна иметь никакого значения.
import javafx.application.Application;
import javafx.event.Event;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.control.TextField;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Duration;
public class IdleTest extends Application {
@Override
public void start(Stage primaryStage) {
StackPane root = new StackPane();
Parent mainUI = buildMainUI();
Scene scene = new Scene(root, 350, 150);
Parent startUI = buildStartUI(() -> root.getChildren().setAll(mainUI));
root.getChildren().add(startUI);
IdleMonitor idleMonitor = new IdleMonitor(Duration.seconds(30),
() -> root.getChildren().setAll(startUI), true);
idleMonitor.register(scene, Event.ANY);
primaryStage.setScene(scene);
primaryStage.show();
}
private Parent buildStartUI(Runnable start) {
Button button = new Button("Start");
button.setOnAction(e -> start.run());
StackPane root = new StackPane(button);
return root ;
}
private Parent buildMainUI() {
TabPane tabPane = new TabPane();
Tab tab1 = new Tab("One");
Parent tab1Content = buildTabUI("Tab 1");
Parent tab1StartContent = buildStartUI(() -> tab1.setContent(tab1Content));
tab1.setContent(tab1StartContent);
IdleMonitor tab1IdleMonitor = new IdleMonitor(Duration.seconds(5),
() -> tab1.setContent(tab1StartContent), true);
tab1IdleMonitor.register(tab1Content, Event.ANY);
Tab tab2 = new Tab("Two");
Parent tab2Content = buildTabUI("Tab 2") ;
Parent tab2StartContent = buildStartUI(() -> tab2.setContent(tab2Content));
tab2.setContent(tab2StartContent);
IdleMonitor tab2IdleMonitor = new IdleMonitor(Duration.seconds(10),
() -> tab2.setContent(tab2StartContent), true);
tab2IdleMonitor.register(tab2Content, Event.ANY);
tabPane.getTabs().addAll(tab1, tab2);
return tabPane ;
}
private Parent buildTabUI(String text) {
Button button = new Button("Click here");
button.setOnAction(e -> System.out.println("Click in "+text));
VBox content = new VBox(10, new Label(text), new TextField(), button);
content.setAlignment(Pos.CENTER);
return content ;
}
public static void main(String[] args) {
launch(args);
}
}