我的应用程序有一个钢琴卷轴音乐编辑器,它使用类似于下面的代码来更改可能数百个小矩形组件(音符)的背景颜色。它太慢了,你可以清楚地看到各个方块的切换。
如何优化?
public class TestManyChildrenRepaint {
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
// Container with many square panels in a grid
final int NB_SQUARES = 70;
JPanel squareContainer = new JPanel(new GridLayout(NB_SQUARES, NB_SQUARES, 1, 1));
List<Square> squares = new ArrayList<>();
for (int i=0; i < NB_SQUARES * NB_SQUARES; i++) {
var s = new Square();
squareContainer.add(s);
squares.add(s);
}
// Toggle selection of all squares
JButton toggle = new JButton("Toggle");
toggle.addActionListener(e -> squares.forEach(s -> s.toggleSelection()));
// Build JFrame
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(toggle, BorderLayout.WEST);
frame.add(squareContainer, BorderLayout.EAST);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
});
}
private static class Square extends JPanel {
private boolean selected;
public Square() {
setPreferredSize(new Dimension(10, 10));
setSelected(false);
}
public void toggleSelection() {
setSelected(!selected);
}
public void setSelected(boolean b) {
selected = b;
setBackground(selected ? Color.BLUE : Color.ORANGE);
}
}
明白了。用这个最小的例子更容易破解。
repaint()
被 setBackground()
调用,这会生成太多对 repaint()
的调用。
我添加了一个
Square.paintComponent()
方法,该方法根据选择状态绘制背景。这样我就可以更改 Square
背景值,而无需调用 repaint()
。只有在所有单独的方块都更新完毕后,我才会调用 squareContainer.repaint()
。