【问题标题】:Pressing JButton inside JTable via keyboard通过键盘在 JTable 中按下 JButton
【发布时间】:2013-09-30 15:59:58
【问题描述】:

我想在 JTable 中显示一个 JButton。这没什么特别的,我发现了很多这样做的例子。但是,我总是在通过键盘(而不是通过鼠标)按下按钮时遇到问题。我希望我可以选择一个单元格并通过按空格(无助记符)按下(也可以在视觉上)按钮。

两个 sn-ps 就像一个魅力,除了支持键:


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) {
    }
}

【问题讨论】:

  • but not on all my systems I checked. - 什么系统?也许其他使用这些系统的人可以检查行为。使用空格键单击按钮可能与 LAF 相关。单击表格中未显示的常规 JButton 是否会导致调用 Action?
  • 已添加信息...当然,单击(通过键盘)常规按钮是有效的。在某些示例中,在允许“真”行选择的情况下单击(通过键盘)也有效。

标签: java swing keyboard jtable jbutton


【解决方案1】:

问题不在于编辑器。 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");

【讨论】:

  • 啊哈! Mac OS X 没有"addToSelection" 的键绑定。
  • 当我尝试修复时,我也想开始修改空格键绑定。但是,我完全失败了,因为我尝试调用标准行为(不知道这是什么) 将其发送给编辑器。你知道工作的可能性吗?如果我只是删除一些预定义的绑定,我有一种不好的感觉。否则,您是完全正确的,按下按钮即可添加。
  • @StefeKlauou I have a bad feelding, if I just remove some predefined binding. - 您的表格无论如何都不使用选择。因此,删除与选择相关的操作应该不会导致问题。
  • 其他列(没有按钮)和他们的需求呢?我更喜欢不删除基本“功能”的解决方案。如果只针对按钮列,可以,但是当前代码删除了整个表格的绑定。
  • @StefeKlauou,您已经关闭了整行的行选择,因此这对于其他列来说无论如何都不是问题,因为您会假设“addToSelection”仅在启用选择时才起作用。此外,正如垃圾神已经指出的那样,此功能甚至在 Mac 中都不存在。无论如何,您已经得到了原始问题的答案。
【解决方案2】:

使用ButtonColumnTableTestTablePopupEditor 都是完整的示例,当在选定的按钮单元格中按下Space 键时,它们可以正常工作。两者都没有表现出典型的ButtonModel 定义的独立按钮外观,但您可以根据需要提供自己的可视队列。这个相关的example 使用彩色边框。

【讨论】:

  • 这两个示例都不适用于我最初帖子中所述的 setRowSelectionAllowed(false)。
  • 两者都适用于我在 Java 6 上使用 setRowSelectionAllowed(false);请编辑您的问题以包含一个显示问题的sscce
  • 不,不起作用。我刚刚使用了您发布的代码,包括“setRowSelectionAllowed(false)”。但是,我将编辑我的帖子,包括所有内容。我还将包括我尝试过的所有系统/版本/LAF。如果它真的适用于您的系统,请添加有关使用的操作系统、LAF、确切版本、按下的键(重现步骤)等信息。我真的尝试了很多东西,但成功率为 0%!
  • 在 Mac OS X、Java 6 上都可以工作;在带有 setRowSelectionAllowed(false) 的 Ubuntu 10.04、Java 6 上失败。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-28
相关资源
最近更新 更多