Как вырезать/копировать/вставить текст в JTextField при нажатии на какой-либо JComponent?

Я создаю пользовательское всплывающее меню, используя только расширенные JComponent в качестве пунктов меню и расширенные JWindow для их хранения. Мой вопрос: как отправить сигнал из экземпляра JComponent при нажатии (имеет MouseListener) в JTextField для выполнения действий вырезания/копирования/вставки?

ИЗМЕНИТЬ:

Постараюсь объяснить точнее.

Класс JTextField (упрощенный):

public class TextInputField extends JTextField implements FocusListener {

        private MenuPopupWindow popUp;

        public TextInputField() {


           popUp = new MenuPopupWindow();//MenuPopupWindow class extends JWindow

           MenuItem paste = new MenuItem("Paste", 
                                         new ImageIcon(getClass().getResource("/images/paste_icon.png")),
                                         "Ctrl+V");//MenuItem class extends JComponent, has implemented MouseListener - and when mouseClicked(MouseEvent e) occurs, somehow action signal have to be sent to this class
            MenuItem copy = ....
            MenuItem cut = ....


            Action pasteAction = getActionMap().get(DefaultEditorKit.pasteAction);
            paste.setAction(pasteAction);//How to make it to work?


            popUp.addMenuItem(paste);
            popUp.addMenuItem(cut);
            popUp.addMenuItem(copy);

        }
        }

Как это сделать правильно?


person Ernestas Gruodis    schedule 12.08.2013    source источник


Ответы (3)


В свете вашего опубликованного кода, я думаю, все, что вам нужно сделать в своем классе TextInputField, это добавить:

paste.addActionListener(pasteAction);

затем в вашем классе MenuItem вы должны ввести код для вызова этих прослушивателей действий.

public class MenuItem implements MouseListener
{
    ...
    @Override public void mouseClicked(MouseEvent event)
    {
        ActionListener[] listeners = (ActionListener[])
            MenuItem.this.getListeners(ActionListener.class);
        for(int i = 0; i < listeners.length; i++)
        {
            listeners[i].actionPerformed
            (
                new ActionEvent(MenuItem.this,someID, someCMDName)
            );
        }
    }

В вашем классе, который расширяет JComponent (я назову его классом «A»), вам нужно будет получить ссылку на ваш JTextField. Простой способ сделать это — добавить закрытую переменную экземпляра типа JTextField в класс A и передать JTextField через конструктор.

поэтому ваш класс должен выглядеть примерно так:

public class A extends JComponent implements ActionListener
{
    private JTextField updateField;

    public A(JTextField updateField[,<your other contructor arguments>...])
    {
        this.updateField = updateField;
        this.addActionListener(this);
    }

    public void actionPerformed(ActionEvent event)
    {
        if(event.getSource().equals(this)
        {
            //copy, paste or do whatever with the JTextField
            //by way of this.updateField;
            //e.g. this.updateField.setText(...);
            //or to simply pass the event along to the JTextField's handlers
            //this.updateField.dispatchEvent(event);
        }
    }
}

тогда вам просто нужно не забыть передать jtextField в конструктор при создании компонента

person S E    schedule 12.08.2013
comment
Это ближе, но хм.. Я реализовал MouseListener в MenuItem, также Action передается из класса TextInputField. Нужно ли мне также внедрять ActionListener в MenuItem? Было бы неплохо использовать только MouseListener. - person Ernestas Gruodis; 13.08.2013
comment
Я пробовал это в классе MenuItem: textField.dispatchEvent(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, DefaultEditorKit.pasteAction)); - но это тоже не работает. - person Ernestas Gruodis; 13.08.2013
comment
о, если вы еще этого не сделали, вам нужно будет вызвать прослушиватели действий в классе пункта меню из обработчиков мыши. Я снова отредактирую способ сделать это. - person S E; 13.08.2013
comment
Действительно спасибо за помощь, наконец-то решил эту проблему - просто сделал: public void mouseClicked(MouseEvent e) { invoker.dispatchEvent(e); } в классе MenuItem, и добавил MouseListener в классе TextInputField, затем Object obj = e.getSource(); if (obj instanceof MenuItem) { if (paste == (MenuItem) obj) { paste(); } ..... } - теперь все работает супер :) - person Ernestas Gruodis; 13.08.2013
comment
рад, что это сработало, пожалуйста, примите ответ или опубликуйте свой собственный, чтобы сайт отметил его как решенный - person S E; 13.08.2013
comment
Так что теперь у меня есть даже 2 способа, как это сделать :) Но я думаю, что отправить MouseEvent из MenuItem в этом случае проще. Спасибо, Аарон, действительно. - person Ernestas Gruodis; 13.08.2013

Я создаю пользовательское всплывающее меню, используя только расширенный JComponent в качестве пунктов меню и расширенный JWindow для их хранения.

Не совсем уверен, что все это значит.

Вы должны просто использовать JPopupMenu и добавить к нему JMenuItems. Прочтите раздел руководства Swing по Вызов всплывающего меню для примера.

Затем, если вам нужны функции вырезания/копирования/вставки, вы можете использовать действия по умолчанию, предоставляемые DefaultEditorKit:

popup.add( new JMenuItem(new DefaultEditorKit.CopyAction()) );
person camickr    schedule 12.08.2013
comment
Спасибо, но это слишком просто для меня, у меня есть цель создать свое собственное всплывающее меню - что уже сделано, просто нужно как-то передать Action/ActionEvent в JTextField. - person Ernestas Gruodis; 13.08.2013
comment
Я не уверен, что это сработает (извините, не было времени проверить), но из чтения источника метод actionPerformed (в основном) выполняет ((JTextComponent)actionEvent.getSource()) для получения JTextComponent из источника события... что было бы в в этом случае JMenuItem.... - person MadProgrammer; 13.08.2013

Итак, мой рабочий пример следует (упрощенно):

    public class TextInputField extends JTextField {

    private MenuPopupWindow popUp;
    private MenuItem copy,
            cut,
            paste,
            selectAll;

    public TextInputField() {

        popUp = new MenuPopupWindow();

        paste = new MenuItem(this, "Paste", new ImageIcon(getClass().getResource("/images/Paste-icon.png")), "Ctrl+V");
        cut = new MenuItem(this, "Cut", new ImageIcon(getClass().getResource("/images/Cut-icon.png")), "Ctrl+X");
        copy = new MenuItem(this, "Copy", new ImageIcon(getClass().getResource("/images/Copy-icon.png")), "Ctrl+C");
        selectAll = new MenuItem(this, "Select All", null, "Ctrl+A");

        popUp.addMenuItem(paste);
        popUp.addMenuItem(cut);
        popUp.addMenuItem(copy);
        popUp.addMenuItem(selectAll);

        addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {

                if (SwingUtilities.isRightMouseButton(e)) {

                    if (getSelectedText() == null) {
                        copy.setEnabled(false);
                        cut.setEnabled(false);
                    } else {
                        copy.setEnabled(true);
                        cut.setEnabled(true);
                    }

                    if (getText().equals("")) {
                        selectAll.setEnabled(false);
                    } else {
                        selectAll.setEnabled(true);
                    }

                    Clipboard c = getToolkit().getSystemClipboard();

                    Transferable t = c.getContents(this);

                    if (t.isDataFlavorSupported(DataFlavor.stringFlavor)) {

                        String s;

                        try {
                            s = (String) t.getTransferData(DataFlavor.stringFlavor);
                            if (s.equals("")) {
                                paste.setEnabled(false);
                            } else {
                                paste.setEnabled(true);
                            }
                        } catch (UnsupportedFlavorException | IOException ex) {
                            Logger.getLogger(TextInputField.class.getName()).log(Level.SEVERE, null, ex);
                        }

                    } else {
                        paste.setEnabled(false);
                    }

                    popUp.setLocation(e.getXOnScreen(), e.getYOnScreen());
                    getCaret().setVisible(false);
                    popUp.setVisible(true);
                } else {
                    Object obj = e.getSource();
                    if (obj instanceof MenuItem) {
                        MenuItem menuItem = (MenuItem) obj;
                        if (paste == menuItem) {
                            paste();
                        } else if (cut == menuItem) {
                            cut();
                        } else if (copy == menuItem) {
                            copy();
                        } else if (selectAll == menuItem) {
                            selectAll();
                        }
                    }

                    getCaret().setVisible(true);
                    popUp.setVisible(false);
                }
            }
        });
   }
}

И в классе MenuItem добавлено (упрощено):

@Override
public void mouseClicked(MouseEvent e) {
    textField.dispatchEvent(e);
}

Отлично работает :)

Решил использовать Component вместо JComponent в классе MenuItem, потому что нет необходимости в конструкторах paintComponent, paintBorder и paintChildren - экономия ресурсов.

person Ernestas Gruodis    schedule 12.08.2013