延迟 ListSelectionListener 事件
Delay in ListSelectionListener event
我有一个普通的JTable 和一个ListSelectionListener。我想它可以正常工作,但有一个问题:
- 我点击 table 行
- 事件触发(方法 valueChanged 启动)
- 在 valueChanged 内部,我启动了一个 http 请求(需要几毫秒)
- table 行被明显选中(蓝色背景)
这会产生明显的延迟。
我可以更改活动顺序吗?我想先有蓝色背景,然后再做 http 请求。
在 valueChanged 方法中插入一个睡眠计时器,使选择等到计时器完成。
您或许应该在后台线程上执行 HTTP 请求。如果花费异常长的时间,这也将具有保持 UI 响应的优势。
您最终会得到类似这样的代码,具体取决于您的实际需求:
private static class HttpWorker extends SwingWorker<Void, Void> {
private final String url;
private HttpWorker(String url) {
this.url = Objects.requireNonNull(url);
}
@Override
protected Void doInBackground() {
// do request, possibly producing some result
}
@Override
protected void done() {
if (!isCancelled()) {
// update UI
}
}
}
private HttpWorker worker;
@Override
public void valueChanged(ListSelectionEvent e) {
if (worker != null) {
// preserve apparent order of operations if
// the user selects something different while
// a background task is already running
worker.cancel(true);
worker = null;
}
worker = new HttpWorker(...);
worker.execute();
}
doInBackground
通常可以执行任何操作,只要您不与其中的 Swing UI 交互。
另见 the SwingWorker
tutorials and documentation。
为了获得完整的答案,在列表选择事件开始时执行以下操作可能有效:
jlist.paintImmediately(0, 0, jlist.getWidth(), jlist.getHeight());
至少在 paintImmediately
被指定做隐含的事情的范围内:
Paints the specified region in this component and all of its descendants that overlap the region, immediately. [...] This method is useful if one needs to update the display while the current event is being dispatched.
我不建议使用它的原因是 JList
没有特殊原因需要在我们自己的侦听器之前更新,这样列表实际上会绘制新的选择。
还有一个问题是,像 HTTP 请求这样的重任务通常不应该在 Swing 线程上完成,因为它会冻结 UI。即使在您希望用户等待一段时间的情况下,您也不会直接在 Swing 线程上执行任务。您将在后台线程中执行此操作并弹出一个模式对话框,可能为用户提供提前取消任务的选项。
我有一个普通的JTable 和一个ListSelectionListener。我想它可以正常工作,但有一个问题:
- 我点击 table 行
- 事件触发(方法 valueChanged 启动)
- 在 valueChanged 内部,我启动了一个 http 请求(需要几毫秒)
- table 行被明显选中(蓝色背景)
这会产生明显的延迟。
我可以更改活动顺序吗?我想先有蓝色背景,然后再做 http 请求。 在 valueChanged 方法中插入一个睡眠计时器,使选择等到计时器完成。
您或许应该在后台线程上执行 HTTP 请求。如果花费异常长的时间,这也将具有保持 UI 响应的优势。
您最终会得到类似这样的代码,具体取决于您的实际需求:
private static class HttpWorker extends SwingWorker<Void, Void> {
private final String url;
private HttpWorker(String url) {
this.url = Objects.requireNonNull(url);
}
@Override
protected Void doInBackground() {
// do request, possibly producing some result
}
@Override
protected void done() {
if (!isCancelled()) {
// update UI
}
}
}
private HttpWorker worker;
@Override
public void valueChanged(ListSelectionEvent e) {
if (worker != null) {
// preserve apparent order of operations if
// the user selects something different while
// a background task is already running
worker.cancel(true);
worker = null;
}
worker = new HttpWorker(...);
worker.execute();
}
doInBackground
通常可以执行任何操作,只要您不与其中的 Swing UI 交互。
另见 the SwingWorker
tutorials and documentation。
为了获得完整的答案,在列表选择事件开始时执行以下操作可能有效:
jlist.paintImmediately(0, 0, jlist.getWidth(), jlist.getHeight());
至少在 paintImmediately
被指定做隐含的事情的范围内:
Paints the specified region in this component and all of its descendants that overlap the region, immediately. [...] This method is useful if one needs to update the display while the current event is being dispatched.
我不建议使用它的原因是 JList
没有特殊原因需要在我们自己的侦听器之前更新,这样列表实际上会绘制新的选择。
还有一个问题是,像 HTTP 请求这样的重任务通常不应该在 Swing 线程上完成,因为它会冻结 UI。即使在您希望用户等待一段时间的情况下,您也不会直接在 Swing 线程上执行任务。您将在后台线程中执行此操作并弹出一个模式对话框,可能为用户提供提前取消任务的选项。