当我设置JProgressBar的min,value和max时,除非我关闭窗口并重新打开它,否则它们不会更新。
照片:
任何人都可以给我任何见解吗?我在这个问题上摸不着头脑。我测试过以确保解析正确完成(这是)。我测试过直接输入数字。显然它可以工作,它只是没有显示窗口第一次打开(这让我觉得如果我更新值,它只会显示最后的值。
*编辑*
女士们,先生们......我可以介绍...... SSCCE。我很抱歉发布这个,因为现在你会感受到我的痛苦:x
package com.jayavon.game.helper;
import javax.swing.*;
import java.awt.event.*;
public class SSCCE extends JFrame implements WindowListener {
private static final long serialVersionUID = 1L;
JFrame frame;
JPanel panel;
JButton characterButton;
JInternalFrame characterFrame;
/* Character Window */
JProgressBar totalExpProgressBar;
Action ClassCharacterButton = new ClassCharacterButton();
public static void main(String[] args){
//for thread safety
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
new SSCCE();
}
});
}
SSCCE() {
initGUI();
}
public void initGUI(){
frame = new JFrame("SSCCE");
panel = (JPanel)frame.getContentPane();
/**********************************
**
** Buttons
**
*********************************/
characterButton = new JButton("");
characterButton.setBounds(50,175,395,100);
characterButton.setVisible(true);
characterButton.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("C"), "characterButtonPress");
characterButton.getActionMap().put("characterButtonPress", ClassCharacterButton);
characterButton.setAction(ClassCharacterButton);
characterButton.setText("Click me three times(open/close/open) to get progress bar to fill");
panel.add(characterButton);
/**********************************
**
** Internal Frames
**
*********************************/
//#### Character frame start ####
characterFrame = new JInternalFrame("Character", true, true, false, false);
characterFrame.setLocation(50, 50);
characterFrame.setSize(300,105);
totalExpProgressBar = new JProgressBar();
totalExpProgressBar.setString("0/0");
totalExpProgressBar.setStringPainted(true);
characterFrame.add(totalExpProgressBar);
characterFrame.setResizable(false);
panel.add(characterFrame);
//#### Character frame end ####
/**********************************
**
** Panel Code
**
*********************************/
panel.setLayout(null);
panel.setFocusable(true);
/**********************************
**
** Frame Code
**
*********************************/
frame.setLocation(100, 100);
frame.setSize(500, 350);
frame.setVisible(true);
frame.setFocusable(true);
frame.addWindowListener(this);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
class ClassCharacterButton extends AbstractAction {
private static final long serialVersionUID = 1L;
public void actionPerformed(ActionEvent e) {
if (characterFrame.isVisible()){
characterFrame.setVisible(false);
} else {
fakeGetServerResponse();
}
}
}
public void fakeGetServerResponse(){
String incommingReply = "proskier-charactersWindow@20|10|10|10|0|234|3|200|400"; //fake message from server
final String splitAt[] = incommingReply.split("@"); //split the character name from the incommingReply at the '@' sign
String beforeAt[] = splitAt[0].split("-");
String commandName = beforeAt[1];
final String afterAt[] = splitAt[1].split("\\|");
if (commandName.equals("charactersWindow")){
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
totalExpProgressBar.setString(afterAt[5] + "/" + afterAt[8]);
totalExpProgressBar.setMinimum(0);
totalExpProgressBar.setMinimum(Integer.parseInt(afterAt[7])); //TODO::SCREW YOU JAVA
totalExpProgressBar.setValue(Integer.parseInt(afterAt[5])); //TODO::SCREW YOU JAVA
totalExpProgressBar.setMaximum(Integer.parseInt(afterAt[8])); //TODO::SCREW YOU JAVA
characterFrame.setVisible(true);
}
});
}
}
@Override
public void windowClosing(WindowEvent arg0){
frame.dispose();
System.exit(1);
}
@Override
public void windowActivated(WindowEvent arg0) {
}
@Override
public void windowClosed(WindowEvent arg0) {
}
@Override
public void windowDeactivated(WindowEvent arg0) {
}
@Override
public void windowDeiconified(WindowEvent arg0) {
}
@Override
public void windowIconified(WindowEvent arg0) {
}
@Override
public void windowOpened(WindowEvent arg0) {
}
}
答案 0 :(得分:4)
您可能正在EDT(事件调度线程)中执行工作。这个线程有一个事件队列,它们按顺序分配一个,因为AWT不是Thread安全的。这允许UI更新事件(对重放或invokeLater等程序事件或鼠标和键事件等用户事件)进行更新和响应。
因此,当您在EDT中工作时,您会阻止线程并阻止它调度事件,例如重绘,点击,关键事件等......
通常解决方案是使用例如SwingWorker。
在另一个线程中移动工作顺便说一句,Thread.sleep(long)是一个静态方法,因此无需调用currentThread(),只需调用Thread.sleep(...)即可。但同样,你应该真的避免在EDT中这样做,因为它阻止它并且也会阻止UI。
答案 1 :(得分:3)
这适用于所有Swing JComponents
,Runnable
和Thread.sleep(int)
以及GUI的准动画
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ShakingButtonDemo implements Runnable {
private JButton button;
private JRadioButton radioWholeButton;
private JRadioButton radioTextOnly;
public static void main(String[] args) throws Exception {
SwingUtilities.invokeLater(new ShakingButtonDemo());
}
@Override
public void run() {
radioWholeButton = new JRadioButton("The whole button");
radioTextOnly = new JRadioButton("Button text only");
radioWholeButton.setSelected(true);
ButtonGroup bg = new ButtonGroup();
bg.add(radioWholeButton);
bg.add(radioTextOnly);
button = new JButton(" Shake with this Button ");
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
shakeButton(radioWholeButton.isSelected());
}
});
JPanel p1 = new JPanel();
p1.setBorder(BorderFactory.createTitledBorder("Shake Options"));
p1.setLayout(new GridLayout(0, 1));
p1.add(radioWholeButton);
p1.add(radioTextOnly);
JPanel p2 = new JPanel();
p2.setLayout(new GridLayout(0, 1));
p2.add(button);
JFrame frame = new JFrame();
frame.setTitle("Shaking Button Demo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(p1, BorderLayout.NORTH);
frame.add(p2, BorderLayout.SOUTH);
frame.setSize(240, 160);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private void shakeButton(final boolean shakeWholeButton) {
final Point point = button.getLocation();
final Insets margin = button.getMargin();
final int delay = 75;
Runnable r = new Runnable() {
@Override
public void run() {
for (int i = 0; i < 30; i++) {
try {
if (shakeWholeButton) {
moveButton(new Point(point.x + 5, point.y));
Thread.sleep(delay);
moveButton(point);
Thread.sleep(delay);
moveButton(new Point(point.x - 5, point.y));
Thread.sleep(delay);
moveButton(point);
Thread.sleep(delay);
} else {// text only
setButtonMargin(new Insets(margin.top, margin.left + 3, margin.bottom, margin.right - 2));
Thread.sleep(delay);
setButtonMargin(margin);
Thread.sleep(delay);
setButtonMargin(new Insets(margin.top, margin.left - 2, margin.bottom, margin.right + 3));
Thread.sleep(delay);
setButtonMargin(margin);
Thread.sleep(delay);
}
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
};
Thread t = new Thread(r);
t.start();
}
private void moveButton(final Point p) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
button.setLocation(p);
}
});
}
private void setButtonMargin(final Insets margin) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
button.setMargin(margin);
}
});
}
}
修改
示例SwingWorker和JProgressBar&amp;的SwingWorker#取消()
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
public class SwingWorkerExample extends JFrame implements ActionListener {
private static final long serialVersionUID = 1L;
private final JButton startButton, stopButton;
private JScrollPane scrollPane = new JScrollPane();
private JList listBox = null;
private DefaultListModel listModel = new DefaultListModel();
private final JProgressBar progressBar;
private mySwingWorker swingWorker;
public SwingWorkerExample() {
super("SwingWorkerExample");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
getContentPane().setLayout(new GridLayout(2, 2));
startButton = makeButton("Start");
stopButton = makeButton("Stop");
stopButton.setEnabled(false);
progressBar = makeProgressBar(0, 99);
listBox = new JList(listModel);
scrollPane.setViewportView(listBox);
add(scrollPane);
//Display the window.
pack();
setVisible(true);
}
//Class SwingWorker<T,V> T - the result type returned by this SwingWorker's doInBackground
//and get methods V - the type used for carrying out intermediate results by this SwingWorker's
//publish and process methods
private class mySwingWorker extends javax.swing.SwingWorker<ArrayList<Integer>, Integer> {
//The first template argument, in this case, ArrayList<Integer>, is what s returned by doInBackground(),
//and by get(). The second template argument, in this case, Integer, is what is published with the
//publish method. It is also the data type which is stored by the java.util.List that is the parameter
//for the process method, which recieves the information published by the publish method.
@Override
protected ArrayList<Integer> doInBackground() {
//Returns items of the type given as the first template argument to the SwingWorker class.
if (javax.swing.SwingUtilities.isEventDispatchThread()) {
System.out.println("javax.swing.SwingUtilities.isEventDispatchThread() returned true.");
}
Integer tmpValue = new Integer(1);
ArrayList<Integer> list = new ArrayList<Integer>();
for (int i = 0; i < 100; i++) {
for (int j = 0; j < 100; j++) { //find every 100th prime, just to make it slower
tmpValue = FindNextPrime(tmpValue.intValue());
//isCancelled() returns true if the cancel() method is invoked on this class. That is the proper way
//to stop this thread. See the actionPerformed method.
if (isCancelled()) {
System.out.println("SwingWorker - isCancelled");
return list;
}
}
//Successive calls to publish are coalesced into a java.util.List, which is what is received by process,
//which in this case, isused to update the JProgressBar. Thus, the values passed to publish range from
//1 to 100.
publish(new Integer(i));
list.add(tmpValue);
}
return list;
}//Note, always use java.util.List here, or it will use the wrong list.
@Override
protected void process(java.util.List<Integer> progressList) {
//This method is processing a java.util.List of items given as successive arguments to the publish method.
//Note that these calls are coalesced into a java.util.List. This list holds items of the type given as the
//second template parameter type to SwingWorker. Note that the get method below has nothing to do with the
//SwingWorker get method; it is the List's get method. This would be a good place to update a progress bar.
if (!javax.swing.SwingUtilities.isEventDispatchThread()) {
System.out.println("javax.swing.SwingUtilities.isEventDispatchThread() + returned false.");
}
Integer percentComplete = progressList.get(progressList.size() - 1);
progressBar.setValue(percentComplete.intValue());
}
@Override
protected void done() {
System.out.println("doInBackground is complete");
if (!javax.swing.SwingUtilities.isEventDispatchThread()) {
System.out.println("javax.swing.SwingUtilities.isEventDispatchThread() + returned false.");
}
try {
//Here, the SwingWorker's get method returns an item of the same type as specified as the first type parameter
//given to the SwingWorker class.
ArrayList<Integer> results = get();
for (Integer i : results) {
listModel.addElement(i.toString());
}
} catch (Exception e) {
System.out.println("Caught an exception: " + e);
}
startButton();
}
boolean IsPrime(int num) { //Checks whether a number is prime
int i;
for (i = 2; i <= num / 2; i++) {
if (num % i == 0) {
return false;
}
}
return true;
}
protected Integer FindNextPrime(int num) { //Returns next prime number from passed arg.
do {
if (num % 2 == 0) {
num++;
} else {
num += 2;
}
} while (!IsPrime(num));
return new Integer(num);
}
}
private JButton makeButton(String caption) {
JButton b = new JButton(caption);
b.setActionCommand(caption);
b.addActionListener(this);
getContentPane().add(b);
return b;
}
private JProgressBar makeProgressBar(int min, int max) {
JProgressBar progressBar1 = new JProgressBar();
progressBar1.setMinimum(min);
progressBar1.setMaximum(max);
progressBar1.setStringPainted(true);
progressBar1.setBorderPainted(true);
getContentPane().add(progressBar1);
return progressBar1;
}
private void startButton() {
startButton.setEnabled(true);
stopButton.setEnabled(false);
System.out.println("SwingWorker - Done");
}
@Override
public void actionPerformed(ActionEvent e) {
if ("Start" == null ? e.getActionCommand() == null : "Start".equals(e.getActionCommand())) {
startButton.setEnabled(false);
stopButton.setEnabled(true);
// Note that it creates a new instance of the SwingWorker-derived class. Never reuse an old one.
(swingWorker = new mySwingWorker()).execute(); // new instance
} else if ("Stop" == null ? e.getActionCommand() == null : "Stop".equals(e.getActionCommand())) {
startButton.setEnabled(true);
stopButton.setEnabled(false);
swingWorker.cancel(true); // causes isCancelled to return true in doInBackground
swingWorker = null;
}
}
public static void main(String[] args) {
// Notice that it kicks it off on the event-dispatching thread, not the main thread.
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
SwingWorkerExample swingWorkerExample = new SwingWorkerExample();
}
});
}
}
答案 2 :(得分:1)
问题似乎是在设置其值后设置进度条的最大值,并且这会将值重置为最小值。
import javax.swing.*;
public class ProgressBarMinValue {
private static void createAndShowGui() {
JProgressBar progressBar = new JProgressBar();
int value = 234;
int denominator = 400;
int minValue = 200;
progressBar.setString(value + "/" + denominator);
progressBar.setMinimum(minValue);
System.out.println("value := " + value);
progressBar.setValue(value); // (A)
progressBar.setMaximum(denominator);
// progressBar.setValue(value); // (B)
JPanel mainPanel = new JPanel();
mainPanel.add(progressBar);
JOptionPane.showMessageDialog(null, mainPanel);
System.out.println("progressBar.getValue() := " + progressBar.getValue());
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
交换注释并取消注释行(A)和(B),并且如果在设置其最小值和最大值后设置进度条的值,则一切正常。
这是你的解决方案。
请注意,我通过不断削减代码来获得此最小SSCCE,直到问题无法再现。