Reputation: 605
I have a simple app that allows users to mark up a PDF document by dragging/dropping predefined widgets into a separate layer.
I am using a JScollPane. The viewport size is the equivalent of a single 8.5x11 page. When the VScrollBar is at the minimum position, the top of the page displays; at the maximum position, the bottom displays. I would like to override this behavior. The minimum position should display the top of the first page, and the maximum should display the bottom of the last page.
Among the dead ends I've hit: Replacing the ScrollBar built into the JScrollPane; Intercepting the AdjustmentEvent fired by the VScrollBar; and studying the ScrollDemo example. This seems like a straightforward feature, but I'm stuck at the beginning.
Any suggestions? Thanks!
Upvotes: 0
Views: 555
Reputation: 605
This seems to do the trick:
class DocumentScroller extends JScrollPane implements ChangeListener {
Component view ;
JPanel bookPanel, bookTop ;
ScrollingDocumentListener listener ;
Dimension pageSize ;
public DocumentScroller ( Component view ) {
this.view = view ;
}
public DocumentScroller ( Component view,
int vsbPolicy, int hsbPolicy ) {
super( vsbPolicy, hsbPolicy ) ;
this.view = view ;
}
public void setViewportView ( Component view ) {
this.view = view ;
}
public void setPageCount ( int pagect ) {
if ( view == null )
return ;
pageSize = view.getPreferredSize() ;
Dimension bookSize = new Dimension( pageSize ) ;
bookSize.height *= pagect ;
bookPanel = new JPanel() ;
bookPanel.setLayout( new BorderLayout() ) ;
bookPanel.setPreferredSize( bookSize ) ;
bookPanel.add( bookTop = new JPanel(),
BorderLayout.NORTH ) ;
bookPanel.add( view, BorderLayout.CENTER ) ;
super.setViewportView( bookPanel ) ;
getViewport().addChangeListener( this ) ;
}
public void setUnitIncrement ( int unitIncrement ) {
getVerticalScrollBar().setUnitIncrement( unitIncrement ) ;
}
public void setValue ( int value ) {
getVerticalScrollBar().setValue( value ) ;
}
public void setScrollingDocumentListener (
ScrollingDocumentListener listener ) {
this.listener = listener ;
}
public void stateChanged ( ChangeEvent e ) {
try {
if ( e.getSource().getClass()
!= Class.forName(
"javax.swing.JViewport" ) )
return ;
}
catch ( Exception ex ) {
return ;
}
Rectangle rect = ( (JViewport) e.getSource()
).getViewRect() ;
int offset = rect.y %pageSize.height ;
int pageTop = rect.y -offset ;
int pos = offset *rect.height /pageSize.height ;
bookTop.setPreferredSize(
new Dimension( 0, pageTop +pos ) ) ;
bookPanel.doLayout() ;
if ( listener != null )
listener.setPage( pageTop /pageSize.height ) ;
}
}
interface ScrollingDocumentListener {
void setPage ( int pageno ) ;
}
Upvotes: 1
Reputation: 2976
Do you want to be able to display the bottom half of the first page and the top half of the second page at the same time (and drag elements from one page to another)? Or just one complete page at the time?
For the first, you need a single component which just displays all pages and add it to a JScrollPane. You probably want to let it implement the Scrollable interface to fine tune the unit/block scrolling.
For the second, you just can display a single (vertical) JScrollBar next to the component and change the shown page depending on it value. In this case you use a scroll bar more like a slider control and your page component isn't really scrollable (no JScrollPane used).
Upvotes: 1