Java Box(BoxLayout)无法按预期工作

时间:2010-09-12 10:32:59

标签: java swing layout

我使用Java Box类有一个奇怪的问题。我使用的是JDK 1.6.21。

我有一个自己的类DropDownPanel,它继承自JPanel。 DropDownPanel的目的是能够隐藏和显示其他组件。如果单击DropDownPanel的标题,则托管组件(现在是JTable)将设置为可见或不可见。它一切都很好。

我将这些DropDownPanel放入一个垂直的Box类中,然后将Box放入一个JScrollPane中。 DropDownPanels的所有X和Y对齐都设置为0,因此Box中不应出现错位。

所以我有以下逻辑树:JScrollPane中Box中DropDownPanel中的JTable。

问题是如果Box只包含DropDownPanels,那么当我在表中添加和删除行时,我会观察到以下行为:

  • 在添加了大量行之后正确显示了JScrollPane,这意味着正确计算了大小和布局。删除足够的行后滚动条消失,因此该表适合JFrame。
  • 正确刷新JTable行,即我看到正确的行数。
  • 但是,JTable似乎永远不会调整自己。添加的行是不可见的,删除的行会消失,但表背景(带有白色)仍然可见。我希望JTable尽可能紧凑。它不是。

现在出现了奇怪的事情。如果我添加一个空的JPanel作为Box的最后一个组件,一切都按照我的预期工作。 JTable始终尽可能紧凑。删除行时,表大小会变小并正确重新绘制。然而,如果没有最后的JPanel,JTable会调整自身的大小(我从滚动条的外观知道它),但永远不会紧凑。调整JFrame的大小没有帮助。强制正确行为的唯一因素是通过DropDownPanel隐藏和显示JTable。然后它显示正确。

由于DropDownPanel是一个扩展的JPanel,而添加的JPanel只是默认的JPanel,我不知道为什么没有Box底部的额外JPanel就无法工作。

最后这是代码。注意注释行。如果它被取消注释,表格表现正常(最好从他的设置开始),如果没有,那么它不是。您需要单击DropDownPanel标题以显示该表。然后,您可以添加大量行,以查看在行数不适合JFrame之后滚动窗格显示,并且当它们执行时它会正确消失。但是,JTable并不像应该的那样紧凑:

package tabletest;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;

public class TableTest {

  public class DropDownPanel extends JPanel implements ActionListener, MouseListener {
  private static final long serialVersionUID = 1L;
  protected JPanel header = new JPanel();
  protected JLabel titleLabel;
  protected Component content;
  protected boolean isExpanded = true;

  public DropDownPanel(String title, Component c) {
    content = c;
    setLayout(new BorderLayout());
    titleLabel = new JLabel(title);
    header.setLayout(new BorderLayout());
    header.add(titleLabel, BorderLayout.WEST);
    add(header, BorderLayout.NORTH);
    add(content, BorderLayout.CENTER);
    header.addMouseListener(this);
    titleLabel.addMouseListener(this);
    apply();
  }

  public void toggleExpanded() {
    isExpanded = !isExpanded;
    apply();
  }

  protected void apply() {
    titleLabel.setText("Drop state: " + (isExpanded ? "Expanded" : "Collapsed"));
    content.setVisible(isExpanded);
    setMaximumSize(new Dimension(1024, getPreferredSize().height));
    invalidate();
  }

  @Override
  public void actionPerformed(ActionEvent e) {
    toggleExpanded();
  }

  @Override
  public void mouseClicked(MouseEvent e) {
    toggleExpanded();
  }

  @Override
  public void mousePressed(MouseEvent e) {}
  @Override
  public void mouseReleased(MouseEvent e) {}
  @Override
  public void mouseEntered(MouseEvent e) {}
  @Override
  public void mouseExited(MouseEvent e) {}
  }

  public void run() {
  JFrame f = new JFrame();
  JPanel p = new JPanel();
  Box box = Box.createVerticalBox();
  p.setLayout(new BorderLayout());
  final JTable table = new JTable();
  table.setFocusable(false);
  table.setFillsViewportHeight(true);
  table.setBackground(Color.white);
  DefaultTableModel m = (DefaultTableModel) table.getModel();
  m.addColumn("Color");
  JButton b = new JButton("Remove row");
  b.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent event) {
    ((DefaultTableModel) table.getModel()).removeRow(0);
    table.invalidate();
    }
  });
  JButton b2 = new JButton("Add row");
  b2.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent event) {
    ((DefaultTableModel) table.getModel()).addRow(new Object[] { "Red" });
    table.invalidate();
    }
  });
  DropDownPanel ddp = new DropDownPanel("Title", table);
  ddp.setAlignmentX(0);
  ddp.setAlignmentY(0);
  box.add(ddp);
  // ---------------------------------------------------------------
  // Without this line, it does not work; with this line, it is fine
  //box.add(new JPanel()); 
  // ---------------------------------------------------------------
  JLabel lll = new JLabel("End of Story");
  lll.setAlignmentX(0);
  lll.setAlignmentY(0);
  box.add(lll);
  p.add(new JScrollPane(box), BorderLayout.CENTER);
  p.add(b, BorderLayout.SOUTH);
  p.add(b2, BorderLayout.NORTH);
  f.add(p);
  ((DefaultTableModel) table.getModel()).addRow(new Object[] { "Red" });
  ((DefaultTableModel) table.getModel()).addRow(new Object[] { "Red" });
  ((DefaultTableModel) table.getModel()).addRow(new Object[] { "Red" });
  ((DefaultTableModel) table.getModel()).addRow(new Object[] { "Red" });
  ((DefaultTableModel) table.getModel()).addRow(new Object[] { "Red" });
  f.pack();
  f.setVisible(true);
  f.setSize(new Dimension(600, 400));
  }

  public static void main(String[] args) {
  new TableTest().run();
  }
}

我现在正在出汗,所以任何帮助都表示赞赏:)

2 个答案:

答案 0 :(得分:1)

通常JTable的直接父级应该是JScrollPane,你应该这样添加表:

DropDownPanel ddp = new DropDownPanel("Title", new JScrollPane(table));

答案 1 :(得分:1)

在DropDownPanel中你添加了组件,即JTable到中心,所以它需要所有空间。 以下引自API doc

  

组件按照布局   他们喜欢的尺寸和   容器尺寸的限制。   NORTH和SOUTH组件可能是   水平拉伸;东方和   WEST组件可能会被拉伸   垂直; CENTER组件可以   水平和伸展   垂直填充任何剩余的空间   结束了。

另请参阅本指南:A Visual Guide to Layout Managers

我已经更改了你的代码。希望这就是你要找的东西:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;

public class TableTest {

    public class DropDownPanel extends JPanel implements ActionListener,
            MouseListener {
        private static final long serialVersionUID = 1L;
        //protected JPanel header = new JPanel();
        protected JLabel titleLabel;
        protected Component content;
        protected boolean isExpanded = true;

        public DropDownPanel(String title, Component c) {
            content = c;
            setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
            titleLabel = new JLabel(title);
            //header.setLayout(new BorderLayout());
            //header.add(titleLabel, BorderLayout.NORTH);
            add(titleLabel);
            add(content);
            //header.addMouseListener(this);
            titleLabel.addMouseListener(this);
            apply();
        }

        public void toggleExpanded() {
            isExpanded = !isExpanded;
            apply();
        }

        protected void apply() {
            titleLabel.setText("Drop state: "
                    + (isExpanded ? "Expanded" : "Collapsed"));
            content.setVisible(isExpanded);
            //setMaximumSize(new Dimension(1024, getPreferredSize().height));
            invalidate();
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            toggleExpanded();
        }

        @Override
        public void mouseClicked(MouseEvent e) {
            toggleExpanded();
        }

        @Override
        public void mousePressed(MouseEvent e) {
        }

        @Override
        public void mouseReleased(MouseEvent e) {
        }

        @Override
        public void mouseEntered(MouseEvent e) {
        }

        @Override
        public void mouseExited(MouseEvent e) {
        }
    }

    public void run() {
        JFrame f = new JFrame();
        JPanel p = new JPanel();
        Box box = Box.createVerticalBox();
        p.setLayout(new BorderLayout());
        final JTable table = new JTable();
        table.setFocusable(false);
        table.setFillsViewportHeight(true);
        table.setBackground(Color.white);
        DefaultTableModel m = (DefaultTableModel) table.getModel();
        m.addColumn("Color");
        JButton b = new JButton("Remove row");
        b.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent event) {
                ((DefaultTableModel) table.getModel()).removeRow(0);
                table.invalidate();
            }
        });
        JButton b2 = new JButton("Add row");
        b2.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent event) {
                ((DefaultTableModel) table.getModel())
                        .addRow(new Object[] { "Red" });
                table.invalidate();
            }
        });
        DropDownPanel ddp = new DropDownPanel("Title", table);
        ddp.setAlignmentX(0);
        ddp.setAlignmentY(0);
        box.add(ddp);
        // ---------------------------------------------------------------
        // Without this line, it does not work; with this line, it is fine
        // box.add(new JPanel());
        // ---------------------------------------------------------------
        JLabel lll = new JLabel("End of Story");
        lll.setAlignmentX(0);
        lll.setAlignmentY(0);
        box.add(lll);
        p.add(new JScrollPane(box), BorderLayout.CENTER);
        p.add(b, BorderLayout.SOUTH);
        p.add(b2, BorderLayout.NORTH);
        f.add(p);
        ((DefaultTableModel) table.getModel()).addRow(new Object[] { "Red" });
        ((DefaultTableModel) table.getModel()).addRow(new Object[] { "Red" });
        ((DefaultTableModel) table.getModel()).addRow(new Object[] { "Red" });
        ((DefaultTableModel) table.getModel()).addRow(new Object[] { "Red" });
        ((DefaultTableModel) table.getModel()).addRow(new Object[] { "Red" });
        f.pack();
        f.setVisible(true);
        f.setSize(new Dimension(600, 400));
    }

    public static void main(String[] args) {
        new TableTest().run();
    }
}