我并不是很理解你对于事务行为的观点。事务关注数据的保证,而你的事务行为应该在数据层面上进行定义,并不应受到UI的影响。换句话说,即使由于用户空闲而导致UI重置,你的原子行为也应该完成或回滚。
也许这可以帮助你。 (注意,我在这些示例中使用了Java 8代码,但如果需要,你可以相当容易地使其符合JavaFX 2.2规范。)这遵循Tomas Mikula的一般方法,它使用Timeline
实现空闲检查。我没有使用Tomas的FX Timer包装器,但如果你喜欢,你当然可以这样做。这个类封装了一个监视器,用于判断用户是否处于空闲状态。你可以注册任何节点(或场景)和事件类型:如果该节点(或场景)发生了该类型的事件,则确定用户不处于空闲状态。如果经过指定的时间没有发生任何已注册的事件,则会在FX Application线程上执行提供的可运行对象。这使得你可以灵活地创建多个监视器(如果需要),并向每个监视器注册一个或多个节点。
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具有包含两个选项卡的选项卡窗格:每个单独的选项卡都以自己的“开始”按钮开头,然后主内容具有标签、文本字段和按钮。
选项卡内容每个都与其关联一个(为测试而短暂的)空闲监视器。选项卡内容上的任何事件都会重置空闲监视器,但选项卡内容外的事件不会重置它。还有一个针对整个窗口的“全局”空闲监视器,它在30秒后重置整个UI。
请注意,数据将被保存:即使由于空闲而超时,您在文本字段中输入的任何文本也将得到适当的保存。这就是我认为“事务”问题根本无关紧要的原因。
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);
}
}