Alterar o comportamento do botão Ctrl + em uma JTable
Pergunta
Existe uma maneira fácil de manipular os controles em uma JTable para dar funcionalidade diferente quando há um botão do teclado pressionado (botão ie. CTRL) e uma linha é selecionada? Fui convidado para criar uma tabela onde o CTRL + Clique (clique do mouse) em uma linha só irá desmarcar uma linha selecionada, não selecione uma linha. Se o usuário CTRL + Cliques uma linha desmarcada, nada vai acontecer.
Eu tenho sido capaz de criar uma tabela, e desabilitar funções como CTRL + A (Selecionar tudo), e eu fui capaz de verificar se o botão de controlo é pressionado quando um MouseEvent é gerado, mas não posso parecem descobrir como o CTRL + Click pode ser ajustado. Aqui está algum código:
package nicky;
import javax.swing.*;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.*;
public class TableTester extends JPanel {
public TableTester() {
super(new GridLayout(1,0));
final String[] columnNames = {"First Name",
"Last Name",
"Sport",
"# of Years",
"Vegetarian"};
final Object[][] data = {
{"Tom", "Roberts","Athletic", new Integer(5), new Boolean(false)},
{"Sarah", "Watt", "Football", new Integer(3), new Boolean(true)},
{"Laura", "Brown", "Swimming", new Integer(2), new Boolean(false)},
{"Simon", "Smith", "Tennis", new Integer(20), new Boolean(true)},
{"Paul", "Jones", "Rugby", new Integer(10), new Boolean(false)}
};
JTable table = new JTable(data, columnNames);
table.setPreferredScrollableViewportSize(new Dimension(500, 100));
table.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
table.addMouseListener(new MouseListener(){
public void mouseEntered(MouseEvent me){}
public void mouseExited(MouseEvent me){}
public void mouseReleased(MouseEvent me){}
public void mouseClicked(MouseEvent me){}
public void mousePressed(MouseEvent me){
if (me.isControlDown()){
System.out.println("This is working ");
}
}
});
InputMap inputMap = table.getInputMap(JTable.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
KeyStroke keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_A, InputEvent.CTRL_MASK);
inputMap.put(keyStroke, "none");
JScrollPane scrollPane = new JScrollPane(table);
add(scrollPane);
}
private static void createAndShowGUI() {
JFrame.setDefaultLookAndFeelDecorated(true);
JFrame frame = new JFrame("TableTester");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
TableTester newContentPane = new TableTester();
newContentPane.setOpaque(true);
frame.setContentPane(newContentPane);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
No método mousePressed Eu tenho jogado ao redor com a obtenção de todas as linhas selecionadas da mesa, e foi, em seguida, indo para verificar se a linha recém-clicado estava nas SelectedRows ... No entanto, eu não tenho certeza se existe uma maneira de ver qual linha está associado com o MouseEvent.
(comportamento Além disso, eu sei que esperado como este não deve ser jogado ao redor com muito, mas é para replicar um sistema legado da empresa)
Todas as ideias / sugestões seria apreciada!
Solução
OK, segunda tomada (eu deixei a primeira vez que pode interessar a alguém por algum outro uso, que conhecem dizem que é lá para fins educacionais ...: -?).)
Eu tive uma olhada no código fonte de JTable e descobri que o mouse eventos são tratados pelo look and feel. Sabendo como ele lida com a chave de controle, eu poderia seguramente substituir o método changeSelection para fazer o que você precisa.
Acho requisitos um pouco estranho (você ainda pode usar Shift + clique, não?), Mas eu não sei contexto.
class SpecialTable extends JTable
{
SpecialTable(Object[][] data, String[] columnNames)
{
super(data, columnNames);
// That's already the default
// setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
}
/**
* Called by javax.swing.plaf.basic.BasicTableUI.Handler.adjustSelection(MouseEvent)
* like: table.changeSelection(pressedRow, pressedCol, e.isControlDown(), e.isShiftDown());
*/
@Override
public void changeSelection(int rowIndex, int columnIndex, boolean toggle, boolean extend)
{
if (toggle && !isRowSelected(rowIndex))
return; // Don't do the selection
super.changeSelection(rowIndex, columnIndex, toggle, extend);
}
}
Muito mais simples e exatamente o que você precisa!
BTW, obrigado por fornecer tal caso bom teste simples, eu poderia ter tentou não se tivesse de escrevê-lo eu mesmo ... :-D Foi um desafio interessante e de aprendizagem.
Outras dicas
Eu tive sucesso com o seguinte, embora eu não estou certo de que é o melhor método ...
class SpecialTable extends JTable
{
boolean bIsControlDown;
int clickedRow;
SpecialTable(Object[][] data, String[] columnNames)
{
super(data, columnNames);
// setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
getSelectionModel().addListSelectionListener(this);
addMouseListener(new MouseInputAdapter()
{
public void mousePressed(MouseEvent me)
{
bIsControlDown = me.isControlDown();
clickedRow = rowAtPoint(me.getPoint());
}
});
}
public void valueChanged(ListSelectionEvent evt)
{
super.valueChanged(evt);
if (bIsControlDown)
{
if (!evt.getValueIsAdjusting())
{
// System.out.println(evt);
// System.out.println("=> " + clickedRow);
getSelectionModel().removeSelectionInterval(clickedRow, clickedRow);
}
}
}
}
Substitua as linhas que definem table
em seu código com apenas:
JTable table = new SpecialTable(data, columnNames);
table.setPreferredScrollableViewportSize(new Dimension(500, 100));
Quando você controlar-clique em uma linha não selecionado, ele será selecionado brevemente, então não selecionada.