JTextField 未正确更新

发布于 2025-01-01 04:38:35 字数 812 浏览 2 评论 0原文

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

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

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

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

I'm currently developing an utility which is executing queries on a MySQL database and I'm currently working on the interface.

When the user clicks on the button "Connect", the status bar (JTextField) text should change to "Connecting...". This works correctly:

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

I implemented a function to connect to a database then the "Connect" button is clicked:

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

In this case, the text of the status bar doesn't change to "Connecting..." until the connection is established.

I removed some of the code, like exception handling, for improved readability.

How can I force the text of the status bar to change before the connection is established?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

棒棒糖 2025-01-08 04:38:35

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

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

有关详细信息,请阅读 Swing 中的并发

Establishing a database connection should not be performed in the Event Dispatch Thread. This is preventing your component from updating. Instead, perform the task in a background thread.

If you need to report results while this action is taking place, either use the SwingWorker class, or update the component using the SwingUtilities class, in particular, invokeLater. Both of these will assure that the component(s) are updated on the EDT and that the long-running task takes place elsewhere.

For more information, please read Concurrency in Swing.

游魂 2025-01-08 04:38:35

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

发生这种情况的实际原因是 Swing 组件内部使用数据结构来存储侦听器(在本例中为 ActionListener),从而以与顺序相比相反的顺序通知侦听器他们被添加了。因此,在您的示例中,创建连接的 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();
  }
});

As others have mentioned the connection logic is best performed on a thread other than the Event Dispatch Thread. However, technically this is not the reason why the text field is not updated until the connection is established.

The actual reason why this occurs is that internally Swing components use a data structure to store listeners (in this case ActionListeners) whereby listeners are notified in reverse order compared to the order they were added. Hence in your example, the ActionListener that creates the connection is notified prior to the listener responsible for updating the text.

A simple fix would be to merge the two ActionListeners into a single block of code; there's no reason you need to add multiple listeners. This will of course cause your GUI to block whilst the connection attempt is being made, which is why others have advised using a mechanism such as SwingWorker to prevent this.

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();
  }
});
走野 2025-01-08 04:38:35

这个问题每两天被问一次。

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

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

This question is asked every two days.

If you execute code in the event dispatch thread, you block this threa, and thus prevents it from executing all its repaint actions necessary for the text to appear in the text field.

Long-running, blocking tasks should be run in a background thread, and this thread must no access the Swing components. Use SwingWorker. Its javadoc explains everything. It also has a link to the relevant section of the Swing tutorial, that you should read.

删除会话 2025-01-08 04:38:35

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

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

This is because you are establishing the connection in the EDT (AWT Event Dispatch Thread). While it is making the connection, nothing is done anymore to updating, handling user input and repainting the window on your screen (graphically). This means the whole application seems to be frozen until the connection is established.
So to solve this you have to make the connection in another Thread. Another dirty, not recommended approach is to force the EDT to repaint the screen after changing the text. This is the simplest way to work, but not the neat one.

This would be accomplished by calling repaint(); and then calling update(getGraphics());. But it is very dirty. I think your screen will even flicker. But this demonstrates the problem nicely. It might be interesting to test this first to see what actually happens.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文