编程语言
首页 > 编程语言> > java-可滚动(GridBagLayout)面板内的空JTables-列在调整大小时折叠

java-可滚动(GridBagLayout)面板内的空JTables-列在调整大小时折叠

作者:互联网

我试图创建一个“分段”表,实际上是通过GridBagLayout在“可滚动” JPanel中布置的多个表.这些表共享相同的表模型(类),表头和列模型,将JTableHeader设置为包含所有内容的JScrollPane的列头视图.只有一个JScrollPane.

frame (BorderLayout)
    |- JScrollPane
        |- JPanel (GridBagLayout)
            |- Section title panel
            |- JTable 1
            |- Section title panel
            |- JTable 2
            |- JTable (fake)
            |- vertical filler

一切似乎都按预期工作,直到我尝试调整任一表中没有值的任意列的大小-如果表中至少有一行,则按预期工作.我考虑过在表中包含“空”行,但是这会干扰过滤,排序等操作.因此,我更改了代码以包含“模糊的”伪表,这是为了始终保持一行而使标题保持良好的状态.

但是,这不起作用.一旦其中一个表为空并尝试调整列大小,表头就会损坏(其中一列会收缩).

enter image description here

为什么会发生这种情况,我该怎么办?

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.LayoutManager;
import java.awt.Rectangle;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.Scrollable;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableColumnModel;
import javax.swing.table.TableModel;

public class SectionTables extends JFrame {

    public SectionTables() {
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setLayout(new BorderLayout());

        GridBagConstraints gbc;

        JPanel tables = new ScrollableJPanel(new GridBagLayout());
        JScrollPane scrollPane = new JScrollPane(tables);

        JPanel section1Title = new JPanel(new BorderLayout());     
        section1Title.setBorder(BorderFactory.createMatteBorder(1, 1, 1, 1, UIManager.getColor("controlShadow")));
        JLabel section1 = new JLabel("Section One", null, JLabel.CENTER);
        section1Title.add(section1);
        gbc = new GridBagConstraints();
        gbc.gridx = 0;
        gbc.gridy = 0;
        gbc.weightx = 1.0d;
        gbc.fill = GridBagConstraints.HORIZONTAL;
        tables.add(section1Title, gbc);

        MyTableModel model1 = new MyTableModel();
        JTable table1 = new MyTable(model1);
        gbc = new GridBagConstraints();
        gbc.gridx = 0;
        gbc.gridy = 1;
        gbc.weightx = 1.0d;
        gbc.fill = GridBagConstraints.HORIZONTAL;
        tables.add(table1, gbc);

        JPanel section2Title = new JPanel(new BorderLayout());     
        section2Title.setBorder(BorderFactory.createMatteBorder(1, 1, 1, 1, UIManager.getColor("controlShadow")));
        JLabel section2 = new JLabel("Section Two", null, JLabel.CENTER);
        section2Title.add(section2);
        gbc = new GridBagConstraints();
        gbc.gridx = 0;
        gbc.gridy = 2;
        gbc.weightx = 1.0d;
        gbc.fill = GridBagConstraints.HORIZONTAL;
        tables.add(section2Title, gbc);

        MyTableModel model2 = new MyTableModel();
        JTable table2 = new MyTable(model2);   
        gbc = new GridBagConstraints();
        gbc.gridx = 0;
        gbc.gridy = 3;
        gbc.weightx = 1.0d;
        gbc.fill = GridBagConstraints.HORIZONTAL;
        tables.add(table2, gbc);

        MyTableModel modelFake = new MyTableModel();
        modelFake.addRow(new String[] {"", "", ""});
        JTable tableFake = new MyObscuredTable();   
        tableFake.setModel(modelFake);
        gbc = new GridBagConstraints();
        gbc.gridx = 0;
        gbc.gridy = 4;
        gbc.weightx = 1.0d;
        gbc.fill = GridBagConstraints.HORIZONTAL;
        tables.add(tableFake, gbc);

        Box.Filler filler1 = new Box.Filler(new Dimension(0, 0), new Dimension(0, 0), new Dimension(0, 32767));
        gbc = new GridBagConstraints();
        gbc.gridx = 0;
        gbc.gridy = 5;
        gbc.weighty = 1.0d;
        gbc.fill = GridBagConstraints.VERTICAL;
        tables.add(filler1, gbc);

        add(scrollPane);

        TableColumnModel columnModel = table1.getColumnModel();
        table2.setColumnModel(columnModel);
        tableFake.setColumnModel(columnModel);

        JTableHeader tableHeader = new JTableHeader(columnModel);
        scrollPane.setColumnHeaderView(tableHeader);
        table1.setTableHeader(tableHeader);
        table2.setTableHeader(tableHeader);
        tableFake.setTableHeader(tableHeader);


        // if tables are filled, the issue does not occur
//        model1.addRow(new String[] {"", "", ""});
//        model2.addRow(new String[] {"", "", ""});

        pack();
        setLocationRelativeTo(null);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new SectionTables().setVisible(true);
            }
        });
    }

    private class MyTableModel extends DefaultTableModel {
        private String[] columnNames = new String[] {"First", "Second", "Third"};
        private Class[] columnClasses = new Class[] {String.class, String.class, String.class};

        @Override
        public int getColumnCount() {
            return columnNames.length;
        }

        @Override
        public String getColumnName(int column) {
            return columnNames[column];
        }

        @Override
        public Class<?> getColumnClass(int columnIndex) {
            return columnClasses[columnIndex];
        }

        @Override
        public boolean isCellEditable(int row, int column) {
            return false;
        }        

    }

    private class ScrollableJPanel extends JPanel implements Scrollable {

        public ScrollableJPanel(LayoutManager layout) {
            super(layout);
        }

        public ScrollableJPanel() {
            super();
        }

        @Override
        public Dimension getPreferredScrollableViewportSize() {
            return getPreferredSize();
        }

        @Override
        public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) {
            return 16;
        }

        @Override
        public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) {
            return 16;
        }

        @Override
        public boolean getScrollableTracksViewportWidth() {
            return true;
        }

        @Override
        public boolean getScrollableTracksViewportHeight() {
            return false;
        }

    }

    private class MyObscuredTable extends JTable {

        @Override
        public Dimension getPreferredSize() {
            int height; 
            height = 1; // obscure null row           
            Container ancestorOfClass = SwingUtilities.getAncestorOfClass(JPanel.class, this);
            int width = ancestorOfClass.getWidth();
            return new Dimension(width, height);
        }

    }

    private class MyTable extends JTable {

        public MyTable(TableModel model) {
            super(model);
        }

        @Override
        public Dimension getPreferredSize() {
            int height; 
            height = getRowHeight() * getRowCount();
            Container ancestorOfClass = SwingUtilities.getAncestorOfClass(JPanel.class, this);
            int width = ancestorOfClass.getWidth();
            return new Dimension(width, height);
        }

    }
}

解决方法:

也许您可以修改这种方法,该方法在使用多个表时使用TableColumnModelListener来使列宽保持同步:

import java.awt.*;
import java.util.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;

public class TableColumnsShared implements Runnable
{
  JTable table1, table2;
  TableColumnModelListener columnListener1, columnListener2;
  Map<JTable, TableColumnModelListener> map;

  public static void main(String[] args)
  {
    SwingUtilities.invokeLater(new TableColumnsShared());
  }

  public void run()
  {
    Vector<String> names = new Vector<String>();
    names.add("One");
    names.add("Two");
    names.add("Three");

    table1 = new JTable(null, names);
    table2 = new JTable(null, names);

    columnListener1 = new ColumnChangeListener(table1, table2);
    columnListener2 = new ColumnChangeListener(table2, table1);

    table1.getColumnModel().addColumnModelListener(columnListener1);
    table2.getColumnModel().addColumnModelListener(columnListener2);

    map = new HashMap<JTable, TableColumnModelListener>();
    map.put(table1, columnListener1);
    map.put(table2, columnListener2);

    JPanel p = new JPanel(new GridLayout(2,1));
    p.add(new JScrollPane(table1));
    p.add(new JScrollPane(table2));

    JFrame frame = new JFrame();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.getContentPane().add(p);
    frame.setSize(300, 200);
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);
  }

  class ColumnChangeListener implements TableColumnModelListener
  {
    JTable sourceTable;
    JTable targetTable;

    public ColumnChangeListener(JTable source, JTable target)
    {
      this.sourceTable = source;
      this.targetTable = target;
    }

    public void columnAdded(TableColumnModelEvent e) {}
    public void columnSelectionChanged(ListSelectionEvent e) {}
    public void columnRemoved(TableColumnModelEvent e) {}
    public void columnMoved(TableColumnModelEvent e) {}

    public void columnMarginChanged(ChangeEvent e)
    {
      TableColumnModel sourceModel = sourceTable.getColumnModel();
      TableColumnModel targetModel = targetTable.getColumnModel();
      TableColumnModelListener listener = map.get(targetTable);

      targetModel.removeColumnModelListener(listener);

      for (int i = 0; i < sourceModel.getColumnCount(); i++)
      {
        targetModel.getColumn(i).setPreferredWidth(sourceModel.getColumn(i).getWidth());
      }

      targetModel.addColumnModelListener(listener);
    }
  }
}

标签:gridbaglayout,swing,jtable,jtableheader,java
来源: https://codeday.me/bug/20191026/1940322.html