Prevent scrollbars disappearing when exiting component inside the JScrollPane

I made a JPanel that contains a JScrollPane that surrounds a JTextArea. I want to hide the scrollbars when the mouse exits the JScrollPane.

If I set the MouseListener on the JScrollPane, then nothing happens. If I set it on the JTextArea then the scrollbars hide/unhide correctly, but you cannot click them because they are outside the bounds of the JTextArea.\

How can I prevent the scrollbars from disappearing when you try to click them?

Code example 1. Hiding and unhiding + changing transparency works.

Problem: You cannot click the scrollbars, they disappear because you exit the JTextArea.

public class TransparentTextArea extends JTextArea {

private static final Color LIGHT_TRANSPARENT = new Color(0, 0, 0, 150);
private static final Color HEAVY_TRANSPARENT = new Color(0, 0, 0, 50);

public TransparentTextArea(final GameModel model) {
    setOpaque(false);
    setForeground(Color.WHITE);
    setBackground(HEAVY_TRANSPARENT);
    setEditable(false);
    addMouseListener(new MouseListener() {

        @Override
        public void mouseReleased(MouseEvent e) {
            // TODO Auto-generated method stub

        }

        @Override
        public void mousePressed(MouseEvent e) {
            // TODO Auto-generated method stub

        }

        @Override
        public void mouseExited(MouseEvent e) {
            model.setLogActive(false);
            setBackground(HEAVY_TRANSPARENT);
        }

        @Override
        public void mouseEntered(MouseEvent e) {
            model.setLogActive(true);
            setBackground(LIGHT_TRANSPARENT);
        }

        @Override
        public void mouseClicked(MouseEvent e) {
            // TODO Auto-generated method stub

        }
    });
}
}

public class Logger extends JScrollPane implements PanelObserver,
    ChangeListener {

private GameModel model;

public Logger(final GameModel model) {
    super(new TransparentTextArea(model));
    this.model = model;
    setOpaque(false);
    getViewport().setOpaque(false);
    setBorder(BorderFactory.createEmptyBorder());
    setViewportBorder(BorderFactory.createEmptyBorder());
    model.addPanelObserver(this);
    model.addChangeListener(this);
}

@Override
public void panelResized() {
    float x = model.getPanelWidth() * 0.01f;
    float y = model.getPanelHeight() * 0.70f;
    float width = model.getPanelWidth() * 0.30f;
    float height = model.getPanelHeight() * 0.28f;

    setBounds((int) x, (int) y, (int) width, (int) height);
}

@Override
public void stateChanged(ChangeEvent e) {
    if (model.isLogActive()) {
        setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
        setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
    } else {
        setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
        setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
    }
}
}

Code example 2.

Problem I tried to fix this by creating a Panel around it and using that MouseExited, but it does not work since the childs consume it.

public class Logger extends JPanel implements PanelObserver, MouseListener {

private static final Color LIGHT_TRANSPARENT = new Color(0, 0, 0, 150);
private static final Color HEAVY_TRANSPARENT = new Color(0, 0, 0, 50);

private GameModel model;
private JTextArea textArea;
private JScrollPane scrollPane;

public Logger(GameModel model) {
    super(null);

    this.model = model;
    setOpaque(false);

    textArea = new JTextArea();
    textArea.setOpaque(false);
    textArea.setForeground(Color.WHITE);
    textArea.setBackground(HEAVY_TRANSPARENT);
    textArea.setEditable(false);

    scrollPane = new JScrollPane(textArea);
    scrollPane.setOpaque(false);
    scrollPane.getViewport().setOpaque(false);
    scrollPane.setBorder(BorderFactory.createEmptyBorder());
    scrollPane.setViewportBorder(BorderFactory.createEmptyBorder());
    add(scrollPane);

    model.addPanelObserver(this);
    addMouseListener(this);
}

@Override
public void panelResized() {
    float x = model.getPanelWidth() * 0.01f;
    float y = model.getPanelHeight() * 0.70f;
    float width = model.getPanelWidth() * 0.30f;
    float height = model.getPanelHeight() * 0.28f;

    setBounds((int) x, (int) y, (int) width, (int) height);
    scrollPane.setBounds(0, 0, (int) width, (int) height);
}

@Override
public void mouseClicked(MouseEvent e) {}

@Override
public void mousePressed(MouseEvent e) {}


@Override
public void mouseReleased(MouseEvent e) {}

@Override
public void mouseEntered(MouseEvent e) {
    scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
    scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
    textArea.setBackground(LIGHT_TRANSPARENT);
}

@Override
public void mouseExited(MouseEvent e) {
        scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
        scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
        textArea.setBackground(HEAVY_TRANSPARENT);
}
}

Answers


Just tried this and it works fine:

 textArea.addMouseMotionListener(new MouseMotionAdapter() {
                @Override
                public void mouseMoved(MouseEvent arg0) {
                    scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
                    scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
                }
            });

 scrollPane.addMouseListener(new MouseAdapter() {

            @Override
            public void mouseExited(MouseEvent e) {

                scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
                scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
            }
        });

The idea is that as long as the mouse is moving within the textArea, the ScrollBar is visible and works fine. As soon as it moves outside the ScrollPane it's not visible anymore.


  • works for me, but there are a few mistakes

  • JScrollPane (in the case that is container) react to only one pixel around its child (1pixel Border)

  • mouse event are consumed by its childs, then whatever added to JScrollPane inside JPanel to consume() mouse event

  • JPanel has FlowLayout implementer in API, change that

  • don't to use NullLayout, use proper LayourManager for JPanel (BorderLayout, GridLayout)

  • JComponents can quite to easilly returns PreferredSize back to the container override getPreferredSize for JPanel, JTextArea(20, 20) etc

  • JPanel must be larger that JViewport in JScrollPane, otherwise (without override JScrollBars) JScrollBar never will be visible

  • near to true were @Omid +1

. . . . .

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
//http://stackoverflow.com/q/16344529/714968
public class MyLogger {

    private JTextArea textArea;
    private JScrollPane scrollPane;

    public MyLogger() {
        textArea = new JTextArea(20, 20);
        scrollPane = new JScrollPane(textArea);
        scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
        scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
        textArea.addMouseListener(new MouseListener() {
            @Override
            public void mouseClicked(MouseEvent e) {
            }

            @Override
            public void mousePressed(MouseEvent e) {
            }

            @Override
            public void mouseReleased(MouseEvent e) {
            }

            @Override
            public void mouseEntered(MouseEvent e) {
                scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
                scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
            }

            @Override
            public void mouseExited(MouseEvent e) {
                scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
                scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
            }
        });
        JFrame frame = new JFrame();
        frame.add(scrollPane);
        frame.setPreferredSize(new Dimension(100, 100));// JFrame must be smaller
        frame.pack();
        frame.setLocation(150, 150);
        frame.setVisible(true);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                MyLogger myLogger = new MyLogger();
            }
        });
    }
}

EDIT

again back to answer posted by @Omid, see what happens

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
//http://stackoverflow.com/q/16344529/714968
public class MyLogger {

    private JTextArea textArea;
    private JScrollPane scrollPane;

    public MyLogger() {
        textArea = new JTextArea(20, 20);
        textArea.setText("This text pane contains no html. It supports letter wrapping, "
                + "\nThis text pane contains no html. It supports letter wrapping!, "
                + "\nThis text pane contains no html. It supports letter wrapping!, "
                + "\nThis text pane contains no html. It supports letter wrapping!, "
                + "\nThis text pane contains no html. It supports letter wrapping!, "
                + "\nThis text pane contains no html. It supports letter wrapping!");
        textArea.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseEntered(MouseEvent e) {
                scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
                scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
            }
        });
        scrollPane = new JScrollPane(textArea);
        scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
        scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
        scrollPane.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseExited(MouseEvent e) {
                scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
                scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
            }
        });
        JFrame frame = new JFrame();
        frame.add(scrollPane);
        frame.setPreferredSize(new Dimension(100, 100));// JFrame must be smaller
        frame.pack();
        frame.setLocation(150, 150);
        frame.setVisible(true);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                MyLogger myLogger = new MyLogger();
            }
        });
    }
}

Need Your Help

Bootstrap Typeahead local, prefetch, or remote is required

javascript jquery asp.net-mvc-4 bootstrap-typeahead

I try to get this example of twitters typeahead to run but i am getting the error in chromes console:

About UNIX Resources Network

Original, collect and organize Developers related documents, information and materials, contains jQuery, Html, CSS, MySQL, .NET, ASP.NET, SQL, objective-c, iPhone, Ruby on Rails, C, SQL Server, Ruby, Arrays, Regex, ASP.NET MVC, WPF, XML, Ajax, DataBase, and so on.