java - 在特定的 JTable 单元格上设置焦点和闪烁光标

标签 java swing jtable focus tablecelleditor

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

当用户在我的 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)情况:

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) 无过滤器:已选择行,但尚未单击编辑 JButton。

enter image description here

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

enter image description here

现在有问题的行为:

1) 过滤条件:行已被选中,但编辑 JButton 尚未被点击。 enter image description here

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

enter image description here

这里是 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

有什么建议吗?

最佳答案

对于你问题的第二部分,我是这样解决的:

首先我使用了

table.setCellSelectionEnabled(true);

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

然后,我用

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

上面的两个 boolean 值分别是 toggle 和 extend。 false,此处为 false 将清除之前的选择并确保选择新的单元格。

上面的代码片段用于选择表格中的特定单元格。我这样做了,这样当我使用 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();

关于java - 在特定的 JTable 单元格上设置焦点和闪烁光标,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24643909/

相关文章:

java - 使用 Gson 序列化匿名类

java - 如何在 Java 上的 JTable 中填充 Excel 的某些行?

java - 如果在两个选定值之间,则会自动选择插入自定义 ListModel 的元素

java - 显示数据库中的 JTable 和计算公式

java - 如何从 JTable 中删除所有列?

java - JTable - Boolean.class 单元格渲染器和 Nimbus 外观的问题

java - 使用 lwjgl 将值从我的 Java 程序传递到 GLSL

java - $and条件不适用于springboot mongodb中的三个或三个以上字段

java - JPA 删除注释

java - 按键不起作用