Invisible components still take up space JPanel

前端 未结 6 1306
渐次进展
渐次进展 2021-01-18 05:22

I have a series of components underneath each other in a JPanel set as a GridLayout. I need to temporarily hide the components but setVisible(false) doesn\'t cu

相关标签:
6条回答
  • 2021-01-18 05:58

    Just for completeness of the answers, you are free to add() and remove() components to and from a layout in order for them not to occupy space.

    That can be a simpler solution sometimes than dealing with custom layouts.

    I'm not a Java Swing expert but you may need to invalidate/revalidate the layout when adding/removing components. Methods invalidate(), revalidate() and repaint() may be useful.

    0 讨论(0)
  • 2021-01-18 06:01

    I really don't like the GridLayout. Instead of writing your own layout manager, I would suggest you take a look at the TableLayout. I use it all the time.

    The initial learning curve is a bit steeper than the GridLayout, but it is easy to get it to behave the way you want.

    http://java.sun.com/products/jfc/tsc/articles/tablelayout/

    0 讨论(0)
  • 2021-01-18 06:05

    Here are 3 ways off the top of my head.

    Hide Components

    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.*;
    
    class HideComponents {
    
        public static void main(String args[]) {
            SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    JPanel gui = new JPanel(new BorderLayout());
                    JToolBar tb = new JToolBar();
                    gui.add(tb, BorderLayout.NORTH);
                    final JButton openTool = new JButton("Open");
                    final JButton saveTool = new JButton("Save");
                    tb.add( openTool );
                    tb.add( saveTool );
    
                    JPanel buttonFlow = new JPanel(new FlowLayout(3));
                    gui.add(buttonFlow, BorderLayout.CENTER);
                    final JButton openFlow = new JButton("Open");
                    final JButton saveFlow = new JButton("Save");
                    buttonFlow.add( openFlow );
                    buttonFlow.add( saveFlow );
    
                    JPanel buttonBox = new JPanel();
                    gui.add(buttonBox, BorderLayout.EAST);
                    BoxLayout bl = new BoxLayout(buttonBox, BoxLayout.Y_AXIS);
                    buttonBox.setLayout(bl);
                    final JButton openBox = new JButton("Open");
                    final JButton saveBox = new JButton("Save");
                    buttonBox.add( openBox );
                    buttonBox.add( saveBox );
    
                    final JCheckBox openChoice = new JCheckBox("Show open", true);
                    openChoice.addActionListener(new ActionListener() {
                        public void actionPerformed(ActionEvent ae) {
                            openTool.setVisible(openChoice.isSelected());
                            openFlow.setVisible(openChoice.isSelected());
                            openBox.setVisible(openChoice.isSelected());
                        }
                    });
                    gui.add(openChoice, BorderLayout.SOUTH);
    
                    JOptionPane.showMessageDialog(null, gui);
                }
            });
        }
    }
    

    On reflection

    Please consider swapping:

    button.setVisible(false);
    

    For:

    button.setEnabled(false);
    

    This will be more intuitive to most users who view the GUI, and has the same ultimate effect.

    Vis:

    Disable Components

    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.*;
    
    class DisableComponents {
    
        public static void main(String args[]) {
            SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    JPanel gui = new JPanel(new BorderLayout());
                    JToolBar tb = new JToolBar();
                    gui.add(tb, BorderLayout.NORTH);
                    final JButton openTool = new JButton("Open");
                    final JButton saveTool = new JButton("Save");
                    tb.add( openTool );
                    tb.add( saveTool );
    
                    JPanel buttonFlow = new JPanel(new FlowLayout(3));
                    gui.add(buttonFlow, BorderLayout.CENTER);
                    final JButton openFlow = new JButton("Open");
                    final JButton saveFlow = new JButton("Save");
                    buttonFlow.add( openFlow );
                    buttonFlow.add( saveFlow );
    
                    JPanel buttonBox = new JPanel();
                    gui.add(buttonBox, BorderLayout.EAST);
                    BoxLayout bl = new BoxLayout(buttonBox, BoxLayout.Y_AXIS);
                    buttonBox.setLayout(bl);
                    final JButton openBox = new JButton("Open");
                    final JButton saveBox = new JButton("Save");
                    buttonBox.add( openBox );
                    buttonBox.add( saveBox );
    
                    final JCheckBox openChoice = new JCheckBox("Enable open", true);
                    openChoice.addActionListener(new ActionListener() {
                        public void actionPerformed(ActionEvent ae) {
                            openTool.setEnabled(openChoice.isSelected());
                            openFlow.setEnabled(openChoice.isSelected());
                            openBox.setEnabled(openChoice.isSelected());
                        }
                    });
                    gui.add(openChoice, BorderLayout.SOUTH);
    
                    JOptionPane.showMessageDialog(null, gui);
                }
            });
        }
    }
    
    0 讨论(0)
  • 2021-01-18 06:10

    because there is still an empty gap where the components were.

    Yes, GridLayout is not that smart. It just uses the total number of components to determine the number of row/columns.

    Is there a quick and easy way to do this?

    I would create a custom layout manager. Just copy the GridLayout code and make a couple of changes. The basic changes would be:

    1. Override the ncomponents variable. Instead of just using the number of components on the panel you would need to loop thorugh all the components and count the visible ones.

    2. In the layout code you would need to add an if (visible) check.

    Edit:

    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.*;
    import javax.swing.border.*;
    
    public class InvisibleGridLayout implements LayoutManager, java.io.Serializable
    {
        int hgap;
        int vgap;
        int rows;
        int cols;
    
        public InvisibleGridLayout() {
        this(1, 0, 0, 0);
        }
    
        public InvisibleGridLayout(int rows, int cols) {
        this(rows, cols, 0, 0);
        }
    
        public InvisibleGridLayout(int rows, int cols, int hgap, int vgap) {
        if ((rows == 0) && (cols == 0)) {
            throw new IllegalArgumentException("rows and cols cannot both be zero");
        }
        this.rows = rows;
        this.cols = cols;
        this.hgap = hgap;
        this.vgap = vgap;
        }
    
        public int getRows() {
        return rows;
        }
    
        public void setRows(int rows) {
        if ((rows == 0) && (this.cols == 0)) {
            throw new IllegalArgumentException("rows and cols cannot both be zero");
        }
        this.rows = rows;
        }
    
        public int getColumns() {
        return cols;
        }
    
        public void setColumns(int cols) {
        if ((cols == 0) && (this.rows == 0)) {
            throw new IllegalArgumentException("rows and cols cannot both be zero");
        }
        this.cols = cols;
        }
    
        public int getHgap() {
        return hgap;
        }
    
        public void setHgap(int hgap) {
        this.hgap = hgap;
        }
    
        public int getVgap() {
        return vgap;
        }
    
        public void setVgap(int vgap) {
        this.vgap = vgap;
        }
    
        public void addLayoutComponent(String name, Component comp) {
        }
    
        public void removeLayoutComponent(Component comp) {
        }
    
        public Dimension preferredLayoutSize(Container parent) {
          synchronized (parent.getTreeLock()) {
        Insets insets = parent.getInsets();
    //  int ncomponents = parent.getComponentCount();
        int ncomponents = getVisibleComponents(parent);
        int nrows = rows;
        int ncols = cols;
    
        if (nrows > 0) {
            ncols = (ncomponents + nrows - 1) / nrows;
        } else {
            nrows = (ncomponents + ncols - 1) / ncols;
        }
        int w = 0;
        int h = 0;
    //  for (int i = 0 ; i < ncomponents ; i++) {
        for (int i = 0 ; i < parent.getComponentCount(); i++) {
            Component comp = parent.getComponent(i);
    
            if (!comp.isVisible()) continue; // added
    
            Dimension d = comp.getPreferredSize();
            if (w < d.width) {
            w = d.width;
            }
            if (h < d.height) {
            h = d.height;
            }
        }
    
        Dimension d = new Dimension(insets.left + insets.right + ncols*w + (ncols-1)*hgap,
                     insets.top + insets.bottom + nrows*h + (nrows-1)*vgap);
    
        return d;
          }
        }
    
        public Dimension minimumLayoutSize(Container parent) {
          synchronized (parent.getTreeLock()) {
            Insets insets = parent.getInsets();
    //  int ncomponents = parent.getComponentCount();
        int ncomponents = getVisibleComponents(parent);
        int nrows = rows;
        int ncols = cols;
    
        if (nrows > 0) {
            ncols = (ncomponents + nrows - 1) / nrows;
        } else {
            nrows = (ncomponents + ncols - 1) / ncols;
        }
        int w = 0;
        int h = 0;
    //  for (int i = 0 ; i < ncomponents ; i++) {
        for (int i = 0 ; i < parent.getComponentCount(); i++) {
            Component comp = parent.getComponent(i);
    
            if (!comp.isVisible()) continue; // added
    
            Dimension d = comp.getMinimumSize();
            if (w < d.width) {
            w = d.width;
            }
            if (h < d.height) {
            h = d.height;
            }
        }
    
        Dimension d = new Dimension(insets.left + insets.right + ncols*w + (ncols-1)*hgap,
                     insets.top + insets.bottom + nrows*h + (nrows-1)*vgap);
    
        return d;
          }
        }
    
        public void layoutContainer(Container parent) {
          synchronized (parent.getTreeLock()) {
        Insets insets = parent.getInsets();
    //  int ncomponents = parent.getComponentCount();
        int ncomponents = getVisibleComponents(parent);
        int nrows = rows;
        int ncols = cols;
        boolean ltr = parent.getComponentOrientation().isLeftToRight();
    
        if (ncomponents == 0) {
            return;
        }
        if (nrows > 0) {
            ncols = (ncomponents + nrows - 1) / nrows;
        } else {
            nrows = (ncomponents + ncols - 1) / ncols;
        }
    
    //  int w = parent.width - (insets.left + insets.right);
    //  int h = parent.height - (insets.top + insets.bottom);
        int w = parent.getSize().width - (insets.left + insets.right);
        int h = parent.getSize().height - (insets.top + insets.bottom);
        w = (w - (ncols - 1) * hgap) / ncols;
        h = (h - (nrows - 1) * vgap) / nrows;
    /*
        if (ltr) {
            for (int c = 0, x = insets.left ; c < ncols ; c++, x += w + hgap) {
            for (int r = 0, y = insets.top ; r < nrows ; r++, y += h + vgap) {
                int i = r * ncols + c;
                if (i < ncomponents) {
                parent.getComponent(i).setBounds(x, y, w, h);
                }
            }
            }
        } else {
    //      for (int c = 0, x = parent.width - insets.right - w; c < ncols ; c++, x -= w + hgap) {
            for (int c = 0, x = parent.getSize().width - insets.right - w; c < ncols ; c++, x -= w + hgap) {
            for (int r = 0, y = insets.top ; r < nrows ; r++, y += h + vgap) {
                int i = r * ncols + c;
                if (i < ncomponents) {
                parent.getComponent(i).setBounds(x, y, w, h);
                }
            }
            }
        }
          }
    */
    
            int i = 0;
    
            if (ltr)
            {
                for (int r = 0, y = insets.top ; r < nrows ; r++, y += h + vgap)
                {
                    int c = 0;
                    int x = insets.left;
    
                    while (c < ncols)
                    {
                        if (i >= parent.getComponentCount()) break;
    
                        Component component = parent.getComponent(i);
    
                        if (component.isVisible())
                        {
                            parent.getComponent(i).setBounds(x, y, w, h);
                            c++;
                            x += w + hgap;
                        }
    
                        i++;
                    }
                }
            }
    
        }}
    
        private int getVisibleComponents(Container parent)
        {
            int visible = 0;
    
            for (Component c: parent.getComponents())
            {
                if (c.isVisible())
                    visible++;
            }
    
            return visible;
        }
    
        public String toString() {
        return getClass().getName() + "[hgap=" + hgap + ",vgap=" + vgap +
                               ",rows=" + rows + ",cols=" + cols + "]";
        }
    
    
    
        public static void main(String[] args)
        {
            final JPanel innerPane = new JPanel();
            JScrollPane scr  = new JScrollPane(innerPane);
    
            innerPane.setLayout(new InvisibleGridLayout(0, 3));
    
    
            for (int i = 0; i < 30; i++)
            {
                JPanel ret = new JPanel();
                JLabel lbl = new JLabel("This is  pane " + i);
    
                ret.add(lbl);
                ret.setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED));
                ret.setBackground(Color.gray);
    
                innerPane.add(ret);
            }
    
            JFrame frame = new JFrame();
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.add(scr);
            frame.setBounds(400, 0, 400, 700);
            frame.setVisible(true);
    
            javax.swing.Timer timer = new javax.swing.Timer(2000, new ActionListener()
            {
                public void actionPerformed(ActionEvent e)
                {
                    for (int i = 0; i < 30; i++)
                    {
                        if (i%2==0)
                            innerPane.getComponent(i).setVisible(false);
                    }
    
                }
            });
            timer.setRepeats(false);
            timer.start();
    
        }
    }
    
    0 讨论(0)
  • 2021-01-18 06:11

    don't call Thread.sleep(int); during EDT, because block EDT, use javax.swing.Timer

    for example

    import java.awt.Color;
    import java.awt.GridLayout;
    import java.awt.event.ActionEvent;
    import javax.swing.*;
    import javax.swing.border.*;
    
    public class SSCCE extends JFrame {
    
        private static final long serialVersionUID = 1L;
        private JPanel innerPane = new JPanel();
        private JScrollPane scr = new JScrollPane(innerPane);
        private Timer timer;
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(new Runnable() {
    
                @Override
                public void run() {
                    SSCCE sSCCE = new SSCCE();
                }
            });
        }
    
        private JPanel getPane() {
            JPanel ret = new JPanel();
            JLabel lbl = new JLabel("This is a pane.");
            ret.add(lbl);
            ret.setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED));
            ret.setBackground(Color.gray);
            return ret;
        }
    
        public SSCCE() {
            innerPane.setLayout(new GridLayout(0, 1));
            add(scr);
            for (int i = 0; i < 30; i++) {
                innerPane.add(getPane());
            }
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            pack();
            setVisible(true);
            start();
        }
    
        private void start() {
            timer = new javax.swing.Timer(2000, updateCol());
            timer.start();
            timer.setRepeats(false);
        }
    
        private Action updateCol() {
            return new AbstractAction("Hide Row Action") {
    
                private static final long serialVersionUID = 1L;
    
                @Override
                public void actionPerformed(ActionEvent e) {
                    for (int i = 0; i < 30; i++) {
                        if (i % 2 == 0) {
                            innerPane.getComponent(i).setVisible(false);
                        }
                    }
                }
            };
        }
    }
    
    0 讨论(0)
  • 2021-01-18 06:12

    try to use BoxLayout with component alignment. For example:

    JPanel innerPane = new JPanel();
    BoxLayout innerPaneLayout = new BoxLayout(innerPane,BoxLayout.Y_AXIS);
    innerPane.setLayout(innerPaneLayout);
    
    for (int i = 0; i < 30; i++)
    {
         JPane newPane = getPane();
         innerPane.add(newPane);
         newPane.setAlignmentY(Component.TOP_ALIGNMENT);
    }
    
    for (int i = 0; i < 30; i++)
    {
          if (i%2==0)
             innerPane.getComponent(i).setVisible(false);
    }
    
    0 讨论(0)
提交回复
热议问题