我在使用Java Box类时遇到了一个奇怪的问题。我正在使用JDK 1.6.21。

我有一个自己的类DropDownPanel,该类继承自JPanel。 DropDownPanel的目的是能够在其上隐藏和显示另一个Component。如果单击DropDownPanel的标题,则托管组件(现在是JTable)将设置为可见或不可见。单独运行即可。

我将这些DropDownPanels放入垂直Box类中,然后将Box放入JScrollPane中。 DropDownPanel的所有X和Y对齐方式都设置为0,因此Box中不应有未对齐的情况。

因此,我有以下逻辑树:JScrollPane框中的DropDownPanel中的JTable。

问题是,如果Box仅包含DropDownPanel,则在向表中添加行或从中删除行时,我会观察到以下行为:

  • 添加了很多行后,正确显示了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();
      }
    }
    

    我现在正在流汗,所以我们将不胜感激:)

    最佳答案

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

    10-07 19:12