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

Zek*_*101 7 java swing focus jtable tablecelleditor

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

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

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

由于isEditable()方法,我可以成功设置行是否可编辑,我table.editCellAt(selectedRow, 0)用来开始编辑.

然而

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

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

有关如何实现这一目标的任何建议?

//////////////////// UPDATE //////////////////////

虽然MadProgrammer的评论解决了这个问题,但它只解决了部分问题,但那是因为我还不够精确.

实际上,当我执行他用"经典JTable"描述的步骤时,即:

table.editCellAt(selectedRow, 0);
table.setSurrendersFocusOnKeystroke(true);
table.getEditorComponent().requestFocus();
Run Code Online (Sandbox Code Playgroud)

我得到闪烁的光标和立即键入的能力.

然而,缺少的部分是我给用户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)
Run Code Online (Sandbox Code Playgroud)

以下是导致异常的行:

table.getEditorComponent().requestFocus();
Run Code Online (Sandbox Code Playgroud)

以下是该软件的实际行为:

1)没有过滤器:选择了行,但尚未单击编辑JButton.

在此输入图像描述

2)没有过滤器:点击JButton - >预期正确的行为.

在此输入图像描述

现在有问题的行为:

1)过滤:选择行,但尚未单击编辑JButton. 在此输入图像描述

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

在此输入图像描述

以下是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
Run Code Online (Sandbox Code Playgroud)

这是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
Run Code Online (Sandbox Code Playgroud)

有人建议吗?

小智 3

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

首先我使用了

table.setCellSelectionEnabled(true);
Run Code Online (Sandbox Code Playgroud)

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

然后,我用了

table.changeSelection(int row, int column, false, false);
Run Code Online (Sandbox Code Playgroud)

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

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

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

table.getEditorComponent()
Run Code Online (Sandbox Code Playgroud)

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

table.editCellAt(int row, int column);
Run Code Online (Sandbox Code Playgroud)

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

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

table().getEditorComponent().requestFocus();
Run Code Online (Sandbox Code Playgroud)

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

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

table.setCellSelectionEnabled(true);
table.changeSelection(int row, int column, false, false);
table.editCellAt(int row, int column);
table().getEditorComponent().requestFocus();
Run Code Online (Sandbox Code Playgroud)