[SWING] Problem z TableCellEditor

0

Cześć wszystkim,

problem dotyczy TableCellEditor w JTable. O co chodzi:
Mam tabelkę JTable i chcę mieć w niej swój edytor wartości komórki. Utworzyłem dlatego klasę:

public class TimeCellEditor extends AbstractCellEditor implements TableCellEditor{
    String value;
    TimeEditor te;
    public TimeCellEditor() {
        super();
        te = new TimeEditor();
    }
    @Override
    public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
        TableModel tm = table.getModel();
        te.setText(""+tm.getValueAt(row, column));
        return te;
    }
    
    @Override
    public Object getCellEditorValue() {
        return te.getText();
    }
    
}

oraz zrobiłem komponent TimeEditor rozszerzający JTextField:

public class TimeEditor extends JTextField implements KeyListener, FocusListener {

    public TimeEditor() {
       super();
       this.addFocusListener(this);
       this.addKeyListener(this);
    }

    TimeEditor(String text) {
        super(text);
        this.addFocusListener(this);
        this.addKeyListener(this);
    }

    @Override
    public void keyTyped(KeyEvent e) {
        System.out.println("X");
        if (e.getKeyChar() >= '0' && e.getKeyChar() <= '9') {
            int caret = this.getCaretPosition();
            if (caret > 4) {
                caret = 4;
            }
            if (caret == 2)
                caret++;
            
            StringBuilder sb = new StringBuilder(this.getText());
            sb.setCharAt(caret, e.getKeyChar());
            this.setText(sb.toString());
            this.setCaretPosition(caret+1);
        }
        e.consume();
    }

    @Override
    public void keyPressed(KeyEvent e) {
        if (e.getKeyChar() == KeyEvent.VK_BACK_SPACE) {
            int caret = this.getCaretPosition();
            if (caret > 0)
                caret--;
            if (caret == 2) {
                caret = 1;
            }
            StringBuilder sb = new StringBuilder(this.getText());
            sb.setCharAt(caret, '_');
            this.setText(sb.toString());
            this.setCaretPosition(caret);
            e.consume();
        }
        
    }

    @Override
    public void keyReleased(KeyEvent e) {
    }

    @Override
    public void focusGained(FocusEvent e) {
        this.setCaretPosition(0);
    }

    @Override
    public void focusLost(FocusEvent e) {
        
    }
    
}

Zarejestrowałem edytory:

jtTimeWindows.getColumnModel().getColumn(0).setCellEditor(new TimeCellEditor());
jtTimeWindows.getColumnModel().getColumn(1).setCellEditor(new TimeCellEditor());

Jeżeli do uruchomienia edycji komórki używam myszki, wszystko działa poprawnie. Odpala się edytor TimeEditor. Problemy pojawiają się jak chcę rozpocząć edycję z klawiatury. Zaznaczając komórkę i wciskając "backspace"(lub F2 lub literkę) uruchamia się domyślny edytor JTextField.

Może mi ktoś pomóc w tym, jak zrobić, aby ten sam edytor uruchamiał się po kliknięci i po interakcji z klawiatury?

0

sprawdź czy w ogóle po wciśnięciu klawisza wchodzi ci do metod keypressed i keyTyped. Np umieść w nich System.out.println("pressed") i sprawdź czy wyrzuca coś na konsoli.

0

W przypadku startu edycji "przez mysz" do metod wchodzi, w przypadku edycji "przez klawiaturę" niestety nie.
Spróbję teraz przeanalizować jak zaimplementowany jest DefaultCellEditor. Jest tam coś co się nazywa "EditorDelegate",
i "przejmuje" zdarzenia z celleditora, może tutaj tkwi problem?

Edit 1:
Zauważyłem, że w przypadku edycji "przez klawiaturę" po uruchomieniu edytora zdarzenia keyTyped wędrują do obiektu JTable,
a nie do komponentu odpowiedzialnego za edycję :/

Edit 2:
Problem rozwiązałem tak:

W JFrame utworzyłem jeden obiekt TimeEditor.
Potem utworzyłem obiekt TimeCellEditor, do którego przekazałem TimeEditor.
Dodałem CellEditor do JTable.
W JFrame forwarduje zdarzenia z tabel do TimeEditor.

0

Zdarzenie klawiaturowe wędruje do tego komponentu, który ma fokus. W jaki sposób (bez użycia myszy) przenosisz fokus na komórkę?

0

Hmm... "Focus"a ręcznie nie ustawiałem. Do tej pory myślałem, ze jeżeli zmieniam zaznaczenie komórki z klawiatury to focus przenosi się automatycznie.
Spróbuje zrobić focus na edytora, w momencie kiedy jest on pobierany przez CellEditora.

Edit:
Dodałem w funkcji: getTableCellEditorComponent()
wywołanie metody requestFocus() / requestFocusInWindow(), ale niestety komponent TimeEditor nie dostaje focusa :/

0

Trochę nie rozumiem, wędrujesz po tabeli przy pomocy strzałek, i wtedy focus ma tabela. Chcesz edytować aktualną komórkę, zatem fokus ma się jakoś cudownie przenieść na komórkę?

0

Wędruje sobię strzałkami po tabeli, ok focus ma tabela. Zaczynam coś pisać lub wciskam np. backspace, wtedy pojawia się CellEditor Myślałem, że on z automatu dostanie focusa (co się dzieje w przypadku klikania myszką).

0

Spróbuj tak:

jtTimeWindows.getColumnModel().getColumn(0).setCellEditor(new DefaultCellEditor(new TimeCellEditor()));

TimeCellEditor nie musi chyba wtedy implementować listenerów.

0

DefaultCellEditor jako parametr konstruktora przyjmuje: JTextField, JComboBox lub JCheckBox,

dlatego spróbowałem:

jtTimeWindows.getColumnModel().getColumn(0).setCellEditor(new DefaultCellEditor(new TimeEditor()));

Efekt ten sam. Po kliknięciu myszką - jest TimeEditor, po naciśnięciu klawiatury - zwykły JTextField.

Problemem tutaj chyba jest ustawienie Focus'a na edytora. W przypadku myszy, focus jest ustawiany z automatu,
w przypadku klawiatury nie. Ręczne wywołanie metody requestFocus() z getTreeCellEditorComponent() nie działa (na komponencie TimeEditor), muszę pokombinować, jak ustawić ten focus.

0

Wstępnie pomogło ustawienie w tabeli:

jTable1.setSurrendersFocusOnKeystroke(true);

w takim wypadku tabela oddaje focus CellEditor'owi. Jeszcze tego dokładnie nie przetestowałem, ale to będzie chyba to.

1 użytkowników online, w tym zalogowanych: 0, gości: 1