javaswingjscrollpanejscrollbarscroll-lock

Add scroll-lock button to JScrollBar


Background

Looking to add a scroll-lock button to the corner of JScrollPane without obscuring the view port contents. The following image shows a JScrollPane wrapped in a SwingNode within a JavaFX application:

Actual

The lower-right corner shows a button with a lock icon that may be toggled, which is the desired result:

Final

Notice how the content at the very bottom of the view port---the portion beside the lock button---is visible. (Clicking the button will simulate pressing the scroll-lock button on the keyboard. Having a scroll-lock button at the top is perfectly fine, if that's any easier.)

Problem

The JScrollPane API shows the following image:

JScrollPane

Enabling the corner component also seems to require adding a column header. The addition of the header obscures part of the view port, in direct proportion to the scroll-lock button height. Here's a screenshot showing the visible column header, which hides part of the document:

Obscured output

Ideas

I've tried making the header view panel transparent, to no avail.

Code

The relevant code within the SwingNode:

// FlyingSaucer subclass
mView = new HtmlPanel(); 
mScrollPane = new JScrollPane( mView );
setContent( mScrollPane );

final var lock = new JButton( "X" );
mScrollPane.setCorner( UPPER_TRAILING_CORNER, lock );
mScrollPane.setVerticalScrollBarPolicy( VERTICAL_SCROLLBAR_ALWAYS );

final var header = new JPanel();
header.setPreferredSize(
  new Dimension( 12, lock.getPreferredSize().height ) );
header.setOpaque( false );
header.setBackground( new Color( 0, 0, 0, 0 ) );
mScrollPane.setColumnHeaderView( header );

See camickr's answer for another example.

Question

How would you add a button to JScrollPane's bottom (or top) corner such that no view port content is obscured?

Related


Solution

  • I would suggest using "wrapper" panels to achieve you desired layout. Something like:

    JButton scrollLock = new JButton("...");
    
    JScrollPane scrollPane = new JScrollPane(...);
    JScrollBar verticalBar = scrollPane.getVerticalScrollBar();
    
    JPanel verticalPanel = new JPanel( new BorderLayout() );
    verticalPanel.add(verticalBar, BorderLayout.CENTER);
    verticalPanel.add(scrollLock, BorderLayout.PAGE_END);
    
    JPanel wrapper = new JPanel( new BorderLayout() );
    wrapper.add(scrollPane, BorderLayout.CENTER);
    wrapper.add(verticalPanel, BorderLayout.LINE_END);
    
    setContent(wrapper);