0
votes

I have an array of JTextPanes inside JScrollPanes. All those components I mentioned are inside a JPanel inside a JScrollPane.

User interface picture

At the start of the program, none of the JTextPanes have any text, so the scrollbars for them are not visible. The scrollbars for the JPanel are visible, because I have a lot of components in it.

My issue is that if the cursor is over one of the JTextPanes and I try to scroll, nothing happens because the computer thinks I want to scroll with the JTextPane's scrollbars. What I would like to happen is for the computer to realize that I'm trying to scroll with the JPanel's scrollbar. Is there any way I could accomplish this?

Thanks!

Edit:

You could produce a similar UI to the one above with this code ( this is the constructor of a class extending JFrame - apologies for ignoring a lot of good coding habits ):

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 );
}
1
What happens when there is text in the text areas and they are showing there scroll bars? - MadProgrammer
I would like it to scroll the text area if the scroll bars are showing, but scroll the JPanel if the scroll bars are not. I know there would be issues for that as well (i.e. you're scrolling up and you suddenly stop), but I think this second situation would be better - user2570465
@MadProgrammer - sorry, I forgot to add the notify in the previous comment. I've found a way to detect when the JTextPanes are resized by using a component listener, but I don't know if there's a state such that the JTextPane's scrollbars aren't "there." If there were such a way, I think I could just "add" the scrollbars back when the component got too big - user2570465
does the JPanel use a layout manager, please post your code. - pstanton
@pstanton - My code uses several different classes I wrote and will get too large and messy, but I can post something that will produce similar results. I'm putting it into an edit right now. - user2570465

1 Answers

2
votes

The following code was taken as a quick hack from Mouse Wheel Controller.

Basically it intercepts the MouseWheelEvent for the scroll pane containing the text area. If the scrollbar is visible it redispatches the event back to the same scroll pane otherwise it finds the parent scrollPane and dispatches the event to that scrollPane.

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