【发布时间】: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
有人建议吗?
【问题讨论】:
-
两件事。尝试设置
JTable的SurrendersFocusOnKeystroke属性并确保编辑器确实具有焦点 -
完美的疯狂程序员,这行得通!如果其他人需要详细信息,我可以使用以下代码实现此目的: table.editCellAt(selectedRow, 0); table.setSurrendersFocusOnKeystroke(true); table.getEditorComponent().requestFocus();非常感谢!!
-
@Zek101 任何带有 Focus 的东西都应该被包装到 invokeLater 中
-
@Zek101 我敢肯定,在 camickr 的博客中,焦点和 TableCellEditor 中是否存在一/二或三倍,再次将焦点(异步)包装到 invokeLater 中
标签: java swing jtable focus tablecelleditor