2013-09-30 69 views
1

我想在JTable中显示JButton。这没什么特别的,我发现了很多例子。但是,我总是遇到按键通过键盘(不通过鼠标)的问题。我期望我可以选择一个单元格并按下SPACE(无助记符)(也可以直观地)按下该按钮。通过键盘在JTable内部按JButton

两个片断的工作就像一个魅力,除了支持键:


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运行时环境(IcedTea6 1.8.1)(6b18-1.8.1-0ubuntu1)
  • WindowsLookAndFeel,金属(跨平台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是否会导致被调用的Action? – camickr

+0

信息添加...当然,点击(通过键盘)一个常规按钮的作品。在某些示例中,同时单击(通过键盘)行选择允许“true”。 –

回答

2

问题不是编辑器。 SPACE键击不会被转发到第一列中的默认编辑器。

问题是,JTable为SPACE键定义了一个Action,因此在它有机会被传递给编辑器之前被拦截。在我的博客搜索Key Bindings条目,您将找到一个列出JTable的所有默认键绑定的程序。被调用的Action称为“addToSelection”,所以我不确定为什么它的工作方式有所不同,具体取决于行选择。

反正一个解决方法是删除此操作:

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

啊哈! Mac OS X没有用于“addToSelection”的键绑定。 – trashgod

+0

当我尝试修复时,我也想开始修改空间的键绑定。但是,我完全失败了,因为我试图调用标准行为(不知道这是什么)*并*将它发送给编辑器。你知道一个可行的可能性吗?我有一个不好的感觉,如果我只是删除一些预定义的绑定。否则,你是完全正确的,并按下按钮与你的添加。 –

+0

@StefeKlauou'我有一个不好的感觉,如果我只是删除一些预定义的绑定。“ - 你的表不反正使用选择。因此,删除与选择相关的操作不应引起问题。 – camickr

2

两个TableTest,它采用ButtonColumn,并TablePopupEditor是正常工作完整的例子当空间关键我按下选定的按钮单元格。既没有表现出典型的ButtonModel-定义的独立按钮外观,但您可以根据需要提供自己的视觉队列。这个相关的example使用彩色边框。

+0

这两个示例都不适用于我的初始文章中所述的setRowSelectionAllowed(false)。 –

+0

这两个都适用于Java 6的'setRowSelectionAllowed(false)';请修改您的问题以包含显示问题的[sscce](http://sscce.org/)。 – trashgod

+0

不,不起作用。我只是使用你发布的代码,包括'setRowSelectionAllowed(false)'。不过,我会编辑我的帖子,包括一切。我还将包括我尝试过的所有系统/版本/ LAF。如果它真的在你的系统上工作,请添加有关使用的操作系统,LAF,确切版本,按键(重现步骤)等信息。我真的尝试了很多东西,但成功率为0%! –