如何创建一个可以从调用类更新值的Progress Bar类

时间:2012-05-04 14:12:39

标签: java swing swingworker jprogressbar event-dispatch-thread

我尝试过以下教程,但我一直迷路。

我需要的是一个创建并显示进度条(JProgressBar)的类,我可以设置值,当我迭代从文件加载的数据并放入数据库内存时。我遇到的问题是,我发现的每个例子都有某种计数器,它填充进度条并从“主”函数执行。每当我改变该教程成为一个我可以随意调用的类并显示条形图时,我都没有显示条形图(IE框架出现但是条形图甚至看起来都没有被添加到框架中,直到之后迭代完成)。

我尝试使用SwingUtilities.invokeLaterSwingWorker(下面的课程中的最新尝试)都有同样的问题。更糟糕的是,我可以执行dbug.myMessage(基本上发送到System.out)并看到一条消息,显示内存中的条形图正在变化而未显示。我显然遗漏了一些可能很简单的东西,但我想不出它是什么。

另外一件事,如果我将教程保留为Java Tutorials Code Sample – 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();
    }

}

3 个答案:

答案 0 :(得分:3)

您应该调用setProgress中提供的doInBackGround方法,而不是在publish方法中调用SwingWorker

publish方法会将这些值传递给在事件调度线程上调用的process方法,并且在此方法中您应该更新进度条。

another question我已经发布了一个完全符合

的例子

答案 1 :(得分:2)

以下示例可能对您有用。它假装加载一个大的XML文件,并为每个“重要数据段”添加一个Panel(在这个例子中它实际上只是一个字符串。)GUI通过SwingWorker中的PropertyChangeEvent进行更新。

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.*;

public class WorkerExample
{

    public static void main(String[] args)
    {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                WorkerGui gui = new WorkerGui();
                JFrame frame = gui.createFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setVisible(true);
            }
        });
    }
}



class WorkerGui
{
    public static final String ADD_NEW_ROW_PROPERTY = "ADD_NEW_ROW";
    private static final Dimension SUB_PANEL_SIZE = new Dimension(350, 50);
    private JButton button;
    private JComponent labelComponent;
    private JScrollPane scroller;
    int labelCount = 0;

    private List<String> loadXml() {
        try {
            // pretend to load a large XML file...
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException ex) {
            Logger.getLogger(WorkerGui.class.getName()).log(Level.SEVERE, null, ex);
        }

        List<String> dataList = new ArrayList<String>();

        for (int i = 1; i <= 20; i++) {
            dataList.add("Important data " + i);
        }

        return dataList;
    }

    ProgressMonitor monitor = null;


    class XmlWorker extends SwingWorker<Void, Void> {

        @Override protected Void doInBackground() throws Exception {
            monitor.setProgress(2);
            List<String> rows = loadXml();

            final int denom = rows.size();

            int i = 1;
            Random random = new Random();
            for (String string : rows) {
                if (monitor.isCanceled()) {
                    break;
                }
                Thread.sleep(random.nextInt(2000));
                firePropertyChange(ADD_NEW_ROW_PROPERTY, null, string);
                setProgress((int)(100 * (i / (double)denom)));
                i++;
            }
            return null;
        }

        @Override protected void done() {
            // restore the button
            button.setEnabled(true);
            button.requestFocus();
        }
    }


    final PropertyChangeListener listener = new PropertyChangeListener() {
        @Override public void propertyChange(PropertyChangeEvent evt) {
            if ("progress".equals(evt.getPropertyName())) {
                monitor.setProgress((Integer)evt.getNewValue());
            } else if (ADD_NEW_ROW_PROPERTY.equals(evt.getPropertyName())) {
                addRow((String)evt.getNewValue());
            }
        }
    };

    private void doWork() {
        monitor = new ProgressMonitor(labelComponent.getTopLevelAncestor(), "Loading XML", "", 0, 100);
        monitor.setProgress(0);
        monitor.setMillisToPopup(0);
        monitor.setMillisToDecideToPopup(0);
        XmlWorker worker = new XmlWorker();
        worker.addPropertyChangeListener(listener);
        worker.execute();
    }

    private JComponent setupGui() {
        labelComponent = Box.createVerticalBox();
        scroller = new JScrollPane(labelComponent,
                                    JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, 
                                    JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
        JPanel buttonPanel = new JPanel();
        button = new JButton("Do it!");
        buttonPanel.add(button);
        button.addActionListener(new ActionListener() {
            @Override public void actionPerformed(ActionEvent e) {
                button.setEnabled(false);
                clear();
                doWork();
            }
        });

        JPanel mainPanel = new JPanel(new BorderLayout());
        mainPanel.add(scroller, BorderLayout.CENTER);
        mainPanel.add(buttonPanel, BorderLayout.SOUTH);
        return mainPanel;
    }

    public JFrame createFrame() {
        JFrame frame = new JFrame("Hello!");
        frame.setSize(400, 400);
        JComponent component = setupGui();
        frame.add(component);
        return frame;
    }

    public void clear() {
        labelComponent.removeAll();
        labelCount = 0;
        scroller.validate();
        scroller.getTopLevelAncestor().repaint();
    }

    /**
     * Creates a JLabel out of the data and adds it to the main panel.
     * Must be called on Event Dispatch Thread!!
     * @param data  the data to add, could be any class.
     */
    public void addRow(String data) {
        if (labelCount > 0) {
            labelComponent.add(Box.createVerticalStrut(10));
        }
        labelCount++;

        final JLabel label = new JLabel(data);
        JPanel panel = new JPanel();
        panel.add(label);

        panel.setPreferredSize(SUB_PANEL_SIZE);
        panel.setMaximumSize(SUB_PANEL_SIZE);
        panel.setBorder(BorderFactory.createLineBorder(Color.BLUE));

        labelComponent.add(panel);
        scroller.validate();
        panel.scrollRectToVisible(panel.getBounds());
    }
}

答案 2 :(得分:0)

我确实让这个工作正在发布,以防万一有人碰巧在这一步上搜索并需要工作代码。

package com.swa.fin.esaa.sgb.myclasses.myzzarchives;

import java.awt.Dimension;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.Serializable;

import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.SwingConstants;
import javax.swing.SwingWorker;

public class MyProgressBarTest {

    public class MyProgressBar extends JPanel implements PropertyChangeListener, 
                                                         Serializable {

        private static final long serialVersionUID = -1632492668549544408L;

        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, Integer> {

            public int myValue = 0;

            @Override
            public Void doInBackground() {
                //Initialize progress property.
                setProgress(0);
                myBar.setValue( myValue );
                myBar.repaint();
                return null;
            }

            public void done() {
            }

            public void mySetValue( int percent ) {
                myValue = (int)( MAX * ( (double)percent / 100.0 ) );
                setProgress( Math.min( myValue, 100 ) );
                myBar.repaint();
            }

        }

        public MyProgressBar() {
            add(myBar);

            myFrame.setUndecorated(false);
            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) {
            if ( "progress" == args.getPropertyName() ) {
                int progress = (Integer) args.getNewValue();
                myBar.setValue(progress);
            }
        }

        public void mySetValue( int percent ) {
            if ( task != null ) {
                task.mySetValue( percent );
            }
            myBar.repaint();
        }

        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();
        }
    }




    public class Tester {

        public Tester() {
        }
        public void testit () {
            MyProgressBar bar = new MyProgressBar();
            bar.createAndShow();
            bar.start();
            bar.mySetValue(  0 );
            try { Thread.sleep( 100 );  } catch (InterruptedException e) { e.printStackTrace(); } 
            bar.mySetValue(  10 );
            try { Thread.sleep( 100 );  } catch (InterruptedException e) { e.printStackTrace(); } 
            bar.mySetValue(  20 );
            try { Thread.sleep( 100 );  } catch (InterruptedException e) { e.printStackTrace(); }
            for ( int count = 20; count <= 100; count++ ) {
                bar.mySetValue(  count );
                try { Thread.sleep( 100 );  } catch (InterruptedException e) { e.printStackTrace(); }
            }
        }
    }


    public static void main ( String[] args ) {
        MyProgressBarTest my = new MyProgressBarTest();
        MyProgressBarTest.Tester test = my.new Tester();

        test.testit();

    }


}

但是如果我接受并从类中调用它来读取XML文件,解组它然后遍历加载的ArrayList并创建放置在JPanel上的JLabel它不会更新任何图形(其中任何一个)在所有的情况下)直到班级完全完成了它正在做的事情,尽管重新制作和东西。

对此有何看法?