2012-05-13 2 views
2

Я хочу вызвать действие сохранения в любом месте приложения (Control + S). Я добавил необходимое связывание ключей, и действие запускается, как ожидалось. Однако, если я попробую Control + S на JTable, таблица начнет мое настраиваемое действие и активирует ячейку таблицы для редактирования. Я думаю, что я отключил действие редактирования во входной карте таблицы. Что мне здесь не хватает?JTable Key Bindings

import java.awt.Dimension; 
import java.awt.event.ActionEvent; 
import javax.swing.AbstractAction; 
import javax.swing.ActionMap; 
import javax.swing.InputMap; 
import javax.swing.JComponent; 
import javax.swing.JFrame; 
import javax.swing.JOptionPane; 
import javax.swing.JScrollPane; 
import javax.swing.JTable; 
import javax.swing.KeyStroke; 
import javax.swing.UIManager; 

public class TestTableKeyBinding extends JFrame{ 

JTable table; 
JScrollPane scroll; 

public static void main(String[] args){ 
    TestTableKeyBinding test = new TestTableKeyBinding(); 
    test.setVisible(true); 
} 

TestTableKeyBinding(){ 
    super(); 
    initUI(); 
    addKeyBindings(); 
} 

void initUI(){ 
    this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    String[] headers = new String[]{"apples", "bananas"}; 
    String[][] data = new String[][]{{"1", "2"},{"4","6"}}; 
    table = new JTable(data, headers); 
    table.setCellSelectionEnabled(true); 
    scroll = new JScrollPane(); 
    scroll.setViewportView(table); 
    this.add(scroll); 
    this.pack(); 
    this.setSize(new Dimension(300, 400)); 

} 

void addKeyBindings(){ 
    //root maps 
    InputMap im = this.getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); 
    ActionMap am = this.getRootPane().getActionMap(); 

    //add custom action 
    im.put(KeyStroke.getKeyStroke("control S"), "save"); 
    am.put("save", saveAction()); 

    //disable table actions via 'none' 
    table.getInputMap().put(KeyStroke.getKeyStroke("control S"), "none"); 
    table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke("control S"), "none"); 
    table.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke("control S"), "none"); 
    table.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("control S"), "none"); 
    ((InputMap)UIManager.get("Table.ancestorInputMap")).put(KeyStroke.getKeyStroke("control S"), "none"); 
} 

AbstractAction saveAction(){ 
    AbstractAction save = new AbstractAction(){ 
     public void actionPerformed(ActionEvent e) { 
      // TODO Auto-generated method stub 
       JOptionPane.showMessageDialog(TestTableKeyBinding.this.table, "Action Triggered."); 
     }   
    }; 
     return save; 
    } 
} 
+0

У меня нет проблем с исполнением этого кода на Win7 JDK1.6. –

+0

@Guillaume Проблема возникает, когда вы управляете + S после выбора ячейки таблицы. Действие активируется, и выбранная ячейка вводит редактирование. – kirbs

ответ

4

Как @Guillaume, у меня не было проблем с запуском кода. Вы можете найти CellEditor, который непреднамеренно побеждает editingStopped(), обсуждается here. Значение sscce может помочь в выяснении проблемы.

Приложение: вы можете отменить редактирование в обработчике saveAction(), как показано ниже.

table.editingCanceled(null); 

Для справки, я обновил свой пример в нескольких отношениях:

  • Control-S не связан с каким-либо JTableAction в общем Look & Feel реализации, так что нет никакой необходимости remove it.
  • Для удобства кросс-платформы используйте getMenuShortcutKeyMask().
  • Качели GUI объекты должны быть сконструированы и обработаны только на event dispatch thread.

Код:

import java.awt.Dimension; 
import java.awt.EventQueue; 
import java.awt.Toolkit; 
import java.awt.event.ActionEvent; 
import java.awt.event.KeyEvent; 
import javax.swing.AbstractAction; 
import javax.swing.ActionMap; 
import javax.swing.InputMap; 
import javax.swing.JComponent; 
import javax.swing.JFrame; 
import javax.swing.JOptionPane; 
import javax.swing.JScrollPane; 
import javax.swing.JTable; 
import javax.swing.KeyStroke; 

public class TestTableKeyBinding extends JFrame { 

    private static final int MASK = 
     Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(); 
    private JTable table; 

    public static void main(String[] args) { 
     EventQueue.invokeLater(new Runnable() { 

      @Override 
      public void run() { 
       TestTableKeyBinding test = new TestTableKeyBinding(); 
       test.setVisible(true); 
      } 
     }); 
    } 

    TestTableKeyBinding() { 
     super(); 
     initUI(); 
     addKeyBindings(); 
    } 

    private void initUI() { 
     this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     String[] headers = new String[]{"apples", "bananas"}; 
     String[][] data = new String[][]{{"1", "2"}, {"4", "6"}}; 
     table = new JTable(data, headers); 
     table.setCellSelectionEnabled(true); 
     this.add(new JScrollPane(table)); 
     this.pack(); 
     this.setSize(new Dimension(300, 400)); 

    } 

    private void addKeyBindings() { 
     //root maps 
     InputMap im = this.getRootPane().getInputMap(
      JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); 
     ActionMap am = this.getRootPane().getActionMap(); 
     //add custom action 
     im.put(KeyStroke.getKeyStroke(KeyEvent.VK_S, MASK), "save"); 
     am.put("save", saveAction()); 
    } 

    private AbstractAction saveAction() { 
     AbstractAction save = new AbstractAction() { 

      @Override 
      public void actionPerformed(ActionEvent e) { 
       JOptionPane.showMessageDialog(
        TestTableKeyBinding.this.table, "Action Triggered."); 
       table.editingCanceled(null); 
      } 
     }; 
     return save; 
    } 
} 
+2

Спасибо! 'table.editingCancelled (null)' именно то, что я искал. – kirbs

+0

Большое спасибо, это решение также хорошо сработало для меня – user489041

1

я, наконец, понял это. Нет привязки ключа к набору, карта действия не существует. Таким образом, призывы не делали ничего.

table.getInputMap().put(KeyStroke.getKeyStroke("control S"), "none"); 
table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke("control S"), "none"); 
table.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke("control S"), "none"); 
table.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("control S"), "none"); 
((InputMap)UIManager.get("Table.ancestorInputMap")).put(KeyStroke.getKeyStroke("control S"), "none"); 

JTable передает ключевое событие для редактированияCellAt там путем запуска таблицы для редактирования. Существует два пути. 1) Добавьте ссылку на действие на карты ввода/действия JTable или 2) переопределите editCellAt, чтобы вернуть значение false. Вот как я обошел эту проблему.

public boolean editCellAt(int row, int column, EventObject e){    
      if(e instanceof KeyEvent){ 
       int i = ((KeyEvent) e).getModifiers(); 
       String s = KeyEvent.getModifiersExText(((KeyEvent) e).getModifiers()); 
       //any time Control is used, disable cell editing    
       if(i == InputEvent.CTRL_MASK){ 
        return false; 
       } 
      }    
      return super.editCellAt(row, column, e);     
     } 
+0

Основываясь на более ясном понимании вашего вопроса, я показал другой подход [здесь] (http://stackoverflow.com/a/10575771/230513). – trashgod

Смежные вопросы