Question

I would like progressively modify a java JFrame design structure, as in the this simple example. In a loop I'am increasing de preferredWidth of a JPanel and using the method pack(). But apparently the pack method is ignored. If I put the pack out of the loop, using it only one time, it's work. Anyone know the reason and a possible solution?

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();
}
}
Was it helpful?

Solution

Here:

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();
}

Swing components must be created/updated in the Event Dispatch Thread. Having said this your thread is blocking the EDT causing the GUI becomes unresponsive. You should synchronize this new thread with the EDT by using SwingUtilities.invokeLater(). Or even better you can do repetitive tasks using a Swing Timer which is a convenience class to handle all this concurrency stuff.

For example:

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();
}

Take a look to How to Use Swing Timers tutorial for a better explanation.

I don't know what are you trying to achieve with this, but be aware of this: Should I avoid the use of set(Preferred|Maximum|Minimum)Size methods in Java Swing? (Yes we should).

OTHER TIPS

You should use appropriate layout manager, BorderLayout in this case:

JPanel pnlPrincipal = new JPanel();
pnlPrincipal.setLayout(new BorderLayout());

// or

JPanel pnlPrincipal = new JPanel(new BorderLayout());
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top