JTextField не корректно обновляет - PullRequest
1 голос
/ 31 января 2012

В настоящее время я занимаюсь разработкой утилиты, которая выполняет запросы к базе данных 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 ]

4 голосов
/ 31 января 2012

Установление соединения с базой данных не должно выполняться в потоке диспетчеризации событий.Это препятствует обновлению вашего компонента.Вместо этого выполняйте задачу в фоновом потоке.

Если вам необходимо сообщить о результатах во время выполнения этого действия, либо используйте класс SwingWorker, либо обновите компонент с помощью SwingUtilities класс, в частности, invokeLater.Оба из них гарантируют, что компонент (ы) будут обновлены в EDT, и что долгосрочное задание выполняется в другом месте.

Для получения дополнительной информации, пожалуйста, прочитайте Параллельность в Swing .

3 голосов
/ 31 января 2012

Как уже упоминалось, логика подключения лучше всего выполняется в потоке, отличном от потока диспетчеризации событий.Однако технически это не причина, по которой текстовое поле не обновляется до тех пор, пока не будет установлено соединение.

Фактическая причина, по которой это происходит, заключается в том, что внутренние компоненты Swing используют структуру данных для хранения прослушивателей (в данном случае ActionListener s), когда слушатели уведомляются в обратном порядке по сравнению с порядком, в который они были добавлены.Следовательно, в вашем примере ActionListener, который создает соединение, уведомляется перед слушателем, ответственным за обновление текста.

Простым решением было бы объединить два ActionListener s в один блок кода.;нет причин для добавления нескольких слушателей.Это, конечно, приведет к блокировке вашего графического интерфейса во время попытки подключения, поэтому другие рекомендуют использовать такой механизм, как 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 голосов
/ 31 января 2012

Этот вопрос задается каждые два дня.

Если вы выполняете код в потоке отправки событий, вы блокируете эту цепочку и, таким образом, не позволяете ей выполнить все свои действия по перерисовке, необходимые для появления текста втекстовое поле.

Долгосрочные, блокирующие задачи должны выполняться в фоновом потоке, и этот поток не должен иметь доступа к компонентам Swing.Используйте SwingWorker.Его Javadoc объясняет все.Там также есть ссылка на соответствующий раздел учебника по Swing, который вы должны прочитать.

1 голос
/ 31 января 2012

Это происходит потому, что вы устанавливаете соединение в EDT (нить диспетчеризации событий AWT).Пока он устанавливает соединение, больше ничего не делается для обновления, обработки пользовательского ввода и перерисовки окна на вашем экране (графически).Это означает, что все приложение кажется замороженным до тех пор, пока соединение не будет установлено.
Поэтому, чтобы решить эту проблему, вы должны установить соединение в другом потоке.Другой грязный, не рекомендуемый подход - заставить EDT перекрашивать экран после изменения текста.Это самый простой способ работы, но не самый аккуратный.

Это можно сделать, вызвав repaint();, а затем вызвав update(getGraphics());.Но это очень грязно.Я думаю, что ваш экран будет даже мерцать.Но это хорошо демонстрирует проблему.Может быть интересно сначала проверить это, чтобы увидеть, что на самом деле происходит.

...