[英]Lose selection of a JTable cell
當您單擊JTable單元格時,該行將變為“已選擇”,因此,當我單擊其他任何內容時,該行將變為未選中狀態。
我正在考慮使用桌子上的鼠標偵聽器來執行此操作,但不確定如何識別(不在桌子上單擊)。 有任何想法嗎?
這是我正在嘗試的:
jTable.addMouseListener(new MouseAdapter(){
@Override
public void mouseClicked(MouseEvent e){
System.out.println("click");}});
但是,當我單擊第一列時,它只會打印單擊,而當我單擊非表中的內容時,則不會打印。
當我識別出該事件時,將調用此方法:
public void loseCellFocus()
{
jTable.getCellEditor().stopCellEditing();
jTable.clearSelection();
}
使用附加到JTable
的FocusListener
,這將告訴您焦點何時移離表。
有關更多詳細信息,請參見如何編寫焦點偵聽器 。
例如...
table.addFocusListener(new FocusAdapter() {
@Override
public void focusLost(FocusEvent e) {
loseCellFocus();
}
});
當然,這僅在將鍵盤焦點轉移到能夠接收鍵盤焦點的新組件時才有效
一旦我單擊任何調用的單元格,就會立即調用我的LosCellFocus()方法
您可以使用JTable#setSurrendersFocusOnKeystroke
或檢查以將焦點轉移到的組件是否是JTable
的子級
例如...
table.addFocusListener(new FocusAdapter() {
@Override
public void focusLost(FocusEvent e) {
if (e.getOppositeComponent().getParent() != table) {
loseCellFocus();
}
}
});
好的,那太亂了。 我不僅必須向JTable
添加FocusListener
,而且還必須確保將其中一個添加到TableCellEditor
組件:P
這只是一個概念證明,我將擁有專門的類,這些類能夠通過一些公共接口引發事件或觸發所需的功能
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.EventQueue;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import javax.swing.DefaultCellEditor;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.JViewport;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.EmptyBorder;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellEditor;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new BorderLayout());
JTable table = new JTable(new DefaultTableModel(10, 10));
JTextField editorField = new JTextField(10);
editorField.setBorder(new EmptyBorder(1, 1, 1, 1));
editorField.addFocusListener(new FocusAdapter() {
@Override
public void focusLost(FocusEvent e) {
TableCellEditor cellEditor = table.getCellEditor();
if (cellEditor != null) {
if (!cellEditor.stopCellEditing()) {
cellEditor.cancelCellEditing();
}
}
Component gotFocus = e.getOppositeComponent();
if (!gotFocus.equals(table)) {
table.clearSelection();
}
}
});
DefaultCellEditor editor = new DefaultCellEditor(editorField);
table.setDefaultEditor(Object.class, editor);
add(new JScrollPane(table));
table.addFocusListener(new FocusAdapter() {
@Override
public void focusLost(FocusEvent e) {
Component gotFocus = e.getOppositeComponent();
if (!gotFocus.getParent().equals(table)) {
TableCellEditor cellEditor = table.getCellEditor();
if (cellEditor != null) {
if (!cellEditor.stopCellEditing()) {
cellEditor.cancelCellEditing();
}
}
table.clearSelection();
}
}
});
JTextField field = new JTextField(10);
add(field, BorderLayout.SOUTH);
}
}
}
好的,因為沿着混亂的局面結束了,所以我真的不想走這條路。 基本上,這會監視所有MouseEvent
和FocusEvent
,它會進行一些向后求和的結果以測試有效條件(因為我們不僅需要確保JTable
是事件的一部分,而且要確保編輯器是事件的一部分),並且基於根據這些結果,停止單元格編輯並清除選擇...
import java.awt.AWTEvent;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.KeyboardFocusManager;
import java.awt.Toolkit;
import java.awt.event.AWTEventListener;
import java.awt.event.FocusEvent;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.EmptyBorder;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellEditor;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
JTable table = new JTable(new DefaultTableModel(5, 5));
setLayout(new GridBagLayout());
setBorder(new EmptyBorder(20, 20, 20, 20));
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
add(new JScrollPane(table), gbc);
add(new JTextField(10), gbc);
Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {
@Override
public void eventDispatched(AWTEvent event) {
if (event instanceof FocusEvent) {
FocusEvent focusEvent = (FocusEvent) event;
if (focusEvent.getID() == FocusEvent.FOCUS_LOST) {
Component focusTo = focusEvent.getOppositeComponent();
Component focusFrom = focusEvent.getComponent();
JTable table = getTableFrom(focusFrom);
if (focusTo == null || !focusTo.getParent().equals(table)) {
stopCellEditing(table);
clearSelection(table);
}
}
} else if (event instanceof MouseEvent) {
MouseEvent mouseEvent = (MouseEvent) event;
if (mouseEvent.getID() == MouseEvent.MOUSE_CLICKED) {
Component focusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
JTable table = getTableFrom(focusOwner);
System.out.println(" table = " + table);
System.out.println("focusOwner = " + focusOwner);
// if ((table != null && mouseEvent.getComponent() != table) || (focusOwner != null && !focusOwner.getParent().equals(table))) {
if ((table != null && mouseEvent.getComponent() != table) && (focusOwner != null && !focusOwner.getParent().equals(table))) {
stopCellEditing(table);
clearSelection(table);
}
}
}
}
protected JTable getTableFrom(Component component) {
JTable table = null;
if (component instanceof JTable) {
table = (JTable) component;
} else if (component != null && component.getParent() instanceof JTable) {
table = (JTable) component.getParent();
}
return table;
}
protected void clearSelection(JTable table) {
if (table != null) {
table.clearSelection();
}
}
protected void stopCellEditing(JTable table) {
if (table != null) {
TableCellEditor cellEditor = table.getCellEditor();
if (cellEditor != null) {
if (!cellEditor.stopCellEditing()) {
cellEditor.cancelCellEditing();
}
}
}
}
}, AWTEvent.FOCUS_EVENT_MASK | AWTEvent.MOUSE_EVENT_MASK);
}
}
}
此示例基本上適用於ALL JTable
(一旦注冊了AWTEventListener
),但是您可以通過更改一些事件源並將它們相互比較來將其配置為監視單個表:P
我有時用JTree
做到這一點。 焦點偵聽器等無效。 最后,我使用的解決方案是使用Toolkit.getDefaultToolkit().addAWTEventListener
並捕獲鍵盤和鼠標事件。 在事件的組件層次結構中查找JTree
,然后調用一個方法來刪除選擇(如果該項目不屬於該樹)。
如果需要,我可以搜索代碼。
編輯
接受的答案中的AWTEventListener比所需的要復雜一些。
final AWTEventListener focusTracker = new AWTEventListener() {
@Override public void eventDispatched(AWTEvent event) {
if (event.getID() != MouseEvent.MOUSE_CLICKED && event.getID() != KeyEvent.KEY_PRESSED)
return;
if (!isPartOfTable((Component) event.getSource())) {
if (table.isEditing()) {
TableCellEditor cellEditor = table.getCellEditor();
cellEditor.cancelCellEditing();
}
table.clearSelection();
table.dispatchEvent(new FocusEvent(table, FocusEvent.FOCUS_LOST));
}
}
protected boolean isPartOfTable(Component component) {
while (component != null && component != table)
component = component.getParent();
return component == table;
}
};
Toolkit.getDefaultToolkit().addAWTEventListener(focusTracker, AWTEvent.KEY_EVENT_MASK | AWTEvent.MOUSE_EVENT_MASK);
注意:當框架關閉時,您需要刪除偵聽器。 我不希望在外部單擊時仍突出顯示表格單元格。 因此,我將焦點丟失事件發布到表上。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.