Как я могу заставить JTextField запустить его ActionEvent, когда KeyEvent.VK_ENTER повторно отправляется на него? - PullRequest
2 голосов
/ 22 февраля 2011

Я играю с KeyboardFocusManager и моим собственным кастомом KeyEventDispatcher, который перераспределяет все KeyEvent с одного конкретного JTextField, независимо от фокуса внутри JFrame. Это работает как талисман, когда речь идет о текстовом вводе, но я также хочу, чтобы JTextField отправлял свой текст на JTextArea, когда к нему пересылается KeyEvent.VK_ENTER. По какой-то причине он просто не будет этого делать. Я установил actionListener на JTextField, который будет запускаться, если у меня есть курсор в текстовом поле и нажимаю ENTER, однако он не запускается, если событие ENTER происходит из KeyboardFocusManager.redispatchEvent(keyEvent).

Я также пытался перераспределить ActionEvent вместо неизмененного KeyEvent в случае нажатия ENTER, но безрезультатно :( Можно подумать, что при передаче ActionEvent компоненту будут запущены его ActionListeners, но нет.

Может кто-нибудь объяснить, почему это так? А может предложить аккуратный способ обойти это?

SSCCE:

package viewlayer.guiutil.focus;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.lang.Runnable;import java.lang.String;
import java.util.Date;

public class Test extends JFrame
{
    private JTextField m_chatInput;
    private JTextArea m_textArea;

    public static void main(String... args)
    {
        Test test1 = new Test();
        test1.run(test1);
    }

    public void run(final Test test)
    {
        test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        test.setSize(250, 400);

        KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(new MyKeyEventDispatcher());

        SwingUtilities.invokeLater(new Runnable()
        {
            public void run()
            {
                test.init();
            }
        });

        test.setVisible(true);
    }

    public void init()
    {
        JPanel panel = new JPanel (new GridBagLayout());
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.insets = new Insets(2,5,1,1);
        gbc.weightx = 1.0;
        gbc.anchor = GridBagConstraints.WEST;
        gbc.gridwidth = GridBagConstraints.REMAINDER;

        JLabel chatLabel = new JLabel("Chat input field:");
        panel.add(chatLabel,gbc);

        m_chatInput = new JTextField(15);
        m_chatInput.setActionCommand(MyActionListener.ACTION_PERFORMED);
        m_chatInput.addActionListener(new MyActionListener());
        panel.add(m_chatInput,gbc);

        JTextField chatInput = new JTextField(15);
        panel.add(chatInput,gbc);

        JLabel text = new JLabel("chat history:");
        panel.add(text,gbc);

        m_textArea = new JTextArea(5, 15);
        m_textArea.setFocusable(false);
        panel.add(m_textArea,gbc);

        JButton postButton = new JButton("Post");
        postButton.setActionCommand(MyActionListener.ACTION_PERFORMED);
        postButton.addActionListener(new MyActionListener());
        panel.add(postButton,gbc);
        gbc.weighty = 1.0;
        gbc.anchor = gbc.NORTHWEST;

        setLayout(new FlowLayout(FlowLayout.LEFT));
        add(panel);
    }

    private class MyKeyEventDispatcher implements KeyEventDispatcher
    {
        public boolean dispatchKeyEvent(KeyEvent keyEvent)
        {
            KeyboardFocusManager.getCurrentKeyboardFocusManager().redispatchEvent(m_chatInput, keyEvent);

            return false;
        }
    }

    private class MyActionListener implements ActionListener
    {
        private static final String ACTION_PERFORMED = "ACTION_PERFORMED";

        public void actionPerformed(ActionEvent actionEvent)
        {
            if(actionEvent.getActionCommand().equals(ACTION_PERFORMED))
            {
                Date date = new Date(System.currentTimeMillis());
                m_textArea.append(date.getHours() +":"+ date.getMinutes() +":"+ date.getSeconds() + " - " + m_chatInput.getText() + "\n");
                m_chatInput.setText("");
            }
        }
    }
}

Ответы [ 3 ]

3 голосов
/ 22 февраля 2011

Код текстового поля имеет тест, чтобы убедиться, что компонент имеет фокус перед вызовом кода слушателя:

    public void actionPerformed(ActionEvent e) {
        JTextComponent target = getFocusedComponent();
        if (target instanceof JTextField) {
            JTextField field = (JTextField) target;
            field.postActionEvent();
        }
    }

Однако вы должны иметь возможность вызывать метод postActionEvent () непосредственно из вашего KeyEventDispatcher:

if (enter key)
   m_chatInput.postActonEvent();
else
   // redispatch the event
0 голосов
/ 22 февраля 2011

Я думаю, я нашел обходной путь, который вы можете использовать, чтобы сосредоточиться на chatInput:

requestFocusInWindow(m_chatInput);
KeyboardFocusManager focusManager =
KeyboardFocusManager.getCurrentKeyboardFocusManager();
focusManager.addPropertyChangeListener(
    new PropertyChangeListener() {
        public void propertyChange(PropertyChangeEvent e) {
            String prop = e.getPropertyName();
            if ("focusOwner".equals(prop)) {
            requestFocusInWindow(m_chatInput);
            }
        }
    }
 );

Я изменил это, основываясь на некотором коде, найденном по адресу:

http://download.oracle.com/javase/tutorial/uiswing/misc/focus.html

0 голосов
/ 22 февраля 2011

Вы должны удалить эту строку:

m_chatInput.setFocusable(false);

и выше линии:

Date date = new Date(System.currentTimeMillis());

Вы должны вставить:

requestFocusInWindow(m_chatInput);

Пожалуйста, напишите, если это сработало для вас или нам нужно немного подправить.

...