【问题标题】:How to implement MouseWheelListener for JPanel without breaking its default implementation?如何在不破坏其默认实现的情况下为 JPanel 实现 MouseWheelListener?
【发布时间】:2016-05-17 11:51:50
【问题描述】:

简单;我在JScrollPane 中有一个JPanel

正如预期的那样; JScrollPane 默认侦听MouseWheelEvent,因此当滚轮旋转和光标悬停在JPanel 上时,滚动效果很好。

但是在那之后;我刚刚更新了JPanel 以便它实现MouseWheelListener,并为JPanel 本身添加了这个鼠标滚轮监听器。

@Override
public void mouseWheelMoved(MouseWheelEvent e) {
    if (e.isControlDown()) {
        if (e.getWheelRotation() < 0) {
            System.out.println("mouse wheel Up");
        } else {
            System.out.println("mouse wheel Down");
        }
    }
}

JPanel 响应此实现,当两者都发生时; Ctrl 被按下并且滚轮正在旋转并且光标悬停在JPanel 上。但是JScrollPane的默认行为却意外丢失了!!!

当我在光标悬停在JPanel 上时旋转滚轮时,JScrollPane 的滚动没有响应!!!

看来; MouseWheelListener 的这个实现打破了 JPanel 的默认值。

所以;如何在不破坏其默认实现的情况下为JPanel 实现MouseWheelListener

【问题讨论】:

    标签: java swing jpanel jscrollpane mousewheel


    【解决方案1】:

    我不知道这是否真的有资格作为正确的答案,因为它是一种解决方法,但我想出了以下解决方案:仅在 时调用 scrollPanemouseWheelMoved 方法Ctrl 未被按下:

    if (e.isControlDown()) {
        if (e.getWheelRotation() < 0) {
            infoLabel.setText("Mouse Wheel Up");
        } else {
            infoLabel.setText("Mouse Wheel Down");
        }
    } else {
        scrollPane.getListeners(MouseWheelListener.class)[0].mouseWheelMoved(e);
    }
    

    完整示例:

    import java.awt.BorderLayout;
    import java.awt.EventQueue;
    import java.awt.GridLayout;
    import java.awt.event.MouseWheelEvent;
    import java.awt.event.MouseWheelListener;
    
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
    import javax.swing.JScrollPane;
    import javax.swing.border.TitledBorder;
    
    public class Example {
        public Example() {
            JFrame frame = new JFrame();
            frame.setLayout(new BorderLayout());
            frame.add(new ScrollPanePanel());
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setSize(400, 400);
            frame.setVisible(true);
        }
    
        public static void main(String[] args) {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    new Example();
                }
            });
        }
    }
    
    class ScrollPanePanel extends JPanel implements MouseWheelListener {
        private JLabel infoLabel;
        private JScrollPane scrollPane;
    
        public ScrollPanePanel() {
    
            JPanel panel = new JPanel(new GridLayout(0, 1));
            for (int i = 1; i <= 100; i++) {
                panel.add(new JLabel("Label " + i));
            }
            panel.addMouseWheelListener(this);
            scrollPane = new JScrollPane(panel);
    
            infoLabel = new JLabel(" ");
            JPanel infoPanel = new JPanel();
            infoPanel.add(infoLabel);
    
            setLayout(new BorderLayout());
            add(scrollPane);
            add(infoPanel, BorderLayout.SOUTH);
    
        }
    
        @Override
        public void mouseWheelMoved(MouseWheelEvent e) {
            if (e.isControlDown()) {
                if (e.getWheelRotation() < 0) {
                    infoLabel.setText("Mouse Wheel Up");
                } else {
                    infoLabel.setText("Mouse Wheel Down");
                }
            } else {
                scrollPane.getListeners(MouseWheelListener.class)[0].mouseWheelMoved(e);
            }
        }
    }
    

    【讨论】:

    • 对不起;两种解决方案都是这样工作的:当我在旋转鼠标滚轮时按下 [Ctrl] - 它不必要地调用两者;我实现的MouseWheelListener 和页面的默认滚动 - 如何在按下 [Ctrl] 时停止默认滚动
    • @SalehFeek 对不起,我误解了这个问题。查看我更新的代码,我希望它现在可以工作。它应该只在按下 CTRL 时更新文本,并且只在 not 按下 CTRL 时调用JScrollPane 的默认滚动。
    • 您的解决方案现在可以正常工作 - 谢谢 - 但我有一个小问题:当车轮移动时,这条线被反复调用scrollPane.getListeners(MouseWheelListener.class)[0].mouseWheelMoved(e);- 所以我的问题是;像这样重复调用同一行代码是明智的做法吗?而它每次都能达到同样的效果?!
    • @SalehFeek getListeners 的一部分可能并不明智,我认为 Ian Roberts 和 Marco13 提到的 dispatchEvent() 的解决方案更好。不过,我认为每次调用同一行代码都没有问题。
    【解决方案2】:

    添加一个else 以在 ctrl 向下时将事件直接重新调度到滚动窗格:

    @Override
    public void mouseWheelMoved(MouseWheelEvent e) {
        if (e.isControlDown()) {
            if (e.getWheelRotation() < 0) {
                System.out.println("mouse wheel Up");
            } else {
                System.out.println("mouse wheel Down");
            }
        } else {
            // pass the event on to the scroll pane
            getParent().dispatchEvent(e);
        }
    }
    

    【讨论】:

      【解决方案3】:

      MouseWheelEvents 和滚动行为有一些微妙的警告。

      例如,当你打开这个页面(我的意思是这个,你正在阅读的页面)时,将鼠标放在中间,并开始用滚轮向下滚动,你将滚动到代码 sn-ps。请注意,虽然代码 sn-ps 包含在具有滚动条的代码块中,但连续旋转鼠标滚轮不会触发滚动在代码块中,但仅在整个页面中。但是,当您移动鼠标时代码块中,然后之后滚动鼠标滚轮,然后您将滚动代码仅阻止 - 而整个页面。

      同样,旋转鼠标滚轮可能不会影响悬停的可滚动。我认为这取决于窗口管理器和外观,但在某些情况下,您将滚动 包含焦点组件的滚动窗格 - 即使鼠标光标位于此组件之外,并且即使它位于可缩放组件上(您也可以观察到这一点,例如,在 Windows 资源管理器中)!


      不过,其中一些机制和细微之处也可以在 Swing 组件中找到。例如,redispatching mechanismMouseWheelEvents 传递给祖先,如果它们不由组件本身处理。

      按照这种模式,一个解决方案(在概念上类似于 the one that LuxxMiner proposed,但可能更通用一点)可能是简单地将 MouseWheelEvent 重新分配给父组件:

      package stackoverflow;
      
      import java.awt.Dimension;
      import java.awt.GridLayout;
      import java.awt.event.MouseWheelEvent;
      import java.awt.event.MouseWheelListener;
      
      import javax.swing.JFrame;
      import javax.swing.JPanel;
      import javax.swing.JScrollPane;
      import javax.swing.SwingUtilities;
      
      public class MouseWheelListenerForPanelInScrollpane
      {
          public static void main(String[] args)
          {
              SwingUtilities.invokeLater(new Runnable()
              {
                  @Override
                  public void run()
                  {
                      createAndShowGUI();
                  }
              });
          }
      
          private static void createAndShowGUI()
          {
              JFrame f = new JFrame();
              f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      
              f.getContentPane().setLayout(new GridLayout(1,2));
      
              MouseWheelListenerPanel m = new MouseWheelListenerPanel();
              m.setPreferredSize(new Dimension(100,4000));
              JScrollPane scrollPane = new JScrollPane(m);
              f.getContentPane().add(scrollPane);
      
              f.setSize(500,500);
              f.setLocationRelativeTo(null);
              f.setVisible(true);
          }
      }
      
      class MouseWheelListenerPanel extends JPanel implements MouseWheelListener
      {
          MouseWheelListenerPanel()
          {
              addMouseWheelListener(this);
          }
      
          @Override
          public void mouseWheelMoved(MouseWheelEvent e)
          {
              if (e.isControlDown())
              {
                  if (e.getWheelRotation() < 0)
                  {
                      System.out.println("mouse wheel Up");
                  }
                  else
                  {
                      System.out.println("mouse wheel Down");
                  }
              }
              else
              {
                  getParent().dispatchEvent(e);
              }
      
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-12-29
        • 1970-01-01
        • 1970-01-01
        • 2021-11-18
        • 2020-08-10
        • 1970-01-01
        相关资源
        最近更新 更多