我在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;
}
}
答案 0 :(得分:10)
因为组件之间仍然存在空隙。
是的,GridLayout并不那么聪明。它只使用组件总数来确定行/列的数量。
有一种快速简便的方法吗?
我会创建一个自定义布局管理器。只需复制GridLayout代码并进行一些更改。基本的变化是:
覆盖ncomponents
变量。您需要循环使用所有组件并计算可见组件,而不是仅仅使用面板上的组件数量。
在布局代码中,您需要添加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();
}
}
答案 1 :(得分:4)
以下是我的三个方面。
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);
}
});
}
}
请考虑交换:
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);
}
});
}
}
答案 2 :(得分:3)
在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);
}
}
}
};
}
}
答案 3 :(得分:2)
我真的不喜欢GridLayout。我建议你看一下TableLayout,而不是编写自己的布局管理器。我一直都在使用它。
初始学习曲线比GridLayout稍微陡峭,但很容易让它按照您想要的方式运行。
答案 4 :(得分:0)
尝试使用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);
}
答案 5 :(得分:0)
仅出于答案的完整性,您可以随意将add()
和remove()
组件往返于布局中,以免它们占用空间。
有时候,这可能比处理自定义布局更简单。
我不是Java Swing专家,但是在添加/删除组件时,您可能需要使布局无效/重新验证。方法invalidate()
,revalidate()
和repaint()
可能有用。