JavaFX 2 用户空闲检测 [英] JavaFX 2 User Idle Detection

查看:17
本文介绍了JavaFX 2 用户空闲检测的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述


我正在尝试使用 JavaFX 作为 UI 制作一个简单的 Java 事务应用程序.
我现在想要做的是从我的应用程序中检测用户空闲状态,该应用程序具有 1 个初级阶段和许多场景.

示例:如果用户空闲 3 分钟,则返回主菜单.

我已经在网上尝试了一些关于如何检测 JavaFX 空闲状态的示例,但我发现总是 - 一个函数空闲状态检测,它发生在所有场景中 - 方法(我认为)对事务应用程序是危险的(例如:应用程序检测事务过程中间的空闲状态).
是否可以在每个场景中检测用户空闲状态?如何?
谢谢.

我已经尝试过的例子:

http://tomasmikula.github.io/blog/2014/06/04/timers-in-javafx-and-reactfx.html

http://ochafik.com/blog/?p=98

推荐答案

我不太明白您对事务行为的看法.事务关注对数据的保证,您的事务行为应该在数据级别定义,不应受到 UI 中发生的事情的影响.换句话说,即使 UI 由于用户空闲而重置,您的原子行为也应该完成或回滚.

I don't really understand the point you are making about transactional behavior. Transactions concern guarantees about the data, and your transactional behavior should be defined at the data level and should not be impacted by what is happening in the UI. In other words, your atomic behavior should complete or rollback even if the UI resets due to the user being idle.

不过,也许这会有所帮助.(请注意,我在这些示例中使用了 Java 8 代码,但如果需要,您可以相当轻松地使其符合 JavaF 2.2.)这遵循 Tomas Mikula 的一般方法,因为它使用 Timeline 来实现空闲检查.我没有使用 Tomas 的 FX Timer 包装器,但如果您愿意,当然可以这样做.该类封装了用户是否空闲的监控器.您可以注册任何节点(或场景)和事件类型:如果该类型的事件发生在该节点(或场景)上,则确定用户没有空闲.如果指定的时间过去了而没有发生任何注册事件,则执行提供的可运行对象(在 FX 应用程序线程上).这使您可以根据需要灵活地创建多个监视器,并为每个监视器注册一个或多个节点.

Maybe this will help, though. (Note I used Java 8 code in these examples, but you can fairly easily make it JavaF 2.2 compliant if you need.) This follows Tomas Mikula's general approach in that it uses a Timeline to implement the idle check. I didn't use Tomas' FX Timer wrapper but you could certainly do so if you like. This class encapsulates a monitor for whether the user is idle. You can register any node (or scene) and type of event: if an event of that type occurs on that node (or scene), the user is determined not to be idle. If the specified time elapses without any registered events occurring, the provided runnable is executed (on the FX Application Thread). This gives you the flexibility to create multiple monitors, if needed, and to register one or more nodes with each.

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();
    }
}

这是一个测试.开始"按钮可能是登录的替代品.主 UI 有一个带有两个选项卡的选项卡窗格:每个单独的选项卡都以自己的开始"按钮开始,然后主要内容有一个标签、文本字段和按钮.

Here's a test. The "Start" buttons are perhaps stand-ins for logging in. The main UI has a tab pane with two tabs: each individual tab starts with its own "Start" button and then the main content has a label, text field, and button.

每个选项卡内容都有一个(简称,用于测试)空闲监视器与之关联.选项卡内容上的任何事件都会重置空闲监视器,但选项卡内容之外的事件不会重置它.整个窗口还有一个全局"空闲监视器,它会在 30 秒后重置整个 UI.

The tab contents each have a (short, for testing) idle monitor associated with them. Any event on the content of the tab will reset the idle monitor, but events outside of the tab content will not reset it. There's also a "global" idle monitor for the entire window which resets the whole UI after 30 seconds.

请注意,数据会被保留:即如果您因空闲而超时,您在文本字段中输入的任何文本都会被正确保留.这就是为什么我认为交易"的问题根本不重要.

Note that the data is preserved: i.e. if you timeout due to the idle, any text you type in the text field is preserved properly. This is why I think the issue with "transactions" should not matter at all.

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);
    }
}

这篇关于JavaFX 2 用户空闲检测的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆