2016-06-23 11 views
3

Ich versuche eine "unterteilte" Tabelle zu erstellen, die eigentlich mehrere Tabellen innerhalb eines "scrollbaren" JPanel über GridBagLayout sind. Die Tabellen teilen sich das gleiche Tabellenmodell (Klasse), Tabellenkopf und Spaltenmodell, die JTableHeader ist als Spaltenkopfansicht eines JScrollPane gesetzt, der alles enthält. Es gibt nur eine JScrollPane.Leere JTables innerhalb eines scrollbaren (GridBagLayout) Panels - Header kollabiert bei Spaltenvergrößerung

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

Alles schien wie erwartet zu arbeiten, bis ich eine beliebige Spalte ohne Werte in eine der beiden Tabellen, um die Größe versucht - wenn die Tabellen mindestens eine Reihe hatte, es funktionierte wie erwartet. Ich überlegte, ob ich "Null" -Reihen in der Tabelle haben sollte, aber das störte das Filtern, Sortieren usw. Also habe ich den Code so geändert, dass er eine "verdeckte" gefälschte Tabelle enthält, die den Header so halten soll, dass er immer eine Zeile hat.

Dies funktioniert jedoch nicht. Sobald eine der Tabellen leer ist und eine Spaltengröße versucht wird, ist der Tabellenkopf beschädigt (eine der Spalten wird verkleinert).

enter image description here

, warum dies geschieht und was kann ich dagegen tun?

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

    } 
} 

Antwort

4

Vielleicht können Sie diesen Ansatz ändern, die eine TableColumnModelListener verwendet die Spaltenbreiten synchron zu halten, wenn mehrere Tabellen: Vorschlag

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

Funktioniert als ein Charme. Danke, Camickr. Ich poste die endgültige Lösung als separate Antwort und akzeptiere deine. – predi

0

Nach @ camickr ist, endete mit diesem nach oben. Viel eleganter als mein ursprünglicher Versuch.

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

    } 
}