At the beginning selecting a row using mouse click or keyboard arrows is possible with the selected row being colored with the normal row selection color.
User can select single row.
User can lock the selected row using code invoked by lock button. Locking itself is made possible by imitating a selected row (which I'm not sure if it is the proper way of doing so) and is done by two things:
DefaultTableCellRenderer
JTable
row selection setRowSelectionAllowed(false)
User can unlock/restore normal selection using code invoked by unlock button. Unlocking is simply to undo the steps of locking:
DefaultTableCellRenderer
JTable
row selection setRowSelectionAllowed(true)
<-- (does not work)How to restore normal JTable
row selection?
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.DefaultListSelectionModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
public class TableRowSelectionControl {
private JButton btnJTableSelectionLocked;
private JButton btnJTableSelectionUnlock;
private JPanel panelControl;
private JScrollPane scrollableTable;
private Integer selectedId;
private boolean lockedSelection;
private Color rowSelectionColor;
private Integer modelRow;
private JTable table;
private Object[][] data;
private JPanel createPanel() {
rowSelectionColor = new Color(184, 207, 229);
btnJTableSelectionLocked = new JButton("Lock selected row");
btnJTableSelectionLocked.setEnabled(false);
btnJTableSelectionLocked.addActionListener(new BtnAction());
btnJTableSelectionUnlock = new JButton("Unlock selection");
btnJTableSelectionUnlock.setEnabled(false);
btnJTableSelectionUnlock.addActionListener(new BtnAction());
panelControl = new JPanel();
panelControl.add(btnJTableSelectionLocked);
panelControl.add(btnJTableSelectionUnlock);
DefaultTableModel model = new DefaultTableModel(new String[]{"Id", "Name", "State"}, 0) {
// Disable cell editing
@Override
public boolean isCellEditable(int row, int column) {
// Disable cells editing.
return false;
}
};
data = new Object[][]{
{1, "Alpha", true},
{5, "Beta", false},
{3, "Gama", true},
{4, "Giga", true},
{7, "Coca", true},};
table = new JTable(model);
table.getSelectionModel().setSelectionMode(DefaultListSelectionModel.SINGLE_SELECTION);
table.getSelectionModel().addListSelectionListener(new RowSelectionListener());
for (Object[] d : data) {
model.addRow(d);
}
JPanel containerPanel = new JPanel(new BorderLayout());
containerPanel.setPreferredSize(new Dimension(350, 200));
scrollableTable = new JScrollPane(table);
containerPanel.add(panelControl, BorderLayout.PAGE_START);
containerPanel.add(scrollableTable, BorderLayout.CENTER);
return containerPanel;
}
private class RowSelectionListener implements ListSelectionListener {
@Override
public void valueChanged(ListSelectionEvent event) {
// Ensure single event invoked
if (!event.getValueIsAdjusting() && !lockedSelection) {
DefaultListSelectionModel selectionModel = (DefaultListSelectionModel) event.getSource();
if (selectionModel.isSelectionEmpty()) {
// Empty selection: table row deselection occurred
btnJTableSelectionLocked.setEnabled(false);
} else {
btnJTableSelectionLocked.setEnabled(true);
int viewRow = table.getSelectedRow();
if (viewRow > -1) {
int idsColumn = 0;
modelRow = table.convertRowIndexToModel(viewRow);
Object selectedIdObject = table.getModel().getValueAt(modelRow, idsColumn);
selectedId = Integer.parseInt(selectedIdObject.toString());
}
}
}
}
}
private DefaultTableCellRenderer getRowsColorRenderer(Integer selectedId) {
DefaultTableCellRenderer renderer;
renderer = new DefaultTableCellRenderer() {
@Override
public Component getTableCellRendererComponent(
JTable table,
Object value,
boolean isSelected,
boolean hasFocus,
int row,
int column) {
Component tableCellRendererComponent
= super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
Integer id = (Integer) table.getModel().getValueAt(row, 0);
if (selectedId != null && id.equals(selectedId)) {
setBackground(rowSelectionColor);
setForeground(table.getForeground());
} else {
setBackground(table.getBackground());
setForeground(table.getForeground());
}
return tableCellRendererComponent;
}
};
return renderer;
}
private class BtnAction implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
Object btnClicked = e.getSource();
int columnsSize = 3;
if (btnClicked == btnJTableSelectionLocked) {
lockedSelection = true;
btnJTableSelectionLocked.setEnabled(false);
btnJTableSelectionUnlock.setEnabled(true);
table.setRowSelectionAllowed(false); // <-- Works fine.
for (int i = 0; i < columnsSize; i++) {
table.getColumnModel().getColumn(i).setCellRenderer(getRowsColorRenderer(selectedId));
}
} else if (btnClicked == btnJTableSelectionUnlock) {
lockedSelection = false;
btnJTableSelectionLocked.setEnabled(true);
btnJTableSelectionUnlock.setEnabled(false);
table.setRowSelectionAllowed(true); // <-- This line does not restore normal selection
for (int i = 0; i < columnsSize; i++) {
table.getColumnModel().getColumn(i).setCellRenderer(getRowsColorRenderer(null));
}
if (modelRow != null) {
// Enforce the same row to be selected on unloking;
// afterwords user can select any row.
table.setRowSelectionInterval(0, modelRow);
}
}
table.repaint();
}
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(() -> {
TableRowSelectionControl tableRowColorControl = new TableRowSelectionControl();
JFrame frame = new JFrame("TableRowSelectionControl");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(tableRowColorControl.createPanel());
frame.pack();
frame.setVisible(true);
});
}
}
Your problem is with you TableCellRenderer
The following...
Component tableCellRendererComponent
= super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
//...
if (selectedId != null && id.equals(selectedId)) {
setBackground(rowSelectionColor);
setForeground(table.getForeground());
} else {
setBackground(table.getBackground());
setForeground(table.getForeground());
}
is overwriting the selection color made by the super
call.
Instead, change it to...
DefaultTableCellRenderer renderer;
renderer = new DefaultTableCellRenderer() {
@Override
public Component getTableCellRendererComponent(
JTable table,
Object value,
boolean isSelected,
boolean hasFocus,
int row,
int column) {
Component tableCellRendererComponent
= super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
Integer id = (Integer) table.getModel().getValueAt(row, 0);
System.out.println("id = " + id + "; selectedId = " + selectedId + "; isSelected = " + isSelected);
if (selectedId != null && id.equals(selectedId)) {
setBackground(rowSelectionColor);
setForeground(table.getForeground());
} else if (!isSelected) {
setBackground(table.getBackground());
setForeground(table.getForeground());
}
return tableCellRendererComponent;
}
};
One thing I might suggest is, instead of switching the cell renderer (which doesn't seem to be working), apply the cell renderer to the table and make use of the put/getClientProperty
support of the JTable
private class BtnAction implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
Object btnClicked = e.getSource();
int columnsSize = 3;
if (btnClicked == btnJTableSelectionLocked) {
System.out.println("Lock");
lockedSelection = true;
btnJTableSelectionLocked.setEnabled(false);
btnJTableSelectionUnlock.setEnabled(true);
table.setRowSelectionAllowed(false); // <-- Works fine.
table.putClientProperty("selectedRowId", selectedId);
} else if (btnClicked == btnJTableSelectionUnlock) {
System.out.println("Unlock");
lockedSelection = false;
btnJTableSelectionLocked.setEnabled(true);
btnJTableSelectionUnlock.setEnabled(false);
table.setRowSelectionAllowed(true); // <-- This line does not restore normal selection
table.putClientProperty("selectedRowId", null);
}
}
}
and...
public class LockableTableCellRenderer extends DefaultTableCellRenderer {
@Override
public Component getTableCellRendererComponent(
JTable table,
Object value,
boolean isSelected,
boolean hasFocus,
int row,
int column) {
Component tableCellRendererComponent = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
Integer id = (Integer) table.getModel().getValueAt(row, 0);
Integer selectedId = (Integer) table.getClientProperty("selectedRowId");
if (selectedId != null && id.equals(selectedId)) {
setBackground(rowSelectionColor);
setForeground(table.getForeground());
} else if (!isSelected) {
setBackground(table.getBackground());
setForeground(table.getForeground());
setBorder(noFocusBorder);
}
return tableCellRendererComponent;
}
}
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.DefaultListSelectionModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumnModel;
public class Test {
private JButton btnJTableSelectionLocked;
private JButton btnJTableSelectionUnlock;
private JPanel panelControl;
private JScrollPane scrollableTable;
private Integer selectedId;
private boolean lockedSelection;
private Color rowSelectionColor;
private Integer modelRow;
private JTable table;
private Object[][] data;
private JPanel createPanel() {
rowSelectionColor = new Color(184, 207, 229);
btnJTableSelectionLocked = new JButton("Lock selected row");
btnJTableSelectionLocked.setEnabled(false);
btnJTableSelectionLocked.addActionListener(new BtnAction());
btnJTableSelectionUnlock = new JButton("Unlock selection");
btnJTableSelectionUnlock.setEnabled(false);
btnJTableSelectionUnlock.addActionListener(new BtnAction());
panelControl = new JPanel();
panelControl.add(btnJTableSelectionLocked);
panelControl.add(btnJTableSelectionUnlock);
DefaultTableModel model = new DefaultTableModel(new String[]{"Id", "Name", "State"}, 0) {
// Disable cell editing
@Override
public boolean isCellEditable(int row, int column) {
// Disable cells editing.
return false;
}
};
data = new Object[][]{
{1, "Alpha", true},
{5, "Beta", false},
{3, "Gama", true},
{4, "Giga", true},
{7, "Coca", true},};
table = new JTable(model);
TableColumnModel columnModel = table.getColumnModel();
LockableTableCellRenderer cellRenderer = new LockableTableCellRenderer();
for (int column = 0; column < columnModel.getColumnCount(); column++) {
columnModel.getColumn(column).setCellRenderer(cellRenderer);
}
table.getSelectionModel().setSelectionMode(DefaultListSelectionModel.SINGLE_SELECTION);
table.getSelectionModel().addListSelectionListener(new RowSelectionListener());
for (Object[] d : data) {
model.addRow(d);
}
JPanel containerPanel = new JPanel(new BorderLayout());
containerPanel.setPreferredSize(new Dimension(350, 200));
scrollableTable = new JScrollPane(table);
containerPanel.add(panelControl, BorderLayout.PAGE_START);
containerPanel.add(scrollableTable, BorderLayout.CENTER);
return containerPanel;
}
private class RowSelectionListener implements ListSelectionListener {
@Override
public void valueChanged(ListSelectionEvent event) {
// Ensure single event invoked
if (!event.getValueIsAdjusting() && !lockedSelection) {
DefaultListSelectionModel selectionModel = (DefaultListSelectionModel) event.getSource();
if (selectionModel.isSelectionEmpty()) {
// Empty selection: table row deselection occurred
btnJTableSelectionLocked.setEnabled(false);
} else {
btnJTableSelectionLocked.setEnabled(true);
int viewRow = table.getSelectedRow();
if (viewRow > -1) {
int idsColumn = 0;
modelRow = table.convertRowIndexToModel(viewRow);
Object selectedIdObject = table.getModel().getValueAt(modelRow, idsColumn);
selectedId = Integer.parseInt(selectedIdObject.toString());
}
}
}
}
}
private class BtnAction implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
Object btnClicked = e.getSource();
int columnsSize = 3;
if (btnClicked == btnJTableSelectionLocked) {
System.out.println("Lock");
lockedSelection = true;
btnJTableSelectionLocked.setEnabled(false);
btnJTableSelectionUnlock.setEnabled(true);
table.setRowSelectionAllowed(false); // <-- Works fine.
table.putClientProperty("selectedRowId", selectedId);
} else if (btnClicked == btnJTableSelectionUnlock) {
System.out.println("Unlock");
lockedSelection = false;
btnJTableSelectionLocked.setEnabled(true);
btnJTableSelectionUnlock.setEnabled(false);
table.setRowSelectionAllowed(true); // <-- This line does not restore normal selection
table.putClientProperty("selectedRowId", null);
}
}
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(() -> {
Test tableRowColorControl = new Test();
JFrame frame = new JFrame("TableRowSelectionControl");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(tableRowColorControl.createPanel());
frame.pack();
frame.setVisible(true);
});
}
public class LockableTableCellRenderer extends DefaultTableCellRenderer {
@Override
public Component getTableCellRendererComponent(
JTable table,
Object value,
boolean isSelected,
boolean hasFocus,
int row,
int column) {
Component tableCellRendererComponent = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
Integer id = (Integer) table.getModel().getValueAt(row, 0);
Integer selectedId = (Integer) table.getClientProperty("selectedRowId");
if (selectedId != null && id.equals(selectedId)) {
setBackground(rowSelectionColor);
setForeground(table.getForeground());
} else if (!isSelected) {
setBackground(table.getBackground());
setForeground(table.getForeground());
setBorder(noFocusBorder);
}
return tableCellRendererComponent;
}
}
}