Качаем - как захватить фокус * сейчас *? - PullRequest
3 голосов
/ 02 августа 2010

Как я могу дать указание моему компоненту Swing захватить фокус прямо сейчас ?requestFocus(), кажется, не отправляется мгновенно.

В идеале, я хотел бы, чтобы (бег от EDT):

textInput.requestFocusInWindow();
System.out.println(textInput.hasFocus());

Для печати true.

Ниже SSCCE.Примечания / требования:

  1. Таблица перемещается с помощью клавиатуры.Столбец C2 имеет составной редактор.
  2. Когда я набираю букву в столбце C2, начинается редактирование.Текстовый компонент внутри составного редактора получает фокус.Нужно набрать письмо, которое запустил редактор.Реализация этого пункта отмечена комментариями с надписью «Уловка».
  3. Текстовое поле - сторонний редактор, у которого слушатель фокуса вмешивается в мой код.Здесь он имитируется как selectAll().

. В настоящее время порядок отправки такой: введите букву в текстовый компонент, затем отправьте фокус слушателям.Затем следующие буквы отправляются правильно, потому что это текстовое поле, которое имеет фокус.

Мне нужно, чтобы оно установило фокус на текстовом компоненте, направило слушателей фокуса и затем передало ему ключевое событие.


public class JTableIssue extends JFrame {
    public JTableIssue() {
        JTable table = new JTable(new Object[][] {
                { "Apple", "Orange", "Strawberry" },
                { "Pineapple", "Orange", "Zergz" } }, new Object[] { "C1",
                "C2", "C3" });
        table.getColumn("C2").setCellEditor(new MyEditor());
        add(new JScrollPane(table));
        pack();
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    public static void main(String[] args) {
        new JTableIssue().setVisible(true);
    }
}

class MyEditor extends AbstractCellEditor implements TableCellEditor {
    MyTextField textField = new MyTextField();
    JPanel panel;

    MyEditor() {
        panel = new JPanel(new BorderLayout()){
            // Trick: Pass all key typed to text field
            @Override
            protected boolean processKeyBinding(KeyStroke ks, KeyEvent e,
                    int condition, boolean pressed) {
                if (ks.getKeyEventType() == KeyEvent.KEY_TYPED) {
                    textField.processKeyBinding(ks, e, condition, pressed);
                }
                return super.processKeyBinding(ks, e, condition, pressed);
            }
        };
        textField.addFocusListener(new FocusAdapter() {
            @Override
            public void focusGained(FocusEvent e) {
                textField.selectAll();
            }
        });
        panel.add(textField, BorderLayout.CENTER);
        // Trick: Pass focus to text field when editor is added to table
        panel.addAncestorListener(new AncestorListener() {
            public void ancestorRemoved(AncestorEvent event) {
            }

            public void ancestorMoved(AncestorEvent event) {
            }

            public void ancestorAdded(AncestorEvent event) {
                textField.requestFocus();
            }
        });
    }

    public Object getCellEditorValue() {
        return textField.getText();
    }

    public Component getTableCellEditorComponent(JTable table, Object value,
            boolean isSelected, int row, int column) {
        textField.setText(value.toString());
        return panel;
    }
}

class MyTextField extends JTextField {
    // Trick: "public"
    @Override
    public boolean processKeyBinding(javax.swing.KeyStroke ks,
            java.awt.event.KeyEvent e, int condition, boolean pressed) {
        return super.processKeyBinding(ks, e, condition, pressed);
    };
}

Ответы [ 3 ]

2 голосов
/ 03 августа 2010

Я понял это.

  1. События в AncestorListener и processKeyBinding() являются частью обработки одного и того же события: "типизирован ключом".
  2. Видимо, единственный способзахватить фокус - requestFocus(), который добавляется в очередь событий после того, как текущий поток событий вызван «набранным ключом».Поэтому захват фокуса и выполнение FocusListener s всегда будут выполняться позже.

Решение: В processKeyBinding() не передавайте ключ внутреннему компоненту немедленно.Поставьте его в очередь событий, чтобы он выполнялся после передачи фокуса и слушателей.То есть обернуть:

if (ks.getKeyEventType() == KeyEvent.KEY_TYPED) {
    textField.processKeyBinding(ks, e, condition, pressed);
}

В SwingUtilities.invokeLater().

0 голосов
/ 03 августа 2010

Я не вижу, как управлять порядком событий, и в целом это не то, что вы должны пытаться сделать.

3. Текстовое поле - сторонний редактор, который имеетслушатель фокуса, мешающий моему коду

Может быть, вы можете удалить FocusListener из редактора.Возможно, вы сможете вызвать слушателя напрямую, используя

savedFocusListener.focusGained(FocusEvent);

в коде AncestorListener, который фокусируется на текстовом поле.

0 голосов
/ 02 августа 2010

Я не думаю, что это возможно.Действия пользовательского интерфейса по своей природе асинхронные (хотя обычно очень быстрые), и невозможно заставить их вести себя синхронно.Если вам это действительно нужно, вы можете запустить событие в обработчике фокуса ввода текста и ждать этого события в другом потоке.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...