如何在不破坏默认实现的情况下为JPanel实现MouseWheelListener?

时间:2016-02-07 21:08:23

标签: java swing jpanel jscrollpane mousewheel

简单;我在import java.awt.Dimension; import java.awt.EventQueue; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import javax.swing.border.TitledBorder; public class Test { public static void main(String[] args) { new Test(); } public Test() { EventQueue.invokeLater(new Runnable() { @Override public void run() { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { ex.printStackTrace(); } JFrame frame = new JFrame("Testing"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.add(new TestPane()); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); } }); } public class TestPane extends JPanel { public TestPane() { setLayout(new GridBagLayout()); JPanel p1 = new JPanel(); p1.setBorder(new TitledBorder(null, "Customer Details", TitledBorder.CENTER, TitledBorder.TOP, null, null)); JPanel p2 = new JPanel(); p2.setBorder(new TitledBorder(null, "Customer Details", TitledBorder.CENTER, TitledBorder.TOP, UIManager.getFont("Label.font").deriveFont(Font.BOLD), null)); JPanel p3 = new JPanel(); p3.setBorder(new TitledBorder(null, "Customer Details", TitledBorder.CENTER, TitledBorder.TOP, UIManager.getFont("Label.font").deriveFont(Font.ITALIC), null)); JPanel p4 = new JPanel(); p4.setBorder(new TitledBorder(null, "Customer Details", TitledBorder.CENTER, TitledBorder.TOP, UIManager.getFont("Label.font").deriveFont(Font.BOLD | Font.ITALIC), null)); GridBagConstraints gbc = new GridBagConstraints(); gbc.gridwidth = GridBagConstraints.REMAINDER; gbc.weightx = 1; gbc.weighty = 1; gbc.fill = GridBagConstraints.BOTH; add(p1, gbc); add(p2, gbc); add(p3, gbc); add(p4, gbc); } @Override public Dimension getPreferredSize() { return new Dimension(200, 200); } } } ;

中有一个JPanel

正如所料;默认情况下,JScrollPane会侦听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"); } } } 响应此实现的时间;按下 Ctrl 并且当光标悬停在JPanel上时,滚轮正在旋转。但是JPanel的默认行为意外丢失!!!

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

似乎; JScrollPane的此实现会中断MouseWheelListener的默认值。

因此;如何在不违反默认实施的情况下为JPanel实施MouseWheelListener

3 个答案:

答案 0 :(得分:8)

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

例如,当您打开此页面(我的意思是您正在阅读的那个页面)时,将鼠标放在中间,然后开始使用滚轮向下滚动,您将滚动代码段。请注意虽然代码片段包含在有滚动条的代码块中,但是连续旋转鼠标滚轮将触发滚动代码块中,但仅限于整个页面。但是当你移动鼠标时 一个代码块,而之后滚动鼠标滚轮,那么你将滚动代码仅阻止 - 并且整个页面。

同样,旋转鼠标滚轮可能不会影响悬停的可滚动条。我认为这取决于Window Manager和Look&amp;感觉,但在某些情况下,您将滚动包含焦点组件的滚动窗格 - 即使鼠标光标位于此组件之外,即使它位于可分割组件之上(您也可以例如,在Windows资源管理器中观察这一点!

然而,其中一些机制和细微之处也可以在Swing组件中找到。例如,redispatching mechanism如果组件本身未处理,则将MouseWheelEvents传递给祖先。

遵循这种模式,一个解决方案(概念上类似于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);
        }

    }
}

答案 1 :(得分:6)

如果ctrl ,请添加else将事件直接重新分配到滚动窗格:

@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);
    }
}

答案 2 :(得分:4)

我不知道这是否真的有资格作为正确的答案,因为它是一种解决方法,但我想出了以下解决方案:只需调用mouseWheelMoved方法即可。仅当 Ctrl 未被按下时才scrollPane

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);
        }
    }
}