这个问题是基于我用一个简单的Swing骰子程序回来的问题。我发布的原始问题是here并且已经接受了答案,但我想确切地知道发生了什么,问题发生的原因以及解决方案的工作原理。
我成功地缩减了原始代码以找到问题的核心,现在看起来非常不同:
ColorPanel
,每个都画一个彩色方块但是当我在repaint()
中拨打MouseListener
时,该程序表现得非常奇怪:
如果您使用getParent().repaint()
,则此行为会消失,程序将按预期运行:
代码减去进口等如下:
public class ColorPanelsWindow extends JFrame{
static class ColorPanel extends JPanel {
//color starts off black
//once it is changed should never be
//black again
private Color color = Color.BLACK;
ColorPanel(){
//add listener
addMouseListener(new MouseAdapter(){
@Override
public void mousePressed(MouseEvent arg0) {
color = rotateColor();
repaint();
//using getParent().repaint() instead of repaint() solves the problem
//getParent().repaint();
}
});
}
//rotates the color black/blue > red > green > blue
private Color rotateColor(){
if (color==Color.BLACK || color == Color.BLUE)
return Color.RED;
if (color==Color.RED)
return Color.GREEN;
else return Color.BLUE;
}
@Override
public void paintComponent(Graphics g){
g.setColor(color);
g.fillRect(0, 0, 100, 100);
}
}
ColorPanelsWindow(){
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new GridLayout(1,0));
add(new ColorPanel());
add(new ColorPanel());
//the size must be set so that the window is too small
// and the two ColorPanels are overlapping
setSize(40, 40);
// setSize(300, 200);
setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(){
@Override
public void run() {
new ColorPanelsWindow();
}
});
}
}
所以我的问题是,这里究竟发生了什么?
答案 0 :(得分:4)
但我想确切知道发生了什么,
我在Windows 7上使用JDK7u60时遇到了同样的问题。对我来说绝对是个错误。
我最好的猜测是双缓冲存在问题。
我在paintComponent()
方法中添加了调试代码。
1)当您单击右侧组件时,仅调用其paintComponent()
方法,并且该面板被绘制为正确的颜色。
2)单击左侧组件时,仅调用其paintComponent()
方法并且面板绘制正确的颜色,但右侧面板将恢复为黑色,而不调用{{1右侧面板上的方法。这让我相信不知何故正在使用一个旧的缓冲区(这将是错误,我不知道如何解决它)。
paintComonent()
的工作原因是因为无论您点击哪个面板,都会强制重新绘制两个组件。
答案 1 :(得分:3)
我不确定您的问题的原因,因为我无法使用您的代码重现错误行为,但您的paintComponent覆盖忽略了调用super的paintComponent方法。把它放进去看看会发生什么。
@Override // method should be protected, not public
protected void paintComponent(Graphics g) {
// ******* add
super.paintComponent(g);
g.setColor(color);
g.fillRect(0, 0, 100, 100);
}
请注意,如果这是我的程序,这是我想要的唯一绘画行为,我会简化我的程序,而不是重写paintComponent,而只是简单地调用setBackground(color);
我也创建了一个颜色数组或列表并迭代它:
public static final Color[] COLORS = {Color.RED, Color.Blue, Color.Green};
private int colorIndex = 0;
// .....
@Override
public void mousePressed(MouseEvent mEvt) {
colorIndex++;
colorIndex %= COLORS.length;
color = COLORS[colorIndex];
setBackground(color);
}
我也会覆盖getPreferredSize方法。
如,
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;
@SuppressWarnings("serial")
public class MyColorsPanelDemo extends JPanel {
private static final int GAP = 20;
public MyColorsPanelDemo() {
setLayout(new GridLayout(1, 0, GAP, GAP));
setBorder(BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP));
add(new ColorPanel());
add(new ColorPanel());
}
private static class ColorPanel extends JPanel {
public static final Color[] COLORS = {Color.red, Color.green, Color.blue};
private static final int PREF_W = 100;
private static final int PREF_H = PREF_W;
private static final Color INIT_BACKGROUND = Color.black;
private int colorIndex = 0;
public ColorPanel() {
setBackground(INIT_BACKGROUND);
addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent mEvt) {
setBackground(COLORS[colorIndex]);
colorIndex++;
colorIndex %= COLORS.length;
}
});
}
@Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
}
private static void createAndShowGui() {
MyColorsPanelDemo mainPanel = new MyColorsPanelDemo();
JFrame frame = new JFrame("MyColorsPanelDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}