我有简单的显示类。每个数字由一个JLabel
表示,设置图标从0到9。
public class Display extends JPanel{
private static final int DIGIT_COUNT = 3;
private JLabel[] labels = new JLabel[DIGIT_COUNT];
private Icon[] numbers = ResourceManager.getInstance().createIconSet(ImageSetResource.DISPLAY_NUMBERS,13);
public Display(){
GridLayout layout = new GridLayout(1,DIGIT_COUNT);
setLayout(layout);
for (int i = 0; i < labels.length; i++) {
labels[i] = new JLabel();
labels[i].setIcon(numbers[0]);
add(labels[i]);
}
setNumber(0);
}
public void setNumber(int number){
int max = 10 ^ DIGIT_COUNT -1;
if (number < 0 && number > max)
throw new IllegalArgumentException("The number needs to be in range <0, " + max + ">");
int[] digits = getDigitArray(number);
for (int i = 0; i < digits.length; i++) {
labels[i].setIcon(numbers[digits[i]]);
}
}
private int[] getDigitArray(int number){
int[] digits = new int[DIGIT_COUNT];
int leftover = number;
for (int i = 0; i < DIGIT_COUNT; i++){
int result = leftover % 10;
leftover = (leftover - result)/10;
digits[DIGIT_COUNT -1 -i] = result;
if (leftover == 0)
break;
}
assert leftover == 0;
return digits;
}
}
此显示也用于每秒更新时间。显示的值在方法setNumber()
中设置。问题是当更新例如从9到10或从79到80时,可见第一个负责10 ^ 1值的JLabel
是更新,而仅10 ^ 0值JLabel
之后。
有没有办法如何实现所有JLabels
始终从用户的角度同时更新?
编辑:
1.Simple Swing计时器代码:
ActionListener taskPerformer = new ActionListener() {
public void actionPerformed(ActionEvent evt) {
display.setNumber(secondsPassed);
}
};
new Timer(1000, taskPerformer).start();
2. @ Marco13感谢你指出那种愚蠢的初学者般的抑扬失误。
3. @ user1803551问题是在JLabel.setIcon()
内JLabel.repaint()
被调用。
这意味着如果我逐个设置图标,JLabels
也可以逐个更新。我不确定JLabel.setText()
。
我试图将SSCCE放在一起,但是所有的标签都立刻被涂上了,问题不明显可能是太简单的例子了。我不能说因为我没有关于Swing
绘画内部的知识。
我正在寻找的方法是以某种方式禁用对组件的重新绘制(从setIcon()
方法调用)并立即重新绘制特定组组件。
答案 0 :(得分:0)
我重写了部分代码,使其更短,更高效,并模拟了在后台运行的计时器。我不得不用常规字符串替换你的图标。
public class Display extends JPanel{
private static final int DIGIT_COUNT = 6;
private static final int MAX = (int) Math.pow(10, DIGIT_COUNT) - 1;
private JLabel[] labels = new JLabel[DIGIT_COUNT];
private String[] numbers = new String[] {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"};
public Display(){
for (int i = 0; i < DIGIT_COUNT; i++)
add(labels[i] = new JLabel(numbers[0]));
}
public void setNumber(int number){
if (number < 0 && number > MAX)
throw new IllegalArgumentException("The number needs to be in range <0, " + MAX + ">");
for (int i = 0; i < DIGIT_COUNT; i++)
labels[DIGIT_COUNT - i - 1].setText(numbers[(number / (int) Math.pow(10, i)) % 10]);
}
public static void main(String[] args) {
JFrame frame = new JFrame();
final Display dis = new Display();
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.add(dis);
frame.pack();
frame.setVisible(true);
new SwingWorker<Void, Integer>() {
@Override
protected Void doInBackground() {
int x = 0;
while (x <= MAX) {
dis.setNumber(x);
x++;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return null;
}
}.execute();
}
}
我相信这种计算秒数的方法并不好,因为工作线程内部的调用等待事件调度线程上调用setNumber
的返回,这需要一些时间,sleep
也可能不会准确,但它只是一个模拟。如果有人可以建议在后台运行计时器的正确方法(更新某些组件),那就太好了。