Java 使用更逻辑的 ScrollBar 进行滚动

标签 java swing mouseevent jscrollpane jscrollbar

我在 JScrollPanes 中有一个 JTextPanes 数组。我提到的所有这些组件都位于 JScrollPane 内的 JPanel 内。

User interface picture

在程序开始时,所有 JTextPanes 都没有任何文本,因此它们的滚动条不可见。 JPanel 的滚动条是可见的,因为其中有很多组件。

我的问题是,如果光标位于 JTextPane 之一上并且我尝试滚动,则不会发生任何事情,因为计算机认为我想使用 JTextPane 的滚动条进行滚动。我希望计算机能够意识到我正在尝试使用 JPanel 的滚动条进行滚动。有什么办法可以实现这个目标吗?

谢谢!

编辑:

您可以使用此代码生成与上面类似的 UI(这是扩展 JFrame 的类的构造函数 - 为忽略许多良好的编码习惯而道​​歉):

public JFrameTest() {
    JPanel panel = new JPanel( new GridLayout( 10 , 10 , 10 , 10 ) );
    for ( int i = 0 ; i < 10 ; i ++ ) {
        for ( int j = 0 ; j < 10 ; j ++ ) {
            JScrollPane paneToAdd = new JScrollPane( new JTextPane() ) {
                /**
                 * 
                 */
                private static final long serialVersionUID = 1L;

                @Override
                public Dimension getPreferredSize() {
                    return new Dimension( 100 , 100 );
                }
            };
            panel.add( paneToAdd );
        }
    }
    add( new JScrollPane( panel ) );

    setSize( 700 , 500 );
    setVisible( true );
    setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
}

最佳答案

以下代码是来自 Mouse Wheel Controller 的快速破解。 .

基本上,它拦截包含文本区域的滚动 Pane 的 MouseWheelEvent。如果滚动条可见,它会将事件重新分派(dispatch)回同一滚动 Pane ,否则它会找到父级滚动 Pane 并将事件分派(dispatch)到该滚动 Pane 。

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class MouseWheelToParent implements MouseWheelListener
{
    private JScrollPane scrollPane;
    private MouseWheelListener[] realListeners;

    public MouseWheelToParent(JScrollPane scrollPane)
    {
        this.scrollPane = scrollPane;
        install();
    }

    public void install()
    {
        if (realListeners != null) return;

        //  Keep track of original listeners so we can use them to
        //  redispatch an altered MouseWheelEvent

        realListeners = scrollPane.getMouseWheelListeners();

        for (MouseWheelListener mwl : realListeners)
        {
            scrollPane.removeMouseWheelListener(mwl);
        }

        //  Intercept events so they can be redispatched

        scrollPane.addMouseWheelListener(this);
    }

    /**
     *  Remove the class as the default listener and reinstall the original
     *  listeners.
     */
    public void uninstall()
    {
        if (realListeners == null) return;

        //  Remove this class as the default listener

        scrollPane.removeMouseWheelListener( this );

        //  Install the default listeners

        for (MouseWheelListener mwl : realListeners)
        {
            scrollPane.addMouseWheelListener( mwl );
        }

        realListeners = null;
    }

//  Implement MouseWheelListener interface

    /**
     *  Redispatch a MouseWheelEvent to the real MouseWheelListeners
     */
    public void mouseWheelMoved(MouseWheelEvent e)
    {
//      System.out.println(e.getScrollType() + " : " + e.getScrollAmount() + " : " + e.getWheelRotation());
        JScrollPane scrollPane = (JScrollPane)e.getComponent();

        if (scrollPane.getVerticalScrollBar().isVisible())
        {
            //  Redispatch the event to original MouseWheelListener

            for (MouseWheelListener mwl : realListeners)
            {
                mwl.mouseWheelMoved( e );
            }
        }
        else
        {
            dispatchToParent(e, scrollPane);
            return;
        }
    }

    private void dispatchToParent(MouseWheelEvent e, JScrollPane scrollPane)
    {
        Component ancestor = SwingUtilities.getAncestorOfClass(JScrollPane.class, scrollPane);

        MouseWheelEvent mwe = new MouseWheelEvent(
            ancestor,
            e.getID(),
            e.getWhen(),
            e.getModifiersEx(),
            e.getX(),
            e.getY(),
            e.getXOnScreen(),
            e.getYOnScreen(),
            e.getClickCount(),
            e.isPopupTrigger(),
            e.getScrollType(),
            e.getScrollAmount(),
            e.getWheelRotation());

        ancestor.dispatchEvent(mwe);
    }

    private static void createAndShowUI()
    {
        JPanel panel = new JPanel( new GridBagLayout() );
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.insets = new Insets(10, 10, 10, 10);

        for (int y = 0; y < 10; y++)
        {
            for (int x = 0; x < 5; x++)
            {
                gbc.gridx = x;
                gbc.gridy = y;
                JTextArea textArea = new JTextArea(5, 20);
                JScrollPane scrollPane = new JScrollPane( textArea );
                scrollPane.setMinimumSize( scrollPane.getPreferredSize() );
                new MouseWheelToParent(scrollPane);
                panel.add(scrollPane, gbc);

                if (x == 0 && y ==0)
                {
                    textArea.append("1\n2\n3\n4\n5\n6\n7\n8\n9");
                    textArea.setCaretPosition(0);
                }

            }
        }

        JFrame frame = new JFrame("TextAreaSSCCE");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add( new JScrollPane( panel ) );
        frame.setSize(400, 400);
        frame.setLocationByPlatform( true );
        frame.setVisible( true );
    }

    public static void main(String[] args)
    {
        EventQueue.invokeLater(new Runnable()
        {
            public void run()
            {
                createAndShowUI();
            }
        });
    }
}

关于Java 使用更逻辑的 ScrollBar 进行滚动,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18264419/

相关文章:

Java:动画 GIF 自动变为部分透明

java - 在 JavaFX 中使用 onMouseEntered 事件重新填充 SVG 路径

c++ - MouseCallback 函数 OpenCV

java - 在eclipse中动态编写.feature文件。

java - JSplitPane 中分隔线移动的动画

java - [Ljava.lang.String;@5d79a22d 结果

java - 比较不同 JButton 的文本

javascript - 检测鼠标方向 - JavaScript

java - Gson - 条件 JSON 反序列化(健全性检查)

java - 如何将 Activity 转换为图像