Diseño con auto-wrap dentro JScrollBar

lvr123:

Estoy tratando de construir un panel con componentes dispuestas horizontalmente, con auto-wrap si no hay suficiente lugar y una barra de desplazamiento vertical.

Algo como esto:

+-----------------+
|[1][2][3][4][5]  |
|                 | 
+-----------------+

la reducción de la anchura:

+-----------+
|[1][2][3]  |
|[4][5]     |
+-----------+

la reducción de la anchura de nuevo, los que aparezca la barra de desplazamiento:

+---------+
|[1][2]  ^|
|[3][4]  v|
+---------+

No estoy lejos de ser una solución:

public class TestFlow extends JFrame {

    public TestFlow() {

        getContentPane().setLayout(new BorderLayout());

        JPanel panel = new JPanel(new FlowLayout());
        JScrollPane scroll = new JScrollPane(panel, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);

        getContentPane().add(scroll, BorderLayout.CENTER);

        panel.add(new MyComponent("A"));
        panel.add(new MyComponent("B"));
        panel.add(new MyComponent("C"));
        panel.add(new MyComponent("D"));
        panel.add(new MyComponent("E"));
        panel.add(new MyComponent("F"));
        panel.add(new MyComponent("G"));
        panel.add(new MyComponent("H"));
        panel.add(new MyComponent("I"));
        panel.add(new MyComponent("J"));
        panel.add(new MyComponent("K"));
        panel.add(new MyComponent("L"));
        panel.add(new MyComponent("M"));
        panel.add(new MyComponent("N"));
        panel.add(new MyComponent("O"));

        scroll.addComponentListener(new ComponentAdapter() {

            @Override
            public void componentResized(ComponentEvent e) {
                Dimension max=((JScrollPane)e.getComponent()).getViewport().getExtentSize();
//                panel.setMaximumSize(new Dimension(max.width,Integer.MAX_VALUE));
                panel.setPreferredSize(new Dimension(max.width,Integer.MAX_VALUE));
//                panel.setPreferredSize(max);
                panel.revalidate();
//                panel.repaint();
//                System.out.println(panel.getSize().width+"--"+max.width);
            }

        });

        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setSize(500, 200);
        setLocationRelativeTo(null);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new TestFlow().setVisible(true));
    }

    private static class MyComponent extends JLabel {

        public MyComponent(String text) {
            super(String.join("", Collections.nCopies((int)(Math.round(Math.random()*4)+4), text)));
            setOpaque(true);
            setBackground(Color.YELLOW);
        }

    }

}

, Pero tienen comportamientos extraños sigue:

Con la solución panel.setPreferredSize(new Dimension(max.width,Integer.MAX_VALUE));

  • después de un cambio de tamaño de la ventana, el panel se vacía. Debo mover manualmente la barra de desplazamiento para tener el contenido que aparece
  • la barra de desplazamiento es siempre visible, mientras que no debería

Con la solución panel.setPreferredSize(max);

  • después de un cambio de tamaño de la ventana, el panel no se vuelve a diseñada. Debo mover manualmente por segunda vez la ventana para tener el contenido de re-trazado.
  • la barra de desplazamiento no es visible, mientras que lo que debería.

Cualquier sugerencia en ese código?

[EDIT] He complica el código original, y aplica las sugerencias que fueron proporcionados hasta ahora.

Para fines de diseño, me gustaría utilizar un MigLayout en la parte superior de mi Grupo. En principio, todo está bien distribuida. Al ampliar la ventana, funciona también. Pero no en la reducción de la ventana. El addComponentListenerno trae ningún addedValue.

public class TestMigFlow extends JFrame {

    public TestMigFlow() {

        getContentPane().setLayout(new BorderLayout());
        JPanel panel = new JPanel(new MigLayout("debug, fill, flowy", "[fill]"));
        JScrollPane scroll = new JScrollPane(panel, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);

        getContentPane().add(scroll, BorderLayout.CENTER);

        panel.add(new JLabel("A title as spearator "), "growy 0");

        JPanel sub = new JPanel(new WrapLayout());
//        panel.add(sub, "growx 0"); // Works well on shrink but not on grow
        panel.add(sub); // Works well on grow but not on shrink

        sub.add(new MyComponent("A"));
        sub.add(new MyComponent("B"));
        sub.add(new MyComponent("C"));
        sub.add(new MyComponent("D"));
        sub.add(new MyComponent("E"));
        sub.add(new MyComponent("F"));
        sub.add(new MyComponent("G"));
        sub.add(new MyComponent("H"));
        sub.add(new MyComponent("I"));
        sub.add(new MyComponent("J"));
        sub.add(new MyComponent("K"));
        sub.add(new MyComponent("L"));
        sub.add(new MyComponent("M"));
        sub.add(new MyComponent("N"));
        sub.add(new MyComponent("O"));

        addComponentListener(new ComponentAdapter() {

            @Override
            public void componentResized(ComponentEvent e) {
                Dimension max = new Dimension(scroll.getWidth(), Short.MAX_VALUE);
                panel.setMaximumSize(max);
                panel.repaint();
            }

        });

        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setSize(200, 500);
        setLocationRelativeTo(null);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new TestMigFlow().setVisible(true));
    }

    private static class MyComponent extends JLabel {

        public MyComponent(String text) {
            super(String.join("", Collections.nCopies((int) (Math.round(Math.random() * 4) + 4), text)));
            setOpaque(true);
            setBackground(Color.YELLOW);
        }

    }
lvr123:

La solucion es

  1. que esperar hasta que el recipiente del panel ha sido redimensionada. Para tener así el addComponentListenera nivel del panel y no al nivel de trama
  2. utilizar el WrapLayout
  3. confiar en la WrapLayout es preferredLayoutSizeel cálculo del tamaño adecuado del panel
  4. utilizar una opción de "fillx" en el MigLayout

El lado negativo de la solución es un poco de parpadeo al cambiar el tamaño de la ventana.

public class TestMigFlow2 extends JFrame {

    public TestMigFlow2() {

        getContentPane().setLayout(new BorderLayout());
        JPanel panel = new JPanel(new MigLayout("fillx, flowy", "[fill]"));
        JScrollPane scroll
                = new JScrollPane(panel, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);

        getContentPane().add(scroll, BorderLayout.CENTER);

        panel.add(new MySeparator("sep1"), "growy 0, shrinky 100");

        JPanel sub = new JPanel(new WrapLayout());
        panel.add(sub, "shrinky 100"); // Works well on grow but not on shrink

        sub.add(new MyComponent("A"));
        sub.add(new MyComponent("B"));
        sub.add(new MyComponent("C"));
        sub.add(new MyComponent("D"));
        sub.add(new MyComponent("E"));
        sub.add(new MyComponent("F"));
        sub.add(new MyComponent("G"));
        sub.add(new MyComponent("H"));
        sub.add(new MyComponent("I"));
        sub.add(new MyComponent("J"));
        sub.add(new MyComponent("K"));
        sub.add(new MyComponent("L"));
        sub.add(new MyComponent("M"));
        sub.add(new MyComponent("N"));
        sub.add(new MyComponent("O"));

        panel.add(new MySeparator("sep2"), "growy 0, shrinky 100");

        panel.addComponentListener(new ComponentAdapter() {
            @Override
            public void componentResized(ComponentEvent e) {

                WrapLayout wl = (WrapLayout) sub.getLayout();
                Dimension prefdim = wl.preferredLayoutSize(sub);
                sub.setPreferredSize(prefdim);
                panel.revalidate();
                panel.repaint();
            }

        });

        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setSize(200, 500);
        setLocationRelativeTo(null);
    }

Lo mismo también trabaja con una BoxLayout en lugar de un MigLayout con 2 adiciones:

  1. añadir VerticulGlue como último elemento
  2. dar al panel una altura máxima a lo largo de la altura pref para evitar que el BoxLayout para compartir el espacio adicional entre el panel y la cola vertical.

    TestBoxLayout pública () {

        getContentPane().setLayout(new BorderLayout());
        JPanel panel = new JPanel();
        BoxLayout layout = new BoxLayout(panel, BoxLayout.PAGE_AXIS);
        panel.setLayout(layout);
        JScrollPane scroll
                = new JScrollPane(panel, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
    
        getContentPane().add(scroll, BorderLayout.CENTER);
    
        JLabel separator;
        separator = new MySeparator("Sep1");
        panel.add(separator);
    
        JPanel sub = new MyPanel(new WrapLayout());
        sub.setAlignmentX(0f);
        panel.add(sub);
    
        sub.add(new MyComponent("A"));
        sub.add(new MyComponent("B"));
        sub.add(new MyComponent("C"));
        sub.add(new MyComponent("D"));
        sub.add(new MyComponent("E"));
        sub.add(new MyComponent("F"));
        sub.add(new MyComponent("G"));
        sub.add(new MyComponent("H"));
        sub.add(new MyComponent("I"));
        sub.add(new MyComponent("J"));
        sub.add(new MyComponent("K"));
        sub.add(new MyComponent("L"));
        sub.add(new MyComponent("M"));
        sub.add(new MyComponent("N"));
        sub.add(new MyComponent("O"));
    
        separator = new MySeparator("Sep2");
        panel.add(separator);
    
        // -- Un filler --
        panel.add(Box.createVerticalGlue());
    
    
        panel.addComponentListener(new ComponentAdapter() {
            @Override
            public void componentResized(ComponentEvent e) {
    
                WrapLayout wl=(WrapLayout) sub.getLayout();
                Dimension prefdim=wl.preferredLayoutSize(sub);
                sub.setPreferredSize(prefdim);
                // Force the max height = pref height to prevent the BoxLayout dispatching the remaining height between the panel and the glue.
                Dimension maxdim=new Dimension(Short.MAX_VALUE,prefdim.height);
                sub.setMaximumSize(maxdim);
                panel.revalidate();
                panel.repaint();
            }
    
        });
    
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setSize(200, 500);
        setLocationRelativeTo(null);
    }
    

Supongo que te gusta

Origin http://43.154.161.224:23101/article/api/json?id=330918&siteId=1
Recomendado
Clasificación