MouseEvent потерян в JScrollPane

Это код, который я использую, чтобы показать проблему, с которой я сталкиваюсь в другом проекте.

Я не получаю никакой строки, как это, если я использую JScrollPane в качестве оболочки для Panel2. Зачем? Я хочу нажать на JscrollPane и напечатать событие следующим образом.

java.awt.event.MouseEvent[MOUSE_CLICKED,(800,469),absolute(808,499),button=1,modifiers=Button1,clickCount=1] on javax.swing.JPanel[,0,0,934x612,layout=java.awt.FlowLayout,alignmentX=0.0,alignmentY=0.0,border=javax.swing.border.LineBorder@cc0e01,flags=9,maximumSize=,minimumSize=,preferredSize=java.awt.Dimension[width=880,height=630]]

Если сейчас я изменю

panel1.add(pane);

в

panel1.add(panel2);

Тогда сообщение выше было напечатано.

public class LostMouseEvent {

public static void main(String[] args) {
    new LostMouseEvent();
}

public LostMouseEvent() {
    EventQueue.invokeLater(new Runnable() {
        @Override
        public void run() {
            JFrame frame = new JFrame();
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setLayout(new BorderLayout());

            JPanel panel1 = new JPanel();
            JPanel panel2 = new JPanel();
            JScrollPane pane = new JScrollPane(panel2);

            panel1.setPreferredSize(new Dimension(880, 630));
            panel1.setBorder(BorderFactory.createLineBorder(Color.blue));
            panel2.setPreferredSize(new Dimension(840, 610));
            panel2.setBorder(BorderFactory.createLineBorder(Color.green));


            panel1.add(pane);
            frame.add(panel1);

            frame.pack();
            frame.setVisible(true);
            frame.setSize(950, 650);

            panel1.addMouseListener(new MyMouseListener());
        }
    });
}

private class MyMouseListener extends MouseAdapter {
    @Override
    public void mouseClicked (MouseEvent me) {
        System.out.println(me);
    }
}
}

UPD: На самом деле в моем проекте больше, чем одна панель2. Первоначально у меня были panel1 и много panel2 внутри. Затем я хотел обернуть каждую панель 2 с помощью JScrollPane и начал сталкиваться с этой проблемой.

Мне нужно иметь только один MouseListener, чтобы минимизировать изменения в коде.

2 ответа

Решение
  • Используйте EDT для создания и управления компонентами Swing
  • Не звоните setSize() скорее позвони pack() перед установкой JFrame видимый.
  • Не звоните setPrefferedSize() скорее переопределить getPrefferedSize()

Ваш код работает, как и ожидалось, он напечатает сообщение, только если panel1 нажата, обратите внимание panel1 позади JScrollPane Таким образом, все, что находится за пределами зеленой границы panel1, Чтобы он работал как для JScrollpane / panel2 а также JPanel / panel1 просто добавьте MouseListener ОБА требуемых компонентов:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;

public class LostMouseEvent {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
        new LostMouseEvent();
            }
        });
    }

    public LostMouseEvent() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());

                JPanel panel1 = new JPanel() {

                    @Override
                    public Dimension getPreferredSize() {
                        return new Dimension(880, 630);
                    }

                };
                JPanel panel2 = new JPanel() {

                    @Override
                    public Dimension getPreferredSize() {
                        return new Dimension(840, 610);
                    }
                };
                JScrollPane pane = new JScrollPane(panel2);

                panel1.setBorder(BorderFactory.createLineBorder(Color.blue));
                panel2.setBorder(BorderFactory.createLineBorder(Color.green));


                panel1.add(pane);
                frame.add(panel1);

                MouseListener ml=new MyMouseListener();

                //add mouse listener to panel1 and panel2
                panel1.addMouseListener(ml);
                panel2.addMouseListener(ml);

                //alternatively add to pane
                //pane.addMouseListener(ml);

                frame.pack();
                frame.setVisible(true);

            }
        });
    }

    private class MyMouseListener extends MouseAdapter {

        @Override
        public void mouseClicked(MouseEvent me) {
            System.out.println(me);
        }
    }
}

РЕДАКТИРОВАТЬ:

Я лично не рекомендовал бы это, однако,

Чтобы добавить одного слушателя к JFrame это захватит все MouseEvent использование Toolkit класс и вызов addAWTEventListener вот так:

Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {
    @Override
    public void eventDispatched(AWTEvent awte) {//all mouse events will be processed here you will have to check for the mouse events you are interested in
    System.out.println(awte);
    }
}, AWTEvent.MOUSE_EVENT_MASK);//for Mouse events only

ОБНОВЛЕНИЕ 1:

Вы также можете добавить MouseListener на ваш JFrame Стеклянное стекло через JFrame.getGlassPane().addMouseListener(ml) не забудьте установить стекло, видимое после настройки JFrame видимый. Это позволит вам только добавить один Listener, Посмотреть здесь:

...

MouseListener ml = new MyMouseListener();

//add mouse listener to panel1 and panel2
//panel1.addMouseListener(ml);
//panel2.addMouseListener(ml);

//alternatively add to pane
//pane.addMouseListener(ml);

frame.getGlassPane().addMouseListener(ml);

frame.pack();
frame.setVisible(true);

frame.getGlassPane().setVisible(true);

...

УПАДТЕ 2:

Основная причина возникновения у вас проблемы MouseEvent заблудиться в JScrollPane потому что это ошибка. Смотрите здесь.

Обходное решение показано:

public Test()
  {
    setUI(new javax.swing.plaf.metal.MetalScrollPaneUI(){
      public void installListeners(JScrollPane scrollPane){}
    });
    JPanel canvas = new JPanel();
    canvas.add( new JLabel("Test") );

    setViewportView( canvas );
    setVisible(true);
  }

MouseEvent потерян в JScrollPane

  • ответ очень / довольно прост, убедитесь, что нет ничего ни о потерянных событиях, ни с JScrollPane,

  • Swing JComponent может запускать событие только в том случае, если там добавлен соответствующий слушатель

  • Вы не добавили MouseListener во второй JPanel,

  • этот JPanel помещается в родительский JPanel, этот родительский объект добавил MouseListener, а затем запускает mouseEvent, конечно, в вашем случае только за пределами границ 2-го JPanel, добавленных в этот контейнер

  • затем 2-й JPanel является deepestComponentAt, и не возможно событие пожара без повторной отправки координат от родителя к потомку

  • Вы можете перезапустить событие также программно,

Другие вопросы по тегам