Java - панель JProgress не отображается (с резьбой)

Я добавляю в программу функцию для сохранения содержимого в файл. Ход выполнения отображается индикатором выполнения (в собственном JFrame), но индикатор выполнения отображается только на последнем прочитанном значении. У меня есть глобальный элемент, который обновляется основным потоком, который представляет собой% выполненной работы, а другой поток читает этот глобальный элемент и соответствующим образом обновляет индикатор выполнения. Прямо сейчас, когда он запускается, JFrame пуст, затем действие завершается, затем индикатор выполнения показывает себя с полной суммой. Как мне заставить его обновлять прогресс по мере его продвижения (и показывать панель JProgressbar с самого начала)? Вот мой код:

public class GenomeAnnotator{
    private JProgressBar csvProgressBar;
    private JFrame csvSaveLoadFrame;     //for the progress bar
    private Container csvCon;
    private double csvPercentSaved;  //% of work completed

    public JFrame m_frame;    //main program frame


....



public static void main(String[] args){
    ...
    showGUI();
    ...
}

public void showGUI(){
   ...

   JMenu file = new JMenu("File");
   JMenu exptann = new JMenu("Export annotation..);
   JMenuItem exptcsv = newJMenuItem("CSV format");
   exptcsv.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(ActionEvent e) {

          ..determine output file + checks...

          System.out.println("Writing to .csv file......"); 

          csvSaveLoadFrame = new JFrame("Saving to csv file..");
          csvProgressBar =new JProgressBar(0,100);

          csvSaveLoadFrame.setSize(300,100);
          csvCon = csvSaveLoadFrame.getContentPane();
          csvCon.setLayout(null);
          csvProgressBar.setBounds(10,10,280,20);
          csvCon.add(csvProgressBar);
          csvSaveLoadFrame.setResizable(false);
          csvSaveLoadFrame.setVisible(true);

          ORF [] ora= orfPanel.getAcceptedOrfs();
          int val;
          double toload = blastData.size() + ora.length; //how much work
          double loaded=0.0; //how much work completed


          /*Thread that will read % value from global and update prog. bar*/
          Thread progressBarMover = new Thread() {
              @Override
              public void run() {
                  int previous=0;
                  while(csvPercentSaved<100){

                      csvProgressBar.setValue((int)csvPercentSaved);
                      //tried putting a sleep() in here when testing
                      //values from global is read successfully


                      }
                  }
                  System.out.println("Thread done!");
                  csvPercentSaved = 0; //reset value when done
                  csvSaveLoadFrame.setVisible(false);
              }
          };
          progressBarMover.start();


          for (int k=0; k<blastData.size(); k++) {

              ..do output work...

              loaded+=1; //update % values
              csvPercentSaved = (loaded/toload)*100;
              val = (int)csvPercentSaved;
              System.out.println("main complete "+val+"%");
          }



          for (int k=0; k<ora.length; k++) {

              ...do more ouput work...

              loaded+=1;
              csvPercentSaved = (loaded/toload)*100; //update % value
              val = (int)csvPercentSaved;
              System.out.println("main complete "+val+"%");

          }
          System.out.println("Output file finished!");
          csvPercentSaved = 100;

      }

  });
exptann.add(exptcsv);
file.add(exptann);
}

ИЗМЕНИТЬ

нашел решение здесь: https://weblogs.java.net/blog/mkarg/archive/2010/01/03/did-you-know-swingworker-can-send-progress-status


person OrangePot    schedule 18.02.2015    source источник
comment
Ответ обновлен, чтобы отразить более глубокий взгляд на ваш код. Пожалуйста, спросите, есть ли у вас какие-либо вопросы.   -  person Hovercraft Full Of Eels    schedule 18.02.2015


Ответы (1)


Там несколько вопросов:

  • Самое главное (и я пропустил это изначально!), вы не выполняете свой длинный код в фоновом потоке, а скорее в потоке событий Swing, EDT. Я имею в виду эти два цикла for: A) for (int k=0; k<blastData.size(); k++) {...} и B) for (int k=0; k<ora.length; k++) {...}, которые выглядят как код, в котором вы загружаете или сохраняете информацию. Это заморозит ваш графический интерфейс.
  • Также важно, что вы выполняете вызовы Swing из фонового потока, в том числе устанавливаете значение индикатора выполнения и устанавливаете видимость JFrame, что вы никогда не захотите делать, и это в основном сводит на нет преимущества использования фонового потока в первую очередь. .
  • Другими словами, вы выполняете всю свою работу с потоками Swing точно в обратном порядке — вызываете Swing из фонового потока и запускаете длительный процесс в потоке событий.
  • Вместо этого поступайте наоборот — выполняйте всю длительную работу в фоновом потоке и выполняйте все вызовы Swing, не поддерживающие потокобезопасность, в EDT.
  • Один из способов сделать это — использовать SwingWorker, выполнять загрузку и сохранение из его метода doInBackground(...).
  • и установите его поле прогресса по мере достижения прогресса.
  • Затем вы должны отслеживать поле прогресса рабочего в PropertyChangeListener, это делается в EDT, а затем использовать его для установки значения вашего индикатора выполнения.
  • Or if you have to use your own background thread, then
    • Have the inner class implement Runnable, not extend Thread
    • Если вы выполняете вызовы Swing из своего фонового потока, затем оберните эти вызовы в Runnable и поставьте их в очередь в потоке событий Swing через SwingUtilities.invokeLater(yourRunnable)

Еще мелкие проблемы:

  • Вы не должны использовать нулевые макеты и абсолютное позиционирование, а лучше использовать менеджеры макетов. Хотя нулевые макеты и setBounds() могут показаться новичкам Swing самым простым и лучшим способом создания сложных графических интерфейсов, чем больше графических интерфейсов Swing вы создадите, тем более серьезные трудности возникнут при их использовании. Они не будут изменять размер ваших компонентов при изменении размера графического интерфейса, они идеально подходят для улучшения или поддержки, они полностью терпят неудачу при размещении в области прокрутки, они выглядят ужасно ужасно при просмотре на всех платформах или разрешениях экрана, которые отличаются от исходного. .
  • Ваше вторичное диалоговое окно должно быть JDialog и, возможно, модальным JDialog, а не другим JFrame. Вы не создаете и не показываете новую автономную программу, а скорее отображаете диалоговое окно вне главного окна графического интерфейса. Если вы хотите, чтобы главное окно GUI не функционировало во время отображения диалогового окна, тогда вам подойдет модальный JDialog, поскольку он работает так же, как JOptionPane (который является формой модального JDialog), и делает вызывающее окно неактивным. -функционально, пока его видно.

Некоторые из моих примеров кода:

person Hovercraft Full Of Eels    schedule 18.02.2015
comment
Действительно полный ответ. - person keuleJ; 18.02.2015
comment
Вы указали мне правильное направление. Будет продолжать исследования. Спасибо! - person OrangePot; 18.02.2015