2015-05-14 3 views
0

Проблемыгрупповая заголовок таблицы с фильтром ниже заголовка

Я хотел бы создать заголовок таблицы с групповой ряд фильтров под заголовком.

Я предполагаю, что простой подход состоит в том, чтобы включить компоненты фильтра в заголовок. Проблема в том, что компоненты не редактируются.

Я искал, но не нашел хороший или рабочий подход. Лучшее и работающее решение, которое я нашел до сих пор относительно компонентов фильтра, помещало их вне таблицы. Но когда у вас есть сгруппированный стол, который просто выглядит и чувствует себя некрасиво. Они должны быть ниже заголовка. Включение компонентов фильтра в нижний колонтитул также не является вариантом.

Я использовал групповую форму кода заголовка таблицы this thread и добавил компонент фильтра.

Проблема в том, что когда я нажимаю на компоненты, я не могу получить к ним доступ. Вместо этого выполняется сортировка строк. Даже добавление прослушивателя мыши в текстовое поле не помогает.

Вопрос

Кто-нибудь знает, как сделать текстовые поля в заголовке таблицы для редактирования? Или у кого-то есть лучший подход к размещению фильтра таблицы под заголовком таблицы?

Код

код до сих пор:

FilterHeader.java

import java.awt.BorderLayout; 
import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.event.MouseAdapter; 
import java.awt.event.MouseEvent; 

import javax.swing.JComboBox; 
import javax.swing.JLabel; 
import javax.swing.JPanel; 
import javax.swing.JTable; 
import javax.swing.JTextField; 
import javax.swing.UIManager; 
import javax.swing.border.EmptyBorder; 

public class FilterHeader extends JPanel { 

    public FilterHeader(JTable table, Object value, int columnIndex) { 

     setLayout(new BorderLayout()); 

     // header 
     JLabel header = new JLabel(); 
     header.setForeground(table.getTableHeader().getForeground()); 
     header.setBackground(table.getTableHeader().getBackground()); 
     header.setFont(table.getTableHeader().getFont()); 

     header.setHorizontalAlignment(JLabel.CENTER); 
     header.setText(value.toString()); 
     header.setBorder(UIManager.getBorder("TableHeader.cellBorder")); 

     add(header, BorderLayout.CENTER); 

     // append filter components to header 
     if(columnIndex == 3) { 

      JComboBox cb = new JComboBox(); 
      cb.setBackground(Color.yellow); 
      cb.setBorder(UIManager.getBorder("TableHeader.cellBorder")); 
      cb.setBorder(new EmptyBorder(0, 0, 0, 0)); 
      cb.setForeground(table.getTableHeader().getForeground()); 
      cb.setPreferredSize(new Dimension(0,table.getRowHeight() + 4)); 

      add(cb, BorderLayout.SOUTH); 

     } else { 

      JTextField tf = new JTextField("enter filtertext"); 
      tf.setBackground(Color.yellow); 
      tf.setBorder(UIManager.getBorder("TableHeader.cellBorder")); 
      tf.setForeground(table.getTableHeader().getForeground()); 
      tf.setHorizontalAlignment(JLabel.CENTER); 

      add(tf, BorderLayout.SOUTH); 

      tf.addMouseListener(new MouseAdapter() { 

       @Override 
       public void mouseClicked(MouseEvent e) { 
        System.out.println("textfield clicked"); // doesn't work 
       } 
      }); 
     } 


    } 

} 

ColumnGroup.java

import java.awt.Component; 
import java.awt.Dimension; 
import java.util.ArrayList; 
import java.util.Collections; 
import java.util.List; 

import javax.swing.JTable; 
import javax.swing.table.TableCellRenderer; 
import javax.swing.table.TableColumn; 

public class ColumnGroup { 

    protected TableCellRenderer renderer; 

    protected List<TableColumn> columns; 
    protected List<ColumnGroup> groups; 

    protected String text; 
    protected int margin = 0; 

    public ColumnGroup(String text) { 
     this(text, null); 
    } 

    public ColumnGroup(String text, TableCellRenderer renderer) { 
     this.text = text; 
     this.renderer = renderer; 
     this.columns = new ArrayList<TableColumn>(); 
     this.groups = new ArrayList<ColumnGroup>(); 
    } 

    public void add(TableColumn column) { 
     columns.add(column); 
    } 

    public void add(ColumnGroup group) { 
     groups.add(group); 
    } 

    /** 
    * @param column 
    *   TableColumn 
    */ 
    public List<ColumnGroup> getColumnGroups(TableColumn column) { 
     if (!contains(column)) { 
      return Collections.emptyList(); 
     } 
     List<ColumnGroup> result = new ArrayList<ColumnGroup>(); 
     result.add(this); 
     if (columns.contains(column)) { 
      return result; 
     } 
     for (ColumnGroup columnGroup : groups) { 
      result.addAll(columnGroup.getColumnGroups(column)); 
     } 
     return result; 
    } 

    private boolean contains(TableColumn column) { 
     if (columns.contains(column)) { 
      return true; 
     } 
     for (ColumnGroup group : groups) { 
      if (group.contains(column)) { 
       return true; 
      } 
     } 
     return false; 
    } 

    public TableCellRenderer getHeaderRenderer() { 
     return renderer; 
    } 

    public void setHeaderRenderer(TableCellRenderer renderer) { 
     this.renderer = renderer; 
    } 

    public String getHeaderValue() { 
     return text; 
    } 

    public Dimension getSize(JTable table) { 
     TableCellRenderer renderer = this.renderer; 
     if (renderer == null) { 
      renderer = table.getTableHeader().getDefaultRenderer(); 
     } 
     Component comp = renderer.getTableCellRendererComponent(table, getHeaderValue() == null || getHeaderValue().trim().isEmpty() ? " " 
       : getHeaderValue(), false, false, -1, -1); 
     int height = comp.getPreferredSize().height; 
     int width = 0; 
     for (ColumnGroup columnGroup : groups) { 
      width += columnGroup.getSize(table).width; 
     } 
     for (TableColumn tableColumn : columns) { 
      width += tableColumn.getWidth(); 
      width += margin; 
     } 
     return new Dimension(width, height); 
    } 

    public void setColumnMargin(int margin) { 
     this.margin = margin; 
     for (ColumnGroup columnGroup : groups) { 
      columnGroup.setColumnMargin(margin); 
     } 
    } 

} 

GroupableTableHeader.java

import java.util.ArrayList; 
import java.util.Collections; 
import java.util.List; 

import javax.swing.table.JTableHeader; 
import javax.swing.table.TableColumn; 
import javax.swing.table.TableColumnModel; 

@SuppressWarnings("serial") 
public class GroupableTableHeader extends JTableHeader { 

    @SuppressWarnings("unused") 
    private static final String uiClassID = "GroupableTableHeaderUI"; 

    protected List<ColumnGroup> columnGroups = new ArrayList<ColumnGroup>(); 

    public GroupableTableHeader(TableColumnModel model) { 
     super(model); 
     setUI(new GroupableTableHeaderUI()); 
     setReorderingAllowed(false); 
     // setDefaultRenderer(new MultiLineHeaderRenderer()); 
    } 

    @Override 
    public void updateUI() { 
     setUI(new GroupableTableHeaderUI()); 
    } 

    @Override 
    public void setReorderingAllowed(boolean b) { 
     super.setReorderingAllowed(false); 
    } 

    public void addColumnGroup(ColumnGroup g) { 
     columnGroups.add(g); 
    } 

    public List<ColumnGroup> getColumnGroups(TableColumn col) { 
     for (ColumnGroup group : columnGroups) { 
      List<ColumnGroup> groups = group.getColumnGroups(col); 
      if (!groups.isEmpty()) { 
       return groups; 
      } 
     } 
     return Collections.emptyList(); 
    } 

    public void setColumnMargin() { 
     int columnMargin = getColumnModel().getColumnMargin(); 
     for (ColumnGroup group : columnGroups) { 
      group.setColumnMargin(columnMargin); 
     } 
    } 

} 

GroupableTableHeaderUI.java

import java.awt.Component; 
import java.awt.Dimension; 
import java.awt.Graphics; 
import java.awt.Rectangle; 
import java.util.Enumeration; 
import java.util.HashMap; 
import java.util.List; 
import java.util.Map; 

import javax.swing.JComponent; 
import javax.swing.JTable; 
import javax.swing.UIManager; 
import javax.swing.plaf.basic.BasicTableHeaderUI; 
import javax.swing.table.DefaultTableCellRenderer; 
import javax.swing.table.TableCellRenderer; 
import javax.swing.table.TableColumn; 
import javax.swing.table.TableColumnModel; 

public class GroupableTableHeaderUI extends BasicTableHeaderUI { 

    protected GroupableTableHeader getHeader() { 
     return (GroupableTableHeader) header; 
    } 

    @Override 
    public void paint(Graphics g, JComponent c) { 
     Rectangle clipBounds = g.getClipBounds(); 
     if (header.getColumnModel().getColumnCount() == 0) { 
      return; 
     } 
     int column = 0; 
     Dimension size = header.getSize(); 
     Rectangle cellRect = new Rectangle(0, 0, size.width, size.height); 
     Map<ColumnGroup, Rectangle> groupSizeMap = new HashMap<ColumnGroup, Rectangle>(); 

     for (Enumeration<TableColumn> enumeration = header.getColumnModel().getColumns(); enumeration.hasMoreElements();) { 
      cellRect.height = size.height; 
      cellRect.y = 0; 
      TableColumn aColumn = enumeration.nextElement(); 
      List<ColumnGroup> groups = getHeader().getColumnGroups(aColumn); 
      int groupHeight = 0; 
      for (ColumnGroup group : groups) { 
       Rectangle groupRect = groupSizeMap.get(group); 
       if (groupRect == null) { 
        groupRect = new Rectangle(cellRect); 
        Dimension d = group.getSize(header.getTable()); 
        groupRect.width = d.width; 
        groupRect.height = d.height; 
        groupSizeMap.put(group, groupRect); 
       } 
       paintCell(g, groupRect, group); 
       groupHeight += groupRect.height; 
       cellRect.height = size.height - groupHeight; 
       cellRect.y = groupHeight; 
      } 
      cellRect.width = aColumn.getWidth(); 
      if (cellRect.intersects(clipBounds)) { 
       paintCell(g, cellRect, column); 
      } 
      cellRect.x += cellRect.width; 
      column++; 
     } 
    } 

    private void paintCell(Graphics g, Rectangle cellRect, int columnIndex) { 
     TableColumn aColumn = header.getColumnModel().getColumn(columnIndex); 
     TableCellRenderer renderer = aColumn.getHeaderRenderer(); 
     if (renderer == null) { 

      // original 
      renderer = getHeader().getDefaultRenderer(); 

      // modified 
      renderer = new DefaultTableCellRenderer() { 
       public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { 

        FilterHeader header = new FilterHeader(table, value, column); 
        return header; 
       } 

      }; 
     } 
     Component c = renderer.getTableCellRendererComponent(header.getTable(), aColumn.getHeaderValue(), false, false, 
       -1, columnIndex); 

     c.setBackground(UIManager.getColor("control")); 

     rendererPane.paintComponent(g, c, header, cellRect.x, cellRect.y, cellRect.width, cellRect.height, true); 
    } 

    private void paintCell(Graphics g, Rectangle cellRect, ColumnGroup cGroup) { 
     TableCellRenderer renderer = cGroup.getHeaderRenderer(); 
     if (renderer == null) { 
      renderer = getHeader().getDefaultRenderer(); 
     } 

     Component component = renderer.getTableCellRendererComponent(header.getTable(), cGroup.getHeaderValue(), false, 
       false, -1, -1); 
     rendererPane 
       .paintComponent(g, component, header, cellRect.x, cellRect.y, cellRect.width, cellRect.height, true); 
    } 

    private int getHeaderHeight() { 
     int headerHeight = 0; 
     TableColumnModel columnModel = header.getColumnModel(); 
     for (int column = 0; column < columnModel.getColumnCount(); column++) { 
      TableColumn aColumn = columnModel.getColumn(column); 
      TableCellRenderer renderer = aColumn.getHeaderRenderer(); 
      if (renderer == null) { 
       renderer = getHeader().getDefaultRenderer(); 
      } 

      Component comp = renderer.getTableCellRendererComponent(header.getTable(), aColumn.getHeaderValue(), false, 
        false, -1, column); 
      int cHeight = comp.getPreferredSize().height; 
      List<ColumnGroup> groups = getHeader().getColumnGroups(aColumn); 
      for (ColumnGroup group : groups) { 
       cHeight += group.getSize(header.getTable()).height; 
      } 
      headerHeight = Math.max(headerHeight, cHeight); 
     } 
     return headerHeight; 
    } 

    @Override 
    public Dimension getPreferredSize(JComponent c) { 
     int width = 0; 
     for (Enumeration<TableColumn> enumeration = header.getColumnModel().getColumns(); enumeration.hasMoreElements();) { 
      TableColumn aColumn = enumeration.nextElement(); 
      width += aColumn.getPreferredWidth(); 
     } 
     return createHeaderSize(width); 
    } 

    private Dimension createHeaderSize(int width) { 
     TableColumnModel columnModel = header.getColumnModel(); 
     width += columnModel.getColumnMargin() * columnModel.getColumnCount(); 
     if (width > Integer.MAX_VALUE) { 
      width = Integer.MAX_VALUE; 
     } 
     return new Dimension(width, getHeaderHeight()); 
    } 

} 

GroupableHeaderExample.java

import java.awt.event.WindowAdapter; 
import java.awt.event.WindowEvent; 

import javax.swing.JFrame; 
import javax.swing.JScrollPane; 
import javax.swing.JTable; 
import javax.swing.RowSorter; 
import javax.swing.table.DefaultTableModel; 
import javax.swing.table.JTableHeader; 
import javax.swing.table.TableColumnModel; 
import javax.swing.table.TableModel; 
import javax.swing.table.TableRowSorter; 

// original from https://stackoverflow.com/questions/21347647/how-to-combine-two-column-headers-in-jtable-in-swings 
public class GroupableHeaderExample extends JFrame { 

     GroupableHeaderExample() { 
     super("Groupable Header Example"); 

     DefaultTableModel dm = new DefaultTableModel(); 
     dm.setDataVector(new Object[][]{ 
      {"1","a","b","c","d","e"}, 
      {"2","f","g","h","i","j"}, 
      {"3","k","l","m","n","o"}, 
      {"4","p","q","r","s","t"} 
      }, 
     new Object[]{"SNo.","1","2","Native","2","3"}); 

     JTable table = new JTable(dm) { 
      protected JTableHeader createDefaultTableHeader() { 
       return new GroupableTableHeader(columnModel); 
      } 
     }; 


     TableColumnModel cm = table.getColumnModel(); 
     ColumnGroup g_name = new ColumnGroup("Name"); 
     g_name.add(cm.getColumn(1)); 
     g_name.add(cm.getColumn(2)); 
     ColumnGroup g_lang = new ColumnGroup("Language"); 
     g_lang.add(cm.getColumn(3)); 
     ColumnGroup g_other = new ColumnGroup("Others"); 
     g_other.add(cm.getColumn(4)); 
     g_other.add(cm.getColumn(5)); 
     g_lang.add(g_other); 

     GroupableTableHeader header = (GroupableTableHeader)table.getTableHeader(); 
     header.addColumnGroup(g_name); 
     header.addColumnGroup(g_lang); 
     JScrollPane scroll = new JScrollPane(table); 
     getContentPane().add(scroll); 
     setSize(400, 120); 

     // allow sorting 
     RowSorter<TableModel> sorter = new TableRowSorter<TableModel>(dm); 
     table.setRowSorter(sorter); 

     } 

     public static void main(String[] args) { 
     GroupableHeaderExample frame = new GroupableHeaderExample(); 
     frame.setSize(1024,768); 
     frame.addWindowListener(new WindowAdapter() { 
      public void windowClosing(WindowEvent e) { 
     System.exit(0); 
      } 
     }); 
     frame.setVisible(true); 
     } 
    } 

И скриншот:

enter image description here

Большое спасибо за помощь!

ответ

1

Решила его, объединив различные источники.

Один источник был this post on StackOverflow, но это решение помещало фильтр только за пределы таблицы.

Другим источником является open source version of a TableFilter on coderazzi. Это очень здорово, но и очень тяжелый вес для моих нужд. И не поддерживает сгруппированные столбцы.Так что в целом, что мне нужно было этот кусок кода:

JViewport headerViewport = new JViewport() { 

    @Override 
    public void setView(Component view) { 
     if (view instanceof JTableHeader) { 
      filterHeader.add(view, BorderLayout.NORTH); 
      super.setView(filterHeader); 
     } 
    } 
}; 

scroll.setColumnHeader(headerViewport); 

и

private class TableFilterHeader extends JPanel { 
    public TableFilterHeader(JTableHeader th) { 
     setLayout(new BorderLayout()); 
     add(new TableFilterRow(th.getTable()), BorderLayout.SOUTH); 
    } 
} 

Скриншот:

enter image description here

Заинтересованные из них могут получить full code from this gist. Отсутствует сам фильтр, но это просто: добавьте прослушиватель документов и примените фильтр.

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