2016-06-23 1 views
3

Я пытаюсь создать «секционированную» таблицу, которая на самом деле представляет собой несколько таблиц, выложенных в «прокручиваемом» JPanel через GridBagLayout. Таблицы используют одну и ту же модель (класс) таблицы, заголовок таблицы и модель столбца, JTableHeader устанавливается как заголовок заголовка столбца JScrollPane, который содержит все. Существует только один JScrollPane.Пустые JTables внутри панели прокручиваемого (GridBagLayout) - заголовок сжимается при изменении размера столбца

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

    } 
} 

ответ

4

Может быть, вы можете изменить этот подход, который использует 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); 
    } 
    } 
} 
+0

Работает как очарование. Спасибо, камикр. Я отправлю окончательное решение в виде отдельного ответа и приму ваше согласие. – predi

0

По предложению @ camickr, в конечном итоге с этим. Гораздо более элегантно, чем моя первоначальная попытка.

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

public class SectionTables extends JFrame { 

    private Map<JTable, TableColumnModelListener> tableToColModelListener; 

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

     tableToColModelListener = new HashMap<JTable, TableColumnModelListener>(); 

     scrollPane.setColumnHeaderView(tableFake.getTableHeader()); 


     MyColumnChangeListener listener; 

     listener = new MyColumnChangeListener(tableFake, table1, table2); 
     tableFake.getColumnModel().addColumnModelListener(listener); 
     tableToColModelListener.put(tableFake, listener); 

     setSize(200, 200); 
     setLocationRelativeTo(null); 
    } 

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

    private class MyColumnChangeListener implements TableColumnModelListener { 

     private JTable sourceTable; 
     private List<JTable> targetTables; 

     public MyColumnChangeListener(JTable source, JTable... targets) { 
      this.sourceTable = source; 
      if (targets.length < 1) { 
       throw new IllegalArgumentException(); 
      } 
      this.targetTables = Arrays.asList(targets); 
     } 

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

     @Override 
     public void columnMarginChanged(ChangeEvent e) { 
      TableColumnModel sourceModel = sourceTable.getColumnModel(); 

      for (JTable targetTable : targetTables) { 
       TableColumnModel targetModel = targetTable.getColumnModel(); 
       TableColumnModelListener listener = tableToColModelListener.get(targetTable); 
       targetModel.removeColumnModelListener(listener); 
       try { 
        for (int i = 0; i < sourceModel.getColumnCount(); i++) { 
         targetModel.getColumn(i).setPreferredWidth(sourceModel.getColumn(i).getWidth()); 
        } 
       } finally { 
        targetModel.addColumnModelListener(listener); 
       } 
      } 
     } 

    } 

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

    } 
} 
Смежные вопросы