我在运行OSX 10.7.5的Mac上使用Eclipse IDE进行开发。此程序构造一个JPanel数组,当用户单击一个面板时,同一行或列上的所有其他面板都会更改颜色,蓝色表示鼠标左键,红色表示右键。当我从IDE运行时一切正常,至少我从未见过它失败。但是当我创建一个.jar文件并通过双击运行时,大部分时间它都能正常工作,但每隔一段时间它就不会改变其他一些面板的颜色。
要测试我选择一个正方形并交替右键单击并左键单击它。正如我所说,大部分时间它都有效,而同一行或同一列中的所有其他面板都会改变颜色。但是,如果我右键单击一个正方形而某些面板保持蓝色则表示失败。如果我再次右击同一个方格,它不会改变显示;失败的面板保持蓝色。这就像经理认为一切都是正确的颜色,并不打扰更新显示。
如果我调整面板大小或使用任一按钮单击任何其他正方形,则所有面板都会翻转为正确的颜色。这段代码没有显式调用repaint(),但我已经尝试过了,并没有解决问题。我曾尝试阅读有关重绘管理器的信息,但还没有找到让显示器可靠更新的方法。正如我所说,我在运行IDE时从未见过这种情况,大部分时间它也可以作为应用程序运行。刚才需要大约50次点击才能获得失败。
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class GUITest extends JPanel {
final static int NROWS = 81;
final static int TOTAL_SQ = NROWS * NROWS;
Square[] square = new Square[TOTAL_SQ];
public GUITest() {
setLayout(new GridLayout(NROWS, NROWS));
for (int i = 0; i < TOTAL_SQ; i++) {
square[i] = new Square(i);
add(square[i]);
}
}
public void squareClicked(int id, int button) {
// determine which row and column
int row = id / NROWS;
int col = id % NROWS;
// change background color of all squares on same row or column
for (int i = 0; i < TOTAL_SQ; i++) {
if ((row == i / NROWS) || (col == i % NROWS))
if (button == MouseEvent.BUTTON3)
square[i].setBackground(Color.RED);
else
square[i].setBackground(Color.BLUE);
}
} // squareClicked
class Square extends JPanel implements MouseListener {
int id = 0; // which square this is
public Square(int id) {
this.id = id;
setBorder(BorderFactory.createLineBorder(Color.black));
addMouseListener(this);
} // Square constructor
public void mouseClicked(MouseEvent e) {
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
public void mousePressed(MouseEvent e) {
}
public void mouseReleased(MouseEvent e) {
squareClicked(id, e.getButton());
}
} // Square
public static void main(String[] args) {
JFrame frame = new JFrame("GUI Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
GUITest app = new GUITest();
frame.setSize(800, 600);
frame.setLocationRelativeTo(null);
frame.getContentPane().add(app, BorderLayout.CENTER);
frame.setVisible(true);
}
}
我还有第二个问题可能与此有关。 IDE显示比应用程序快得多。 IDE会快速更新。应用程序单独更新每个面板,速度明显变慢。我猜IDE正在使用双缓冲显示器。我也读到了这一点,但是在整个显示器准备就绪之前,看不到如何让它保持更新状态。
提前致谢。
答案 0 :(得分:1)
我没有看到您的逻辑有任何问题,当我在Windows 7上使用JDK7从命令行运行代码时,我无法复制您的问题。
但是,当我运行代码时,我在框架加载时会出现异常:
C:\Java>java GUITest
Exception in thread "AWT-EventQueue-0" java.lang.IllegalArgumentException: Comparison method violates its general contract!
at java.util.TimSort.mergeLo(Unknown Source)
at java.util.TimSort.mergeAt(Unknown Source)
at java.util.TimSort.mergeCollapse(Unknown Source)
at java.util.TimSort.sort(Unknown Source)
at java.util.TimSort.sort(Unknown Source)
at java.util.Arrays.sort(Unknown Source)
at java.util.Collections.sort(Unknown Source)
at javax.swing.SortingFocusTraversalPolicy.enumerateAndSortCycle(Unknown Source)
at javax.swing.SortingFocusTraversalPolicy.getFocusTraversalCycle(Unknown Source)
at javax.swing.SortingFocusTraversalPolicy.getFirstComponent(Unknown Source)
at javax.swing.LayoutFocusTraversalPolicy.getFirstComponent(Unknown Source)
at javax.swing.SortingFocusTraversalPolicy.getDefaultComponent(Unknown Source)
我尝试的第一件事是确保所有代码都在EDT上执行:
EventQueue.invokeLater(new Runnable()
{
public void run()
{
JFrame frame = new JFrame("GUI Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
GUITest app = new GUITest();
frame.getContentPane().add(app, BorderLayout.CENTER);
frame.setSize(800,600);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
我仍然有例外。然后我尝试更改代码以减少单个面板上显示的组件数量:
setLayout( new GridLayout(NROWS,1) );
int squares = 0;
for (int i = 0; i < NROWS; i++)
{
JPanel panel = new JPanel( new GridLayout(1, NROWS) );
for (int j = 0; j < NROWS; j++)
{
square[squares] = new Square(squares);
panel.add( square[squares] );
squares++;
}
add( panel );
}
我不再得到例外。不知道这是否有帮助。
此外,Swing默认是双缓冲的,所以我不确定为什么每个组件都单独更新。 Swing应该组合对单个组件的重绘请求,以便它们一次完成,但可能只有组件组被重新绘制。
唯一的解决方法是不使用组件,而是创建自己的组件,对每个矩形进行自定义绘制。当然,这将涉及更多,因为您还需要进行自己的“命中检测”以确定单击了哪个矩形。