如何在线程内的 JInternalFrame 中执行可更新的 JProgressBar?
How to do an updateable JProgressBar in an JInternalFrame inside a thread?
这是我目前所知道的,可能是完全错误的...
问题似乎是更新循环内的百分比,然后在 SwingUtilities.invokeLater
程序的外部调用它。
此外 JInternalFrame
位于程序的其余部分之后,也许 JDialog
会更好。
将在这里提供更多需要的代码,如果您需要更多信息,也愿意 post 在 github 上讨论整个项目。(如果允许的话)
这是我的第一个代码项目,如有任何帮助,我们将不胜感激!
package twoDMapEditor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.lang.reflect.InvocationTargetException;
import javax.swing.BorderFactory;
import javax.swing.JInternalFrame;
import javax.swing.JProgressBar;
import javax.swing.SwingUtilities;
public class SaveActionListener implements ActionListener {
public void actionPerformed(ActionEvent me) {
final JProgressBar progressBar = new JProgressBar();
progressBar.setValue(0);
progressBar.setStringPainted(true);
progressBar.setBorder(BorderFactory.createTitledBorder("Saving..."));
final JInternalFrame loadingDialog = new JInternalFrame();
loadingDialog.add(progressBar);
loadingDialog.pack();
loadingDialog.setVisible(true);
TwoDMapEditor.frame.add(loadingDialog);
TwoDMapEditor.frame.revalidate();
TwoDMapEditor.frame.repaint();
new Thread(new Runnable() {
public void run() {
final int percentage = 0;
int i = 0, j;
while (i < TwoDMapEditor.size[0]) {
j = 0;
while(j < TwoDMapEditor.size[1]){
if (!TwoDMapEditor.mySql.updateMapPiece(i, j)) {
System.out.println("Something went wrong");
}
//percentage = ((i * TwoDMapEditor.size[1]) + j+1) * 100 / (TwoDMapEditor.size[0] * TwoDMapEditor.size[1]);
j++;
}
i++;
}
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
progressBar.setValue(percentage);
}
});
} catch (InvocationTargetException | InterruptedException e1) {
e1.printStackTrace();
}
try {
java.lang.Thread.sleep(100);
}
catch(Exception e) { }
}
}).start();
}
}
编辑:现在知道了:
package twoDMapEditor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.BorderFactory;
import javax.swing.JInternalFrame;
import javax.swing.JProgressBar;
import javax.swing.SwingWorker;
public class SaveActionListener implements ActionListener, PropertyChangeListener {
JProgressBar progressBar;
ProgressBar progressBarClass;
JInternalFrame loadingDialog;
SaveActionListener(){
progressBar = new JProgressBar();
progressBar.setValue(0);
progressBar.setStringPainted(true);
progressBar.setBorder(BorderFactory.createTitledBorder("Saving..."));
loadingDialog = new JInternalFrame();
loadingDialog.add(progressBar);
loadingDialog.pack();
loadingDialog.setVisible(true);
TwoDMapEditor.frame.add(loadingDialog);
TwoDMapEditor.frame.revalidate();
TwoDMapEditor.frame.repaint();
}
class ProgressBar extends SwingWorker<Void, Void>{
public int percentage = 1;
protected Void doInBackground(){
int i = 0, j;
while (i < TwoDMapEditor.size[0]) {
j = 0;
while(j < TwoDMapEditor.size[1]){
if (!TwoDMapEditor.mySql.updateMapPiece(i, j)) {
System.out.println("Something went wrong");
}
percentage = ((i * TwoDMapEditor.size[1]) + j+1) * 100 / (TwoDMapEditor.size[0] * TwoDMapEditor.size[1]);
progressBar.setValue(percentage);
System.out.println(percentage);
j++;
}
i++;
}
return null;
}
public void done(){
loadingDialog.dispose();
}
}
public void actionPerformed(ActionEvent me) {
progressBarClass = new ProgressBar();
progressBarClass.addPropertyChangeListener(this);
progressBarClass.execute();
}
public void propertyChange(PropertyChangeEvent pce) {
System.out.println(TwoDMapEditor.saveActionListener.progressBarClass.percentage);
progressBar.setValue(TwoDMapEditor.saveActionListener.progressBarClass.percentage);
}
}
没有完全可运行的示例,很难知道问题出在哪里。
你应该勇敢地在循环中更新进度。如果你能保证每个 TwoDMapEditor.size[1]
都是相同的值,那就更容易了。
你基本上需要知道两件事,可能的迭代总数和你已经完成的迭代次数,但我在你的代码片段中没有看到任何可能提供该信息的信息。
无论如何,我还建议使用 SwingWorker
,因为它可以很容易地通知 UI 进度状态更改,例如...
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Random;
import javax.swing.JDesktopPane;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class TestProgress {
public static void main(String[] args) {
new TestProgress();
}
public TestProgress() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JDesktopPane dp = new JDesktopPane() {
@Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
};
JInternalFrame inf = new JInternalFrame("Progressing", true, false, false, false);
inf.add(new TestPane());
inf.pack();
dp.add(inf);
inf.setVisible(true);
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(dp);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JProgressBar pb;
public TestPane() {
setLayout(new GridBagLayout());
pb = new JProgressBar();
add(pb);
LongRunningProcessWorker worker = new LongRunningProcessWorker();
worker.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
String name = evt.getPropertyName();
SwingWorker worker = (SwingWorker) evt.getSource();
switch (name) {
case "progress":
System.out.println(worker.getProgress());
pb.setValue(worker.getProgress());
break;
case "state":
switch (worker.getState()) {
case DONE:
// Close the window or something
break;
}
break;
}
}
});
worker.execute();
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
public class LongRunningProcessWorker extends SwingWorker {
@Override
protected Object doInBackground() throws Exception {
Random rnd = new Random();
int outterMax = rnd.nextInt(150) + 50;
int innerMax = rnd.nextInt(150) + 50;
System.out.println(outterMax + "/" + innerMax);
for (int outter = 0; outter < outterMax; outter++) {
for (int inner = 0; inner < innerMax; inner++) {
float progress = (float)((outter * innerMax) + inner) / (float)(innerMax + outterMax);
Thread.sleep(10); // Simulate some processing
}
}
return null;
}
}
}
查看 Concurrency in Swing and Worker Threads and SwingWorker 了解更多详情
这是我目前所知道的,可能是完全错误的...
问题似乎是更新循环内的百分比,然后在 SwingUtilities.invokeLater
程序的外部调用它。
此外 JInternalFrame
位于程序的其余部分之后,也许 JDialog
会更好。
将在这里提供更多需要的代码,如果您需要更多信息,也愿意 post 在 github 上讨论整个项目。(如果允许的话)
这是我的第一个代码项目,如有任何帮助,我们将不胜感激!
package twoDMapEditor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.lang.reflect.InvocationTargetException;
import javax.swing.BorderFactory;
import javax.swing.JInternalFrame;
import javax.swing.JProgressBar;
import javax.swing.SwingUtilities;
public class SaveActionListener implements ActionListener {
public void actionPerformed(ActionEvent me) {
final JProgressBar progressBar = new JProgressBar();
progressBar.setValue(0);
progressBar.setStringPainted(true);
progressBar.setBorder(BorderFactory.createTitledBorder("Saving..."));
final JInternalFrame loadingDialog = new JInternalFrame();
loadingDialog.add(progressBar);
loadingDialog.pack();
loadingDialog.setVisible(true);
TwoDMapEditor.frame.add(loadingDialog);
TwoDMapEditor.frame.revalidate();
TwoDMapEditor.frame.repaint();
new Thread(new Runnable() {
public void run() {
final int percentage = 0;
int i = 0, j;
while (i < TwoDMapEditor.size[0]) {
j = 0;
while(j < TwoDMapEditor.size[1]){
if (!TwoDMapEditor.mySql.updateMapPiece(i, j)) {
System.out.println("Something went wrong");
}
//percentage = ((i * TwoDMapEditor.size[1]) + j+1) * 100 / (TwoDMapEditor.size[0] * TwoDMapEditor.size[1]);
j++;
}
i++;
}
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
progressBar.setValue(percentage);
}
});
} catch (InvocationTargetException | InterruptedException e1) {
e1.printStackTrace();
}
try {
java.lang.Thread.sleep(100);
}
catch(Exception e) { }
}
}).start();
}
}
编辑:现在知道了:
package twoDMapEditor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.BorderFactory;
import javax.swing.JInternalFrame;
import javax.swing.JProgressBar;
import javax.swing.SwingWorker;
public class SaveActionListener implements ActionListener, PropertyChangeListener {
JProgressBar progressBar;
ProgressBar progressBarClass;
JInternalFrame loadingDialog;
SaveActionListener(){
progressBar = new JProgressBar();
progressBar.setValue(0);
progressBar.setStringPainted(true);
progressBar.setBorder(BorderFactory.createTitledBorder("Saving..."));
loadingDialog = new JInternalFrame();
loadingDialog.add(progressBar);
loadingDialog.pack();
loadingDialog.setVisible(true);
TwoDMapEditor.frame.add(loadingDialog);
TwoDMapEditor.frame.revalidate();
TwoDMapEditor.frame.repaint();
}
class ProgressBar extends SwingWorker<Void, Void>{
public int percentage = 1;
protected Void doInBackground(){
int i = 0, j;
while (i < TwoDMapEditor.size[0]) {
j = 0;
while(j < TwoDMapEditor.size[1]){
if (!TwoDMapEditor.mySql.updateMapPiece(i, j)) {
System.out.println("Something went wrong");
}
percentage = ((i * TwoDMapEditor.size[1]) + j+1) * 100 / (TwoDMapEditor.size[0] * TwoDMapEditor.size[1]);
progressBar.setValue(percentage);
System.out.println(percentage);
j++;
}
i++;
}
return null;
}
public void done(){
loadingDialog.dispose();
}
}
public void actionPerformed(ActionEvent me) {
progressBarClass = new ProgressBar();
progressBarClass.addPropertyChangeListener(this);
progressBarClass.execute();
}
public void propertyChange(PropertyChangeEvent pce) {
System.out.println(TwoDMapEditor.saveActionListener.progressBarClass.percentage);
progressBar.setValue(TwoDMapEditor.saveActionListener.progressBarClass.percentage);
}
}
没有完全可运行的示例,很难知道问题出在哪里。
你应该勇敢地在循环中更新进度。如果你能保证每个 TwoDMapEditor.size[1]
都是相同的值,那就更容易了。
你基本上需要知道两件事,可能的迭代总数和你已经完成的迭代次数,但我在你的代码片段中没有看到任何可能提供该信息的信息。
无论如何,我还建议使用 SwingWorker
,因为它可以很容易地通知 UI 进度状态更改,例如...
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Random;
import javax.swing.JDesktopPane;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class TestProgress {
public static void main(String[] args) {
new TestProgress();
}
public TestProgress() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JDesktopPane dp = new JDesktopPane() {
@Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
};
JInternalFrame inf = new JInternalFrame("Progressing", true, false, false, false);
inf.add(new TestPane());
inf.pack();
dp.add(inf);
inf.setVisible(true);
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(dp);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JProgressBar pb;
public TestPane() {
setLayout(new GridBagLayout());
pb = new JProgressBar();
add(pb);
LongRunningProcessWorker worker = new LongRunningProcessWorker();
worker.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
String name = evt.getPropertyName();
SwingWorker worker = (SwingWorker) evt.getSource();
switch (name) {
case "progress":
System.out.println(worker.getProgress());
pb.setValue(worker.getProgress());
break;
case "state":
switch (worker.getState()) {
case DONE:
// Close the window or something
break;
}
break;
}
}
});
worker.execute();
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
public class LongRunningProcessWorker extends SwingWorker {
@Override
protected Object doInBackground() throws Exception {
Random rnd = new Random();
int outterMax = rnd.nextInt(150) + 50;
int innerMax = rnd.nextInt(150) + 50;
System.out.println(outterMax + "/" + innerMax);
for (int outter = 0; outter < outterMax; outter++) {
for (int inner = 0; inner < innerMax; inner++) {
float progress = (float)((outter * innerMax) + inner) / (float)(innerMax + outterMax);
Thread.sleep(10); // Simulate some processing
}
}
return null;
}
}
}
查看 Concurrency in Swing and Worker Threads and SwingWorker 了解更多详情