簡體   English   中英

如何制作進度欄類,其值可以從調用類中更新

[英]How can I make a Progress Bar class that's value can be Updated from the calling class

我嘗試了以下教程,但是我總是迷失在某個地方。

我需要一個創建並顯示進度條( JProgressBar )的類,當我遍歷從文件加載的數據並將其放入數據庫內存時,可以設置該值。 我遇到的問題是,我發現的每個示例都具有某種計數器,該計數器填充進度條並從“主要”功能執行。 每次我將該教程更改為可以隨意調用並顯示欄的班級時,我都不會看到欄顯示(即,框架出現了,但是直到出現之后,該欄才看起來好像已添加到框架中迭代完成)。

我已經嘗試過使用SwingUtilities.invokeLaterSwingWorker (下面的類的最新嘗試),它們都具有相同的問題。 更糟糕的是,我可以執行dbug.myMessage (基本上發送到System.out ),然后看到一條消息,顯示dbug.myMessage在內存中的變化只是沒有顯示。 我顯然錯過了一些可能很簡單的東西,但我想不出它是什么。

另一件事,如果我將本教程保留為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();
    }

}

您應該調用SwingWorker可用的publish方法,而不是在doInBackGround方法中調用setProgress

publish方法會將這些值傳遞給在事件調度線程上調用的process方法,在這種方法中,您應該更新進度條。

另一個問題中,我已經發布了一個示例,該示例正是這樣

也許以下示例對您有用。 它假裝加載一個大型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());
    }
}

我確實做到了這一點,並發布以防萬一有人偶然搜索此腳步並需要工作代碼。

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,則它不會更新任何圖形(所有圖形都不會)直到班級完全完成其所做的工作(盡管有重繪和填充)。

有什么想法嗎?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM