JTextField未正确更新

时间:2012-01-30 21:22:12

标签: java sql swing jtextfield concurrency

我目前正在开发一个在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);
            }
        }
    });

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

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

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

4 个答案:

答案 0 :(得分:4)

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

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

有关详情,请参阅Concurrency in Swing

答案 1 :(得分:3)

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

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

一个简单的解决方法是将两个ActionListener合并为一个代码块;没有理由需要添加多个侦听器。这当然会导致您的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();
  }
});

答案 2 :(得分:2)

每两天就会提出一个问题。

如果在事件调度线程中执行代码,则会阻止此threa,从而阻止它执行文本字段中显示所需的所有重绘操作。

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

答案 3 :(得分:1)

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

这可以通过调用repaint();然后调用update(getGraphics());来完成。但是非常脏。我认为你的屏幕会闪烁。但这很好地证明了这个问题。首先测试它可能会很有趣,看看究竟发生了什么。