2013-09-30 5 views
1

Я хочу показать JButton в JTable. Это ничего особенного, и я нашел много примеров этого. Однако у меня всегда возникают проблемы с нажатием кнопок через клавиатуру (не через мышь). Я ожидаю, что я могу выбрать ячейку и нажать (также визуально) кнопку, нажав SPACE (без мнемоники).Нажатие JButton внутри JTable с клавиатуры

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


http://tips4java.wordpress.com/2009/07/12/table-button-column/

Автор утверждает, что работают ключи. Я считаю, что они это сделали, но не во всех моих системах, которые я проверил. Однако поддерживаемые мнемоники работают отлично.

(размещен здесь: Adding Jbutton to JTable)


http://www.java2s.com/Code/Java/Swing-Components/ButtonTableExample.htm

(размещен здесь: Adding Jbutton to JTable)

В примере, он отлично работает! Однако это не работает для моего стола. Просто отключить выбор строк (я должен использовать выбор соты), и нажав на кнопку с помощью клавиши больше не работает:

table.setRowSelectionAllowed(false);


Я изо всех сил старался выяснить, что происходит не так и как это исправить , но я потерпел неудачу. Мое единственное достижение - вызвать действие за кнопкой, но кнопка не нажата (я имею в виду визуальное поведение).


Некоторые данные добавлены:

Я ... (во многих комбинациях)

  • Ubuntu 10,04, Windows 7, Windows 8
  • Java 7u21, JDK 1.6.0_33, OpenJDK Runtime Environment (IcedTea6 1.8.1) (6b18-1.8.1-0ubuntu1)
  • WindowsLookAndFeel, Metal (Cross Platform LAF), Nimbus

0% успех!


TableTest.java

import java.awt.event.ActionEvent; 
import java.util.LinkedList; 
import java.util.List; 

import javax.swing.AbstractAction; 
import javax.swing.Action; 
import javax.swing.JFrame; 
import javax.swing.JScrollPane; 
import javax.swing.JTable; 
import javax.swing.UIManager; 
import javax.swing.UnsupportedLookAndFeelException; 
import javax.swing.table.AbstractTableModel; 

public class TableTest extends JFrame { 

    public TableTest() { 

     this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     JTable table = new JTable(new TestModel()); 
     table.setRowSelectionAllowed(false); 
     table.getColumnModel().getColumn(1).setPreferredWidth(3); 
     table.getColumnModel().getColumn(2).setPreferredWidth(3); 
     this.add(new JScrollPane(table)); 
     Action increase = new AbstractAction("+") { 

      @Override 
      public void actionPerformed(ActionEvent e) { 
       JTable table = (JTable) e.getSource(); 
       int row = Integer.valueOf(e.getActionCommand()); 
       TestModel model = (TestModel) table.getModel(); 
       model.increment(row, 0); 
      } 
     }; 
     ButtonColumn inc = new ButtonColumn(table, increase, 1); 
     Action decrease = new AbstractAction("-") { 

      @Override 
      public void actionPerformed(ActionEvent e) { 
       JTable table = (JTable) e.getSource(); 
       int row = Integer.valueOf(e.getActionCommand()); 
       TestModel model = (TestModel) table.getModel(); 
       model.decrement(row, 0); 
      } 
     }; 
     ButtonColumn dec = new ButtonColumn(table, decrease, 2); 
     pack(); 
    } 

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

class TestModel extends AbstractTableModel { 

    List<TestRecord> records = new LinkedList<TestRecord>(); 

    private static class TestRecord { 

     private int val = 0; 
    } 

    public void increment(int row, int col) { 
     records.get(row).val++; 
     fireTableCellUpdated(row, 0); 
    } 

    public void decrement(int row, int col) { 
     records.get(row).val--; 
     fireTableCellUpdated(row, 0); 
    } 

    public TestModel() { 
     records.add(new TestRecord()); 
     records.add(new TestRecord()); 
    } 

    @Override 
    public Class<?> getColumnClass(int col) { 
     if (col == 0) { 
      return Integer.class; 
     } else { 
      return ButtonColumn.class; 
     } 
    } 

    @Override 
    public boolean isCellEditable(int row, int col) { 
     return true; 
    } 

    @Override 
    public int getColumnCount() { 
     return 3; 
    } 

    @Override 
    public int getRowCount() { 
     return records.size(); 
    } 

    @Override 
    public Object getValueAt(int row, int col) { 
     if (col == 0) { 
      return records.get(row).val; 
     } else if (col == 1) { 
      return "+"; 
     } else { 
      return "-"; 
     } 
    } 
} 

ButtonColumn.java

import java.awt.Color; 
import java.awt.Component; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.awt.event.MouseEvent; 
import java.awt.event.MouseListener; 

import javax.swing.AbstractCellEditor; 
import javax.swing.Action; 
import javax.swing.Icon; 
import javax.swing.JButton; 
import javax.swing.JTable; 
import javax.swing.UIManager; 
import javax.swing.border.Border; 
import javax.swing.border.LineBorder; 
import javax.swing.table.TableCellEditor; 
import javax.swing.table.TableCellRenderer; 
import javax.swing.table.TableColumnModel; 

/** 
* The ButtonColumn class provides a renderer and an editor that looks like a 
* JButton. The renderer and editor will then be used for a specified column in 
* the table. The TableModel will contain the String to be displayed on the 
* button. 
* 
* The button can be invoked by a mouse click or by pressing the space bar when 
* the cell has focus. Optionally a mnemonic can be set to invoke the button. 
* When the button is invoked the provided Action is invoked. The source of the 
* Action will be the table. The action command will contain the model row 
* number of the button that was clicked. 
* 
*/ 
public class ButtonColumn extends AbstractCellEditor implements 
     TableCellRenderer, TableCellEditor, ActionListener, MouseListener { 
    private JTable table; 
    private Action action; 
    private int mnemonic; 
    private Border originalBorder; 
    private Border focusBorder; 

    private JButton renderButton; 
    private JButton editButton; 
    private Object editorValue; 
    private boolean isButtonColumnEditor; 

    /** 
    * Create the ButtonColumn to be used as a renderer and editor. The renderer 
    * and editor will automatically be installed on the TableColumn of the 
    * specified column. 
    * 
    * @param table 
    *   the table containing the button renderer/editor 
    * @param action 
    *   the Action to be invoked when the button is invoked 
    * @param column 
    *   the column to which the button renderer/editor is added 
    */ 
    public ButtonColumn(JTable table, Action action, int column) { 
     this.table = table; 
     this.action = action; 

     renderButton = new JButton(); 
     editButton = new JButton(); 
     editButton.setFocusPainted(false); 
     editButton.addActionListener(this); 
     originalBorder = editButton.getBorder(); 
     setFocusBorder(new LineBorder(Color.BLUE)); 

     TableColumnModel columnModel = table.getColumnModel(); 
     columnModel.getColumn(column).setCellRenderer(this); 
     columnModel.getColumn(column).setCellEditor(this); 
     table.addMouseListener(this); 
    } 

    /** 
    * Get foreground color of the button when the cell has focus 
    * 
    * @return the foreground color 
    */ 
    public Border getFocusBorder() { 
     return focusBorder; 
    } 

    /** 
    * The foreground color of the button when the cell has focus 
    * 
    * @param focusBorder 
    *   the foreground color 
    */ 
    public void setFocusBorder(Border focusBorder) { 
     this.focusBorder = focusBorder; 
     editButton.setBorder(focusBorder); 
    } 

    public int getMnemonic() { 
     return mnemonic; 
    } 

    /** 
    * The mnemonic to activate the button when the cell has focus 
    * 
    * @param mnemonic 
    *   the mnemonic 
    */ 
    public void setMnemonic(int mnemonic) { 
     this.mnemonic = mnemonic; 
     renderButton.setMnemonic(mnemonic); 
     editButton.setMnemonic(mnemonic); 
    } 

    @Override 
    public Component getTableCellEditorComponent(JTable table, Object value, 
      boolean isSelected, int row, int column) { 
     if (value == null) { 
      editButton.setText(""); 
      editButton.setIcon(null); 
     } else if (value instanceof Icon) { 
      editButton.setText(""); 
      editButton.setIcon((Icon) value); 
     } else { 
      editButton.setText(value.toString()); 
      editButton.setIcon(null); 
     } 

     this.editorValue = value; 
     return editButton; 
    } 

    @Override 
    public Object getCellEditorValue() { 
     return editorValue; 
    } 

    // 
    // Implement TableCellRenderer interface 
    // 
    @Override 
    public Component getTableCellRendererComponent(JTable table, Object value, 
      boolean isSelected, boolean hasFocus, int row, int column) { 
     if (isSelected) { 
      renderButton.setForeground(table.getSelectionForeground()); 
      renderButton.setBackground(table.getSelectionBackground()); 
     } else { 
      renderButton.setForeground(table.getForeground()); 
      renderButton.setBackground(UIManager.getColor("Button.background")); 
     } 

     if (hasFocus) { 
      renderButton.setBorder(focusBorder); 
     } else { 
      renderButton.setBorder(originalBorder); 
     } 

     // renderButton.setText((value == null) ? "" : value.toString()); 
     if (value == null) { 
      renderButton.setText(""); 
      renderButton.setIcon(null); 
     } else if (value instanceof Icon) { 
      renderButton.setText(""); 
      renderButton.setIcon((Icon) value); 
     } else { 
      renderButton.setText(value.toString()); 
      renderButton.setIcon(null); 
     } 

     return renderButton; 
    } 

    // 
    // Implement ActionListener interface 
    // 
    /* 
    * The button has been pressed. Stop editing and invoke the custom Action 
    */ 
    @Override 
    public void actionPerformed(ActionEvent e) { 
     int row = table.convertRowIndexToModel(table.getEditingRow()); 
     fireEditingStopped(); 

     // Invoke the Action 

     ActionEvent event = new ActionEvent(table, 
       ActionEvent.ACTION_PERFORMED, "" + row); 
     action.actionPerformed(event); 
    } 

    // 
    // Implement MouseListener interface 
    // 
    /* 
    * When the mouse is pressed the editor is invoked. If you then then drag 
    * the mouse to another cell before releasing it, the editor is still 
    * active. Make sure editing is stopped when the mouse is released. 
    */ 
    @Override 
    public void mousePressed(MouseEvent e) { 
     if (table.isEditing() && table.getCellEditor() == this) 
      isButtonColumnEditor = true; 
    } 

    @Override 
    public void mouseReleased(MouseEvent e) { 
     if (isButtonColumnEditor && table.isEditing()) 
      table.getCellEditor().stopCellEditing(); 

     isButtonColumnEditor = false; 
    } 

    @Override 
    public void mouseClicked(MouseEvent e) { 
    } 

    @Override 
    public void mouseEntered(MouseEvent e) { 
    } 

    @Override 
    public void mouseExited(MouseEvent e) { 
    } 
} 
+0

', но не на все мои системах я checked.' - Какие системы? Возможно, другие, использующие эти системы, могут проверять поведение. Нажатие кнопки с помощью пробела может зависеть от LAF. При нажатии на обычный JButton, не отображаемый в таблице, вызывается действие, которое вызывается? – camickr

+0

информация добавлена ​​... Конечно, нажатие (по клавиатуре) работает обычная кнопка. Также нажатие (по клавиатуре) с выбором строки допускает «истина» в некоторых примерах. –

ответ

2

Проблема не в редакторе. Ход клавиши SPACE не пересылается в редактор по умолчанию в первом столбце.

Проблема заключается в том, что JTable определяет действие для ключа SPACE, чтобы он был перехвачен, прежде чем он получит возможность передать его в редактор. Найдите мой блог для записи Key Bindings, где вы найдете программу, в которой перечислены все стандартные привязки клавиш для JTable. Вызывается действие, которое вызывается «addToSelection», поэтому я не уверен, почему он работает по-разному в зависимости от выбора строки.

Во всяком случае одно решение, чтобы удалить это Действие:

InputMap im = table.getInputMap(JTable.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); 
KeyStroke space = KeyStroke.getKeyStroke("SPACE"); 
im.put(space, "none"); 
+0

Aha! Mac OS X не имеет привязки ключей для '' addToSelection''. – trashgod

+0

Когда я пробовал исправление, я также хотел начать изменять привязку клавиш для пробела. Однако я полностью потерпел неудачу, потому что я попробовал назвать стандартное поведение (не зная, что это такое) * и * отправив его в редактор. Вы знаете о рабочей возможности? У меня плохое свидание, если я просто удалю некоторые предопределенные привязки. В противном случае вы полностью правы, и нажатие кнопки работает с вашим дополнением. –

+0

@StefeKlauou «У меня плохое свидание, если я просто удалю некоторые предопределенные привязки». Ваша таблица не использует выбор в любом случае. Поэтому удаление действия, связанного с выбором, не должно вызывать проблемы. – camickr

2

И TableTest, который использует ButtonColumn и TablePopupEditor полные примеры, которые работают правильно, когда Space ключ i s нажата в выбранной ячейке кнопки. Ни один из них не типичный ButtonModel -определенный внешний вид автономной кнопки, но вы можете предоставить свои собственные визуальные очереди по мере необходимости. Этот связанный example использует цветную рамку.

+0

Оба примера не работают с setRowSelectionAllowed (false), как описано в моей начальной записи. –

+0

Оба работают для меня с 'setRowSelectionAllowed (false)' на Java 6; отредактируйте свой вопрос, чтобы включить [sscce] (http://sscce.org/), который показывает проблему. – trashgod

+0

Нет, не работает. Я просто использовал введенный вами код, в том числе isetRowSelectionAllowed (false). Тем не менее, я отредактирую сообщение, включая все. Я также буду включать все системы/версии/LAF, которые я пробовал. Если это действительно работает в вашей системе, пожалуйста, добавьте информацию об используемых ОС, LAF, точной версии, нажатой клавише (шаги для воспроизведения) и т. Д. Я действительно пробовал много вещей, но 0% успеха! –

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