不可见组件仍然占用 JPanel 空间

发布于 2024-12-09 12:39:06 字数 5909 浏览 3 评论 0原文

我在 JPanel 中设置了一系列位于 GridLayout 中的组件。 我需要暂时隐藏组件,但 setVisible(false) 并不能解决这个问题,因为组件所在的位置仍然有一个空白。

有没有一种快速且简单的方法可以做到这一点?或者我是否必须继续保存 JPanel 的状态,删除组件,然后恢复它?

SSCCE:

[GridLayout2.java]

import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.Insets;

public class GridLayout2 extends GridLayout 
{
  public GridLayout2() {
    this(1, 0, 0, 0);
  }

  public GridLayout2(int rows, int cols) {
    this(rows, cols, 0, 0);
  }

  public GridLayout2(int rows, int cols, int hgap, int vgap) {
    super(rows, cols, hgap, vgap);
  }

  public Dimension preferredLayoutSize(Container parent) {
    //System.err.println("preferredLayoutSize");
    synchronized (parent.getTreeLock()) {
      Insets insets = parent.getInsets();
      int ncomponents = parent.getComponentCount();
      int nrows = getRows();
      int ncols = getColumns();
      if (nrows > 0) {
        ncols = (ncomponents + nrows - 1) / nrows;
      } 
      else {
        nrows = (ncomponents + ncols - 1) / ncols;
      }
      int[] w = new int[ncols];
      int[] h = new int[nrows];
      for (int i = 0; i < ncomponents; i ++) {
        int r = i / ncols;
        int c = i % ncols;
        Component comp = parent.getComponent(i);
        Dimension d = comp.getPreferredSize();
        if (w[c] < d.width) {
          w[c] = d.width;
        }
        if (h[r] < d.height) {
          h[r] = d.height;
        }
      }
      int nw = 0;
      for (int j = 0; j < ncols; j ++) {
        nw += w[j];
      }
      int nh = 0;
      for (int i = 0; i < nrows; i ++) {
        nh += h[i];
      }
      return new Dimension(insets.left + insets.right + nw + (ncols-1)*getHgap(), 
          insets.top + insets.bottom + nh + (nrows-1)*getVgap());
    }
  }

  public Dimension minimumLayoutSize(Container parent) {
    System.err.println("minimumLayoutSize");
    synchronized (parent.getTreeLock()) {
      Insets insets = parent.getInsets();
      int ncomponents = parent.getComponentCount();
      int nrows = getRows();
      int ncols = getColumns();
      if (nrows > 0) {
        ncols = (ncomponents + nrows - 1) / nrows;
      } 
      else {
        nrows = (ncomponents + ncols - 1) / ncols;
      }
      int[] w = new int[ncols];
      int[] h = new int[nrows];
      for (int i = 0; i < ncomponents; i ++) {
        int r = i / ncols;
        int c = i % ncols;
        Component comp = parent.getComponent(i);
        Dimension d = comp.getMinimumSize();
        if (w[c] < d.width) {
          w[c] = d.width;
        }
        if (h[r] < d.height) {
          h[r] = d.height;
        }
      }
      int nw = 0;
      for (int j = 0; j < ncols; j ++) {
        nw += w[j];
      }
      int nh = 0;
      for (int i = 0; i < nrows; i ++) {
        nh += h[i];
      }
      return new Dimension(insets.left + insets.right + nw + (ncols-1)*getHgap(), 
          insets.top + insets.bottom + nh + (nrows-1)*getVgap());
    }
  }

  public void layoutContainer(Container parent) {
    //System.err.println("layoutContainer");
    synchronized (parent.getTreeLock()) {
      Insets insets = parent.getInsets();
      int ncomponents = parent.getComponentCount();
      int nrows = getRows();
      int ncols = getColumns();
      if (ncomponents == 0) {
        return;
      }
      if (nrows > 0) {
        ncols = (ncomponents + nrows - 1) / nrows;
      } 
      else {
        nrows = (ncomponents + ncols - 1) / ncols;
      }
      int hgap = getHgap();
      int vgap = getVgap();
      // scaling factors      
      Dimension pd = preferredLayoutSize(parent);
      double sw = (1.0 * parent.getWidth()) / pd.width;
      double sh = (1.0 * parent.getHeight()) / pd.height;
      // scale
      int[] w = new int[ncols];
      int[] h = new int[nrows];
      for (int i = 0; i < ncomponents; i ++) {
        int r = i / ncols;
        int c = i % ncols;
        Component comp = parent.getComponent(i);
        Dimension d = comp.getPreferredSize();
        d.width = (int) (sw * d.width);
        d.height = (int) (sh * d.height);
        if (w[c] < d.width) {
          w[c] = d.width;
        }
        if (h[r] < d.height) {
          h[r] = d.height;
        }
      }
      for (int c = 0, x = insets.left; c < ncols; c ++) {
        for (int r = 0, y = insets.top; r < nrows; r ++) {
          int i = r * ncols + c;
          if (i < ncomponents) {
            parent.getComponent(i).setBounds(x, y, w[c], h[r]);
          }
          y += h[r] + vgap;
        }
        x += w[c] + hgap;
      }
    }
  }  
}

[SSCCE.java]

import java.awt.Color;
import javax.swing.*;
import javax.swing.border.*;

public class SSCCE extends JFrame{

    JPanel innerPane = new JPanel();
    JScrollPane scr  = new JScrollPane(innerPane);

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


    public SSCCE() {

        setSize(400, 800);
        innerPane.setLayout(new GridLayout2(0, 1));

        add(scr);

        for (int i = 0; i < 30; i++)
        {
            innerPane.add(getPane());
        }

        setVisible(true);

        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {}

        for (int i = 0; i < 30; i++)
        {
            if (i%2==0)
                innerPane.getComponent(i).setVisible(false);
        }

    }


    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;

    }

}

screenshot

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 cut it, because there is still an empty gap where the components were.

Is there a quick and easy way to do this? Or do I have to stay saving the state of the JPanel, removing the components, then restoring it?

SSCCE:

[GridLayout2.java]

import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.Insets;

public class GridLayout2 extends GridLayout 
{
  public GridLayout2() {
    this(1, 0, 0, 0);
  }

  public GridLayout2(int rows, int cols) {
    this(rows, cols, 0, 0);
  }

  public GridLayout2(int rows, int cols, int hgap, int vgap) {
    super(rows, cols, hgap, vgap);
  }

  public Dimension preferredLayoutSize(Container parent) {
    //System.err.println("preferredLayoutSize");
    synchronized (parent.getTreeLock()) {
      Insets insets = parent.getInsets();
      int ncomponents = parent.getComponentCount();
      int nrows = getRows();
      int ncols = getColumns();
      if (nrows > 0) {
        ncols = (ncomponents + nrows - 1) / nrows;
      } 
      else {
        nrows = (ncomponents + ncols - 1) / ncols;
      }
      int[] w = new int[ncols];
      int[] h = new int[nrows];
      for (int i = 0; i < ncomponents; i ++) {
        int r = i / ncols;
        int c = i % ncols;
        Component comp = parent.getComponent(i);
        Dimension d = comp.getPreferredSize();
        if (w[c] < d.width) {
          w[c] = d.width;
        }
        if (h[r] < d.height) {
          h[r] = d.height;
        }
      }
      int nw = 0;
      for (int j = 0; j < ncols; j ++) {
        nw += w[j];
      }
      int nh = 0;
      for (int i = 0; i < nrows; i ++) {
        nh += h[i];
      }
      return new Dimension(insets.left + insets.right + nw + (ncols-1)*getHgap(), 
          insets.top + insets.bottom + nh + (nrows-1)*getVgap());
    }
  }

  public Dimension minimumLayoutSize(Container parent) {
    System.err.println("minimumLayoutSize");
    synchronized (parent.getTreeLock()) {
      Insets insets = parent.getInsets();
      int ncomponents = parent.getComponentCount();
      int nrows = getRows();
      int ncols = getColumns();
      if (nrows > 0) {
        ncols = (ncomponents + nrows - 1) / nrows;
      } 
      else {
        nrows = (ncomponents + ncols - 1) / ncols;
      }
      int[] w = new int[ncols];
      int[] h = new int[nrows];
      for (int i = 0; i < ncomponents; i ++) {
        int r = i / ncols;
        int c = i % ncols;
        Component comp = parent.getComponent(i);
        Dimension d = comp.getMinimumSize();
        if (w[c] < d.width) {
          w[c] = d.width;
        }
        if (h[r] < d.height) {
          h[r] = d.height;
        }
      }
      int nw = 0;
      for (int j = 0; j < ncols; j ++) {
        nw += w[j];
      }
      int nh = 0;
      for (int i = 0; i < nrows; i ++) {
        nh += h[i];
      }
      return new Dimension(insets.left + insets.right + nw + (ncols-1)*getHgap(), 
          insets.top + insets.bottom + nh + (nrows-1)*getVgap());
    }
  }

  public void layoutContainer(Container parent) {
    //System.err.println("layoutContainer");
    synchronized (parent.getTreeLock()) {
      Insets insets = parent.getInsets();
      int ncomponents = parent.getComponentCount();
      int nrows = getRows();
      int ncols = getColumns();
      if (ncomponents == 0) {
        return;
      }
      if (nrows > 0) {
        ncols = (ncomponents + nrows - 1) / nrows;
      } 
      else {
        nrows = (ncomponents + ncols - 1) / ncols;
      }
      int hgap = getHgap();
      int vgap = getVgap();
      // scaling factors      
      Dimension pd = preferredLayoutSize(parent);
      double sw = (1.0 * parent.getWidth()) / pd.width;
      double sh = (1.0 * parent.getHeight()) / pd.height;
      // scale
      int[] w = new int[ncols];
      int[] h = new int[nrows];
      for (int i = 0; i < ncomponents; i ++) {
        int r = i / ncols;
        int c = i % ncols;
        Component comp = parent.getComponent(i);
        Dimension d = comp.getPreferredSize();
        d.width = (int) (sw * d.width);
        d.height = (int) (sh * d.height);
        if (w[c] < d.width) {
          w[c] = d.width;
        }
        if (h[r] < d.height) {
          h[r] = d.height;
        }
      }
      for (int c = 0, x = insets.left; c < ncols; c ++) {
        for (int r = 0, y = insets.top; r < nrows; r ++) {
          int i = r * ncols + c;
          if (i < ncomponents) {
            parent.getComponent(i).setBounds(x, y, w[c], h[r]);
          }
          y += h[r] + vgap;
        }
        x += w[c] + hgap;
      }
    }
  }  
}

[SSCCE.java]

import java.awt.Color;
import javax.swing.*;
import javax.swing.border.*;

public class SSCCE extends JFrame{

    JPanel innerPane = new JPanel();
    JScrollPane scr  = new JScrollPane(innerPane);

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


    public SSCCE() {

        setSize(400, 800);
        innerPane.setLayout(new GridLayout2(0, 1));

        add(scr);

        for (int i = 0; i < 30; i++)
        {
            innerPane.add(getPane());
        }

        setVisible(true);

        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {}

        for (int i = 0; i < 30; i++)
        {
            if (i%2==0)
                innerPane.getComponent(i).setVisible(false);
        }

    }


    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;

    }

}

screenshot

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

短叹 2024-12-16 12:39:07

因为组件所在的位置仍然有一个空白。

是的,GridLayout 没有那么智能。它只是使用组件的总数来确定行/列的数量。

有没有一种快速、简单的方法可以做到这一点?

我会创建一个自定义布局管理器。只需复制 GridLayout 代码并进行一些更改即可。基本的更改是:

  1. 覆盖ncomponents变量。您需要遍历所有组件并计算可见组件的数量,而不仅仅是使用面板上的组件数量。

  2. 在布局代码中,您需要添加 if (visible) 检查。

编辑:

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

    }
}

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

    }
}
梦屿孤独相伴 2024-12-16 12:39:07

以下是我无法想象的三种方法。

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

请考虑交换:

button.setVisible(false);

对于:

button.setEnabled(false);

对于大多数查看 GUI 的用户来说,这将更加直观,并且具有同样的最终效果。

可见:

禁用组件

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

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);
            }
        });
    }
}
前事休说 2024-12-16 12:39:07

在 EDT 期间不要调用 Thread.sleep(int);,因为会阻止 EDT,请使用 javax.swing.Timer

例如

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

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);
                    }
                }
            }
        };
    }
}
南七夏 2024-12-16 12:39:07

我真的不喜欢GridLayout。我建议您查看 TableLayout,而不是编写自己的布局管理器。我一直用它。

最初的学习曲线比 GridLayout 稍陡一些,但很容易让它按照您想要的方式运行。

http://java.sun.com/products/jfc/tsc/articles/表格布局/

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/

仙女 2024-12-16 12:39:07

尝试使用 BoxLayout 进行组件对齐。例如:

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

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);
}
恰似旧人归 2024-12-16 12:39:07

为了保证答案的完整性,您可以自由地在布局中添加和删除组件,以便它们不占用空间。

有时,这可能是比处理自定义布局更简单的解决方案。

我不是 Java Swing 专家,但在添加/删除组件时您可能需要使布局失效/重新生效。 invalidate()revalidate()repaint() 方法可能很有用。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文