多次repaint()后如何重绘JComponent一次?
How to repaint JComponent once after several repaint()?
我的程序在 JButton 列表上循环。对于每个 JButton,它每秒重新绘制一次:
public class a {
static JFrame frame = new JFrame();
static Set<MyButton> components = new HashSet<MyButton>();
public static void main(String[] args) {
JPanel lPanel = new JPanel(new GridLayout(0,18));
for (int i = 0; i < 500; i++) {
MyButton lButton = new MyButton("Hello" + i);
lPanel.add(lButton);
components.add(lButton);
}
frame.add(lPanel);
frame.pack();
frame.setVisible(true);
blinking();
}
public static void blinking() {
Timer blinkTimer = new Timer(500, new ActionListener() {
boolean on = false;
public void actionPerformed(ActionEvent e) {
for (MyButton lButton : components) {
lButton.blink(on);
}
on = !on;
}
});
blinkTimer.start();
}
}
public class MyButton extends JButton {
public MyButton(String text) {
super(text);
}
public void blink(boolean on) {
setBackground(on ? Color.DARK_GRAY : Color.LIGHT_GRAY);
setForeground(on ? Color.WHITE : Color.BLACK);
}
}
结果:
我想确保所有按钮同时更新它们的背景和前景色。
JButton extends JComponent
和 JComponent.setBackground
调用 repaint()
,以及 JComponent.setForeground
.
因此,我的程序每秒为每个按钮调用 repaint()
两次,并且颜色并不总是同时更新。
如何保证所有按钮的颜色同时更新?我认为解决方案是只调用一个 repaint()
,也许在按钮容器上,但我该怎么做?
按钮是否都在面板的同一层?那为什么不使用那个层的背景而不是按钮的背景呢?
例如:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Main {
private static JButton newButton() {
final JButton b = new JButton("x");
b.setContentAreaFilled(false);
//b.setOpaque(false); //Do not make this call, because setContentAreaFilled documentation says so.
return b;
}
public static void main(final String[] args) {
final JButton tester = newButton();
final Dimension testerDim = tester.getPreferredSize();
final Dimension maxDim = new Dimension(1200, 700);
final int rows = maxDim.width / testerDim.width,
cols = maxDim.height / testerDim.height;
final JPanel buttonPanel = new JPanel(new GridLayout(0, cols));
final int n = rows * cols;
buttonPanel.add(tester);
for (int i = 1; i < n; ++i)
buttonPanel.add(newButton());
final JFrame frame = new JFrame("Button grid");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(buttonPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
final Color bg = buttonPanel.getBackground();
final Timer timer = new Timer(500, new ActionListener() {
private boolean on = false;
@Override
public void actionPerformed(final ActionEvent e) {
buttonPanel.setBackground(on? bg: bg.darker());
on = !on;
}
});
timer.setRepeats(true);
timer.start();
}
}
我认为这是您可以用单个 core/thread 做的最好的事情。
此外,如果您想要按钮之间的其他组件,它们的背景与图层的背景不同,那么只需将它们设为不透明 (setOpaque(true)
),如果它们还没有。
解决方案:使用 setIgnoreRepaint()
并仅重绘框架:
frame.setIgnoreRepaint(true);
for (JButton lButton : components) {
// blink the buttons background on and off
lButton.blink(on);
}
frame.setIgnoreRepaint(false);
frame.repaint();
on = !on;
setIgnoreRepaint 文档有点误导,因为它说暂停重绘系统事件。所以我们正在考虑 OS 可以发送的事件。但实际上它忽略了重绘(隐式或显式),并且不忽略直接在组件上调用的方法(paint / paintImmediatly ...所有这些)。
我的程序在 JButton 列表上循环。对于每个 JButton,它每秒重新绘制一次:
public class a {
static JFrame frame = new JFrame();
static Set<MyButton> components = new HashSet<MyButton>();
public static void main(String[] args) {
JPanel lPanel = new JPanel(new GridLayout(0,18));
for (int i = 0; i < 500; i++) {
MyButton lButton = new MyButton("Hello" + i);
lPanel.add(lButton);
components.add(lButton);
}
frame.add(lPanel);
frame.pack();
frame.setVisible(true);
blinking();
}
public static void blinking() {
Timer blinkTimer = new Timer(500, new ActionListener() {
boolean on = false;
public void actionPerformed(ActionEvent e) {
for (MyButton lButton : components) {
lButton.blink(on);
}
on = !on;
}
});
blinkTimer.start();
}
}
public class MyButton extends JButton {
public MyButton(String text) {
super(text);
}
public void blink(boolean on) {
setBackground(on ? Color.DARK_GRAY : Color.LIGHT_GRAY);
setForeground(on ? Color.WHITE : Color.BLACK);
}
}
结果:
我想确保所有按钮同时更新它们的背景和前景色。
JButton extends JComponent
和 JComponent.setBackground
调用 repaint()
,以及 JComponent.setForeground
.
因此,我的程序每秒为每个按钮调用 repaint()
两次,并且颜色并不总是同时更新。
如何保证所有按钮的颜色同时更新?我认为解决方案是只调用一个 repaint()
,也许在按钮容器上,但我该怎么做?
按钮是否都在面板的同一层?那为什么不使用那个层的背景而不是按钮的背景呢?
例如:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Main {
private static JButton newButton() {
final JButton b = new JButton("x");
b.setContentAreaFilled(false);
//b.setOpaque(false); //Do not make this call, because setContentAreaFilled documentation says so.
return b;
}
public static void main(final String[] args) {
final JButton tester = newButton();
final Dimension testerDim = tester.getPreferredSize();
final Dimension maxDim = new Dimension(1200, 700);
final int rows = maxDim.width / testerDim.width,
cols = maxDim.height / testerDim.height;
final JPanel buttonPanel = new JPanel(new GridLayout(0, cols));
final int n = rows * cols;
buttonPanel.add(tester);
for (int i = 1; i < n; ++i)
buttonPanel.add(newButton());
final JFrame frame = new JFrame("Button grid");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(buttonPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
final Color bg = buttonPanel.getBackground();
final Timer timer = new Timer(500, new ActionListener() {
private boolean on = false;
@Override
public void actionPerformed(final ActionEvent e) {
buttonPanel.setBackground(on? bg: bg.darker());
on = !on;
}
});
timer.setRepeats(true);
timer.start();
}
}
我认为这是您可以用单个 core/thread 做的最好的事情。
此外,如果您想要按钮之间的其他组件,它们的背景与图层的背景不同,那么只需将它们设为不透明 (setOpaque(true)
),如果它们还没有。
解决方案:使用 setIgnoreRepaint()
并仅重绘框架:
frame.setIgnoreRepaint(true);
for (JButton lButton : components) {
// blink the buttons background on and off
lButton.blink(on);
}
frame.setIgnoreRepaint(false);
frame.repaint();
on = !on;
setIgnoreRepaint 文档有点误导,因为它说暂停重绘系统事件。所以我们正在考虑 OS 可以发送的事件。但实际上它忽略了重绘(隐式或显式),并且不忽略直接在组件上调用的方法(paint / paintImmediatly ...所有这些)。