2013-03-19 65 views
6

Tôi hiện đang xây dựng một JTable nhỏ và muốn đánh dấu tiêu đề cột (và tiêu đề hàng - phần tiêu đề hàng thực sự hoạt động) khi một ô được chọn để giúp dễ dàng hơn tìm tên được liên kết với ô này. Dưới đây là một hình ảnh:Làm nổi bật tiêu đề cột của JTable

enter image description here

Tôi đã cố gắng chuyển đổi ra các renderer cho tiêu đề với điều này:

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

Nhưng nó chỉ được gọi khi tôi nhấp vào tiêu đề và luôn nói isSelected là sai .

Đây là mã tôi sử dụng cho hàng-tên, bao gồm các điểm nhấn bên trong renderer - Mã không phải là của tôi, tôi chỉ cần sửa đổi nó một chút:

/* 
* 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; 
     } 
    } 
} 

Và ở đây chúng tôi có một phần liên quan để tạo ra bảng:

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

Và costTableModel lớp, chỉ cho đầy đủ vì:

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

    } 
} 

Cảm ơn sự giúp đỡ của bạn trước!

Trả lời

4

Vấn đề cơ bản mà tôi gặp phải là không có kết nối giữa tiêu đề bảng và thay đổi lựa chọn. Trong thực tế, tiêu đề thực sự thông minh với hình ảnh của nó ...

Tôi đã kết thúc việc cung cấp tiêu đề của riêng mình, đính kèm một người nghe vào mô hình lựa chọn của bảng và sơn lại tiêu đề trên lựa chọn đã thay đổi.

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

Trước hết, cảm ơn! Điều đó trông khá giống với những gì tôi cần, tôi hiện không có thời gian để thực hiện nó vào mã của tôi, nhưng tôi sẽ làm điều đó tối nay và báo cáo lại ở đây. – wlfbck

+0

Được rồi, tôi đã tạo nó ngay bây giờ! Nó hoạt động hoàn hảo, ngoại trừ một điều nhỏ (đánh dấu một số tiêu đề cột), nhưng tôi sẽ cố gắng tìm ra điều đó và tự tìm hiểu thêm về JTables :) – wlfbck

+0

hmm ... không hiểu cách nghe lựa chọn _row_ giúp vẽ lại các thay đổi lựa chọn _column_. Trên thực tế, nó không: chọn một ô, sau đó di chuyển vùng chọn trong cùng hàng và điểm nổi bật của cột không được cập nhật. – kleopatra

8

Một biến thể nhẹ: như tôi đọc câu hỏi, vấn đề chính là tiêu đề không cập nhật trên cột thay đổi lựa chọn. Có tiêu đề tùy chỉnh nghe theo số hàng thay đổi lựa chọn không giúp gì nhiều cho trường hợp đó.

Thực tế, một JTableHeader đã là nghe ColumnModel và thông báo thay đổi của mô hình bao gồm các thay đổi lựa chọn. Chỉ có phương pháp columnSelectionChange là cố ý thực hiện để làm gì:

// --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. 

Một tiêu đề tùy chỉnh đơn giản có thể thực hiện để sơn lại (ở đây lười biếng tôi làm nó trong phương thức nhà máy của bảng chỉ để tha cho tôi hệ thống dây điện để bàn, bạn có thể dễ dàng làm cho nó trở thành một lớp độc lập :-).

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

Cũng chỉnh Mad renderer một chút, sử dụng bảng 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; 
    } 
} 

Như để quan sát:

luôn nói isSelected là sai

Lý do là một dấu nháy nhẹ trong BasicTableHeaderUI:

ui.selected != columnModel.selected 

uiSelected là cột có thể truy cập vào keybindings - nếu laf hỗ trợ nó và tiêu đề là focusOwner. Không thực sự có ý nghĩa với tôi, nhưng hoàn toàn xác định ngữ nghĩa của lựa chọn ui và columnModel rơi vào sự phấn khích về fx babe mới, điều đó đã bị lãng quên ;-)

+0

đẹp, nó hoạt động. Tuy nhiên tôi không hiểu tại sao DefaultTableCellHeaderRenderer chỉ nhập vào sun.swing.table và không phải javax.swing.table – Edoz

+0

Làm cách nào bạn truy cập 'DefaultTableCellHeaderRenderer'? –

Các vấn đề liên quan