2012-03-26 5 views
8

グループヘッダーの上部に余分なマージされたセルを追加したいと思います。JTableヘッダーの上にマージされたヘッダー。

私はこのフォーラムでこのlinkに答えましたが、私が正確に必要としているのは答えられていないようです(.NET)link2。 もし私が明確でないなら、私は出てきたいものの写真を添付し​​ます。

merged table headers

私が列を持っていると私は絵に描かれているこれらのスーパーの列が表示されるようにする必要があります。

助けが必要ですか?

+0

編集ありがとうございます! – Vagelism

+0

この質問は非常によく聞かれます。また、固定列や基本的なルック・アンド・フィールだけ、または2行のみ、あるいは商用ライセンスも部分的にしか解決できませんでした。現在、L&Fサポート、列と任意の数の行の移動機能を備えた無料のソリューションが存在します。私は将来のサーチャーのためのリンクを[この回答](http://stackoverflow.com/a/31496799/4540645)に残しておきます。 – Qualtagh

答えて

6

hereまたはhere

+2

私はこのサンプルコードをうまく動作させるのに苦労しました。しかし最終的にはいくつかの修正を行った後に動作します。 – Kai

2

を与えられたグループ化可能表ヘッダーの例を試してみてくださいここで完璧に動作するコードです:

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

import java.beans.PropertyChangeEvent; 
import java.beans.PropertyChangeListener; 

import java.util.Enumeration; 

import java.io.ObjectOutputStream; 
import java.io.ObjectInputStream; 
import java.io.IOException; 


/** 
    Example of a table header that allows cells to span multiple columns. 

    Copyright (C) 2001 Christian Kaufhold <[email protected]> 

    This library is free software; you can redistribute it and/or 
    modify it under the terms of the GNU Library General Public 
    License as published by the Free Software Foundation; either 
    version 2 of the License, or (at your option) any later version. 

    This library is distributed in the hope that it will be useful, 
    but WITHOUT ANY WARRANTY; without even the implied warranty of 
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 
    Library General Public License for more details. 

    You should have received a copy of the GNU Library General Public 
    License along with this library; if not, write to the Free 
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
*/ 

/** Just a default renderer. To work with TableHeader, the corresponding 
    TableHeader must be read from the JTable client property (see code), 
    since JTable.getTableHeader() cannot be used. 
*/ 
class DefaultHeaderRenderer 
    extends DefaultTableCellRenderer 
{ 
    { 
     setBorder(UIManager.getBorder("TableHeader.cellBorder")); 
    } 

    public void updateUI() 
    { 
     super.updateUI(); 

     setHorizontalAlignment(CENTER); 

     setBorder(UIManager.getBorder("TableHeader.cellBorder")); 
    } 


    public Component getTableCellRendererComponent 
     (JTable table, Object value, boolean selected, boolean focused, 
     int row, int column) 
    { 
     TableHeader header; 

     if (table != null && (header = (TableHeader)table.getClientProperty(TableHeader.KEY)) != null) 
     { 
      setForeground(header.getForeground()); 
      setBackground(header.getBackground()); 

      setFont(header.getFont()); 

      setComponentOrientation(header.getComponentOrientation()); 

      setEnabled(header.isEnabled()); 
     } 
     else 
     { 
      setForeground(UIManager.getColor("TableHeader.foreground")); 
      setBackground(UIManager.getColor("TableHeader.background")); 

      setFont(UIManager.getFont("TableHeader.font")); 

      setComponentOrientation(ComponentOrientation.UNKNOWN); 

      setEnabled(true); 
     } 

     setText(value != null ? value.toString() : ""); 

     return this; 
    } 
} 

/** An alternative TableHeader that allows header cells to span multiple 
    columns. This is just a bare-bones prototype, things to do are: 
    - Optimize paint code to paint only concerned columns 
    - Area conversion (columnAtPoint, headerRect or similar) 
    - getToolTipText(MouseEvent) 
    - resizing of columns (which of the columns should be resized?) 
    - moving of columns (which cannot be done in real time since JTable 
     doesn't know that it has to paint multiple dragged columns.) 
    - how to serialize if the renderer isn't serializable? 
    - Accessibility 

    Note: JTable aggressively installs its JTableHeader in the column header 
    view of JScrollPane, even if it is set to 'null'. To avoid confusion, 
    override its configureEnclosingScrollPane() method to do nothing, for 
    example. 

    Typically, a TableHeader is set up like this: 

    TableColumnModel columns = ...; 

    // columns contains some XTableColumns that have spans set. 

    JTable table = new FixedJTable(data, columns); // see above which fix 

    table.setTableHeader(null); 

    TableHeader header = new TableHeader(table); 

    JScrollPane pane = new JScrollPane(table); 

    pane.setColumnHeaderView(header); 
*/ 

public class TableHeader 
    extends JComponent 
{ 
    /** TableColumn that also has a headerSpan property. */ 
    public static class XTableColumn 
     extends TableColumn 
    { 
     private int headerSpan; 


     public XTableColumn() 
     { 
      headerSpan = 1; 
     } 

     /** number of columns that the header cell spans. */ 
     public final int headerSpan() 
     { 
      return headerSpan; 
     } 

     /** set 'headerSpan'. requires newHeaderSpan > 0. During the 
      manipulation of TableColumnModels, there may be times where 
      a column spans more columns than there are at the right of it. 
      This state is only allowed during such modifications. Once they 
      are finished, all spans must not be too large. 
      XTableColumns that are hidden by the spans of their predecessors 
      are ignored (in the TableHeader, of course not by the JTable). 

      Due to the broken notification way of TableColumnModel/Table- 
      Column there is no way to notify the header that it must 
      repaint(). 
      If firePropertyChange were not private, we could send the 
      following fake event 
      firePropertyChange("width", getWidth(), getWidth()); 
      which would handle that (only width and preferred width 
      changes can reach the header). 
      The moral is: don't change spans later, or if, repaint the 
      header manually. 
     */ 
     public void setHeaderSpan(int newHeaderSpan) 
     { 
      headerSpan = newHeaderSpan; 
     } 
    } 


    private static TableCellRenderer staticDefaultRenderer 
     = new DefaultHeaderRenderer(); 

    /** Under this key, the table header is stored in the JTable, so that 
     the renderer can access it. See demo renderer above. 
    */ 
    public static Object KEY = TableHeader.class; 

    private JTable table; 

    private transient TableColumnModel columns; 

    private TableCellRenderer defaultRenderer 
     = staticDefaultRenderer; 


    private transient Listener listener; 


    public TableHeader(JTable table) 
    { 
     this.table = table; 

     table.putClientProperty(KEY, this); 

     this.columns = table.getColumnModel(); 

     this.listener = createListener(); 

     table.addPropertyChangeListener(listener); 

     columns.addColumnModelListener(listener); 

     add(new CellRendererPane()); 

     updateUI(); 
    } 


    public void updateUI() 
    { 
     LookAndFeel.installColorsAndFont 
      (this, "TableHeader.background", "TableHeader.foreground", 
      "TableHeader.font"); 

     LookAndFeel.installBorder(this, "TableHeader.border"); 

     if (defaultRenderer instanceof JComponent) 
      ((JComponent)defaultRenderer).updateUI(); 

     revalidate(); repaint(); 
    } 


    public final JTable table() 
    { 
     return table; 
    } 

    public void setTable(JTable t) 
    { 
     JTable oldTable = table; 
     TableColumnModel oldColumns = columns; 

     table.putClientProperty(KEY, null); 

     table.removePropertyChangeListener(listener); 

     columns.removeColumnModelListener(listener); 

     table = t; 

     table.putClientProperty(KEY, this); 

     columns = t.getColumnModel(); 

     table.addPropertyChangeListener(listener); 

     columns.addColumnModelListener(listener); 

     revalidate(); repaint(); 

     firePropertyChange("table", oldTable, table); 
     firePropertyChange("columns", oldColumns, columns); 
    } 

    public final TableColumnModel columns() 
    { 
     return columns; 
    } 

    /** For serialization, the TableCellRenderer is needed to be serializable. 
    */ 
    public void setDefaultRenderer(TableCellRenderer r) 
    { 
     TableCellRenderer oldRenderer = defaultRenderer; 

     defaultRenderer = r; 

     revalidate(); repaint(); 

     firePropertyChange("defaultRenderer", oldRenderer, defaultRenderer); 
    } 

    public final TableCellRenderer defaultRenderer() 
    { 
     return defaultRenderer; 
    } 


    private TableCellRenderer renderer(TableColumn c) 
    { 
     TableCellRenderer result = c.getHeaderRenderer(); 

     if (result != null) 
      return result; 

     return defaultRenderer; 
    } 


    private Component component(TableCellRenderer r, TableColumn c, int column) 
    { 
     return r.getTableCellRendererComponent 
      (table, c.getHeaderValue(), false, false, -1, column); 
    } 


    private Dimension size(long innerWidth) 
    { 
     Insets i = getInsets(); 

     return new Dimension((int)Math.min(innerWidth + i.left + i.bottom, Integer.MAX_VALUE), innerHeight() + i.top + i.bottom); 
    } 


    /** Alas, this cannot be cached. */ 
    private int innerHeight() 
    { 
     int result = 0; 

     int count = columns.getColumnCount(); 

     for (int j = 0; j < count;) 
     { 
      TableColumn c = columns.getColumn(j); 

      int span; 

      if (c instanceof XTableColumn) 
       span = ((XTableColumn)c).headerSpan(); 
      else 
       span = 1; 

      Component d = component(renderer(c), c, j); 

      result = Math.max(result, d.getPreferredSize().height); 

      j += span; 
     } 

     return result; 
    } 



    public Dimension getMinimumSize() 
    { 
     if (isMinimumSizeSet()) 
      return super.getMinimumSize(); 

     return size(minWidth(columns)); 
    } 

    public Dimension getPreferredSize() 
    { 
     if (isPreferredSizeSet()) 
      return super.getPreferredSize(); 

     return size(preferredWidth(columns)); 
    } 

    public Dimension getMaximumSize() 
    { 
     if (isMaximumSizeSet()) 
      return super.getMaximumSize(); 

     return size(maxWidth(columns)); 
    } 


    public void paintComponent(Graphics g) 
    { 
     Insets i = getInsets(); 

     Rectangle clip = g.getClipBounds(); 

     CellRendererPane pane = (CellRendererPane)getComponent(0); 

     Rectangle r = new Rectangle(); 

     r.x = i.left; 
     r.y = i.top; 
     r.height = getHeight() - i.top - i.bottom; 

     if (r.height <= 0) 
      return; 


     int count = columns.getColumnCount(); 

     for (int j = 0; j < count;) 
     { 
      TableColumn c = columns.getColumn(j); 

      r.width = c.getWidth(); 

      int span; 

      if (c instanceof XTableColumn) 
      { 
       span = ((XTableColumn)c).headerSpan(); 

       if (j + span > count) 
       { 
        System.err.println("column: "+j+" span: "+span+" > "+count); 
        System.err.println("This state of TableColumnModel is forbidden!"); 
        span = count - j; 
       } 

       for (int k = 1; k < span; k++) 
        r.width += columns.getColumn(j + k).getWidth(); 
      } 
      else 
      { 
       span = 1; 
      } 

      Component d = component(renderer(c), c, j); 

      pane.paintComponent(g, d, this, 
       r.x, r.y, r.width, r.height, true); 

      r.x += r.width; 

      j += span; 
     } 

     pane.removeAll(); 
    } 


    private void readObject(ObjectInputStream in) 
     throws IOException, ClassNotFoundException 
    { 
     in.defaultReadObject(); 

     listener = createListener(); 

     table.addPropertyChangeListener(listener); 

     columns = table.getColumnModel(); 

     columns.addColumnModelListener(listener); 
    } 


    protected Object clone() 
     throws CloneNotSupportedException 
    { 
     throw new CloneNotSupportedException(); 
    } 


    private Listener createListener() 
    { 
     return new Listener(); 
    } 


    private class Listener 
     implements TableColumnModelListener, PropertyChangeListener 
    { 
     public void propertyChange(PropertyChangeEvent e) 
     { 
      if (e.getPropertyName().equals("columnModel")) 
      { 
       TableColumnModel oldColumns = columns; 

       columns.removeColumnModelListener(this); 

       columns = table.getColumnModel(); 

       columns.addColumnModelListener(this); 

       revalidate(); repaint(); 

       firePropertyChange("columns", oldColumns, columns); 
      } 
     } 


     public void columnAdded(TableColumnModelEvent e) 
     { 
      revalidate(); repaint(); 
     } 

     public void columnRemoved(TableColumnModelEvent e) 
     { 
      revalidate(); repaint(); 
     } 

     public void columnSelectionChanged(ListSelectionEvent e) 
     { 
     } 

     public void columnMoved(TableColumnModelEvent e) 
     { 
      repaint(); 
     } 

     public void columnMarginChanged(ChangeEvent e) 
     { 
      revalidate(); repaint(); 
     } 
    } 

    /* Utility methods. Copied here from TableColumnModels. */ 

    public static long minWidth(TableColumnModel columns) 
    { 
     long result = 0; 

     for (Enumeration e = columns.getColumns(); e.hasMoreElements();) 
      result += ((TableColumn)e.nextElement()).getMinWidth(); 

     return result; 
    } 

    public static long preferredWidth(TableColumnModel columns) 
    { 
     long result = 0; 

     for (Enumeration e = columns.getColumns(); e.hasMoreElements();) 
      result += ((TableColumn)e.nextElement()).getPreferredWidth(); 

     return result; 
    } 

    public static long maxWidth(TableColumnModel columns) 
    { 
     long result = 0; 

     for (Enumeration e = columns.getColumns(); e.hasMoreElements();) 
      result += ((TableColumn)e.nextElement()).getMaxWidth(); 

     return result; 
    } 
} 


class TableHeaderExample 
{ 
    public static void main(String[] args) 
    { 
     DefaultTableModel data = new DefaultTableModel(10, 0); 

     data.addColumn("ABC"); 
     data.addColumn("DEF"); 
     data.addColumn("GHI"); 
     data.addColumn("JKL"); 
     data.addColumn("MNO"); 
     data.addColumn("PQR"); 

     TableColumnModel columns = new DefaultTableColumnModel(); 

     TableHeader.XTableColumn abc = new TableHeader.XTableColumn(); 
     abc.setHeaderValue("ABC"); 
     abc.setHeaderSpan(2); 

     TableColumn ghi = new TableColumn(2); 
     ghi.setHeaderValue("GHI"); 

     TableHeader.XTableColumn jkl = new TableHeader.XTableColumn(); 
     jkl.setHeaderValue("JKL"); 
     jkl.setHeaderSpan(3); 
     jkl.setModelIndex(3); 

     columns.addColumn(abc); 
     columns.addColumn(new TableColumn(1)); 
     columns.addColumn(ghi); 
     columns.addColumn(jkl); 
     columns.addColumn(new TableColumn(4)); 
     columns.addColumn(new TableColumn(5)); 

     JTable table = new JTable(data, columns) 
     { 
      protected void configureEnclosingScrollPane() 
      { 
      } 
     }; 

     table.setTableHeader(null); 

     TableHeader header = new TableHeader(table); 

     header.setForeground(Color.blue); 
     header.setFont(header.getFont().deriveFont(18.0f)); 

     JScrollPane pane = new JScrollPane(table); 

     pane.setColumnHeaderView(header); 

     JFrame f = new JFrame(); 

     f.setContentPane(pane); 

     f.pack(); 

     f.setVisible(true); 
    } 
} 
関連する問題