java - 在 JTable 中显示行选择器(光标/指针)

标签 java swing jtable cursor selector

我正在将 MS-Access 应用程序迁移到 Java。 我关心的是数据网格。我的第一个没问题(JScrollPane 中的 JTable),但缺少您可以在 MS-Access 网格或 OpenOffice Base 网格中看到的行选择器(光标)。 “行选择器”是指行左侧的黑色小箭头。 有没有一种标准的方法可以用 JTable 实现这种视觉效果。 (我还想知道这个缺失功能​​背后的基本原理:Sun 试图通过不实现它来避免什么问题(如果有的话)?)。

谢谢。

-- 编辑:Camickr,我已将您的代码段与您在编辑中显示的修改一起使用。效果很好!谢谢!!!

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

/*
 *    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 RowNumberTable extends JTable
    implements ChangeListener, PropertyChangeListener, TableModelListener
{
    private JTable main;

    public static void main(String[] args) {
        JTable mainTable = new JTable(new MyTableModel());
        mainTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        JScrollPane scrollPane = new JScrollPane(mainTable);
        RowNumberTable rowTable = new RowNumberTable(mainTable);
        rowTable.getSelectionModel()
            .addListSelectionListener(rowTable.new RowListener());
        scrollPane.setRowHeaderView(rowTable);
        scrollPane.setCorner(JScrollPane.UPPER_LEFT_CORNER, rowTable.getTableHeader());

        // Create a panel to hold all other components
        JPanel topPanel = new JPanel();
        topPanel.setLayout( new BorderLayout() );
        topPanel.add( scrollPane, BorderLayout.CENTER );

        // Set the frame characteristics
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setTitle( "Selector" );
        frame.setBackground( Color.gray );
        frame.getContentPane().add( topPanel );
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public RowNumberTable(JTable table)
    {
        main = table;
        main.addPropertyChangeListener( this );
        main.getModel().addTableModelListener( this );

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

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

        getColumnModel().getColumn(0).setPreferredWidth(22);
        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)
    {
        int rowHeight = main.getRowHeight(row);

        if (rowHeight != super.getRowHeight(row))
        {
            super.setRowHeight(row, rowHeight);
        }

        return rowHeight;
    }

    /*
     *  No model is being used for this table so just use the row number
     *  as the value of the cell.
     */
    @Override
    public Object getValueAt(int row, int column)
    {
        //return Integer.toString(row + 1);
        if (main.isRowSelected(row))
            return "\u25BA"; // Unicode Black Right-pointing Pointer
        else
            return " ";
    }

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

    /*
     *  Do nothing since the table ignores the model
     */
    @Override
    public void setValueAt(Object value, int row, int column) {}

    //
    //  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 ("rowHeight".equals(e.getPropertyName()))
        {
            repaint();
        }

        if ("model".equals(e.getPropertyName()))
        {
            main.getModel().addTableModelListener( this );
            revalidate();
        }
    }

    //
    //  Implement the TableModelListener
    //
    @Override
    public void tableChanged(TableModelEvent e)
    {
        revalidate();
    }

    /*
     *  Attempt to mimic the table header renderer
     */
    private static class RowNumberRenderer extends DefaultTableCellRenderer
    {
        public RowNumberRenderer()
        {
            setHorizontalAlignment(JLabel.CENTER);
        }

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

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

            return this;
        }
    }

    private class RowListener implements ListSelectionListener {
        public void valueChanged(ListSelectionEvent event) {
            if (event.getValueIsAdjusting()) {
                return;
            }
            int row =  main.getSelectedRow();
            System.out.println("selected row : "  +
                main.getSelectionModel().getLeadSelectionIndex() + " - " +
                main.getModel().getValueAt(row, 0) ); 
        }
    }
}

class MyTableModel extends AbstractTableModel {
    private String[] columnNames = {"First Name",
        "Last Name",
        "Sport",
        "# of Years",
        "Vegetarian"};
    private Object[][] data = {
        {"Kathy", "Smith",
            "Snowboarding", new Integer(5), new Boolean(false)},
        {"John", "Doe",
            "Rowing", new Integer(3), new Boolean(true)},
        {"Sue", "Black",
            "Knitting", new Integer(2), new Boolean(false)},
        {"Jane", "White",
            "Speed reading", new Integer(20), new Boolean(true)},
        {"Joe", "Brown",
            "Pool", new Integer(10), new Boolean(false)}
        };

    public int getColumnCount() {
        return columnNames.length;
    }

    public int getRowCount() {
        return data.length;
    }

    public String getColumnName(int col) {
        return columnNames[col];
    }

    public Object getValueAt(int row, int col) {
        return data[row][col];
    }

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

最佳答案

您需要向滚动 Pane 添加“行标题”。

查看 Row Number Table有关此方法的示例。默认实现显示行号,当前选择的行加粗。

如果需要,您可以自定义渲染器以显示“箭头图标”而不是粗体。

编辑:

您需要对原始代码进行的唯一更改如下:

@Override
public Object getValueAt(int row, int column)
{
    //return Integer.toString(row + 1);
    if (main.isRowSelected(row))
        return "\u25BA";
    else
        return " ";
}

不需要 ListSelectionListener。您可以在呈现行时查询行选择。

无需将 TableModel 传递给 RowTableModel 的构造函数。

关于java - 在 JTable 中显示行选择器(光标/指针),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28478119/

相关文章:

java - 如何在 Swing GUI 中启动 JTable?

java - 在 JFrame 中键入会出现错误

java - 如何以编程方式访问 Eclipse 帮助系统?

java - 如何在Android中使用java将JSONObject结果存储到BeanClass中?

java - 如何关闭 eclipse 中某些文件夹(如 node_modules)的 javascript 验证(包括 tern/lint/jshint)?

java - Swing JTextArea : Resize Dialog properly after automatic LineWrap

java - 如何计算a^(1/n)?

java - 如何在 JTable 上创建多颜色行

java - 单元格渲染器 Java Swing 的单元格的圆角边缘

java - 创建一个选定初始元素的表格