修改JTable的选择行为,仅选择一行或一列中的可变数量的单元格。

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

Alter selection behavior for a JTable to only select a variable number of cells in a row or column

问题

I have a JTable in which I alter between having row or column selection enabled. This feature works well but I want to be able to determine the number of cells which are highlighted adjacent to the currently selected cell. Currently, either the entire row or column is selected. I have tried to add a ListSelectionModel to implement this functionality but it only allows for either an entire row or column to be selected. Here are example images:

修改JTable的选择行为,仅选择一行或一列中的可变数量的单元格。

and

修改JTable的选择行为,仅选择一行或一列中的可变数量的单元格。

ADJACENTSELECTION is by default set to two so I'd like to highlight the 2 cells to the right and left of the selected cell when rowSelection is enabled or 2 cells above and below the selected cell when rowSelection is false. Any help would be greatly appreciated. Here is my code:

package selectionTest;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.KeyStroke;
import javax.swing.border.Border;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableModel;

public class App {

    private void display() {
        JFrame f = new JFrame("Demo");
        JPanel gui = new JPanel(new BorderLayout());
        GridTable gridTable = new GridTable(25, 25);
        gui.add(gridTable, BorderLayout.CENTER);
        f.add(gui);
        f.setBackground(Color.BLUE);
        gui.setBackground(Color.WHITE);
        f.setLocationByPlatform(true);
        f.pack();
        f.setSize(500, 600);
        f.setVisible(true);

    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                new App().display();
            }
        });
    }

}

class GridTable extends JTable {

    static int ADJACENTSELECTION = 2;
    boolean rowSelection = false;
    int rows, cols;

    public GridTable(int rows, int cols) {
        this.rows = rows;
        this.cols = cols;
        this.setModel(new DefaultTableModel(rows, cols));
        this.setShowGrid(true);
        Border blackline = BorderFactory.createLineBorder(Color.black);
        this.setBorder(blackline);
        this.setGridColor(Color.black);
        ActionMap map = this.getActionMap();
        Action action = switchOrientation();
        String keyStrokeAndKey = "control O";
        KeyStroke keyStroke = KeyStroke.getKeyStroke(keyStrokeAndKey);
        this.getInputMap().put(keyStroke, keyStrokeAndKey);
        this.getActionMap().put(keyStrokeAndKey, action);
        this.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
            public void valueChanged(ListSelectionEvent event) {
                int row = getSelectedRow();
                int column = getSelectedColumn();
                if (rowSelection) {
                    setRowSelectionInterval(Math.max(0, row - ADJACENTSELECTION), Math.min(row, row + ADJACENTSELECTION));
                } else {
                    setColumnSelectionInterval(Math.max(0, column - ADJACENTSELECTION), Math.min(column, column + ADJACENTSELECTION));
                }
            }
        });
    }

    private AbstractAction switchOrientation() {
        AbstractAction switchOrientation = new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                rowSelection = !rowSelection;
                setColumnSelectionAllowed(rowSelection);
                setRowSelectionAllowed(!rowSelection);
            }
        };
        return switchOrientation;
    }

}
英文:

I have a JTable in which I alter between having row or column selection enabled. This feature works well but I want to be able to determine the number of cells which are highlighted adjacent to the currently selected cell. Currently, either the entire row or column is selected. I have tried to add a ListSelectionModel to implement this functionality but it only allows for either an entire row or column to be selected. Here are example images:

修改JTable的选择行为,仅选择一行或一列中的可变数量的单元格。

and

修改JTable的选择行为,仅选择一行或一列中的可变数量的单元格。

ADJACENTSELECTION is by default set to two so I'd like to highlight the 2 cells to the right and left of the selected cell when rowSelection is enabled or 2 cells above and below the selected cell when rowSelection is false. Any help would be greatly appreciated. Here is my code:

package selectionTest;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.KeyStroke;
import javax.swing.border.Border;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableModel;

public class App {

    private void display() {
        JFrame f = new JFrame("Demo");
        JPanel gui = new JPanel(new BorderLayout());
        GridTable gridTable = new GridTable(25, 25);
        gui.add(gridTable, BorderLayout.CENTER);
        f.add(gui);
        f.setBackground(Color.BLUE);
        gui.setBackground(Color.WHITE);
        f.setLocationByPlatform(true);
        f.pack();
        f.setSize(500, 600);
        f.setVisible(true);

    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                new App().display();
            }
        });
    }

}

class GridTable extends JTable {

    static int ADJACENTSELECTION = 2;
    boolean rowSelection = false;
    int rows, cols;

    public GridTable(int rows, int cols) {
        this.rows = rows;
        this.cols = cols;
        this.setModel(new DefaultTableModel(rows, cols));
        this.setShowGrid(true);
        Border blackline = BorderFactory.createLineBorder(Color.black);
        this.setBorder(blackline);
        this.setGridColor(Color.black);
        ActionMap map = this.getActionMap();
        Action action = switchOrientation();
        String keyStrokeAndKey = "control O";
        KeyStroke keyStroke = KeyStroke.getKeyStroke(keyStrokeAndKey);
        this.getInputMap().put(keyStroke, keyStrokeAndKey);
        this.getActionMap().put(keyStrokeAndKey, action);
        this.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
            public void valueChanged(ListSelectionEvent event) {
                int row = getSelectedRow();
                int column = getSelectedColumn();
                if (rowSelection) {
                    setRowSelectionInterval(Math.max(0, row - ADJACENTSELECTION), Math.min(row, row + ADJACENTSELECTION));
                } else {
                    setColumnSelectionInterval(Math.max(0, column - ADJACENTSELECTION), Math.min(column, column + ADJACENTSELECTION));
                }
            }
        });
    }

    private AbstractAction switchOrientation() {
        AbstractAction switchOrientation = new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                rowSelection = !rowSelection;
                setColumnSelectionAllowed(rowSelection);
                setRowSelectionAllowed(!rowSelection);
            }
        };
        return switchOrientation;
    }

}

答案1

得分: 2

以下是翻译好的部分:

  1. 在你的 GridTable 方法中,通过添加 this.setCellSelectionEnabled(true); 来允许选择特定单元格:
public GridTable(int rows, int cols) {
    this.setCellSelectionEnabled(true);
    //...
  1. 确保 SelectionInterval 的范围和值是正确的:

如果是行选择:

if (rowSelection == true){
    //使用 `getRowCount()` 来正确设置选择范围
    setRowSelectionInterval(Math.max(0, row - ADJACENTSELECTION), Math.min(getRowCount()-1, row + ADJACENTSELECTION));
}

如果是列选择:

else{
    //使用 `getColumnCount()` 来正确设置选择范围
    setColumnSelectionInterval(Math.max(0, column - ADJACENTSELECTION), Math.min(getColumnCount()-1, column + ADJACENTSELECTION));
}
  1. 当你更新选择时,确保不会再次触发选择事件。你可以通过使用布尔值来跟踪选择事件来实现这一点:
this.getSelectionModel().addListSelectionListener(new ListSelectionListener(){
    //使用这个来跟踪更改
    boolean initial = true;
    //...

    public void valueChanged(ListSelectionEvent e){
        if (initial){
            int column = getSelectedColumn();
            int row = getSelectedRow();
            //...
  1. 最后,将所有内容整合在一起,这是完整的选择监听器(不要忘记将 this.setCellSelectionEnabled(true); 添加到 GridTable 中):
this.getSelectionModel().addListSelectionListener(new ListSelectionListener(){
    //使用这个来跟踪更改
    boolean initial = true;

    public void valueChanged(ListSelectionEvent e){
        //只有在第一次选择时更改值(这可以防止下面的代码再次触发自身)
        if (initial){
            int column = getSelectedColumn();
            int row = getSelectedRow();
            initial = false;
            if (rowSelection == true){
                setRowSelectionInterval(Math.max(0, row - ADJACENTSELECTION), Math.min(getRowCount()-1, row + ADJACENTSELECTION));
            }
            else{
                setColumnSelectionInterval(Math.max(0, column - ADJACENTSELECTION), Math.min(getColumnCount()-1, column + ADJACENTSELECTION));
            }
        }
        //在选择完成后将值设置回来
        else{
            initial = true;
        }
    }
});

这将突出显示所选单元格以及选择范围两侧的两个单元格。

英文:

You are almost there, just a couple of extra steps and you can update the selection listener to only highlight specific cells:

  1. Allow for selection of specific cells by adding this.setCellSelectionEnabled(true); to your GridTable method:

    public GridTable(int rows, int cols) {
        this.setCellSelectionEnabled(true);
        //...
    
  2. make sure that the SelectionInterval ranges/values are correct:

    if (rowSelection == true){
        //Correct using `getRowCount()` for selection range
        setRowSelectionInterval(Math.max(0, row - ADJACENTSELECTION), Math.min(getRowCount()-1, row + ADJACENTSELECTION));
    }
    else{
        //Correct using `getColumnCount()` for selection range
        setColumnSelectionInterval(Math.max(0, column - ADJACENTSELECTION), Math.min(getColumnCount()-1, column + ADJACENTSELECTION));
    }
    
  3. Make sure that when you update the selection that it does not trigger the selection event to happen again. You can do this by using a boolean to track the selection event:

    this.getSelectionModel().addListSelectionListener(new ListSelectionListener(){
        //Use this to track changes
        boolean initial = true;
        //...
        public void valueChanged(ListSelectionEvent e){
            if (initial){
                int column = getSelectedColumn();
                int row = getSelectedRow();
                //...
    
  4. Finally, putting it all together, this is the full selection listener (And don't forget to add this.setCellSelectionEnabled(true); to GridTable):

    this.getSelectionModel().addListSelectionListener(new ListSelectionListener(){
        //Use this to track changes
        boolean initial = true;
    
        public void valueChanged(ListSelectionEvent e){
            //Only change value on first select (This prevents the below from triggering itself)
            if (initial){
                int column = getSelectedColumn();
                int row = getSelectedRow();
                initial = false;
                if (rowSelection == true){
     	           setRowSelectionInterval(Math.max(0, row - ADJACENTSELECTION), Math.min(getRowCount()-1, row + ADJACENTSELECTION));
                }
                else{
     	           setColumnSelectionInterval(Math.max(0, column - ADJACENTSELECTION), Math.min(getColumnCount()-1, column + ADJACENTSELECTION));
                }
            }
            //Set the value back once a selection is complete
            else{
                initial = true;
            }
        }
    });
    

This will highlight the selected cell, and two cells either side of the selection

huangapple
  • 本文由 发表于 2020年8月11日 09:26:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/63350209.html
匿名

发表评论

匿名网友

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

确定