Обновление JProgressBar и планирование потоков - PullRequest
2 голосов
/ 05 марта 2020

Привет стек обменников,

У меня проблема с индикаторами выполнения в java Swing. Я думаю, что мои недоразумения возникают из-за моего плохого понимания потоков и очереди событий Swing (я мало знаю о java потоках и о том, что именно происходит на AWTEventQueue, хотя я обычно понимаю, что такое многопоточность).

Контекст заключается в том, что JButton нажимается, чтобы начать длинный расчет. Перед началом расчета я делаю индикатор выполнения в JFrame, который, как я думал, будет нарисован, но это не так. Рамка появляется, но она просто серая. На кнопке, в этом примере, написано "clickMe".

В прослушивателе действий "clickMe" я сначала создаю и отображаю JFrame в подзадаче, которая называется "run" (я не ясно, когда это запланировано TBH). Затем я вызываю doTask(), который работает в том же потоке, что и прослушиватель действий (который, я думаю, AWTEventThread ??). doTask() запускается, распечатывая номера на консоль. С выводом doTask() смешиваются числа итераций индикатора выполнения (с момента, когда слушатель действия запустил makeProgressBar()).

Таким образом, на выходе получается, что и индикатор выполнения работает, и AWTEventThread, но значение, установленное в JProgressBar GUI, никогда не обновляется.

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

Это мой код:

package problemclass;

import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.SwingUtilities;

public class ProblemClass 
{

    void progressBarButtonClick()
    {
        JFrame buttonInAFrame = new JFrame();
        JPanel buttonInAFramePanel = new JPanel();
        JButton clickMe = new JButton("Click me!");

        buttonInAFramePanel.add(clickMe);       


        clickMe.addActionListener(new ActionListener() {
            @Override
                    public void actionPerformed(ActionEvent e) 
                {
                JFrame progBarFrame = makeProgressBar();                
                doTask();
                progBarFrame.dispose();
                    }
        });


        buttonInAFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        buttonInAFrame.add(buttonInAFramePanel);
        buttonInAFrame.pack();
        buttonInAFrame.setVisible(true);
    }

    private void doTask()
    {

        for(int i = 0; i < 20000; i++)
        {
            if (i % 100 == 0) 
            {
                System.out.println("TASK iteration " + i);

                try 
                {
                    Thread.sleep(1000);
                } 
                catch (InterruptedException e) {}
            }
        }
    }

    private JFrame makeProgressBar()
    {
        JFrame progBarFrame = new JFrame();
        JPanel progBarPanel = new JPanel();

        JProgressBar progressBar = new JProgressBar();
        progBarPanel.add(progressBar);      
        progressBar.setValue(0);
            progressBar.setStringPainted(true);
            progressBar.setIndeterminate(true);


        new Thread(new Runnable() 
        {
            public void run() 
            {
                for (int i = 0; i <= 100; i++) 
                {

                    final int j = i; 
                    System.out.println("Progress Iteration " + j);

                    SwingUtilities.invokeLater(new Runnable() 
                    {
                        public void run() 
                        {
                           progressBar.setValue(j);
                        }
                    });

                    try 
                    {
                        java.lang.Thread.sleep(100);
                    }
                    catch(Exception e) { }
                }
            }
        }).start();

        progBarFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        progBarFrame.add(progBarPanel);
        progBarFrame.pack();
        progBarFrame.setVisible(true);

        return progBarFrame;
    }
    public static void main(String[] args)
    {
        EventQueue.invokeLater(() ->
        {       
            new ProblemClass().progressBarButtonClick();
        });
    }
}

Ответы [ 2 ]

0 голосов
/ 05 марта 2020

Так же, как и вы, я недавно поработал над индикаторами выполнения и многопоточностью и сходил с ума, пока не понял, что это так просто. В двух словах, это код, который я имею, когда нажимается моя кнопка:

 // Create 2 threads. One handles your GUI. Other does the task
        Thread t1 = new Thread(new Runnable() {
          @Override
          public void run() {
          // code goes here.
          //In here I choose to hide the button, display the progress bar
                      }
          });  
        t1.start();

       Thread t2 = new Thread(new Runnable() {
        @Override
        public void run() {
            // code goes here.
            //In here I get the task done, then hide the progress bar

             }
           });  
        t2.start();

Работает как шарм каждый раз. Надеюсь, это поможет!

0 голосов
/ 05 марта 2020
JFrame progBarFrame = makeProgressBar();                
doTask();

Не совсем точно, что вы пытаетесь сделать.

Приведенный выше код имеет два цикла:

  1. В методе makePrgressBar () вы запускаете Заправьте и вызовите SwingUtilities.invokeLater (…), чтобы обновить индикатор выполнения, что правильно.

  2. , но затем в doTack () вы запускаете еще один l oop. На этот раз вы не запускаете поток, поэтому код вызывается в EDT, и поскольку вы используете Thread.sleep, EDT будет спать, а GUI не будет перекрашиваться, пока не будет завершен весь l oop.

Я бы посоветовал вам избавиться от метода doTask (), так как я не знаю, зачем вам два блока кода с l oop. Или, если вам это действительно нужно, тогда вам также нужно использовать Thread и invokeLater (…).

...