我有一个带复选框的JTable作为列之一.我还在标题中有一个复选框来检查/取消选中所有.
AFAIK JTable的默认行为是,如果选择新行,它将取消选择之前选择的所有行.但是我们可以通过复选框实现CTRL点击行为.保留以前选定的行.
我面临的主要问题是使用复选框启用多个JTable行选择.
预期产出
检查第一行然后选择第一行,如果选中第三行,则选择第三行以及第一行(已经选中并选中)
实际输出
检查并选择第一行时,如果选择第三行,则取消选择先前选择的所有行,仅选择第三行.
我有一个示例代码,它模拟我想要实现的场景,与Add Another One按钮相同,但有复选框选择.
import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.table.AbstractTableModel;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.TableColumn;
import javax.swing.event.CellEditorListener;
public class JTableRowSelectProgramatically extends JPanel {
final JTable table = new JTable(new MyTableModel());
public JTableRowSelectProgramatically() {
initializePanel();
}
private void initializePanel() {
setLayout(new BorderLayout());
setPreferredSize(new Dimension(475,150));
table.setFillsViewportHeight(true);
JScrollPane pane = new JScrollPane(table);
JLabel label2 = new JLabel("Row: ");
final JTextField field2 = new JTextField(3);
JButton add = new JButton("Select");
table.setRowSelectionAllowed(true);
table.setColumnSelectionAllowed(false);
table.getSelectionModel().addListSelectionListener(new ListSelectionListenerImpl());
TableColumn tc = table.getColumnModel().getColumn(3);
tc.setCellEditor(table.getDefaultEditor(Boolean.class));
tc.setCellRenderer(table.getDefaultRenderer(Boolean.class));
((JComponent) table.getDefaultRenderer(Boolean.class)).setOpaque(true);
tc.getCellEditor().addCellEditorListener(new CellEditorListenerImpl());
add.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
int index2 = 0;
try {
index2 = Integer.valueOf(field2.getText());
} catch (NumberFormatException e) {
e.printStackTrace();
}
table.addRowSelectionInterval(index2,index2);
field2.setText(String.valueOf(index2));
}
});
JPanel command = new JPanel(new FlowLayout());
command.add(label2);
command.add(field2);
command.add(add);
add(pane,BorderLayout.CENTER);
add(command,BorderLayout.SOUTH);
}
public static void showFrame() {
JPanel panel = new JTableRowSelectProgramatically();
panel.setOpaque(true);
JFrame frame = new JFrame("JTable Row Selection");
frame.setDefaultCloSEOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(panel);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JTableRowSelectProgramatically.showFrame();
}
});
}
public class MyTableModel extends AbstractTableModel {
private String[] columns = {"ID","NAME","AGE","A STUDENT?"};
private Object[][] data = {
{1,"Alice",20,new Boolean(false)},{2,"Bob",10,{3,"Carol",15,{4,"Mallory",25,new Boolean(false)}
};
public int getRowCount() {
return data.length;
}
public int getColumnCount() {
return columns.length;
}
public Object getValueAt(int rowIndex,int columnIndex) {
return data[rowIndex][columnIndex];
}
@Override
public String getColumnName(int column) {
return columns[column];
}
@Override
public boolean isCellEditable(int rowIndex,int columnIndex) {
return columnIndex == 3;
}
//
// This method is used by the JTable to define the default
// renderer or editor for each cell. For example if you have
// a boolean data it will be rendered as a check Box. A
// number value is right aligned.
//
@Override
public Class> getColumnClass(int columnIndex) {
return data[0][columnIndex].getClass();
}
@Override
public void setValueAt(Object aValue,int rowIndex,int columnIndex) {
if (columnIndex == 3) {
data[rowIndex][columnIndex] = aValue;
fireTableCellUpdated(rowIndex,columnIndex);
}
}
}
class ListSelectionListenerImpl implements ListSelectionListener {
public void valueChanged(ListSelectionEvent lse) {
ListSelectionModel lsm = (ListSelectionModel) lse.getSource();
int row = table.getRowCount();
if (lsm.isSelectionEmpty()) {
} else {
// If any column is clicked other than checkBox then do normal selection
// i.e select the click row and deselects the prevIoUs selection
if (table.getSelectedColumn() != 3) {
for (int i = 0; i < row; i++) {
if (lsm.isSelectedIndex(i)) {
table.setValueAt(true,i,3);
} else {
table.setValueAt(false,3);
}
}
}
}
}
}
public class CellEditorListenerImpl implements CellEditorListener{
public void editingStopped(ChangeEvent e) {
for(int i=0; i
最佳答案
实现这些TableModel方法后,可以在按钮侦听器中使用setValueAt()来根据需要调整模型,以使复选框状态和选择模型保持同步.有一个相关的例子here.
@Override
public boolean isCellEditable(int rowIndex,int columnIndex) {
return columnIndex == 3;
}
@Override
public void setValueAt(Object aValue,int columnIndex) {
if (columnIndex == 3) {
data[rowIndex][columnIndex] = aValue;
fireTableCellUpdated(rowIndex,columnIndex);
}
}
附录:作为一个具体示例,您的清除侦听器可能会调用TableModel中的方法,例如clearChecks():
MyTableModel model = (MyTableModel) table.getModel();
model.clearChecks();
...
private void clearChecks() {
for (int i = 0; i < data.length; i++) {
data[i][3] = false;
}
fireTableRowsUpdated(0,data.length);
}