在Java Swing中同时实现行选择和单元格选择是可能的吗?

huangapple go评论73阅读模式
英文:

Can you have row selection and cell selection at the same time in Java Swing?

问题

我有一个 JTable,并且只想在点击表格中第一列的单元格时选择该单元格。当我点击其他任何列中的单元格时,我希望选择整行。我该如何实现这个?

英文:

I have a JTable and want to select the cell only when a cell in the first column of the table is clicked. When I click on a cell in any other column I want the entire row to be selected. How can I achieve this?

答案1

得分: 1

你需要实现接口 TableColumnModelListener 并将其添加到你的 JTableTableColumnModel 中。

以下是一个示例代码。

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.time.LocalDate;
import java.time.Month;

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.WindowConstants;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.TableColumnModelEvent;
import javax.swing.event.TableColumnModelListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableColumnModel;
import javax.swing.table.TableModel;

public class TableSel implements Runnable, TableColumnModelListener {
    // ...(略去了其余部分)

    @Override
    public void columnSelectionChanged(ListSelectionEvent event) {
        if (!event.getValueIsAdjusting()) {
            int selectedColumn = table.getSelectedColumn();
            if (selectedColumn == 0) {
                table.setColumnSelectionAllowed(true);
            }
            else {
                table.setColumnSelectionAllowed(false);
            }
        }
    }

    // ...(略去了其余部分)
}

在这个代码片段中,我使用了一个自定义的 TableModel,但这并不是实现所需行为的必要条件。

你问题的答案在上述代码的以下部分。

  1. 实现 TableColumnModelListener 接口
public class TableSel implements Runnable, TableColumnModelListener {
  1. 在接口实现中,只需实现 columnSelectionChanged(ListSelectionEvent) 方法。其他方法可以为空。
  2. 将你的实现添加到 JTable
table = new JTable(model);
TableColumnModel tcm = table.getColumnModel();
tcm.addColumnModelListener(this);

需要注意的是,我还将选择模式设置为单选。

table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);

JTable 有行选择和列选择两种模式。默认情况下启用行选择而不启用列选择。可以查看 setColumnSelectionAllowed()setRowSelectionAllowed() 方法。当两者都设置为 true 时,选择单个单元格。仅启用行选择时,选择一个单元格将选择包含该单元格的整行。同样,当仅允许列选择时,选择一个单元格将选择整个列。

因此,基本上你想要切换列选择的开关。如果所选列是第一列,那么需要启用列选择,而对于其他任何列,需要禁用列选择。

英文:

You need to implement the interface TableColumnModelListener and add it to the TableColumnModel of your JTable.

Here is an example.

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.time.LocalDate;
import java.time.Month;

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.WindowConstants;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.TableColumnModelEvent;
import javax.swing.event.TableColumnModelListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableColumnModel;
import javax.swing.table.TableModel;

public class TableSel implements Runnable, TableColumnModelListener {
    private JFrame  frame;
    private JTable  table;

    @Override // java.lang.Runnable
    public void run() {
        showGui();
    }

    @Override // javax.swing.event.TableColumnModelListener
    public void columnAdded(TableColumnModelEvent event) {
        // Do nothing.
    }

    @Override // javax.swing.event.TableColumnModelListener
    public void columnRemoved(TableColumnModelEvent event) {
        // Do nothing.
    }

    @Override // javax.swing.event.TableColumnModelListener
    public void columnMoved(TableColumnModelEvent event) {
        // Do nothing.
    }

    @Override // javax.swing.event.TableColumnModelListener
    public void columnMarginChanged(ChangeEvent event) {
        // Do nothing.
    }

    @Override // javax.swing.event.TableColumnModelListener
    public void columnSelectionChanged(ListSelectionEvent event) {
        if (!event.getValueIsAdjusting()) {
            int selectedColumn = table.getSelectedColumn();
            if (selectedColumn == 0) {
                table.setColumnSelectionAllowed(true);
            }
            else {
                table.setColumnSelectionAllowed(false);
            }
        }
    }

    private JScrollPane createTable() {
        TableModel model = new CustoMod();
        table = new JTable(model);
        table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
        table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        TableColumnModel tcm = table.getColumnModel();
        tcm.addColumnModelListener(this);
        JScrollPane scrollPane = new JScrollPane(table);
        return scrollPane;
    }

    private void showGui() {
        frame = new JFrame("Table");
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.add(createTable(), BorderLayout.CENTER);
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new TableSel());
    }
}

class CustoMod extends AbstractTableModel {
    private static final String[]  COLUMNS;
    private static final Object[][]  DATA;

    static {
        COLUMNS = new String[]{"Surname", "Name", "Games", "Goals", "Born"};
        DATA = new Object[][] {
            {"Rumney","Harold", 171, 28, LocalDate.of(1907, Month.MAY, 16)},
            {"Regan","Jack", 196, 3, LocalDate.of(1912, Month.SEPTEMBER, 12)},
            {"Coventry","Syd", 227, 62, LocalDate.of(1899, Month.JUNE, 13)},
            {"Picken","Billy", 212, 46, LocalDate.of(1956, Month.JUNE, 7)},
            {"Collier","Albert", 205, 54, LocalDate.of(1909, Month.JULY, 9)},
            {"Buckley","Nathan", 260, 263, LocalDate.of(1972, Month.JULY, 26)},
            {"Merrett","Thorold", 180, 148, LocalDate.of(1933, Month.SEPTEMBER, 30)},
            {"Rose","Bob", 152, 214, LocalDate.of(1928, Month.AUGUST, 07)},
            {"Millane","Darren", 147, 78, LocalDate.of(1965, Month.AUGUST, 9)},
            {"Fothergill","Des", 111, 337, LocalDate.of(1920, Month.JULY, 15)},
            {"Weideman","Murray", 180, 262, LocalDate.of(1936, Month.FEBRUARY, 16)},
            {"Lee","Dick", 230, 707, LocalDate.of(1899, Month.MARCH, 19)},
            {"Kyne","Phonse", 245, 237, LocalDate.of(1915, Month.OCTOBER, 29)},
            {"Coventry","Gordon", 306, 1299, LocalDate.of(1901, Month.SEPTEMBER, 25)},
            {"Daicos","Peter", 250, 549, LocalDate.of(1961, Month.SEPTEMBER, 20)},
            {"Thompson","Len", 268, 217, LocalDate.of(1947, Month.AUGUST, 27)},
            {"Tuddenham","Des", 182, 251, LocalDate.of(1943, Month.JANUARY, 29)},
            {"Collier","Harry", 253, 299, LocalDate.of(1907, Month.OCTOBER, 01)},
            {"Shaw","Tony", 313, 157, LocalDate.of(1960, Month.JULY, 23)},
            {"Richardson","Wayne", 277, 323, LocalDate.of(1946, Month.DECEMBER, 8)},
            {"Whelan","Marcus", 173, 31, LocalDate.of(1914, Month.JUNE, 27)},
            {"Brown","Gavin", 254, 195, LocalDate.of(1967, Month.SEPTEMBER, 25)},
        };
    }

    @Override
    public int getRowCount() {
        return DATA.length;
    }

    @Override
    public Class<?> getColumnClass(int columnIndex) {
        Class<?> theClass;
        switch (columnIndex) {
            case 0:
            case 1:
                theClass = String.class;
                break;
            case 2:
            case 3:
                theClass = Integer.class;
                break;
            case 4:
                theClass = LocalDate.class;
            default:
                theClass = Object.class;
        }
        return theClass;
    }

    @Override
    public int getColumnCount() {
        return COLUMNS.length;
    }

    @Override
    public String getColumnName(int column) {
        return COLUMNS[column];
    }

    @Override
    public Object getValueAt(int rowIndex, int columnIndex) {
        return DATA[rowIndex][columnIndex];
    }
}

I use a custom TableModel but it is not required in order to implement the behavior you desire.

The answer to your question is in the following parts of the above code.

  1. Implement interface TableColumnModelListener
public class TableSel implements Runnable, TableColumnModelListener {
  1. In the implementation of the interface, you only need to implement method columnSelectionChanged(ListSelectionEvent). The other methods can be empty.
  2. Add your implementation to the JTable
table = new JTable(model);
TableColumnModel tcm = table.getColumnModel();
tcm.addColumnModelListener(this);

Note that I also set the selection mode to single selection.

table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);

A JTable has row selection and column selection. By default row selection is enabled and column selection is not. See methods setColumnSelectionAllowed() and setRowSelectionAllowed(). When both are set to true a single cell is selected. When only row selection is enabled, then selecting a cell selects the whole row containing that cell. Likewise when only column selection is allowed.

So basically you want to turn column selection on and off. If the selected column is the first column, then column selection needs to be enabled and for any other column it needs to be disabled.

huangapple
  • 本文由 发表于 2020年10月2日 12:49:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/64166299.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定