Java 如何一次更新多个Swing组件(JLabel)-防止逐个更新/重新绘制
我有一个简单的显示类。每个数字由一个JLabel表示,设置图标从0到9Java 如何一次更新多个Swing组件(JLabel)-防止逐个更新/重新绘制,java,swing,Java,Swing,我有一个简单的显示类。每个数字由一个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(Im
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;
}
}
2.@Marco13谢谢你指出那个愚蠢的初学者喜欢的扬抑错误
3.@user1803551问题是在JLabel.setIcon中调用了JLabel.repaint。
这意味着,如果我一个接一个地设置图标,JLabel也可以一个接一个地更新。但是我不确定JLabel.setText是否正确
我试着把SSCCE放在一起,但是所有的标签都一次画好了,问题不明显,可能太简单了。我不能说,因为我不具备关于秋千绘画内部的知识
我正在寻找一种方法,以某种方式禁用从setIcon方法调用的组件上的重新绘制,并立即重新绘制特定组组件。我重写了部分代码,使其更短、更高效,并模拟了在后台运行的计时器。我不得不用常规字符串替换你的图标
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的返回,这需要一些时间,而且睡眠可能不太准确,但这只是一种模拟。如果有人能建议在后台运行计时器以更新某些组件的正确方法,那就太好了。这篇文章演示了这个问题。旁白:我很确定int max=10^DIGIT\u COUNT-1;不是在做你认为它能做的事。它的计算结果不是数字计数的10次方-^是一个按位异或,这里的结果很可能是垃圾。这甚至可能与问题有关,但是。。。谁知道。。您可能应该使用int max=intMath.pow10,数字\u COUNT-1;相反,我试图将SSCCE组装在一起,但所有的标签都同时被涂上了…-这就是为什么要创建SSCCE来简化问题。现在,您必须查看真正的代码,看看有什么区别。我们无法帮助您,因为我们不知道您真正的代码是什么样子的。并立即重新绘制特定的组组件-这是Swing的默认行为。RepaintManger接收绘制请求并将它们分组以执行一次重新绘制。如果它们没有一起绘制,那么在设置每个标签的图标之间会有一些时间延迟。实际上,当所有实际代码都发布在这里时,情况就是这样,因为它并不长。它包含在setNumber方法中,我还包含了计时器代码。我的问题是,我甚至不能说这是正常行为还是我的代码中有什么不好的地方。我只是看不出有什么不对劲。后续的绘制请求都是在事件调度线程上完成的。如果它在SSCCE中工作,那么您就证明它按预期工作。如果它在你真正的程序中不起作用,那么你正在做一些不同/错误的事情。为什么在实际应用程序中代码的长度会发生变化?更新标签的定时器代码应该是相同的。@ LeNoob,如果这个答案解决了你的问题,请考虑接受它,或者如果有帮助的话,进行投票。
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();
}
}