【问题标题】:Setting focus AND blinking cursor on specific JTable cell在特定的 JTable 单元格上设置焦点和闪烁光标
【发布时间】:2014-08-29 21:39:04
【问题描述】:

我有一个非常简单的问题。

当用户在我的JTable 中选择了一行后单击“编辑”按钮时,软件会检查是否允许编辑该行。

如果是,我想将焦点放在该行的第一个单元格中,并使用闪烁的光标,以便用户可以直接开始在单元格中输入。

借助 isEditable() 方法,我可以成功设置行是否可编辑,并且我使用 table.editCellAt(selectedRow, 0) 开始编辑。

然而

1) 该单元格中没有出现闪烁的光标

2) 用户不能立即输入单元格 (他仍然需要双击单元格)

关于如何实现这一点的任何建议?

////////////////更新//////////////////////////

虽然MadProgrammer的评论解决了问题,但也只是解决了一部分问题,那是因为我不够准确。

确实,当我执行他用“经典 JTable”描述的步骤时,即:

table.editCellAt(selectedRow, 0);
table.setSurrendersFocusOnKeystroke(true);
table.getEditorComponent().requestFocus();

我得到了闪烁的光标和立即输入的能力。

但是缺少的部分是我为用户提供了 2 个选项。

1) 他可以直接手动选择表格中的一行,这个解决方案很好。

2) 但是我还为用户提供了使用 JTextField 来更轻松地找到他正在搜索的行的能力。为此,我使用带有 regexFilter 的 TableRowSorter 来过滤显示的行。当我在那里尝试 MadProgrammer 的解决方案时(启用过滤),我得到一个 java.lang.NullPointerException 并且没有进行进一步的编辑。

这是一个例外:

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at dialogs.DialogEditCouleurs.actionPerformed(DialogEditCouleurs.java:229)
at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
at javax.swing.DefaultButtonModel.setPressed(Unknown Source)
at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source)
at java.awt.AWTEventMulticaster.mouseReleased(Unknown Source)
at java.awt.AWTEventMulticaster.mouseReleased(Unknown Source)
at java.awt.Component.processMouseEvent(Unknown Source)
at javax.swing.JComponent.processMouseEvent(Unknown Source)
at java.awt.Component.processEvent(Unknown Source)
at java.awt.Container.processEvent(Unknown Source)
at java.awt.Component.dispatchEventImpl(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Window.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.awt.EventQueue.access$200(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue$4.run(Unknown Source)
at java.awt.EventQueue$4.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.WaitDispatchSupport$2.run(Unknown Source)
at java.awt.WaitDispatchSupport$4.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.awt.WaitDispatchSupport.enter(Unknown Source)
at java.awt.Dialog.show(Unknown Source)
at java.awt.Component.show(Unknown Source)
at java.awt.Component.setVisible(Unknown Source)
at java.awt.Window.setVisible(Unknown Source)
at java.awt.Dialog.setVisible(Unknown Source)
at dialogs.DialogEditCouleurs.<init>(DialogEditCouleurs.java:123)
at panels.PanelPropertiesEdit.actionPerformed(PanelPropertiesEdit.java:940)
at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
at javax.swing.DefaultButtonModel.setPressed(Unknown Source)
at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source)
at java.awt.AWTEventMulticaster.mouseReleased(Unknown Source)
at java.awt.AWTEventMulticaster.mouseReleased(Unknown Source)
at java.awt.Component.processMouseEvent(Unknown Source)
at javax.swing.JComponent.processMouseEvent(Unknown Source)
at java.awt.Component.processEvent(Unknown Source)
at java.awt.Container.processEvent(Unknown Source)
at java.awt.Component.dispatchEventImpl(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Window.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.awt.EventQueue.access$200(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue$4.run(Unknown Source)
at java.awt.EventQueue$4.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)

这是导致异常的行:

table.getEditorComponent().requestFocus();

这是软件的实际行为:

1) 没有过滤器:选择了行,但尚未点击 Edit JButton。

2) 无过滤器:点击了 JButton --> 预期行为正确。

现在有问题的行为:

1) 过滤 : 行已被选中,但尚未单击 ​​Edit JButton。

2) 过滤: Edit JButton clicked --> 没有变化和上面的异常引发(不要打扰工具提示)

这是 JDIalog 的相关部分:

public class DialogEditColors extends JDialog implements ActionListener, KeyListener
{
final WebNotificationPopup          notificationPopup   = new WebNotificationPopup();
final TableRowSorter<TableModel>    sorter;
private JTable                      tableau  = null;
private EditTableModel              model    = null;
private JPanel                      panelBoutons = null;
private WebTextField                txtFieldSearch  = null;
private JLabel                      lblTitle    = null;
private JButton                     btnAdd  = null, btnDelete = null, btnEdit = null;
private JButton                     btnAnnuler  = null, btnSaveCouleur = null;
private JScrollPane                 scroller    = null;
private ColorDao                    colorDao = new ColorDao(Share.connection);

public DialogEditColors()
    {
        super();
        setSize(439, 313);
        setTitle("  Edition couleurs");
        getContentPane().setLayout(null);
        setModal(true);
        setResizable(false);
        setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
        setLocationRelativeTo(null);

        btnSaveCouleur = new JButton("Enregistrer");
        btnSaveCouleur.setBounds(317, 247, 89, 26);
        btnSaveCouleur.addActionListener(this);

        btnAnnuler = new JButton("Annuler");
        btnAnnuler.setBounds(214, 247, 89, 26);
        btnAnnuler.addActionListener(this);

        btnAdd = new JButton("");
        btnAdd.setBounds(new Rectangle(10, 8, 33, 26));
        btnAdd.addActionListener(this);

        btnDelete = new JButton("");
        btnDelete.setBounds(new Rectangle(53, 8, 33, 26));
        btnDelete.addActionListener(this);

        btnEdit = new JButton("");
        btnEdit.setBounds(new Rectangle(96, 8, 33, 26));
        btnEdit.addActionListener(this);

        panelBoutons = new JPanel();
        panelBoutons.setBorder(new LineBorder(Color.GRAY));
        panelBoutons.setBounds(27, 11, 378, 43);
        panelBoutons.setLayout(null);

        txtFieldSearch = new WebTextField("", 10);
        txtFieldSearch.setBounds(193, 9, 175, 24);
        panelBoutons.add(txtFieldSearch);
        txtFieldSearch.setTrailingComponent(new WebImage(IconUtil.createIcon("/images/search.png").getImage()));
        txtFieldSearch.addKeyListener(this);

        Object[][] data = new Object[colorDao.findAll().size()][2];
        String[] title = { "Couleur", "Description" };

        int i = 0;
        for (Couleur coul : colorsDao.findAll())
            {
                data[i][0] = coul.getNom();
                data[i][1] = coul.getDescription();
                i++;
            }

        model = new EditTableModel(data, title);
        tableau = new JTable(model)
        {//COLORING THE BACKGROUND IN ALTERNATE COLORS
            public Component prepareRenderer(TableCellRenderer renderer, int row, int column)
                {
                    Component returnComp = super.prepareRenderer(renderer, row, column);
                    Color alternateColor = new Color(242, 242, 242);
                    Color whiteColor = Color.WHITE;
                    if ( !returnComp.getBackground().equals(getSelectionBackground()) )
                        {
                            Color bg = (row % 2 == 0 ? alternateColor : whiteColor);
                            returnComp.setBackground(bg);
                            bg = null;
                        }
                    return returnComp;
                };
        };

        tableau.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        tableau.setCellSelectionEnabled(true);
        sorter = new TableRowSorter<TableModel>(model);
        tableau.setRowSorter(sorter);
        sorter.addRowSorterListener(tableau);

        scroller = new JScrollPane(tableau);
        scroller.setBounds(27, 65, 378, 171);
        addComponents();
        setVisible(true);
    }//END OF CONSTRUCTOR

private void addComponents()
    {
        getContentPane().add(scroller);
        getContentPane().add(btnSaveCouleur);
        getContentPane().add(btnAnnuler);
        panelBoutons.add(btnAdd);
        panelBoutons.add(btnDelete);
        panelBoutons.add(btnEdit);
        getContentPane().add(panelBoutons);
    }//END OF METHOD

public void actionPerformed(ActionEvent e)
    {
     if ( e.getSource() == btnEdit )
            {
                int selectedRow = 0;
                if ( tableau.getSelectedRowCount() != 0 ) //THERE IS A CHOSEN COLOR IN JTABLE 
                    {
                        String selectedColor = (tableau.getValueAt(tableau.getSelectedRow(), tableau.getSelectedColumn()))
                                .toString();
                        //WE'RE TESTING IF THE COLOR IS READONLY
                        if ( colorDao.findByName(selectedColor).get(0).getReadOnly() == true )
                            {//IF THE COLOR IS READONLY
                                notificationPopup.setIcon(NotificationIcon.error);
                                notificationPopup.setContent("This item is readonly : impossible to edit it !");
                                NotificationManager.showNotification(notificationPopup);
                            }

                        else
                            {////THE COLOR IS NOT READONLY --> EDITING IS ALLOWED
                                //1) NOTIFY THE MODEL THAT EDITING IS ALLOWED
                                model.setEditingValidated(true);
                                //2) TEST WETHER FILTER IS ACTIVE OR NOT TO SEE IF INDEX CONVERSION IS NEEDED 
                                if ( txtFieldSearch.getText() == "" )
                                    {//NO FILTER
                                        selectedRow = tableau.getSelectedRow();
                                    }
                                else
                                    {//FILTER IS ACTIVE
                                        int modelIndex = tableau.convertRowIndexToModel(tableau.getSelectedRow());
                                        selectedRow = modelIndex;
                                    }

                                model.setEditingValidatedRowNb(selectedRow);
                                tableau.editCellAt(selectedRow, 0);
                                tableau.setSurrendersFocusOnKeystroke(true);
                                tableau.getEditorComponent().requestFocus();
                            }
                    }
                else
                    {   //NO CHOSEN COLOR
                        notificationPopup.setIcon(NotificationIcon.error);
                        notificationPopup.setContent("No chosen color !");
                        NotificationManager.showNotification(notificationPopup);
                    }
            }

        else if ( e.getSource() == btnAnnuler )
            {//WE LEAVE THE DIALOG WITHOUT DOING ANYTHING
                Share.chosenColor = null;
                this.dispose();
            }
    }//END OF METHOD

public void keyReleased(KeyEvent e)
    {
        if ( e.getSource() == txtFieldSearch )
            {
                String text = txtFieldSearch.getText();
                if ( text.length() == 0 )
                    {
                        sorter.setRowFilter(null);
                    }
                else
                    {
                        sorter.setRowFilter(RowFilter.regexFilter("(?i)" + text));
                    }
                ((AbstractTableModel) tableau.getModel()).fireTableDataChanged();
            }
    }//END OF METHOD
}//END OF CLASS

这里是 TableModel 的相关部分:

public class EditTableModel extends AbstractTableModel implements Serializable
{
protected Vector    dataVector;
protected Vector    columnIdentifiers;
protected boolean   isEditingValidated      = false;
protected int       editingValidatedRowNb   = 0;

public boolean isCellEditable(int row, int column)
    {
        //IF EDITING IS NOT VALIDATED NOTHING IS EDITABLE / RETURN FALSE
        if ( !isEditingValidated ) 
            {
                return false;
            }
        //ELSE A FURTHER TEST IS NEEDED TO DECIDE
        else
            {
                //IF THE CURRENT ROW IS THE ROW FOR WHICH EDITING IS VALIDATED RETURN TRUE
                if ( row == editingValidatedRowNb )
                    {
                        return true;
                    }
                //ELSE THE ROW IS ANOTHER ROW SO RETURN FALSE
                else
                    {
                        return false;
                    }
            }
    }//END OF METHOD
}//END OF CLASS

有人建议吗?

【问题讨论】:

  • 两件事。尝试设置JTableSurrendersFocusOnKeystroke 属性并确保编辑器确实具有焦点
  • 完美的疯狂程序员,这行得通!如果其他人需要详细信息,我可以使用以下代码实现此目的: table.editCellAt(selectedRow, 0); table.setSurrendersFocusOnKeystroke(true); table.getEditorComponent().requestFocus();非常感谢!!
  • @Zek101 任何带有 Focus 的东西都应该被包装到 invokeLater 中
  • @Zek101 我敢肯定,在 camickr 的博客中,焦点和 TableCellEditor 中是否存在一/二或三倍,再次将焦点(异步)包装到 invokeLater 中

标签: java swing jtable focus tablecelleditor


【解决方案1】:

对于您问题的第二部分,我解决了如下问题:

首先我使用了

table.setCellSelectionEnabled(true);

只是为了确保选择 JTable 中的特定单元格已启用。

然后,我用了

table.changeSelection(int row, int column, false, false);

上面的两个布尔值分别是toggle和extend。 false,这里的false会清除之前的选择,确保新的单元格被选中。

上面的 sn-p 用于选择表格中的特定单元格。我这样做了,所以当我使用 editCellAt() 方法时,它肯定会开始编辑当前选择的单元格。

如果由于任何原因 editCellAt() 无法正常工作,那么您将从 getEditorComponent() 中获得 null。由于目前没有组件正在编辑即您的问题。

table.getEditorComponent()

然后开始编辑我使用的单元格

table.editCellAt(int row, int column);

这用于以编程方式开始编辑单元格组件。

最后让光标闪烁/聚焦在我使用的那个特定单元格上

table().getEditorComponent().requestFocus();

希望这会有所帮助。它对我来说就像魅力一样。如果没有,请告诉我。

简而言之,我添加了以下代码行:

table.setCellSelectionEnabled(true);
table.changeSelection(int row, int column, false, false);
table.editCellAt(int row, int column);
table().getEditorComponent().requestFocus();

【讨论】:

    猜你喜欢
    • 2023-03-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-01
    • 2015-04-28
    • 1970-01-01
    • 2018-01-04
    • 2012-08-26
    相关资源
    最近更新 更多