英文:
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:
and
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:
and
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
以下是翻译好的部分:
- 在你的
GridTable
方法中,通过添加this.setCellSelectionEnabled(true);
来允许选择特定单元格:
public GridTable(int rows, int cols) {
this.setCellSelectionEnabled(true);
//...
- 确保
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));
}
- 当你更新选择时,确保不会再次触发选择事件。你可以通过使用布尔值来跟踪选择事件来实现这一点:
this.getSelectionModel().addListSelectionListener(new ListSelectionListener(){
//使用这个来跟踪更改
boolean initial = true;
//...
public void valueChanged(ListSelectionEvent e){
if (initial){
int column = getSelectedColumn();
int row = getSelectedRow();
//...
- 最后,将所有内容整合在一起,这是完整的选择监听器(不要忘记将
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:
-
Allow for selection of specific cells by adding
this.setCellSelectionEnabled(true);
to yourGridTable
method:public GridTable(int rows, int cols) { this.setCellSelectionEnabled(true); //...
-
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)); }
-
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(); //...
-
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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论