我们的系统目前允许用户拖放落在JTree上。当用户将鼠标悬停在树中的节点上时,我们编写了代码来扩展树节点。然而,Java和现代计算机的速度是它们的节点往往会非常快速地扩展。如果用户非常快速地拖动树中的许多节点,则所有节点都会扩展。
我们需要的是在树节点扩展发生之前的一些延迟,可能是一两秒。如果用户没有停留在节点上以获得分配的延迟,则节点不应该扩展。
实现此行为的最佳方法是什么。
答案 0 :(得分:3)
您可以使用ScheduledExecutorService执行任务以在给定延迟后展开节点。您还可以在用户移动新节点时取消挂起的任务。
例如:
public class ReScheduler {
private ScheduledFuture<?> currentTask = null;
private static final ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
public void schedule(Runnable command, long delay, TimeUnit units) {
if (currentTask != null) {
currentTask.cancel();
currentTask = null;
}
currentTask = executor.schedule(command, delay, units);
}
}
在您的客户端代码中,在Swing UI线程上,使用现有的ReScheduler实例,只要新节点悬停在其上,您就会执行以下操作:
myRescheduler.schedule(new Runnable() {
public void run() {
SwingUtilities.invokeLater(task to expand the node in the tree!);
}
}, 2, TimeUnit.SECONDS);
为了获得最佳实践,您应该为“Executors.newScheduledThreadPool”提供一个线程工厂,该工厂将命名所创建的线程。类似于NamedThreadFactory。
做StanislavL建议的实际上会更直接一些。只要将鼠标悬停在组件上,就可以安排将扩展该组件的任务。当任务启动时,请检查用户是否仍然将鼠标悬停在已安排任务的组件上。
public void hovered() {
final Component node = node currently hovered over; // node is the component
// that is causing the task to be scheduled
executor.schedule(new Runnable() {
public void run() {
// see if the node that the mouse is over now is the same node it was over 2 seconds ago
if (getComponentUnderMouse() == node) {
expand(node); // do this on the EDT
} else {
// do nothing because we are over some other node
}
}
}, 2, TimeUnit.SECONDS);
}
答案 1 :(得分:1)
当鼠标位于节点上时,您可以使用所需的延迟启动Timer。调用Timer动作时,只需检查鼠标是否仍在同一节点上。如果是,请展开,如果不是什么都不做。