【问题标题】:GUI update works in IDE but not always from jar fileGUI 更新在 IDE 中有效,但并不总是来自 jar 文件
【发布时间】:2013-11-29 03:33:58
【问题描述】:

我在运行 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 正在使用双缓冲显示。我也读到过,但不知道如何让它在整个显示准备好之前推迟更新。

提前致谢。

【问题讨论】:

  • 1) 文字墙警报!使用段落。 2) “我有第二个问题可能是相关的。” 整个单词不包含'?'那么..您的第一个问题是什么?

标签: java eclipse swing user-interface


【解决方案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 应该结合单个组件的重绘请求,以便它们一次完成,但可能只有一组组件被重绘。

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

【讨论】:

  • 感谢您的回复。我之前没有得到例外。我决定打开一个终端窗口并从那里运行以查看是否得到它。我没有,所以这仍然是一个问题。但我也没有失败,至少到目前为止没有,而且显示更新非常快。我在想这可能是 JVM 中的一个设置,因为我唯一看到它是当我在 mac finder 中双击 jar 文件时。双击文件与从终端窗口运行有什么不同?我不知道。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-29
  • 2015-07-05
  • 2011-08-20
  • 2020-04-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多