# JScrollPane - Problem



## Chasor (28. Jan 2010)

Folgendes Problem:
Ich habe in einer Klasse "Field" (JComponent) Zeichenmethoden für ein Gitter.
Dieses Field wird einem JPanel hinzugefügt, in dem u.a. MouseListener/ComponentListener etc. stecken.
Das JPanel wiederum wird einem JScrollPane hinzugefügt.
Der JScrollPane wird dem Container hinzugefügt.

Alles funktioniert soweit, nur wenn die Zeichnung in Field über den Fensterrand geht (geschieht per Zoomfunktion), erscheinen keine Scrollbars, wie es eigentlich der Fall sein sollte. Habe ich die Componenten falsch miteinander verknüpft, oder wo liegt der Fehler?


Gui.java

```
// GUI-Layout
	Container c=getContentPane();
    panel=new JPanel();
    panel.setBackground(Color.WHITE);
    panel.setBorder(new EmptyBorder(50,50,50,50));
	panel.setLayout(new GridLayout());
    scr = new JScrollPane(panel, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
    panel.add(field=new Field());
    scr.setViewportView(panel);
    c.add(scr,BorderLayout.CENTER);
    setTitle("Monogramme"); 
    setSize(550,600);
```

Field.java

```
public void paintComponent(Graphics g)
	{
		super.paintComponent(g);
		Graphics2D g2d = (Graphics2D) g;
		g2d.scale(Gui.zoom,Gui.zoom);
		zoomedAffineTransform = g2d.getTransform();
		// Gitter zeichnen
		for(i=0;i<=nbCols;i++)
		{
			g2d.drawLine(wert*i-place, wert*nbCols-place, wert*i-place, 0-place);
		}

		for(i=0;i<=nbRows;i++)
		{
			g2d.drawLine(0-place, wert*i-place, wert*nbRows-place, wert*i-place);
		}
	}
```


----------



## SlaterB (28. Jan 2010)

malen kann ja jeder wohin er will, das ScropllPane wird sicher nicht analysieren, wieweit in x-Richtung beim letzten paint() gemalt wurde,
wie groß eine Komponente im Layout ist hängt von setSize(), setPreferredSize() usw. ab, 
gegebenenfalls zusammen mit validate() für Layoutneuberechnung


----------



## Chasor (29. Jan 2010)

Mein Aufbau der Componenten sieht wie folgt aus:


```
Container c=getContentPane();
	field = new Field();
	field.setBackground(Color.WHITE);
    scr = new JScrollPane(field, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
    scr.setBorder(new EmptyBorder(50,50,50,50));
    scr.setViewportView(field);
    c.add(scr,BorderLayout.CENTER);
    setTitle("Mono"); 
    setSize(550,600);
```


Die ZoomIn-Methode so:

```
public void actionPerformed(ActionEvent e)
    	{
    		zoom=zoom*1.1;
    		xDim = (int) (getWidth()*zoom);
    		yDim = (int) (getHeight()*zoom);
    		//field.setSize(new Dimension (xDim,yDim));
    		field.setSize(xDim,yDim);
    		// System.out.println(xDim +"  "+ yDim);
    		// Mit der place-Variable wird das Gitter wieder zentriert im Panel angezeigt.
    		// Da es zu int gecastet wird, entsteht ab niedrigen Zoom-Werten eine kleine Verschiebung nach oben links.
    		field.place=(int)((-getWidth()+getWidth()*zoom)/2);
    		field.repaint();
     	}
```


Er zoomt heran (Zeichnung wird größer), jedoch kann man an den ScrollBars nirgends scrollen.
Das field erbt übrigens von JComponent, somit sollte sich die Component-Size mit field.setSize vergrößern und die ScrollBars sollten erscheinen, weil die Componente über die Größe des ScrollPanes geht, richtig? Das tut's aber leider nicht ... :/
Als kleine Zwischenfrage noch:
Wieso funktioniert field.setBackground(Color.WHITE); nicht? Der Hintergrund bleibt Grau :/


Hier 2 Bilder, wie es derzeit ist:


----------



## Chasor (30. Jan 2010)

Da das Problem immernoch besteht, weiterer Code

gui.java extends JFrame

```
// GUI-Layout
	c=getContentPane();
	field = new Field();
    scr = new JScrollPane(field);
    scr.setPreferredSize(new Dimension(550,600));
    scr.setBorder(new EmptyBorder(50,50,50,50));
    //scr.setViewportView(field);
    c.add(scr);
    setTitle("Monogramme");
    setSize(550,600);
[...]
    // ZoomIn
    mIn.addActionListener(new ActionListener()
    {  
    	public void actionPerformed(ActionEvent e)
    	{
    		zoom=zoom*1.1;
    		xDim = (int) (field.getWidth()*zoom);
    		yDim = (int) (field.getHeight()*zoom);
    		field.setPreferredSize(new Dimension(xDim, yDim));
    		field.repaint();
     	} 
    });
```

field.java extends JComponent

```
public void paintComponent(Graphics g)
	{
		super.paintComponent(g);
		Graphics2D g2d = (Graphics2D) g;
		g2d.scale(Gui.zoom,Gui.zoom);
		zoomedAffineTransform = g2d.getTransform();
		// Gitter zeichnen
		for(i=0;i<=nbCols;i++)
		{
			g2d.drawLine(wert*i, wert*nbCols, wert*i, 0);
		}

		for(i=0;i<=nbRows;i++)
		{
			g2d.drawLine(0, wert*i, wert*nbRows, wert*i);
		} 
		
		// Zellen ausfüllen, bei denen das Array den Inhalt "1" hat
		for(int k = 0; k < nbCols; k++)
		{
			for(int l = 0; l < nbRows; l++)
			{
				if(array[k][l] == 1)
				{
					g2d.setColor(Color.BLACK);
					g2d.fillRect(0+k*wert,0+l*wert,wert,wert);
				}
				if(array[k][l] == 2)
				{
					g2d.fillOval(k*wert+wert/4, l*wert+wert/4, wert-wert/2, wert-wert/2);
				}
			}
		}
	}
```



Das Problem ist immernoch:
Wenn ich zoomIn durchführe, vergrößert sich das Gitter, und zeichnet über die Grenzen des "fields" hinaus. Der Scrollpane bringt jedoch keinerlei Scrollbars :/.
Was habe ich falsch gemacht, wie kann ich es hinbekommen, dass man nach dem Zoom über die Ränder scrollen kann? Irgendwie muss ich das ScrollPane ja quasi auch vom Bereich her um den gleichen Zoom-Faktor vergrößern, damit man scrollen kann, doch wie?


----------



## SlaterB (30. Jan 2010)

oh, ganz vergessen gestern,
also ich habe bisschen ausprobiert,

richtig erklären kann ich es nicht, mit gleichzeitigen Aufruf sowohl von setSize() als auch setPreferredSize() scheint es zu klappen,
hier ein gekürztes lauffähiges Beispiel,
das hättest du ruhig auch so ungefähr posten können, mit all den Ausschnitten, ... und unbekannten/ fehlenden Variablen kann man doch kaum was anfangen


```
public class Test {

	public static void main(String[] args) throws Exception {
		new GUI().setVisible(true);
	}

}

class GUI extends JFrame {

	int size = 540;

	public GUI() {
		final Field field = new Field();
		field.setPreferredSize(new Dimension(size, size));
		field.setSize(new Dimension(size, size));
		final JScrollPane scr = new JScrollPane(field);
		add(scr);
		setSize(550, 600);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		
		JButton mIn = new JButton("zoom");
		mIn.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				size = (int) (size * 1.2);
				field.setPreferredSize(new Dimension(size, size));
				field.setSize(new Dimension(size, size));
				validate();
				repaint();
			}
		});
		add(mIn, BorderLayout.SOUTH);
	}
}

class Field extends JComponent {
	public void paintComponent(Graphics g) {
		super.paintComponent(g);
		Graphics2D g2d = (Graphics2D) g;
		g2d.drawLine(5, 5, 5000, 5000);
	}
}
```


----------



## Chasor (30. Jan 2010)

Genial, danke für die Mühe , es funktioniert endlich.

Kann man das ScrollPane auch z.B. durch Drag&Drop der rechten Maustaste scrollen? Lässt sich das irgendwie implementieren?


----------



## SlaterB (30. Jan 2010)

irgendwie gehts bestimmt, zum einen die Maus kennenlernen,
http://www.java-forum.org/awt-swing-swt/95589-paintcomponent-maus-verschieben.html
Position beim Klicken merken usw.,

zum anderen das Scrollen steuern, im einfachen Fall die JScrollBar holen und einen Wert setzen,
was eine Umrechnung in dessen Wertebereich erfordert,
da gibts sicher auch schönere Wega a la 'zeige Bereich Pixel 500-1000 vom Inhalt', aber entsprechende Methoden vergesse ich immer


----------



## Chasor (2. Feb 2010)

Habe mich mal an eine Implementierung gewagt:

(field ist JComponent, das in meinen JScrollPane scr gesetzt wird)

```
int lastDragPointx;
	int lastDragPointy;
    boolean beingDragged = false;
```


```
scr = new JScrollPane(field);
```


```
// MouseListener
    field.addMouseListener(new MouseAdapter()
    {
    // Scrollen des JScrollPanes mit Drag&Drop der mittleren Maustaste (not working)
    public void mouseDragged(MouseEvent e)
    {
    	// Frage Mausposition ab
    	xPos = e.getX(); 
    	yPos = e.getY();
    	if (e.getButton() == MouseEvent.BUTTON2)
    	{
    		if (!beingDragged)
    		{
    			beingDragged = true;
    			setLastMouseDragPoint(xPos, yPos);
    		}
    		handleMouseDragInBrowserPanel(e);
    	}
    }
    public void mouseReleased(MouseEvent e)
    {
    	if (e.getButton() == MouseEvent.BUTTON2)
    	{
    		if (beingDragged)
    		{
    			beingDragged = false;
    		}
    	}
    }});
```


```
public void setLastMouseDragPoint(int x, int y) {
	lastDragPointx = x;
	lastDragPointy = y;		
}

public void handleMouseDragInBrowserPanel (MouseEvent e)
{
	JViewport viewPort = scr.getViewport();
	Point scrollPosition = viewPort.getViewPosition();
	 
	int dx = e.getX() - lastDragPointx;
	int dy = e.getY() - lastDragPointy;
	 
	scrollPosition.x -= dx;
	scrollPosition.y -= dy;
	 
	viewPort.setViewPosition ( scrollPosition );
}
```


Es klappt einfach nicht :/
(Mouse2 sollte mittlere Maustaste sein, da Mouse3 die rechte ist, oder?)


----------



## Ebenius (3. Feb 2010)

Benutz doch einfach meine gute alte JXScrollPane. 


```
/* $Id: JXScrollPane.java,v 1.3 2009/02/10 14:55:00 ebenius Exp $ */

/* Copyright 2009 Sebastian Haufe

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       [url]http://www.apache.org/licenses/LICENSE-2.0[/url]

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License. */

package com.ebenius.widget;

import static java.awt.AWTEvent.MOUSE_EVENT_MASK;
import static java.awt.AWTEvent.MOUSE_MOTION_EVENT_MASK;
import static java.awt.event.InputEvent.BUTTON3_DOWN_MASK;
import static java.awt.event.MouseEvent.MOUSE_DRAGGED;
import static java.awt.event.MouseEvent.MOUSE_PRESSED;
import static java.awt.event.MouseEvent.MOUSE_RELEASED;

import java.awt.*;
import java.awt.event.AWTEventListener;
import java.awt.event.InputEvent;
import java.awt.event.MouseEvent;
import java.util.HashSet;
import java.util.Set;

import javax.swing.JScrollPane;
import javax.swing.JViewport;
import javax.swing.SwingUtilities;

/**
 * A {@link JScrollPane} derivate, enhanced by mouse dragging support.
 * 
 * @see #isViewDraggingEnabled()
 * @see #isHorizontalViewDraggingEnabled()
 * @see #isVerticalViewDraggingEnabled()
 * @version $Revision: 1.3 $ as of $Date: 2009/02/10 14:55:00 $
 * @author Sebastian Haufe
 */
public class JXScrollPane extends JScrollPane {

  /** Serial version UID */
  private static final long serialVersionUID = 4240385570313149664L;
  private static ToolkitMouseListener multiListener = null;

  // -------------------------------------------------------------------------
  // Instance fields
  // -------------------------------------------------------------------------

  private Point draggingFrom;
  private int viewDragModifierMask = BUTTON3_DOWN_MASK;
  private boolean horizontalViewDraggingEnabled = true;
  private boolean verticalViewDraggingEnabled = true;

  // -------------------------------------------------------------------------
  // Constructors
  // -------------------------------------------------------------------------

  /**
   * Creates an empty (no viewport view) <code>JXScrollPane</code> where both
   * horizontal and vertical scrollbars appear when needed.
   */
  public JXScrollPane() {
    super();
    enableEvents(AWTEvent.MOUSE_MOTION_EVENT_MASK);
    enableEvents(AWTEvent.MOUSE_EVENT_MASK);
  }

  /**
   * Creates a <code>JXScrollPane</code> that displays the view component in a
   * viewport whose view position can be controlled with a pair of scrollbars.
   * The scrollbar policies specify when the scrollbars are displayed, For
   * example, if <code>vsbPolicy</code> is
   * <code>VERTICAL_SCROLLBAR_AS_NEEDED</code> then the vertical scrollbar
   * only appears if the view doesn't fit vertically. The available policy
   * settings are listed at {@link #setVerticalScrollBarPolicy} and
   * {@link #setHorizontalScrollBarPolicy}.
   * 
   * @see #setViewportView
   * @param view the component to display in the scrollpane's viewport
   * @param vsbPolicy an integer that specifies the vertical scrollbar policy
   * @param hsbPolicy an integer that specifies the horizontal scrollbar
   *          policy
   */
  public JXScrollPane(Component view, int vsbPolicy, int hsbPolicy) {
    super(view, vsbPolicy, hsbPolicy);
    enableEvents(AWTEvent.MOUSE_MOTION_EVENT_MASK);
    enableEvents(AWTEvent.MOUSE_EVENT_MASK);
  }

  /**
   * Creates a <code>JXScrollPane</code> that displays the contents of the
   * specified component, where both horizontal and vertical scrollbars appear
   * whenever the component's contents are larger than the view.
   * 
   * @see #setViewportView
   * @param view the component to display in the scrollpane's viewport
   */
  public JXScrollPane(Component view) {
    super(view);
    enableEvents(AWTEvent.MOUSE_MOTION_EVENT_MASK);
    enableEvents(AWTEvent.MOUSE_EVENT_MASK);
  }

  /**
   * Creates an empty (no viewport view) <code>JXScrollPane</code> with
   * specified scrollbar policies. The available policy settings are listed at
   * {@link #setVerticalScrollBarPolicy} and
   * {@link #setHorizontalScrollBarPolicy}.
   * 
   * @see #setViewportView
   * @param vsbPolicy an integer that specifies the vertical scrollbar policy
   * @param hsbPolicy an integer that specifies the horizontal scrollbar
   *          policy
   */
  public JXScrollPane(int vsbPolicy, int hsbPolicy) {
    super(vsbPolicy, hsbPolicy);
    enableEvents(AWTEvent.MOUSE_MOTION_EVENT_MASK);
    enableEvents(AWTEvent.MOUSE_EVENT_MASK);
  }

  // -------------------------------------------------------------------------
  // Viewport dragging support
  // -------------------------------------------------------------------------

  /**
   * Determines whether the view is draggable based on the given mouse event.
   * This implementation checks whether {@link #isViewDraggingEnabled()
   * dragging is enabled} and the {@link #getViewDragModifierMask()} matches
   * the {@link MouseEvent#getModifiersEx() modifiers} of the given mouse
   * event.
   * <p>
   * The method is being called on {@link MouseEvent MOUSE_PRESSED} and
   * {@link MouseEvent#MOUSE_DRAGGED} events to check whether the event is
   * used or dismissed for view dragging.
   * 
   * @param e the mouse event to inspect
   * @return {@code true} if the mouse event is a view drag trigger
   */
  protected boolean isViewDraggable(MouseEvent e) {
    final int mask = viewDragModifierMask;
    return isViewDraggingEnabled() && (mask & e.getModifiersEx()) == mask;
  }

  /**
   * Determines whether the given point is in the viewport of {@code this}
   * scroll pane.
   * 
   * @param point the point to check
   * @return {@code true} if the point is on the viewport
   */
  protected boolean viewportContainsPoint(Point point) {
    return getViewport().getBounds().contains(point);
  }

  /**
   * Start dragging the view with the given mouse event.
   * 
   * @param e the mouse event
   */
  protected void startDraggingView(MouseEvent e) {
    draggingFrom = e.getPoint();
    setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
    multiListener.setCurrentDraggingSlave(this);
  }

  /**
   * Stop dragging the view with the given mouse event.
   * 
   * @param e the mouse event
   */
  protected void stopDraggingView(MouseEvent e) {
    multiListener.setCurrentDraggingSlave(null);
    draggingFrom = null;
    setCursor(null);
  }

  /**
   * Drag the view according to the given mouse event.
   * 
   * @param e the mouse event
   */
  protected void dragView(MouseEvent e) {
    final JViewport viewport = getViewport();
    final Component view = viewport.getView();
    final Point from;

    /* currently not dragging or no viewport view; get out-a-here */
    if ((from = draggingFrom) == null || view == null) {
      return;
    }

    /* the amount of dragging */
    final Point to = e.getPoint();
    int dx = isHorizontalViewDraggingEnabled() ? from.x - to.x : 0;
    int dy = isVerticalViewDraggingEnabled() ? from.y - to.y : 0;

    // /* accelerate by the unit increment */
    // if (view instanceof Scrollable) {
    // final Scrollable scrollable = (Scrollable) view;
    // final Rectangle viewRect = viewport.getViewRect();
    // dx *= scrollable.getScrollableUnitIncrement(viewRect, dx, HORIZONTAL);
    // dy *= scrollable.getScrollableUnitIncrement(viewRect, dy, VERTICAL);
    // }

    /* calculate the new view position */
    final Point viewPos = viewport.getViewPosition();
    final Dimension viewSize = viewport.getViewSize();
    final Dimension extentSize = viewport.getExtentSize();
    final int maxViewPosX = viewSize.width - extentSize.width;
    final int maxViewPosY = viewSize.height - extentSize.height;
    viewPos.x = Math.max(0, Math.min(viewPos.x + dx, maxViewPosX));
    viewPos.y = Math.max(0, Math.min(viewPos.y + dy, maxViewPosY));

    /* move the view and repaint the viewport */
    viewport.setViewPosition(viewPos);
    viewport.repaint();
    draggingFrom = to;
  }

  // -------------------------------------------------------------------------
  // Event dispatching
  // -------------------------------------------------------------------------

  @Override
  protected void processMouseEvent(MouseEvent e) {
    super.processMouseEvent(e);
    processDragEvent(e);
  }

  @Override
  protected void processMouseMotionEvent(MouseEvent e) {
    super.processMouseMotionEvent(e);
    processDragEvent(e);
  }

  protected void processDragEvent(MouseEvent e) {
    switch (e.getID()) {
    case MOUSE_DRAGGED:
      if (draggingFrom != null && !e.isConsumed() && isViewDraggable(e)) {
        dragView(e);
      }
      break;
    case MOUSE_RELEASED:
      stopDraggingView(e);
      break;
    case MOUSE_PRESSED:
      if (!e.isConsumed()
            && isViewDraggable(e)
            && viewportContainsPoint(e.getPoint())) {
        startDraggingView(e);
      }
      break;
    }
  }

  // -------------------------------------------------------------------------
  // Child listener support
  // -------------------------------------------------------------------------

  @Override
  public void addNotify() {
    synchronized (ToolkitMouseListener.class) {
      if (multiListener == null) {
        multiListener = new ToolkitMouseListener();
      }
      multiListener.addSlave(this);
    }

    super.addNotify();
  }

  @Override
  public void removeNotify() {
    super.removeNotify();

    synchronized (ToolkitMouseListener.class) {
      if (multiListener != null && !multiListener.removeSlave(this)) {
        multiListener = null;
      }
    }
  }

  // -------------------------------------------------------------------------
  // Bean getters and setters
  // -------------------------------------------------------------------------

  /**
   * Returns the modifier mask to be checked for triggering view drag support.
   * By default, this is the {@link InputEvent#BUTTON3_DOWN_MASK}.
   * 
   * @return the modifier mask
   */
  public int getViewDragModifierMask() {
    return viewDragModifierMask;
  }

  /**
   * Sets the modifier mask to be checked for triggering view drag support. By
   * default, this is the {@link InputEvent#BUTTON3_DOWN_MASK}.
   * 
   * @param modifierMask the modifier mask to set
   */
  public void setViewDragModifierMask(int modifierMask) {
    final int old = this.viewDragModifierMask;
    this.viewDragModifierMask = modifierMask;
    firePropertyChange("viewDragModifierMask", //$NON-NLS-1$
          old, viewDragModifierMask);
  }

  /**
   * Determines whether {@code this} scroll pane's view dragging is enabled in
   * at least one direction. Defaults to {@code true}.
   * 
   * @return {@code true} if view dragging is enabled
   * @see #isHorizontalViewDraggingEnabled()
   * @see #isVerticalViewDraggingEnabled()
   */
  public boolean isViewDraggingEnabled() {
    return horizontalViewDraggingEnabled || verticalViewDraggingEnabled;
  }

  /**
   * Determines whether {@code this} scroll pane's view dragging is enabled in
   * horizontal direction. Defaults to {@code true}.
   * 
   * @return {@code true} if horizontal view dragging is enabled
   */
  public boolean isHorizontalViewDraggingEnabled() {
    return horizontalViewDraggingEnabled;
  }

  /**
   * Sets whether {@code this} scroll pane's horizontal view dragging is
   * enabled. Defaults to {@code true}.
   * 
   * @param enabled {@code true} to enable view dragging horizontally
   */
  public void setHorizontalViewDraggingEnabled(boolean enabled) {
    final boolean old = this.horizontalViewDraggingEnabled;
    this.horizontalViewDraggingEnabled = enabled;
    firePropertyChange("horizontalViewDraggingEnabled", //$NON-NLS-1$
          old, horizontalViewDraggingEnabled);
  }

  /**
   * Determines whether {@code this} scroll pane's view dragging is enabled in
   * vertical direction. Defaults to {@code true}.
   * 
   * @return {@code true} if vertical view dragging is enabled
   */
  public boolean isVerticalViewDraggingEnabled() {
    return verticalViewDraggingEnabled;
  }

  /**
   * Sets whether {@code this} scroll pane's vertical view dragging is
   * enabled. Defaults to {@code true}.
   * 
   * @param enabled {@code true} to enable view dragging vertically
   */
  public void setVerticalViewDraggingEnabled(boolean enabled) {
    final boolean old = this.verticalViewDraggingEnabled;
    this.verticalViewDraggingEnabled = enabled;
    firePropertyChange("horizontalViewDraggingEnabled", //$NON-NLS-1$
          old, verticalViewDraggingEnabled);
  }

  // -------------------------------------------------------------------------
  // Inner classes
  // -------------------------------------------------------------------------

  private static class ToolkitMouseListener implements AWTEventListener {

    private final Set<JXScrollPane> slaves = new HashSet<JXScrollPane>();
    private JXScrollPane currentDraggingSlave = null;

    /** Creates a new {@code ToolkitMouseListener}. */
    public ToolkitMouseListener() {}

    public void eventDispatched(AWTEvent e) {
      final JXScrollPane slave = currentDraggingSlave;
      switch (e.getID()) {
      case MOUSE_DRAGGED:
        if (slave != null) {
          slave.processDragEvent(convertMouseEvent((MouseEvent) e, slave));
        }
        break;
      case MOUSE_RELEASED:
        if (slave != null) {
          slave.stopDraggingView(convertMouseEvent((MouseEvent) e, slave));
        }
        break;
      case MOUSE_PRESSED:
        redispatchDragEvent((MouseEvent) e);
        break;
      default:
        return;
      }
    }

    private void redispatchDragEvent(MouseEvent e) {
      final Component src = (Component) e.getSource();
      for (Component c = src.getParent(); c != null; c = c.getParent()) {
        if (c instanceof JXScrollPane) {
          ((JXScrollPane) c).processDragEvent(convertMouseEvent(e, c));
          break;
        }
      }
    }

    private MouseEvent convertMouseEvent(
          MouseEvent e,
          Component targetComponent) {
      return SwingUtilities.convertMouseEvent((Component) e.getSource(), e,
            targetComponent);
    }

    void addSlave(JXScrollPane slave) {
      synchronized (ToolkitMouseListener.class) {
        slaves.add(slave);
        if (slaves.size() == 1) {
          slave.getToolkit().addAWTEventListener(this, MOUSE_EVENT_MASK);
        }
      }
    }

    boolean removeSlave(JXScrollPane slave) {
      synchronized (ToolkitMouseListener.class) {
        slaves.remove(slave);
        final boolean hasMoreSlaves = !slaves.isEmpty();
        if (!hasMoreSlaves) {
          slave.getToolkit().removeAWTEventListener(this);
        }
        return hasMoreSlaves;
      }
    }

    void setCurrentDraggingSlave(JXScrollPane slave) {
      synchronized (ToolkitMouseListener.class) {
        final JXScrollPane oldSlave = currentDraggingSlave;
        final Toolkit tk;
        long mask;
        if (slave != null) {
          tk = slave.getToolkit();
          mask = MOUSE_EVENT_MASK | MOUSE_MOTION_EVENT_MASK;
        } else if (oldSlave != null) {
          tk = oldSlave.getToolkit();
          mask = MOUSE_EVENT_MASK;
        } else {
          return;
        }

        tk.removeAWTEventListener(this);
        tk.addAWTEventListener(this, mask);
        this.currentDraggingSlave = slave;
      }
    }
  }
}
```
Ebenius


----------

