java - GUI 更新可以在 IDE 中工作,但并不总是从 jar 文件中进行

标签 java eclipse swing user-interface

我在运行 OSX 10.7.5 的 Mac 上使用 Eclipse IDE 进行开发。该程序构造了一个 JPanel 数组,当用户单击一个面板时,同一行或同一列上的所有其他面板都会改变颜色,鼠标左键为蓝色,右键为红色。当我从 IDE 运行时,一切正常,至少我从未见过它失败。但是,当我创建一个 .jar 文件并通过双击该文件运行时,大多数时候它工作正常,但偶尔它不会改变其他一些面板的颜色。

为了测试,我选择一个方 block ,然后右键单击和左键单击它。正如我所说,大多数时候它都能工作,同一行或同一列中的所有其他面板都会改变颜色。但是,如果我右键单击一个正方形并且某些面板保持蓝色,那就是失败。如果我再次右键单击同一个方 block ,它不会改变显示;失败的面板保持蓝色。就好像经理认为一切都是正确的颜色并且懒得更新显示。

如果我调整面板大小或使用任一按钮单击任何其他方 block ,所有面板都会翻转为正确的颜色。这段代码没有显式调用 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 使用的是双缓冲显示。我也读到了这一点,但不知道如何让它推迟更新,直到整个显示器准备好。

提前致谢。

最佳答案

我没有发现您的逻辑有任何问题,并且当我在 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 应该合并各个组件的重绘请求,以便一次性完成这些请求,但可能只重绘一组组件。

解决这个问题的唯一方法是不使用组件,而是创建自己的组件来对每个矩形进行自定义绘制。当然,这会更加复杂,因为您还需要进行自己的“点击检测”来确定单击了哪个矩形。

关于java - GUI 更新可以在 IDE 中工作,但并不总是从 jar 文件中进行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20277930/

相关文章:

android - Eclipse Android 项目已创建且始终缺少 R 元素

java - Spring 布局中的水平线

Java GUI 自动调整大小

java - 编辑另一个 LinkedHashMap 内 ArrayList 内 LinkedHashMap 中键的值

java - Java 独立应用程序中静态连接对象的缺点

java - Spring Bean配置文件无法从Gradle中声明的依赖项中找到类

Eclipse 在自动导入静态类方面存在一些问题

java - 如何将控件放入 JTable 的 JTableHeader 中?

java - 生成5分钟的随机数

java - 将 JFrame 保存为图像文件(.JPG、.PNG、.BMP 等)