3

Вопрос по swing, java – Как заставить двух JPanels слушать одно и то же событие?

у меня естьJFrame и внутри этогоJFrame есть дваJPanels. Когда я нажимаю клавишу, они оба должны слушать это ключевое событие и действовать. Я хочу взять все события клавиатуры и доставить их обоимJPanels. Ты знаешь как это сделать?

Изменить: Поскольку они должны делать разные вещи, мне нужны два разных слушателя, извините за не конкретность.

Edit2: я сделал простой код, чтобы показать вам проблему. Когда я нажимаю клавишу вверх, оба изJPanelотображаемые s должны изменить свою строку; в этом коде только один из них фактически реагирует!

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;

/**
*
 * @author antonioruffolo
 */
public class TwoPanelsTest extends JFrame {

public TwoPanelsTest() {

    setDefaultCloseOperation(EXIT_ON_CLOSE);
    setResizable(false);
    setSize(800, 600);

    PanelTest panelTest1= new PanelTest();
    PanelTest panelTest2= new PanelTest();

    GridBagLayout layout= new GridBagLayout();
    this.setLayout(layout);

    GridBagConstraints c = new GridBagConstraints();

    c.ipadx = 220;
    c.ipady = 390;
    c.insets.right= 0;
    c.insets.left=30;
    layout.setConstraints(panelTest1, c);
    this.add(panelTest1);

    layout.setConstraints(panelTest2, c);
    c.ipadx = 220;
    c.ipady = 390;
    c.insets.right=250;
    c.insets.left=50;
    this.add(panelTest2);


    setVisible(true);
    setLocationRelativeTo(null);
    setTitle("Test");
    setFocusable(false);
}

private class PanelTest extends JPanel{

    private String string="I'm not called by the event";
    private InputMap inputmap;
    private ActionMap actionmap;

    public PanelTest(){
        setFocusable(false);
        setDoubleBuffered(true);

        this.setBackground(Color.WHITE);
        inputmap = getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
        inputmap.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), "up");
        actionmap = getActionMap();
        actionmap.put("up", new ActionController(this));
    }

    public void setString(String string){
        this.string=string;
    }

    @Override
    public void paintComponent( Graphics g){
        super.paintComponent(g);

        Font infoFont= new Font("OCR A Std", Font.BOLD, 10);
        g.setFont(infoFont);
        g.drawString(string, 10, 50);
    }
}//PanelTest

private class ActionController extends AbstractAction{

    private PanelTest panel;

    public ActionController (PanelTest panel){
        this.panel=panel;
    }

    @Override
    public void actionPerformed(ActionEvent ae) {
        panel.setString("Action performed");
        panel.repaint();
    }

}

public static void main(String[] args) {
    TwoPanelsTest t = new TwoPanelsTest();
}
}
  • @ AR89: я понимаю, что ты имеешь в виду. Я добавил пример выше.

    от
  • Я знаю, что лучше использовать KeyBindings, выше я разместил простой код, описывающий мою проблему. Когда вы нажимаете кнопку «вверх» ключ, они оба должны изменить отображаемую строку, но только один из них действительно делает это! Я использовал JComponent.WHEN_IN_FOCUSED_WINDOW, потому что ваша карта ввода не подходит для этого случая (если вы ее измените, вы увидите, что она не будет работать)

    от AR89
  • Большое спасибо, ваш пример работает отлично, я буду использовать его как шаблон!

    от AR89
  • Смотрите такжеEventListenerList firing order.

    от
  • Этот подход изложен вEventListenerList .

    от
  • 1

    Вы можете использовать шаблон наблюдателя для этого.

    http://en.wikipedia.org/wiki/Observer_pattern

    MyKeyEventListener listener = new MyKeyEventListener();
    JPanel one = new JPanel();
    one.addKeyListener(listener);//method might be wrong
    JPanel two = new JPanel();
    two.addKeyListener(listener);
    listener.addObserver(one);
    listener.addObserver(two);
    

  • 2

    Одним из способов является использование методов из

    SwingUtilities для Java6 (уведомлениеSwingUtilities для Java7 есть несколько изменений, но это не важно в этом случае) можно перенаправить, распространить несколько событийСтандартные Swing Listeners, простопример о перенаправлении событий мыши из одного контейнера в другой,

  • 1

    Вы должны создать

    XXListener реализация и добавить этот слушатель по.addXXListener на все компоненты, которые вам нужны.

  • 5

    Вместо

    KeyListenerиспользоватьKey Bindings и имеют отчетливыйAction реализации для каждой панели. ИспользуяWHEN_ANCESTOR_OF_FOCUSED_COMPONENT карта ввода, обе панели могут отвечать.

    Приложение: Поскольку поиск заканчивается после нахождения действительной привязки для ключа, пример нижеforwards событие к элементамList<MyPanel>каждый из которых может по-разному реагировать через доступныйAction.

    import java.awt.EventQueue;
    import java.awt.GridLayout;
    import java.awt.event.ActionEvent;
    import java.awt.event.KeyEvent;
    import java.util.Arrays;
    import java.util.List;
    import javax.swing.AbstractAction;
    import javax.swing.Action;
    import javax.swing.BorderFactory;
    import javax.swing.JComponent;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
    import javax.swing.KeyStroke;
    
    /** @see http://stackoverflow.com/q/10011564/230513 */
    public class TwoPanelsTest extends JFrame {
    
        private MyPanel one = new MyPanel("One");
        private MyPanel two = new MyPanel("Two");
        private List<MyPanel> list = Arrays.asList(one, two);
    
        public TwoPanelsTest() {
            super("TwoPanelsTest");
            this.setDefaultCloseOperation(EXIT_ON_CLOSE);
            JPanel panel = new JPanel(new GridLayout(0, 1, 10, 10));
            panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
            panel.add(one);
            panel.add(two);
            panel.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)
                .put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), "up");
            panel.getActionMap().put("up", new AbstractAction() {
    
                @Override
                public void actionPerformed(ActionEvent e) {
                    for (MyPanel panel : list) {
                        panel.getAction().actionPerformed(e);
                    }
                }
            });
            this.add(panel);
            this.pack();
            this.setLocationRelativeTo(null);
            this.setVisible(true);
        }
    
        private static class MyPanel extends JPanel {
    
            private String string = " will be updated though its action.";
            private Action action = new UpdateAction(this);
            private String name;
            private JLabel label;
    
            public MyPanel(String name) {
                this.name = name;
                this.label = new JLabel(name + string, JLabel.CENTER);
                this.setLayout(new GridLayout());
                this.setFocusable(true);
                this.add(label);
            }
    
            public Action getAction() {
                return action;
            }
    
            private void update() {
                label.setText(name + ": " + System.nanoTime());
            }
    
            private static class UpdateAction extends AbstractAction {
    
                private MyPanel panel;
    
                public UpdateAction(MyPanel panel) {
                    this.panel = panel;
                }
    
                @Override
                public void actionPerformed(ActionEvent ae) {
                    panel.update();
                }
            }
        }
    
        public static void main(String[] args) {
            EventQueue.invokeLater(new Runnable() {
    
                @Override
                public void run() {
                    TwoPanelsTest t = new TwoPanelsTest();
                }
            });
        }
    }