Мой JProgressBar не обновляется до 100%

Хорошо, у меня есть следующий код.

public class MyProgressBar extends JPanel implements MyData, Serializable {

    /**
     * 
     */

    public static final int MAX                = 10000;
    public static final int WIDTH              = 400;
    public static final int HEIGHT             = 75;

    private JProgressBar    MyBar              = new JProgressBar( SwingConstants.HORIZONTAL, 0, MAX );
    private JFrame          MyFrame            = new JFrame();

    private int             MyValue            = 0;

    private Thread          MyThread           = new Thread( new ProgressThread() );



    public MyProgressBar() {
        add(MyBar);

        int x = ( MyData.SCREEN.width  / 2 ) - ( WIDTH  / 2);
        int y = ( MyData.SCREEN.height / 2 ) - ( HEIGHT / 2);

        this.setBounds( x, y, WIDTH, HEIGHT );

        MyFrame.setBounds( x, y, WIDTH, HEIGHT );
        MyFrame.setUndecorated(true);
        MyFrame.getContentPane().setSize( new Dimension( WIDTH, HEIGHT ) );
        MyFrame.setMinimumSize( new Dimension( WIDTH, HEIGHT ) );
        MyFrame.setPreferredSize( new Dimension( WIDTH, HEIGHT ) );
        MyFrame.setSize( new Dimension( WIDTH, HEIGHT ) );
        MyFrame.setVisible(false);
        MyFrame.getContentPane().setLayout(null);

        MyBar.setStringPainted( true );
        MyBar.setBorderPainted( true );
        MyBar.setValue( 0 );
        MyBar.setBounds( 0, 0, WIDTH, HEIGHT );

        MyFrame.add( MyBar );
        MyFrame.pack();
        MyFrame.repaint();

    }

    public void MyUpdateBar() {
        MyBar.setValue( MyValue );
        MyBar.repaint();
        MyFrame.repaint();
        this.repaint();
        //dbug.Message( "MYPROGRESSBAR", "MyUpdateBar", "Value is %3.2f %d", MyBar.getPercentComplete(), MyValue );
    }

    public void MySetValue( int percent ) {
        MyValue = (int)( MAX * ( (double)percent / 100.0 ) );
        MyUpdateBar();
        //dbug.Message( "MYPROGRESSBAR", "MySetValue", "Value is %3.2f %d percent was %d", MyBar.getPercentComplete(), MyValue, percent );
    }

    public void CreateAndShow () {
        MyFrame.setVisible(true);
        MyThread.start();
    }

    public void HideAndClear () {
        MyThread.stop();
        //frame.setVisible(false);
    }

    class ProgressThread implements Runnable {
        public void run() {
            EventQueue.invokeLater(new Runnable() {
                public void run() {
                    while( MyValue < MyBar.getMaximum() ) {
                        MyBar.setValue( MyValue );
                        MyBar.repaint();
                        MyFrame.repaint();
                        dbug.Message( "MYPROGRESSBAR", "THREAD", "Value is %3.2f %d", MyBar.getPercentComplete(), MyValue );
                    }
                }
            });
        }

    }



}

Как видите, я создал класс, в котором хочу показывать прогресс. Что происходит, я создаю экземпляр класса. Загрузите мой файл XML, а затем, когда я анализирую данные, я звоню, чтобы обновить MyValue, которое я вижу, когда я позволяю своим сообщениям dbug выходить. Однако сама полоса даже не отображается, пока не будет заполнена на 100%. Я читал о многопоточности и следовании чужому примеру, и если я оставил его как его пример, это сработало. Если я сделал несколько настроек (изменив цикл в потоке, чтобы заполнить заданное значение индикатора выполнения, чтобы прочитать значение), он даже не отображается, пока не станет 100.

Что я сделал не так?

Спасибо!


person Patrick Aquilone    schedule 03.05.2012    source источник
comment
Если вам нужен пример с правильным использованием индикатора выполнения, я написал его здесь (ProgressBarForDataFetching: tus.svn.sourceforge.net/viewvc/tus/tjacobs/ui/ex, который обрабатывает обновления от DataFetcher, другого написанного мной класса, который считывает InputStream. Вы можете найти DataFetcher на том же сайте под tjacobs.io   -  person ControlAltDel    schedule 03.05.2012


Ответы (5)


Ваш поток выполняет SwingUtilities.invokeLater. Вы эффективно используете Event Dispatch Thread Swing. Не уверен, чего вы пытаетесь достичь. Но похоже, что вы блокируете EDT, и ваш цикл while не обновляется, так как MySetValue не выполняется.

Рассмотрите возможность использования SwingWorker для длительных операций. Как использовать индикаторы выполнения демонстрирует использование SwingWorker с JProgressBar.

Убедитесь, что вы вызываете метод setValue из файла Event Dispatch Thread. Вы можете использовать SwingUtilities.invokeLater для этого. Узнайте больше о Threads и Swing.

Рассмотрим этот упрощенный пример:

public static void main(String[] arguments) {
    JFrame frame = new JFrame();
    frame.setDefaultCloseOperation(EXIT_ON_CLOSE);

    final JProgressBar bar = new JProgressBar(0, 100);

    Thread t = new Thread(){
        public void run(){
            for(int i = 0 ; i < 100 ; i++){
                final int percent = i;
                SwingUtilities.invokeLater(new Runnable() {
                    public void run() {
                        bar.setValue(percent);
                    }
                  });

                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {}
            }
        }
    };
    frame.add(bar);
    frame.pack();
    frame.setVisible(true);
    t.start();
}
person tenorsax    schedule 03.05.2012
comment
Я изменил EventQueue на SwingUtilities, и он ведет себя так же. - person Patrick Aquilone; 03.05.2012
comment
@JesterHawk SwingUtilities.invokeLater на самом деле звонит EventQueue.invokeLater. Проблема в том, что вы блокируете EDT в цикле while. - person tenorsax; 03.05.2012
comment
Проблема в том, что я могу заставить что-то подобное работать. Но мне нужно иметь возможность вызвать метод и установить процент завершения из другого класса (класс, объявленный this), и когда я пытаюсь добавить это, я ничего не получаю. - person Patrick Aquilone; 04.05.2012

Проблема в том, что вы используете цикл в EDT, который обновляет прогресс. Пока этот цикл не завершится, EDT не может отправлять события (такие как перерисовка, повторная проверка, invokeLater, события мыши, ключевые события и т. д.), препятствующие обновлению индикатора выполнения.

Вы должны попытаться найти способ позволить EDT отправлять свои события между каждым обновлением индикатора выполнения. В идеале вы перемещаете свою «работу» за пределы EDT с помощью SwingWorker. , а тем временем индикатор выполнения обновляется с помощью прослушивателей изменений свойств в EDT.

К вашему сведению, в Java методы и переменные начинаются со строчной буквы. Ваш код действительно трудно читать другим.

person Guillaume Polet    schedule 03.05.2012
comment
Я не знал этого о переменных и методах. Я изменю свой код, чтобы сделать его более читаемым. Спасибо. - person Patrick Aquilone; 03.05.2012
comment
@JesterHawk это то, что я понял, поэтому я подумал, по крайней мере, дать вам знать ;-) - person Guillaume Polet; 03.05.2012

Итак, я попытался следовать учебнику, и вот где я нахожусь.

Хорошо, я пробовал следовать учебникам, но я все время где-то теряюсь. Что мне нужно, так это класс, который создает и отображает индикатор выполнения (JProgressBar), значение которого я могу установить, когда я перебираю данные, загруженные из файла, и помещаю их в память базы данных. Мои проблемы заключаются в том, что в каждом найденном мной примере есть какой-то счетчик, который заполняет индикатор выполнения и выполняется из «основной» функции. Каждый раз, когда я изменяю этот учебник, чтобы он был классом, который я могу вызывать по желанию и отображать панель, я не получаю отображение панели (т.е. рамка появляется, но панель даже не выглядит так, как будто она добавлена ​​в кадр до тех пор, пока не повторение сделано). Я пытался использовать SwingUtilities.invokeLater и SwingWorker (последняя попытка класса ниже), у всех одна и та же проблема. Что еще хуже, я могу сделать dbug.myMessage (в основном отправляет в System.out) и увидеть сообщение, которое показывает, что полоса меняется в памяти, просто не отображается. Я, очевидно, упускаю что-то, вероятно, простое, но я не могу придумать, что это такое.

О, и еще одно, если я оставлю руководство как есть (http://docs.oracle.com/javase/tutorial/displayCode.html?code=http://docs.oracle.com/javase/tutorial/uiswing/examples/components/ProgressBarDemo2Project/src/components/ProgressBarDemo2.java) и просто измените метод main на метод createAndShow, он работает, но, конечно, не делает того, что я нужно это сделать.

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

Итак, вот мой измененный код, который, похоже, не работает:

public class MyProgressBar extends JPanel implements PropertyChangeListener, 
                                                     MyData, 
                                                     Serializable {

    /**
     * 
     */
    private static final long serialVersionUID = -1632492668549544408L;

    private MyDebug         dbug               = new MyDebug( MyData.MYDEBUGCHECK.MYPROGRESSBAR.getOn() );

    public static final int MAX                = 100;
    public static final int WIDTH              = 400;
    public static final int HEIGHT             = 75;

    private JProgressBar    myBar              = new JProgressBar( SwingConstants.HORIZONTAL, 0, MAX );
    private JFrame          myFrame            = new JFrame();

    public  Task            task;


    class Task extends SwingWorker<Void, Void> {

        public int myValue = 0;

        @Override
        public Void doInBackground() {
            //Initialize progress property.
            setProgress(0);
            while (myValue < 100) {
                //Make random progress.
                //myValue += random.nextInt(10);
                setProgress( Math.min( myValue, 100 ) );
                dbug.myMessage( "MYPROGRESSBAR", "doInBackground", "Value is %3.2f %d", myBar.getPercentComplete(), myValue );
                myBar.repaint();
            }
            return null;
        }

        public void done() {
        }

        public void mySetValue( int percent ) {
            myValue = (int)( MAX * ( (double)percent / 100.0 ) );
            dbug.myMessage( "MYPROGRESSBAR", "mySetValue", "Value is %3.2f %d percent was %d", myBar.getPercentComplete(), myValue, percent );
        }

    }



    public MyProgressBar() {
        add(myBar);

        int x = ( MyData.SCREEN.width  / 2 ) - ( WIDTH  / 2);
        int y = ( MyData.SCREEN.height / 2 ) - ( HEIGHT / 2);

        this.setBounds( x, y, WIDTH, HEIGHT );

        myFrame.setBounds( x, y, WIDTH, HEIGHT );
        myFrame.setUndecorated(true);
        myFrame.getContentPane().setSize( new Dimension( WIDTH, HEIGHT ) );
        myFrame.setMinimumSize( new Dimension( WIDTH, HEIGHT ) );
        myFrame.setPreferredSize( new Dimension( WIDTH, HEIGHT ) );
        myFrame.setSize( new Dimension( WIDTH, HEIGHT ) );
        myFrame.setVisible(false);
        myFrame.getContentPane().setLayout(null);
        myFrame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);

        myBar.setStringPainted( true );
        myBar.setBorderPainted( true );
        myBar.setValue( 0 );
        myBar.setBounds( 0, 0, WIDTH, HEIGHT );
        myBar.addPropertyChangeListener( this );

        myFrame.add( myBar );

        //Create and set up the content pane.
        //JComponent newContentPane = new MyProgressBar();
        JComponent newContentPane = myBar;
        newContentPane.setOpaque(true);                     //content panes must be opaque

        myFrame.setContentPane(newContentPane);
        myFrame.pack();

    }

    public void createAndShow () {

        //Display the window.
        myFrame.setVisible(true);
        myFrame.repaint();

    }

    public void hideAndClear () {
        //myFrame.setVisible(false);
    }


    @Override
    public void propertyChange(PropertyChangeEvent args) {
        dbug.myMessage( "MYPROGRESSBAR", "propertyChange", "Value is %s", args.getPropertyName() );
        if ( "progress" == args.getPropertyName() ) {
            int progress = (Integer) args.getNewValue();
            //myBar.setValue(progress);
        }
    }

    public void start () {
        //Instances of javax.swing.SwingWorker are not reusuable, so
        //we create new instances as needed.
        task = new Task();
        task.addPropertyChangeListener(this);
        task.execute();
    }

}
person Patrick Aquilone    schedule 04.05.2012

Приведенный ниже фрагмент кода обновляет индикатор выполнения в процессе выполнения.

    SwingUtilities.invokeLater(new Runnable() {
           public void run() {
           progressBar.setValue((int)percentage);
           //below code to update progress bar while running on thread
           progressBar.update(progressBar.getGraphics());}
         });   
person Kirk Patrick Brown    schedule 08.11.2017

Динамическое обновление индикатора выполнения достигается с помощью следующего кода:

 int progress = Math.round(((float)finished/(float)(total)) * 100);
 uploadPrgressBar.setIndeterminate(progress == 0);
 uploadPrgressBar.setValue(progress);
 uploadPrgressBar.update(uploadPrgressBar.getGraphics());

Вызовите метод, содержащий приведенный выше код в цикле (логика кода), и он будет динамически обновлять индикатор выполнения после каждой итерации.

person Renjith Thomas    schedule 29.07.2020