Обновление одного JTextPane из множества разных классов

Мне нужно синхронизировать две базы данных с помощью кнопки. Под кнопкой у меня есть JTextPane в JScrollPanel. Мой класс TextPane выглядит так:

public class InfoArea extends JTextPane {
  private final HTMLEditorKit   kit              = new HTMLEditorKit();
  private final HTMLDocument    doc              = new HTMLDocument();
  private static ia;

  public static InfoArea getInfoArea {
    if (ia == null) ia = new InfoArea();
    return ia;
  }

  private InfoArea() {
    setEditorKit(kit);
    setDocument(doc);

    showInfo("Please wait...");

    setEditable(false);
  }

  public void showInfo(String msg) {

    try {
      kit.insertHTML(doc, doc.getLength(), "<b><font color=\"#00AA00\">" + msg + "</font></b>", 0, 0, null);
    } catch (BadLocationException | IOException e) {
      e.printStackTrace();
    }
  }
}

«TextPane» добавляется к SOUTH в графическом интерфейсе.

Теперь у меня есть несколько классов, которые делают:

private static final InfoArea ia = InfoArea.getInfoArea();

Сначала я инициализирую соединения с базой данных. Поскольку это делается очень быстро, информация отображается сразу. Но тогда я делаю что-то вроде этого:

private void doSmth() {
  for(int i = 0; i < smth; ++i) {
    if(sync()) ia.showInfo("OK");
    else ia.showInfo("Not OK");
  }
}

В других классах это может быть какое-то время в наборе результатов. Проблема в том, что текстовое поле не обновляется до тех пор, пока не будет запущен каждый метод. Я красный об этом поведении, и я знаю, что проблема связана с потоком диспетчера событий (EDT). Я попытался обновить showInfo (String msg) следующим образом:

private void showInfo(String msg) {
  SwingUtilities.invokeLater(new Runnable() {

    public void run() {

      try {
          kit.insertHTML(doc, doc.getLength(), msg, 0, 0, null);
      } catch (BadLocationException | IOException e) {
          e.printStackTrace();
      }
    }
  });
}

Но это не помогает. Я также пробовал SwingWorker с переопределением doInBackground(), publish() и process(), но тоже безуспешно. Я также попробовал рабочий поток вместо SwingUitilities. Последнее, что я пробовал:

private void doSmth() {
  for(int i = 0; i < smth; ++i) {
    SwingUtilities.invokeLater(new Runnable() {

      public void run() {
        if(sync()) ia.showInfo("OK");
        else ia.showInfo("Not OK");
      }
    });
  }
}

Нет успеха. Также я считаю эту попытку худшей, потому что она блокирует EDT.

Как вы могли заметить, я сейчас немного в отчаянии, потому что не знаю, где еще искать. И извините, что не опубликовал все попытки с SwingWorker и WorkerThreads, но они бы взорвали этот пост. И он уже достаточно велик.

Может кто-нибудь сказать мне, что я должен сделать, чтобы заставить его работать? Мне это нужно для клиента, который хочет что-то увидеть во время процесса синхронизации. Я также готов предоставить дополнительную информацию, если чего-то не хватает.


person aProgger    schedule 09.03.2015    source источник
comment
Я обновил showInfo(String msg), чтобы уточнить, почему я использую insertHTML   -  person aProgger    schedule 10.03.2015


Ответы (1)


Сам решил. Я неправильно понял некоторые статьи, которые я прочитал вчера. Решение состоит в том, чтобы поместить всю задачу в поток, а не только метод, который выводит.

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

public void syncDB() {

  ia.showInfo("Sync cat...");
  doCatSync();

  ia.showInfo("Sync item...");
  doItemSync();
  ...
}

Теперь мне нужно обернуть нить вокруг задач:

public void syncDB() {

  new Thread() {

    public void run() {

      ia.showInfo("Sync cat...");
      doCatSync();

      ia.showInfo("Sync item...");
      doItemSync();
      ...
    }
  }.start();
}

Это помогло. Я всегда открыт для улучшений.

person aProgger    schedule 10.03.2015
comment
Если вам нужно обновить содержимое JTextPane во время процесса, хорошим методом будет SwingWorker. Кстати, меня не очень соблазнил ваш kit.insertHTML(doc, doc.getLength(), msg, 0, 0, null);... Какой смысл использовать insertHTML, если ваше сообщение представляет собой обычный текст? - person Sharcoux; 10.03.2015
comment
Я должен был упомянуть, что сообщение имеет вид ‹b›‹font color = …› + msg + ‹/font›‹/b›. Я использую вставкуHTML, потому что мне не нужно добавлять теги ‹html›,‹/html›. insertHTML делает это за меня. Он также добавляет ‹лифчик› сам по себе. Каждое сообщение отображается на новой строке. - person aProgger; 10.03.2015