[英]How can I make a Progress Bar class that's value can be Updated from the calling class
我嘗試了以下教程,但是我總是迷失在某個地方。
我需要一個創建並顯示進度條( JProgressBar
)的類,當我遍歷從文件加載的數據並將其放入數據庫內存時,可以設置該值。 我遇到的問題是,我發現的每個示例都具有某種計數器,該計數器填充進度條並從“主要”功能執行。 每次我將該教程更改為可以隨意調用並顯示欄的班級時,我都不會看到欄顯示(即,框架出現了,但是直到出現之后,該欄才看起來好像已添加到框架中迭代完成)。
我已經嘗試過使用SwingUtilities.invokeLater
和SwingWorker
(下面的類的最新嘗試),它們都具有相同的問題。 更糟糕的是,我可以執行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.