2013-03-19 35 views
6

我当前正在构建一个小JTable,并且希望突出显示列标题(和行标题 - 行标题部分实际上是工作),当单元格被选中时使它更容易找到这个单元格的相关名称。这里是一个图片:突出显示一个JTable的列标题

enter image description here

我已经尝试切换出渲染与此头:

table.getTableHeader().setDefaultRenderer(new ColumnHeaderRenderer()); 

但是,当我在标题点击总是说isSelected是假的它只是叫。

这是我使用的行名,其中包括渲染器里面的重头戏码 - 代码是不是我,我只是修改了一些:

/* 
* Use a JTable as a renderer for row numbers of a given main table. 
* This table must be added to the row header of the scrollpane that 
* contains the main table. 
*/ 
public class RowNameTable extends JTable 
     implements ChangeListener, PropertyChangeListener { 

    private JTable main; 

    public RowNameTable(JTable table) { 
     main = table; 
     main.addPropertyChangeListener(this); 

     setFocusable(false); 
     setAutoCreateColumnsFromModel(false); 
     setModel(main.getModel()); 
     setSelectionModel(main.getSelectionModel()); 

     TableColumn column = new TableColumn(); 
     column.setHeaderValue(" "); 
     addColumn(column); 
     column.setCellRenderer(new RowNameRenderer(main)); 

     getColumnModel().getColumn(0).setPreferredWidth(table.getColumnModel().getColumn(0).getPreferredWidth()); 
     setPreferredScrollableViewportSize(getPreferredSize()); 
    } 

    @Override 
    public void addNotify() { 
     super.addNotify(); 

     Component c = getParent(); 

     // Keep scrolling of the row table in sync with the main table. 

     if (c instanceof JViewport) { 
      JViewport viewport = (JViewport) c; 
      viewport.addChangeListener(this); 
     } 
    } 

    /* 
    * Delegate method to main table 
    */ 
    @Override 
    public int getRowCount() { 
     return main.getRowCount(); 
    } 

    @Override 
    public int getRowHeight(int row) { 
     return main.getRowHeight(row); 
    } 

    /* 
    * This table does not use any data from the main TableModel, 
    * so just return a value based on the row parameter. 
    */ 
    @Override 
    public Object getValueAt(int row, int column) { 
     return Integer.toString(row + 1); 
    } 

    /* 
    * Don't edit data in the main TableModel by mistake 
    */ 
    @Override 
    public boolean isCellEditable(int row, int column) { 
     return false; 
    } 
// 
// Implement the ChangeListener 
// 

    public void stateChanged(ChangeEvent e) { 
     // Keep the scrolling of the row table in sync with main table 

     JViewport viewport = (JViewport) e.getSource(); 
     JScrollPane scrollPane = (JScrollPane) viewport.getParent(); 
     scrollPane.getVerticalScrollBar().setValue(viewport.getViewPosition().y); 
    } 
// 
// Implement the PropertyChangeListener 
// 

    public void propertyChange(PropertyChangeEvent e) { 
     // Keep the row table in sync with the main table 

     if ("selectionModel".equals(e.getPropertyName())) { 
      setSelectionModel(main.getSelectionModel()); 
     } 

     if ("model".equals(e.getPropertyName())) { 
      setModel(main.getModel()); 
     } 
    } 

    /* 
    * Borrow the renderer from JDK1.4.2 table header 
    */ 
    private static class RowNameRenderer extends DefaultTableCellRenderer { 

     private JTable main; 

     public RowNameRenderer(JTable main) { 
      this.main = main; 
      setHorizontalAlignment(JLabel.CENTER); 
     } 

     @Override 
     public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { 
      if (table != null) { 
       JTableHeader header = table.getTableHeader(); 

       if (header != null) { 
        setForeground(header.getForeground()); 
        setBackground(header.getBackground()); 
        setFont(header.getFont()); 
       } 
      } 

      if (isSelected) { 
       setFont(getFont().deriveFont(Font.BOLD)); 
      } 

      setText((value == null) ? "" : main.getColumnName(row)); 
      setBorder(UIManager.getBorder("TableHeader.cellBorder")); 

      return this; 
     } 
    } 
} 

在这里,我们有相关的部分创建该表:

costTableModel = new CostTableModel(costCalc); 
    table = new JTable(costTableModel); 
    table.setPreferredScrollableViewportSize(table.getPreferredSize()); 
    table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); 
    table.setCellSelectionEnabled(true); 

    scrollPane = new JScrollPane(table); 

    RowNameTable nameTable = new RowNameTable(table); 
    scrollPane.setRowHeaderView(nameTable); 

和类costTableModel,只是为了完整性缘故

public class CostTableModel extends AbstractTableModel { 
    private CostCalculator costCalc; 

    public CostTableModel(CostCalculator costCalc) { 
     this.costCalc = costCalc; 
    } 

    @Override 
    public int getRowCount() { 
     return costCalc.getPersonsList().size(); 
    } 

    @Override 
    public int getColumnCount() { 
     return costCalc.getPersonsList().size(); 
    } 

    @Override 
    public String getColumnName(int col) { 
     return costCalc.getPersonsList().get(col).getName(); 
    } 

    @Override 
    public Object getValueAt(int rowIndex, int columnIndex) { 
     Person debtor = costCalc.getPersonsList().get(rowIndex); 
     Person debtee = costCalc.getPersonsList().get(columnIndex); 

     return costCalc.getAmountOwed(debtor, debtee); 
    } 

    @Override 
    public Class getColumnClass(int c) { 
     return getValueAt(0, c).getClass(); 

    } 
} 

感谢您提前给予您的帮助!

回答

4

我遇到的基本问题是表头和选择变化之间没有联系。事实上,标题真的很聪明,它的重新绘制...

我结束了提供我自己的标题,它附加了一个监听器到表的选择模型,并重新修改了选择标题改变。

import java.awt.BorderLayout; 
import java.awt.Color; 
import java.awt.Component; 
import java.awt.EventQueue; 
import java.util.List; 
import javax.swing.Icon; 
import javax.swing.JFrame; 
import javax.swing.JScrollPane; 
import javax.swing.JTable; 
import javax.swing.RowSorter; 
import javax.swing.RowSorter.SortKey; 
import static javax.swing.SortOrder.ASCENDING; 
import static javax.swing.SortOrder.DESCENDING; 
import javax.swing.UIManager; 
import javax.swing.UnsupportedLookAndFeelException; 
import javax.swing.event.ListSelectionEvent; 
import javax.swing.event.ListSelectionListener; 
import javax.swing.table.DefaultTableCellRenderer; 
import javax.swing.table.DefaultTableModel; 
import javax.swing.table.JTableHeader; 

public class TestColumnHighlight { 

    public static void main(String[] args) { 
     new TestColumnHighlight(); 
    } 

    public TestColumnHighlight() { 
     EventQueue.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       try { 
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 
       } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { 
       } 

       JTable table = new JTable(); 
       DefaultTableModel model = new DefaultTableModel(
           new Object[]{"abc", "def", "ghi", "jkl"}, 
           0); 

       model.addRow(new Object[]{0, 0, 0, 0}); 
       model.addRow(new Object[]{0, 0, 0, 0}); 
       model.addRow(new Object[]{0, 0, 0, 0}); 
       model.addRow(new Object[]{0, 0, 0, 0}); 
       model.addRow(new Object[]{0, 0, 0, 0}); 

       table.setModel(model); 
       table.setTableHeader(new CustomTableHeader(table)); 
       table.getTableHeader().setDefaultRenderer(new ColumnHeaderRenderer()); 

       JFrame frame = new JFrame("Testing"); 
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
       frame.setLayout(new BorderLayout()); 
       frame.add(new JScrollPane(table)); 
       frame.pack(); 
       frame.setLocationRelativeTo(null); 
       frame.setVisible(true); 
      } 
     }); 
    } 

    public class CustomTableHeader extends JTableHeader { 

     public CustomTableHeader(JTable table) { 
      super(); 
      setColumnModel(table.getColumnModel()); 
      table.getColumnModel().getSelectionModel().addListSelectionListener(new ListSelectionListener() { 
       @Override 
       public void valueChanged(ListSelectionEvent e) { 
        repaint(); 
       } 
      }); 
     } 

     @Override 
     public void columnSelectionChanged(ListSelectionEvent e) { 
      repaint(); 
     } 

    } 

    public class ColumnHeaderRenderer extends DefaultTableHeaderCellRenderer { 

     @Override 
     public Component getTableCellRendererComponent(JTable table, Object value, boolean selected, boolean focused, int row, int column) { 
      super.getTableCellRendererComponent(table, value, selected, focused, row, column); 

      int selectedColumn = table.getSelectedColumn(); 
      System.out.println("Selected " + selectedColumn + "-" + column); 
      if (selectedColumn == column) { 
       Color bg = table.getSelectionBackground(); 
       setBackground(bg); 
       setOpaque(true); 
      } else { 
       setOpaque(false); 
      } 

      return this; 
     } 

    } 

    public class DefaultTableHeaderCellRenderer extends DefaultTableCellRenderer { 

     public DefaultTableHeaderCellRenderer() { 
      setHorizontalAlignment(CENTER); 
      setHorizontalTextPosition(LEFT); 
      setVerticalAlignment(BOTTOM); 
      setOpaque(false); 
     } 

     @Override 
     public Component getTableCellRendererComponent(JTable table, Object value, 
         boolean isSelected, boolean hasFocus, int row, int column) { 
      super.getTableCellRendererComponent(table, value, 
          isSelected, hasFocus, row, column); 
      JTableHeader tableHeader = table.getTableHeader(); 
      if (tableHeader != null) { 
       setForeground(tableHeader.getForeground()); 
      } 
      setIcon(getIcon(table, column)); 
      setBorder(UIManager.getBorder("TableHeader.cellBorder")); 
      return this; 
     } 

     protected Icon getIcon(JTable table, int column) { 
      SortKey sortKey = getSortKey(table, column); 
      if (sortKey != null && table.convertColumnIndexToView(sortKey.getColumn()) == column) { 
       switch (sortKey.getSortOrder()) { 
        case ASCENDING: 
         return UIManager.getIcon("Table.ascendingSortIcon"); 
        case DESCENDING: 
         return UIManager.getIcon("Table.descendingSortIcon"); 
       } 
      } 
      return null; 
     } 

     protected SortKey getSortKey(JTable table, int column) { 
      RowSorter rowSorter = table.getRowSorter(); 
      if (rowSorter == null) { 
       return null; 
      } 

      List sortedColumns = rowSorter.getSortKeys(); 
      if (sortedColumns.size() > 0) { 
       return (SortKey) sortedColumns.get(0); 
      } 
      return null; 
     } 
    } 
} 
+0

首先,谢谢!这看起来非常像我需要的东西,我目前没有时间将其实现到我的代码中,但我今晚会做,并在此处报告。 – wlfbck 2013-03-19 11:06:24

+0

好吧,我现在建立它!它完美的工作,除了一个小东西(标记几个列标题),但我会尽力弄清楚我的自我,并学习一些关于JTables :) – wlfbck 2013-03-20 00:01:49

+0

嗯......不明白如何倾听_row_选择有助于重新绘制_column_选择更改。实际上,它不会:选择一个单元格,然后在同一行中移动选择内容,并且列的高亮区不会更新。 – kleopatra 2013-03-23 17:10:20

8

轻微的变体:如我读的问题,主要问题是不能更新关于选择变化的标题。有一个自定义标题听选择的变化对这种情况没有多大帮助。

事实上,一个JTableHeader已经正在监听ColumnModel并且模型的更改通知包含选择更改。只有columnSelectionChange方法故意实现什么都不做:

// --Redrawing the header is slow in cell selection mode. 
// --Since header selection is ugly and it is always clear from the 
// --view which columns are selected, don't redraw the header. 

自定义标题可以简单地实现重绘(这里偷懒我做它在表上的工厂方法只是接线饶了我的表,你可以很容易地让它成为一个独立的课程:-)。

final JTable table = new JTable(new AncientSwingTeam()) { 

    @Override 
    protected JTableHeader createDefaultTableHeader() { 
     // subclassing to take advantage of super's auto-wiring 
     // as ColumnModelListener 
     JTableHeader header = new JTableHeader(getColumnModel()) { 

      @Override 
      public void columnSelectionChanged(ListSelectionEvent e) { 
       repaint(); 
      } 

     }; 
     return header; 
    } 

}; 
table.setCellSelectionEnabled(true); 
table.getTableHeader().setDefaultRenderer(new ColumnHeaderRenderer()); 

还调整了疯狂的渲染了一下,使用表API:

/** 
* Slightly adjusted compared to @Mad 
* - use table's selectionBackground 
* - use table's isColumnSelected to decide on highlight 
*/ 
public static class ColumnHeaderRenderer extends DefaultTableCellHeaderRenderer { 

    @Override 
    public Component getTableCellRendererComponent(JTable table, Object value, boolean selected, 
     boolean focused, int row, int column) { 
     super.getTableCellRendererComponent(table, value, selected, focused, row, column); 
     if (table.isColumnSelected(column)) { 
      setBackground(table.getSelectionBackground()); 
     } 
     return this; 
    } 
} 

至于观察:

总是说isSelected是假的

的原因是BasicTableHeaderUI中的一个小问题:

ui.selected != columnModel.selected 

uiSelected是可供键绑定访问的列 - 如果laf支持它并且标头为focusOwner。对我来说没有任何意义,但完全定义了用户界面和columnModel选择的语义落入了对于新宝贝fx的兴奋之中,这被忘记了;-)

+0

很好,它的工作原理。然而,我不明白为什么DefaultTableCellHeaderRenderer只在导入sun.swing.table而不是javax.swing.table – Edoz 2014-07-20 01:41:57

+0

你是如何访问'DefaultTableCellHeaderRenderer'? – 2014-12-05 19:32:37