Class ScrollPane

All Implemented Interfaces:
ImageObserver, MenuContainer, Serializable, Accessible

public class ScrollPane extends Container implements Accessible
Emulator for ScrollPane — AWT's scrolling container, not JScrollPane. Holds exactly one child, gives it its full size, and shows a movable window onto it. Peers over SScrollPane (Vaadin Scroller).
ScrollPane sp = new ScrollPane(ScrollPane.SCROLLBARS_AS_NEEDED);
sp.add(tallPanel);             // a second add() evicts the first
sp.setScrollPosition(0, 200);
Point p = sp.getScrollPosition();

The scrollbars are not components

Unlike Swing's JScrollBar, AWT's scrollbars are drawn by the peer and never enter the component tree. What user code gets instead is a pair of ScrollPaneAdjustable value models, one per axis, via getVAdjustable() / getHAdjustable(). The range is derived, not set: their setMinimum / setMaximum / setVisibleAmount throw AWTError, verbatim as in AWT.

Scrolling is server→browser only

setScrollPosition(int, int) pushes to the browser and getScrollPosition() reads back what was pushed — correct in the same request, which is the common migrated idiom. But a user's wheel or drag is invisible to the server: there is no scroll DOM listener, so getScrollPosition() does not track a gesture and no AdjustmentListener fires for one. Four migrated idioms break on this, all silently — save/restore of a scroll offset, two panes synchronised through an AdjustmentListener, "scroll to bottom only if already at bottom", and hand-rolled paging near getMaximum(). Nothing renders wrong: the browser owns overflow, and a Vaadin Grid or VirtualList inside the pane lazy-loads over its own channel. Deliberate per D_awt_scrollpane / SD_sscrollpane, which record why the read direction is not built.

Geometry answers are the JDK's own un-realized answers

getViewportSize() is always 100×100 and both scrollbar dimensions are always 0 — which is literally what a never-laid-out JDK ScrollPane reports (its ctor seeds width = height = 100, and the scrollbar getters return 0 while peer == null). A rare case where dummy geometry and JDK geometry agree exactly, so none of the three WARNs.

Leaf peer is locked down per R_leaf_peer_lockdown

Nothing in java.awt extends ScrollPane, and javax.swing.plaf is out of scope (R_match_swing_errors sub-bucket (b)). Both public ctors funnel into one super(SScrollPane.class, …), so every instance — including a user-code subclass — peers over a Scroller and no ctor offers a peer seam.

The policy constants are 0/1/2, numerically identical to Adjustable's HORIZONTAL/VERTICAL/ NO_ORIENTATION. So new ScrollPane(Adjustable.VERTICAL) compiles and silently means SCROLLBARS_ALWAYS — no throw, wrong pane. The safe direction is javax.swing.ScrollPaneConstants, whose values are 20–22 / 30–32 and therefore disjoint: one of those handed to this ctor throws IllegalArgumentException, loudly.

See Also:
  • Field Details

  • Constructor Details

    • ScrollPane

      public ScrollPane()
      Chains to this(SCROLLBARS_AS_NEEDED), as the JDK does.
    • ScrollPane

      public ScrollPane(int scrollbarDisplayPolicy)
      Parameters:
      scrollbarDisplayPolicy - SCROLLBARS_AS_NEEDED, SCROLLBARS_ALWAYS or SCROLLBARS_NEVER
      Throws:
      IllegalArgumentException - on any other value, with AWT's message. Thrown while evaluating super(...)'s argument, so it leaves no half-built ScrollPane
  • Method Details

    • addImpl

      protected final void addImpl(Component comp, Object constraints, int index)
      Adds the single child, evicting any previous one.

      The body order is AWT's and is observable: the existing child is removed before the index check, so add(c2, null, 1) on a populated pane leaves the pane empty and then throws. A wart, but free to reproduce.

      Two departures from java.awt.ScrollPane.addImpl.

      • No addToPanel branch. The JDK wraps a lightweight child in a Panel with a BorderLayout, so getComponent(0) there is the wrapper, not what you added. That fork exists to give a native scrolled-window a heavyweight child to host; our peer's shadow root is a bare <slot> that accepts any element, and SB-Emulators has no lightweight/heavyweight split to test in the first place. So getComponent(0) here is the child — more permissive than the JDK, where the corresponding cast throws ClassCastException. See D_awt_scrollpane.
      • addSlotChild rather than super.addImpl, because Scroller owns its content slot and Container.addImpl would insertChild into the peer element and fight setContent (the D_shadow_children_tree_shape rationale, transferred verbatim). addSlotChild still runs the add-to-self and ancestor-cycle checks and still fires COMPONENT_ADDED + HIERARCHY_CHANGED.
      Container.addImpl's own IllegalArgumentException("illegal component position") bounds check is skipped: ScrollPane's index > 0 check with its own message replaces it.
      Overrides:
      addImpl in class Container
    • remove

      public void remove(int index)
      Removes the child at index, clearing the peer's content slot.

      Overridden where the JDK does not override it (there, the native peer handles removal). Necessary because Container.remove(int) calls removed.peer.getElement().removeFromParent(), which would rip the element out while Scroller.getContent() still pointed at it. This is also how addImpl's own remove(0) reaches the right code.

      Overrides:
      remove in class Container
      Throws:
      ArrayIndexOutOfBoundsException - if out of range, as in AWT
    • getScrollbarDisplayPolicy

      public int getScrollbarDisplayPolicy()
      Returns:
      the ctor-set policy; AWT provides no setter
    • getViewportSize

      public Dimension getViewportSize()
      Returns:
      always 100×100 — see the class javadoc. Computed directly rather than through getWidth()/getInsets(), which would WARN and answer 0; the JDK's ctor seeds width = height = 100 and its insets here are zero, so this constant is the faithful answer for a pane that was never laid out. Fresh instance — AWT lets callers mutate it
    • getHScrollbarHeight

      public int getHScrollbarHeight()
      Returns:
      always 0 — the JDK's own answer whenever peer == null or the policy is SCROLLBARS_NEVER. Our scrollbars are the browser's and report no dimensions
    • getVScrollbarWidth

      public int getVScrollbarWidth()
      Returns:
      always 0, for the same reason as getHScrollbarHeight()
    • getVAdjustable

      public Adjustable getVAdjustable()
      Returns:
      the vertical axis's value model. Declared Adjustable rather than ScrollPaneAdjustable because the JDK declares the wider type "to maintain backward compatibility"; narrowing it would diverge from the signature migrated code compiled against. Cast to ScrollPaneAdjustable works, as in AWT
    • getHAdjustable

      public Adjustable getHAdjustable()
      Returns:
      the horizontal axis's value model; see getVAdjustable()
    • setScrollPosition

      public void setScrollPosition(int x, int y)
      Scrolls to (x, y) within the child.

      Exactly hAdjustable.setValue(x); vAdjustable.setValue(y), as in AWT, so it fires up to two AdjustmentEvents. Unlike AWT the values are not clamped to the child's extent — see ScrollPaneAdjustable for why, and note the browser clamps on arrival so the rendered result is still legal.

      Throws:
      NullPointerException - if the pane has no child. AWT chose NPE with this message rather than IllegalStateException
    • setScrollPosition

      public void setScrollPosition(Point p)
      Parameters:
      p - the target position
      Throws:
      NullPointerException - if p is null — thrown by the p.x dereference before the child check, so a null Point NPEs (without a message) even on an empty pane. Order matters and is AWT's
    • getScrollPosition

      public Point getScrollPosition()
      Returns:
      the last position pushed, not necessarily where the user is — see the class javadoc. Fresh instance
      Throws:
      NullPointerException - if the pane has no child, as in AWT
    • setLayout

      public final void setLayout(LayoutManager mgr)
      Refuses to install a layout manager, as java.awt.ScrollPane does. getLayout() therefore answers null forever.
      Overrides:
      setLayout in class Container
      Parameters:
      mgr - ignored
      Throws:
      AWTError - always, even for null
    • doLayout

      public void doLayout()
      Delegates to layout() exactly as the JDK's does. Our Container.doLayout() dispatches to the LayoutManager and only falls through to layout() when there is none — which happens to always be true here, since setLayout(LayoutManager) throws. Overriding makes the layout() hook live by construction rather than by that coincidence (R_no_vaadin_in_api limb 2).
      Overrides:
      doLayout in class Container
    • layout

      @Deprecated public void layout()
      Deprecated.
      As of JDK 1.1, replaced by doLayout(). Retained because doLayout() calls it and user code overrides it — AWT-era code hooks layout here.
      Overrides:
      layout in class Container
    • printComponents

      public void printComponents(Graphics g)
      User-authored Graphics paint of components is permanently out of scope (R_match_swing_errors sub-bucket (b))
      Overrides:
      printComponents in class Container
      Parameters:
      g - ignored
    • addNotify

      public void addNotify()
      Overrides:
      addNotify in class Container
    • processMouseWheelEvent

      protected void processMouseWheelEvent(MouseWheelEvent e)
      The hook is reachable — Component.processEvent routes MouseWheelEvent here — but nothing currently dispatches one, so in practice it does not run. That is an absent source rather than a dead hook, so R_no_vaadin_in_api limb 2 is satisfied. No ScrollPaneWheelScroller arithmetic: that class is JDK-internal and the browser already wheel-scrolls the peer natively, which is what the flag asks for.

      e.consume() on the enabled path is the JDK's, kept so the call graph matches; per D_event_consume it marks the event and suppresses nothing, the browser having already scrolled

      Overrides:
      processMouseWheelEvent in class Component
      Parameters:
      e - the wheel event
    • setWheelScrollingEnabled

      public void setWheelScrollingEnabled(boolean handleWheel)
      Parameters:
      handleWheel - false is R_match_swing_errors sub-bucket (c) drop-and-WARN: CSS cannot disable the wheel while keeping scrollbars draggable (overflow: hidden and ScrollDirection.NONE both kill scrolling outright). The value round-trips regardless; true, the default, is free because the browser wheel-scrolls the peer natively
    • isWheelScrollingEnabled

      public boolean isWheelScrollingEnabled()
    • paramString

      public String paramString()
      Verbatim JDK format, including the empty-pane (0,0) fallback.
      Overrides:
      paramString in class Container
    • getAccessibleContext

      public AccessibleContext getAccessibleContext()
      Specified by:
      getAccessibleContext in interface Accessible
      Overrides:
      getAccessibleContext in class Component
      Returns:
      always null — accessibility contexts are permanently out of scope (R_match_swing_errors sub-bucket (b)), as on Panel / Button