1

我已经尝试过遵循教程,但我一直在某个地方迷路。

我需要的是一个创建和显示进度条JProgressBar(我的问题是,我发现的每个示例都有某种计数器,它填充进度条并从“主”函数执行。每次我将该教程更改为我可以随意调用并显示栏的类时,我都没有显示栏(即框架出现,但栏甚至看起来不像是添加到框架中,直到之后迭代完成)。

我已经尝试过使用SwingUtilities.invokeLaterSwingWorker(在下面的课程中的最新尝试)都遇到了同样的问题。更糟糕的是,我可以做一个dbug.myMessage(基本上发送到System.out)并看到一条消息,显示该条在内存中发生变化,只是没有显示。我显然错过了一些可能很简单的东西,但我想不出它是什么。

另一件事,如果我按照Java 教程代码示例 - 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();
    }

}
4

3 回答 3

3

与其调用方法,setProgress不如调用.doInBackGroundpublishSwingWorker

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

另一个问题中,我已经发布了一个示例,该示例正是这样做的

于 2012-05-04T14:40:20.287 回答
2

也许下面的例子对你有用。它假装加载一个大的 XML 文件,并为每个“重要数据段”添加一个面板(在本例中实际上只是一个字符串)。通过 SwingWorker 中的 PropertyChangeEvent 更新 GUI。

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());
    }
}
于 2012-05-05T22:48:56.643 回答
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 上的 JLabels,它不会更新任何图形(其中任何一个)直到班级完全完成了它正在做的事情,尽管重新粉刷和其他东西。

对此有什么想法吗?

于 2012-05-05T18:19:59.510 回答