6

私は現在小さな JTable を構築しており、セルが選択されたときに列ヘッダー (および行ヘッダー - 行ヘッダー部分は実際に機能しています) を強調表示して、このセルに関連付けられた名前を見つけやすくしたいと考えています。ここに写真があります:

ここに画像の説明を入力

私はすでにこれでヘッダーのレンダラーを切り替えようとしました:

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

しかし、ヘッダーをクリックしたときにのみ呼び出され、常に isSelected が false であると表示されます。

これは、レンダラー内のハイライトを含む行名に使用するコードです。コードは私が作成したものではありません。少し変更しただけです。

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

2 に答える 2

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 を使用して、Mad のレンダラーを少し調整しました。

/**
 * 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 が false であると常に言う

その理由は、BasicTableHeaderUI のちょっとした癖です。

ui.selected != columnModel.selected

uiSelected はキーバインドにアクセスできる列です - laf がそれをサポートし、ヘッダーが focusOwner である場合。私にはあまり意味がありませんが、UI と columnModel の選択のセマンティクスを完全に定義することは、忘れられている新しいベイビー fx についての興奮に陥りました ;-)

于 2013-03-23T17:48:12.647 に答える
5

私が抱えていた基本的な問題は、テーブル ヘッダーと選択の変更の間に関連性がないことでした。実際、ヘッダーは再描画が非常に巧妙です...

テーブルの選択モデルにリスナーをアタッチし、変更された選択のヘッダーを再描画する独自のヘッダーを提供することになりました。

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;
        }
    }
}
于 2013-03-19T01:44:37.040 に答える