java - 在循环中使用 JFrame.pack()

标签 java multithreading swing event-dispatch-thread pack

我想逐步修改 java JFrame 设计结构,如这个简单的示例所示。在循环中,我增加了 JPanel 的首选宽度并使用方法 pack()。但显然 pack 方法被忽略了。如果我把这个包从循环中拿出来,只使用一次,那就可以了。有人知道原因和可能的解决方案吗?

public class Calculadora extends JFrame {

private JPanel pnl = new JPanel();
private boolean flag;

public Calculadora() {
    JPanel pnlPrincipal = new JPanel();
    pnlPrincipal.setPreferredSize(new Dimension(300, 300));
    pnlPrincipal.setBackground(Color.BLACK);
    JButton btnAnexo = new JButton("Anexo");
    btnAnexo.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            if (flag) {
                closeAnexo();
                flag = false;
            } else {
                openAnexo();
                flag = true;
            }
        }
    });
    pnlPrincipal.add(btnAnexo);
    this.pnl.setBackground(Color.WHITE);
    this.pnl.setPreferredSize(new Dimension(0, 300));
    this.add(pnl, BorderLayout.EAST);
    this.add(pnlPrincipal, BorderLayout.CENTER);
    this.pack();
    this.setVisible(true);
}

private void openAnexo() {
    new Thread () {
        @Override
        public void run() {
            for (int i = pnl.getWidth(); i <= 200; i++) {
                pnl.setPreferredSize(new Dimension(i, 300));
                pack();
            }
        }
    }.start();
}

private void closeAnexo() {
    new Thread () {
        @Override
        public void run() {
            for (int i = pnl.getWidth(); i >= 0; i--) {
                pnl.setPreferredSize(new Dimension(i, 300));
                pack();
            }
        }
    }.start();
}

public static void main(String[] args) {
    new Calculadora();
}
}

最佳答案

这里:

private void openAnexo() {
    new Thread () {
        @Override
        public void run() {
            for (int i = pnl.getWidth(); i <= 200; i++) {
                pnl.setPreferredSize(new Dimension(i, 300));
                pack();
            }
        }
    }.start();
}

必须在 Event Dispatch Thread 中创建/更新 Swing 组件。话虽如此,您的线程正在阻塞 EDT,导致 GUI 变得无响应。您应该使用 SwingUtilities.invokeLater() 将此新线程与 EDT 同步。 。或者更好的是,您可以使用 Swing Timer 执行重复性任务。这是一个处理所有并发问题的便利类。

例如:

private void openAnexo() {
    javax.swing.Timer timer = new javax.swing.Timer(200, new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            int width = pnl.getWidth();
            if(width > 200) {
                ((javax.swing.Timer)e.getSource()).stop();
            } else {
                pnl.setPreferredSize(new Dimension(width + 1, 300));
                Calculadora.this.pack();
            }

        }
    });
    timer.setRepeats(true);
    timer.setDelay(200);
    timer.start();
}

查看 How to Use Swing Timers教程以获得更好的解释。

我不知道你想用这个实现什么目的,但请注意这一点:Should I avoid the use of set(Preferred|Maximum|Minimum)Size methods in Java Swing? (是的,我们应该)。

关于java - 在循环中使用 JFrame.pack(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22353568/

相关文章:

r - 加速 gganimate 渲染

multithreading - 在 Scala 上创建线程本地对象

java - 如何配置 IntelliJ IDEA 以允许 Java 文件中的 shebang

java - 返回需要父类(super class)的扩展类

java - 'java.lang.NullPointerException' 错误的未知来源

java - 如何在长时间运行的任务中显示消息?

java - 嵌套 Swing 容器不显示

java - 在 Java 中反序列化不可信数据的安全影响是什么?

c# - 在多线程观察者模式中使用什么集合?

java - 无法清除 JFrame