JTable cell focus bleibt

jtable
focus
cell

#1

Bei einer JTable zeige ich auf Klick in eine Zeile einen detailierteren Dialog an. Das klappt soweit auch gut. Die Tabelle wurde mit

table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);

erstellt. Wenn ich nach Beendigung des Dialogs “wieder zurück” bin, versuche ich die Selektion in der Tabelle zu entfernen mit:

    table.clearSelection();

Die schwarze Selektion der Zeile verschwindet auch, leider wird, wenn die Tabelle den Fokus wieder erhält, nachdem der andere Dialog weg ist, ein blauer kleiner Rahmen um die Zelle gezeichnet, in die ich geklickt habe.

Ich habe auch schon versucht, mit der Hilfklasse

[code]import java.awt.Component;
import java.awt.Container;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;

import javax.swing.DefaultCellEditor;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.border.EmptyBorder;
import javax.swing.table.TableCellEditor;

public class CellFocusLoosingTable extends JTable {

private static final long serialVersionUID = 1L;

public CellFocusLoosingTable() {
    addLoosingCellEditor();
    addLoosingFocusListener();
}

private void addLoosingCellEditor() {
    JTextField editorField = createCellEditorField();
    DefaultCellEditor editor = new DefaultCellEditor(editorField);
    setDefaultEditor(Object.class, editor);
}

private JTextField createCellEditorField() {
    JTextField editorField = new JTextField(10);
    editorField.setBorder(new EmptyBorder(1, 1, 1, 1));
    editorField.addFocusListener(new FocusAdapter() {
        @Override
        public void focusLost(FocusEvent event) {
            editorFocusLost(event);
        }
    });
    return editorField;
}

private void editorFocusLost(FocusEvent event) {
    TableCellEditor cellEditor = getCellEditor();
    if (cellEditor != null) {
        if (!cellEditor.stopCellEditing()) {
            cellEditor.cancelCellEditing();
        }
    }

    Component gotFocus = event.getOppositeComponent();
    if (!this.equals(gotFocus)) {
        clearSelection();
    }
}

private void addLoosingFocusListener() {
    addFocusListener(new FocusAdapter() {
        @Override
        public void focusLost(FocusEvent event) {
            tableFocusLost(event);
        }
        @Override
        public void focusGained(FocusEvent event) {
            // nix
        }
    });
}

private void tableFocusLost(FocusEvent event) {

// getSelectionModel().clearSelection(); Auch nicht.
//
Component gotFocus = event.getOppositeComponent();
if (gotFocus != null) {
Container parent = gotFocus.getParent();
if (parent != null) {
if (!parent.equals(this)) {
TableCellEditor cellEditor = getCellEditor();
if (cellEditor != null) {
if (!cellEditor.stopCellEditing()) {
cellEditor.cancelCellEditing();
}
}
clearSelection();
}
}
}
}

}[/code]

zu arbeiten, vergeblich.

Ich habe auch schon viel gegoogelt, es finden sich zahlreiche Beispiele:

Das klappt auch immer ganz wunderbar, wenn man den Focus woanders hat. Aber mein Problem ist, dass die Tabelle den Focus ja zurückerhält.

Ich habe auch schon versucht, einen FocusListener zu verwenden, der bei focusGained() reagiert, ohne Erfolg.

Bevor ich jetzt ein KSKB bastel, wollte ich hören, ob das Problem nicht schon eh jemandem bekannt ist. Sonst mach ich das gern, falls jemand mitbasteln möchte.


#2

Ein nicht angezeigtes andere Element, wie ein JTextField, das danach den Fokus zugewiesen bekommt, hilft. Nicht so richtig elegant…

Inzwischen habe ich allerdings eh schon ein anderes Feld in der Gui, da ist das nicht ganz so schlimm. Trotzdem wäre es wünschenswert, wenn man dieses Verhalten abstellen könnte.


#3

der TableCellRenderer malt Border wenn hasFocus = true übergeben bekommen,
die JTable richtet sich dazu nach getLeadSelectionIndex() im SelectionModel,

was zu beeinflussen ist wohl nicht ganz leicht, wobei ich gerade beim Codebeispiel aus


mit

if (row == -1) { t.clearSelection(); ListSelectionModel m = t.getSelectionModel(); m.setAnchorSelectionIndex(-1); m.setLeadSelectionIndex(-1); }
erfolgreich bin, aber wie stabil sowas ist…,

grundsätzlich wie so vieles von Swing kaum als variabel vorgesehen

meine Ideen zum härteren Eingriff wären:

  • eigenes SelectionModel mit genauer Kontrolle über LeadSelection,

  • oder JTable überschreiben zu prepareRenderer, immerhin nur eine public-Methode,
    hauptsächlich mit Beschäfigung zu just diesem Focus, recht ideal für Überschreiben,
    hier von grepcode:

[code] public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
Object value = getValueAt(row, column);
boolean isSelected = false;
boolean hasFocus = false;

    // Only indicate the selection and focused cell if not printing
    if (!isPaintingForPrint()) {
        isSelected = isCellSelected(row, column);

        boolean rowIsLead = (selectionModel.getLeadSelectionIndex() == row);
        boolean colIsLead = (columnModel.getSelectionModel().getLeadSelectionIndex() == column);
        hasFocus = (rowIsLead && colIsLead) && isFocusOwner();
    }
    return renderer.getTableCellRendererComponent(this, value, isSelected, hasFocus, row, column);
}

[/code]