mal*_*rdz 6 java concurrency swing drawing
对于这个糟糕的问题标题感到抱歉,我对这个错误的原因感到困惑,并且不知道该怎么说这个问题.
我正在学习基本的Swing,并从在线书籍Java编程入门中学习这个练习.
我没有按照信中的说明进行操作,而是尝试这样做:
我的实施:
这个bug非常具体:
如果我点击骰子滚动它们,在我调整窗口大小之前,错误将不会出现......
我想我在某个地方犯了一个基本的错误,这个错误只是伪装成这种奇怪的行为.
我试图尽可能地减少代码,只需要花费很长时间就可以解决bug出现时的问题,以及什么时候没有:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class JDie extends JPanel {
private Color color;
private int value;
JDie(){
value = getValue();
color = Color.BLACK;
//add listener
addMouseListener(new MouseAdapter(){
@Override
public void mousePressed(MouseEvent arg0) {
value = getValue(); //'roll' the die
repaint();
}
});
}
/*private helper methods */
private int getValue(){
int v =(int)(Math.random()*6) + 1;
//change color just to show that the
//value has changed
color = getRandomColor();
return v;
}
private Color getRandomColor(){
float r = (float)Math.random();
float g = (float)Math.random();
float b = (float)Math.random();
return new Color(r, g, b);
}
//draws the pips for the die
@Override
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(color);
//draw pips
//set pip size
int pip_side = 10;
switch(value){
case 1:
g.fillRect(3*pip_side, 3*pip_side, pip_side, pip_side);
break;
case 2:
g.fillRect(5*pip_side, pip_side, pip_side, pip_side);
g.fillRect(pip_side, 5*pip_side, pip_side, pip_side);
break;
case 3:
g.fillRect(5*pip_side, pip_side, pip_side, pip_side);
g.fillRect(pip_side, 5*pip_side, pip_side, pip_side);
g.fillRect(3*pip_side, 3*pip_side, pip_side, pip_side);
break;
case 4:
g.fillRect(pip_side, pip_side, pip_side, pip_side);
g.fillRect(5*pip_side, 5*pip_side, pip_side, pip_side);
g.fillRect(5*pip_side, pip_side, pip_side, pip_side);
g.fillRect(pip_side, 5*pip_side, pip_side, pip_side);
break;
case 5:
g.fillRect(pip_side, pip_side, pip_side, pip_side);
g.fillRect(5*pip_side, 5*pip_side, pip_side, pip_side);
g.fillRect(5*pip_side, pip_side, pip_side, pip_side);
g.fillRect(pip_side, 5*pip_side, pip_side, pip_side);
g.fillRect(3*pip_side, 3*pip_side, pip_side, pip_side);
break;
case 6:
g.fillRect(pip_side, pip_side, pip_side, pip_side);
g.fillRect(5*pip_side, 5*pip_side, pip_side, pip_side);
g.fillRect(5*pip_side, pip_side, pip_side, pip_side);
g.fillRect(pip_side, 5*pip_side, pip_side, pip_side);
g.fillRect(pip_side, 3*pip_side, pip_side, pip_side);
g.fillRect(5*pip_side, 3*pip_side, pip_side, pip_side);
break;
}
}
}
public class DieTest extends JFrame{
DieTest(){
setLayout(new GridLayout());
add(new JDie());
add(new JDie());
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//if I set the size smaller than the JDie is displaying
//and resize the window before 'rolling' the dice
//then the bug appears...?!
setSize(80, 80);
//setting the size larger than both JDie
//and it works fine whether you resize or not
// setSize(200, 200);
setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(){
@Override
public void run() {
new DieTest();
}
});
}
}
Run Code Online (Sandbox Code Playgroud)
- - - - - - - 编辑 - - - - - - - - -
再次运行代码,我现在已经注意到它不会100%发生,但是bug仍然存在.这是一个我刚刚接受它的gif,可以更好地说明问题:

当我再次点击第一个骰子时,您可以清楚地看到原始颜色正在重绘的原始值.当我调整窗口大小时,第二个骰子的值跳回一个,到它以前的值......我真的不明白这个......
---------------编辑2 ---------------------
所以看来我的电脑设置也有一些影响,细节是:
这是一个棘手的问题,因为我知道这是我的代码还是其他一些导致问题的程序.作为一个新手我怎么能知道未来的问题是由于我糟糕的编程还是别的......令人沮丧.
----------编辑3 -----------
作为对并发性方面的快速调查:我将所有实例字段设置为volatile我将所有方法(包括paintComponent)设置为synchronized我删除了Math.random()调用(虽然我读了另一个线程说这是线程安全实现)并用实例Random对象替换它
不幸的是,我仍然得到了视觉转换.
我注意到的另一件事是它现在似乎发生的次数要少得多,现在大约十分之一.我一直希望它能够得到修复,然后下一次尝试再次出现问题.在我正在处理的原始程序中,它看起来更像是三分之一(我现在完全改变了程序,所以不要手动).
--------编辑4 ---------我已经提出了一个稍微简化的版本,它不再使用任何随机值,仍然会产生视觉转换.这个代码似乎经常发生:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ColorPanelsWindow extends JFrame{
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
//click on panel to rotate color
addMouseListener(new MouseAdapter(){
@Override
public void mousePressed(MouseEvent arg0) {
color = rotateColor();
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();
}
});
}
}
Run Code Online (Sandbox Code Playgroud)
几点意见:
是的,是的,我完全知道你在说什么。我的申请也受到了同样的影响。
尽管我很难弄清楚原因,但我 - 即使现在 - 也不确定这是否真的是我所想的;这种情况正在发生,(技术性太强,不适合在这里发布)我确实修复了它,但我什至不知道它为什么起作用。
因此,不要重新绘制组件本身,而是重新绘制其容器(或其容器的容器 - 如果仍然没有修复)。
getParent().repaint();
Run Code Online (Sandbox Code Playgroud)
希望有帮助。