延迟 ListSelectionListener 事件

Delay in ListSelectionListener event

我有一个普通的JTable 和一个ListSelectionListener。我想它可以正常工作,但有一个问题:

  1. 我点击 table 行
  2. 事件触发(方法 valueChanged 启动)
  3. 在 valueChanged 内部,我启动了一个 http 请求(需要几毫秒)
  4. 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 线程上执行任务。您将在后台线程中执行此操作并弹出一个模式对话框,可能为用户提供提前取消任务的选项。