2011-11-26 24 views
5

Tengo un JFrame que contiene un conjunto de JPanels en un CardLayout. Cada JPanel tiene un tamaño diferente y quiero que el JFrame se adapte al tamaño del JPanel actualmente mostrado (no el JPanel para adaptarse al tamaño del JFrame).¿Cómo establecer un tamaño de JFrame para que se ajuste al CardLayout que se muestra en JPanel?

¿Cómo puedo lograrlo?

+2

* "Quiero que el JFrame se adapte al tamaño del JPanel que se muestra actualmente" * Sería extraño para el usuario tener un tamaño de cambio de fotograma simplemente porque el contenido mostrado cambia. –

+0

Tener un tamaño de corrección JFrame es bastante feo cuando el panel interno no coincide. Lo intenté. – JVerstry

+0

No estoy seguro de que esto funcione pero puede intentar esto: 'frame.setSize (panel.getPreferredSize()); ' –

Respuesta

11

El general es: si tiene un problema de diseño, siempre resolverlo con un LayoutManager apropiado. Nunca modifique la sugerencia de dimensionamiento de un componente para alcanzar su objetivo.

En este caso, es particularmente fácil ajustar CardLayout. Por defecto, calcula su prefSize al máximo de prefSizes de todas las cartas. Simplemente subclase e implementar para devolver el prefSize (además de inserciones) de la tarjeta visible en ese momento:

public static class MyCardLayout extends CardLayout { 

    @Override 
    public Dimension preferredLayoutSize(Container parent) { 

     Component current = findCurrentComponent(parent); 
     if (current != null) { 
      Insets insets = parent.getInsets(); 
      Dimension pref = current.getPreferredSize(); 
      pref.width += insets.left + insets.right; 
      pref.height += insets.top + insets.bottom; 
      return pref; 
     } 
     return super.preferredLayoutSize(parent); 
    } 

    public Component findCurrentComponent(Container parent) { 
     for (Component comp : parent.getComponents()) { 
      if (comp.isVisible()) { 
       return comp; 
      } 
     } 
     return null; 
    } 

} 

Usando esa (endeudamiento @ ejemplo de mKorbel), el principal método reduce limpiamente:

private static void createAndShowUI() { 
    final CardLayout cardLayout = new MyCardLayout(); 
    final JPanel cardHolder = new JPanel(cardLayout); 
    final JFrame frame = new JFrame("MultiSizedPanels"); 
    JLabel[] labels = { 
     new JLabel("Small Label", SwingConstants.CENTER), 
     new JLabel("Medium Label", SwingConstants.CENTER), 
     new JLabel("Large Label", SwingConstants.CENTER)}; 

    for (int i = 0; i < labels.length; i++) { 
     int padding = 50 * (i + 1); 
     Border lineBorder = BorderFactory.createCompoundBorder(
      BorderFactory.createLineBorder(Color.blue), 
      BorderFactory.createEmptyBorder(padding, padding, padding, padding)); 
     labels[i].setBorder(lineBorder); 
     JPanel containerPanel = new JPanel(); 
     containerPanel.add(labels[i]); 
     cardHolder.add(containerPanel, String.valueOf(i)); 
    } 
    JButton nextButton = new JButton("Next"); 
    nextButton.addActionListener(new ActionListener() { 

     @Override 
     public void actionPerformed(ActionEvent e) { 
      cardLayout.next(cardHolder); 
      frame.pack(); 
     } 
    }); 
    JPanel btnHolder = new JPanel(); 
    btnHolder.add(nextButton); 

    frame.add(cardHolder, BorderLayout.CENTER); 
    frame.add(btnHolder, BorderLayout.SOUTH); 
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    frame.pack(); 
    frame.setLocation(150, 150); 
    frame.setVisible(true); 
} 
+0

Gracias. Eso es más limpio y exactamente lo que quería. – JVerstry

+0

ahora es el mundo más claro y hermoso +1 – mKorbel

+0

Tan limpio que no lo puedo creer. ¡Gracias! –

2

Creo que puede tener un gestor de diseño incorrecto para lo que quiere hacer (dejando de lado, por el momento, que no estoy seguro de que quiera hacer lo que dice que quiere hacer).

Todavía no he encontrado documentación sobre lo que sospecho, que es que CardLayout cambia el tamaño de todos sus hijos al tamaño de su contenedor. Lo que encontrar el siguiente comentario de su método "layoutContainer":

  * Each component in the <code>parent</code> container is reshaped 
     * to be the size of the container, minus space for surrounding 
     * insets, horizontal gaps, and vertical gaps. 

Creo que este es un comportamiento razonable, ya que sería muy molesto para un usuario que tiene el salto tamaño del panel alrededor como paneles están atravesados.

Si este es realmente el comportamiento que desea, entonces creo que desea un administrador de diseño diferente. Y dado que es un comportamiento inusual para una IU en general, es posible que no encuentre uno estándar para hacer esta 'característica' en particular, por lo que tal vez tenga que escribir la suya propia.

4

Aquí está el SSCCE.

1) Para aumentar/disminuir continuamente el tamaño, debería buscar alguna API de animación.

o

2) Si no hay ninguna tarea en segundo plano con salida a la interfaz gráfica de usuario, se puede hacer una pausa mientras el dimensionamiento de la JFrame. En ese caso, retrasaría el aumento/disminución usando Thread#sleep(int) envuelto en el hilo Runnable.

3) Aviso (no para OP) usando Thread#sleep(int) directamente durante EDT sería congelar GUI hasta que el retraso haya terminado.

import java.awt.*; 
import java.awt.event.*; 
import javax.swing.*; 
import javax.swing.border.Border; 
//based on HFOE http://stackoverflow.com/questions/5414177/change-size-of-jpanel-using-cardlayout/5414770#5414770 
public class MultiSizedPanels { 

    private static void createAndShowUI() { 
     final CardLayout cardLayout = new CardLayout(); 
     final JPanel cardHolder = new JPanel(cardLayout); 
     final JFrame frame = new JFrame("MultiSizedPanels"); 
     JLabel[] labels = { 
      new JLabel("Small Label", SwingConstants.CENTER), 
      new JLabel("Medium Label", SwingConstants.CENTER), 
      new JLabel("Large Label", SwingConstants.CENTER)}; 

     for (int i = 0; i < labels.length; i++) { 
      int padding = 50; 
      Dimension size = labels[i].getPreferredSize(); 
      size = new Dimension(size.width + 2 * (i + 1) * padding, size.height + 2 * (i + 1) * padding); 
      labels[i].setPreferredSize(size); 
      Border lineBorder = BorderFactory.createLineBorder(Color.blue); 
      labels[i].setBorder(lineBorder); 
      JPanel containerPanel = new JPanel(); 
      if (i == 1) { 
       containerPanel.setPreferredSize(new Dimension(300, 200)); 
       containerPanel.add(labels[i], BorderLayout.CENTER); 
       cardHolder.add(containerPanel, String.valueOf(i)); 
      } else if (i == 2) { 
       containerPanel.setPreferredSize(new Dimension(600, 400)); 
       containerPanel.add(labels[i], BorderLayout.CENTER); 
       cardHolder.add(containerPanel, String.valueOf(i)); 
      } else { 
       containerPanel.setPreferredSize(new Dimension(800, 600)); 
       containerPanel.add(labels[i], BorderLayout.CENTER); 
       cardHolder.add(containerPanel, String.valueOf(i)); 
      } 
     } 
     JButton nextButton = new JButton("Next"); 
     nextButton.addActionListener(new ActionListener() { 

      public void actionPerformed(ActionEvent e) { 
       cardLayout.next(cardHolder); 
       Dimension dim = new Dimension(); 
       for (Component comp : cardHolder.getComponents()) { 
        if (comp.isVisible() == true) { 
         dim = comp.getPreferredSize(); 
        } 
       } 
       frame.setPreferredSize(dim); 
       java.awt.EventQueue.invokeLater(new Runnable() { 

        public void run() { 
         frame.pack(); 
        } 
       }); 
      } 
     }); 
     JPanel btnHolder = new JPanel(); 
     btnHolder.add(nextButton); 

     frame.add(cardHolder, BorderLayout.CENTER); 
     frame.add(btnHolder, BorderLayout.SOUTH); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.pack(); 
     frame.setLocation(150, 150); 
     frame.setVisible(true); 
    } 

    public static void main(String[] args) { 
     java.awt.EventQueue.invokeLater(new Runnable() { 

      public void run() { 
       createAndShowUI(); 
      } 
     }); 
    } 
} 
+0

-1 por el uso excesivo de setPrefSize: la regla general es (como bien sabe :-) solucionar los problemas de dimensionamiento mediante el uso de un LayoutManager apropiado. Si no encuentra uno que esté haciendo lo que quiere, escriba/ajuste un LayoutManager que sí ... – kleopatra

0
Try this code this may help you. 




protected void paintComponent(Graphics g) { 
if (getModel().isArmed()) { 
     g.setColor(Color.lightGray); 
} else { 
    g.setColor(getBackground()); 
} 
g.fillOval(0, 0, getSize().width-1, getSize().height-1); 
System.out.println("width is "+getSize().width+"height is "+getSize().height); 
super.paintComponent(g); 
} 
protected void paintBorder(Graphics g) { 
g.setColor(getForeground()); 
g.drawOval(0, 0, getSize().width-1, getSize().height-1); 
} 
Shape shape; 
public boolean contains(int x, int y) { 
if (shape == null || !shape.getBounds().equals(getBounds())) { 
    shape = new Ellipse2D.Float(0, 0, getWidth(), getHeight()); 
} 
return shape.contains(x, y); 
}} 
Cuestiones relacionadas