【问题标题】:JTextField not correctly updatingJTextField 未正确更新
【发布时间】:2012-01-30 21:22:12
【问题描述】:

我目前正在开发一个在 MySQL 数据库上执行查询的实用程序,并且我目前正在处理接口。

当用户单击“连接”按钮时,状态栏 (JTextField) 文本应更改为“正在连接...”。这可以正常工作:

connectButton.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            statusBar.setText("Connecting...");
            }
        }
    });

我实现了一个连接数据库的功能,然后单击“连接”按钮:

connectButton.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            Class.forName("com.mysql.jdbc.Driver");
            statusBar.setText("Connecting...");
            connection = DriverManager.getConnection("jdbc:mysql://" + database);
            }
        }
    });

在这种情况下,状态栏的文本在连接建立之前不会变为“正在连接...”。

为了提高可读性,我删除了一些代码,例如异常处理。

如何在连接建立之前强制改变状态栏的文字?

【问题讨论】:

标签: java sql swing jtextfield concurrency


【解决方案1】:

不应在事件调度线程中执行建立数据库连接。这会阻止您的组件更新。而是在后台线程中执行任务。

如果您需要在执行此操作时报告结果,请使用SwingWorker 类,或使用SwingUtilities 类更新组件,尤其是invokeLater。这两者都将确保组件在 EDT 上更新,并且长时间运行的任务发生在其他地方。

更多信息,请阅读Concurrency in Swing

【讨论】:

  • 好的,谢谢。我想我需要学习如何使用 SwingWorker。你能推荐我一些好的教程或简单的例子吗?
  • 您不需要使用SwingWorker,您只需需要了解 Swing 线程模型。 :D
【解决方案2】:

正如其他人所提到的,连接逻辑最好在 Event Dispatch Thread 以外的线程上执行。但是,从技术上讲,这并不是文本字段在建立连接之前不更新的原因。

发生这种情况的实际原因是 Swing 组件在内部使用数据结构来存储侦听器(在本例中为 ActionListeners),因此侦听器的通知顺序与之前的顺序相比相反添加。因此,在您的示例中,创建连接的 ActionListener 在负责更新文本的侦听器之前得到通知。

一个简单的解决方法是将两个ActionListeners 合并到一个代码块中;没有理由需要添加多个侦听器。这当然会导致您的 GUI 在尝试连接时阻塞,这就是为什么其他人建议使用诸如 SwingWorker 之类的机制来防止这种情况发生。

connectButton.addActionListener(new ActionListener() {
  public void actionPerformed(ActionEvent e) {
    statusBar.setText("Connecting...");

    new SwingWorker<Void, Void>() {
      protected Void doInBackground() {
        // Called on a background thread.
        connectToDatabase();
        return null;
      }

      protected void done() {
        // Called on Event Dispatch thread once connect routine has completed.
        try {
          get(); // Propagate any exceptions back to Event Dispatch thread.
        } catch (Exception ex) {
          ex.printStackTrace();
          JOptionPane.showMessageDialog(null,
            "Failed to connect: " + ex.getMessage(),
            "Error",
            JOptionPane.ERROR_MESSAGE);
        }
      }
    }.execute();
  }
});

【讨论】:

  • 我只有一个听众。我只是指定了多个,所以你可以理解我的问题。
【解决方案3】:

这个问题每两天问一次。

如果您在事件分派线程中执行代码,则会阻塞该线程,从而阻止它执行所有必要的重绘操作,以使文本出现在文本字段中。

长时间运行的阻塞任务应该在后台线程中运行,并且该线程不能访问 Swing 组件。使用SwingWorker。它的 javadoc 解释了一切。它还有一个指向 Swing 教程相关部分的链接,您应该阅读。

【讨论】:

    【解决方案4】:

    这是因为您在 EDT(AWT 事件调度线程)中建立连接。在建立连接时,不再更新、处理用户输入和重新绘制屏幕上的窗口(以图形方式)。这意味着在建立连接之前,整个应用程序似乎都被冻结了。
    所以要解决这个问题,你必须在另一个线程中建立连接。另一种不推荐的肮脏方法是在更改文本后强制 EDT 重新绘制屏幕。这是最简单的工作方式,但不是整洁的方式。

    这可以通过调用repaint(); 然后调用update(getGraphics()); 来完成。但它非常肮脏。我想你的屏幕甚至会闪烁。但这很好地说明了这个问题。首先对此进行测试以了解实际发生的情况可能会很有趣。

    【讨论】:

      猜你喜欢
      • 2013-03-19
      • 2021-10-26
      • 1970-01-01
      • 2021-11-03
      • 2018-01-20
      • 2020-04-09
      • 2013-04-02
      • 2017-03-09
      • 1970-01-01
      相关资源
      最近更新 更多