帆软报表设计器源代码。
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

279 lines
12 KiB

package com.fr.design.mainframe;
import javax.swing.JScrollBar;
import javax.swing.JViewport;
import javax.swing.Scrollable;
import javax.swing.SwingConstants;
import java.awt.Component;
import java.awt.Rectangle;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
/**
* 实现设计器面板的触摸板滚动移动交互 https://work.fineres.com/browse/REPORT-55989
*
* mouseWheelMoved 的具体实现来自
* @link {javax.swing.plaf.basic.BasicScrollPaneUI.Handler#mouseWheelMoved}
* scrollByUnits 的具体实现来自
* @link {javax.swing.plaf.basic.BasicScrollPaneUI#scrollByUnits}
* scrollByBlock 的具体实现来自
* @link {javax.swing.plaf.basic.BasicScrollPaneUI#scrollByBlock}
*/
public class DesignerTranslateMouseWheelHandler implements MouseWheelListener {
private final ScrollPane scrollpane;
public DesignerTranslateMouseWheelHandler(ScrollPane scrollpane) {
this.scrollpane = scrollpane;
}
@Override
public void mouseWheelMoved(MouseWheelEvent e) {
if (scrollpane.isWheelScrollingEnabled() &&
e.getWheelRotation() != 0) {
JScrollBar toScroll = scrollpane.getVerticalScrollBar();
int direction = e.getWheelRotation() < 0 ? -1 : 1;
int orientation = SwingConstants.VERTICAL;
// find which scrollbar to scroll, or return if none
if (toScroll == null || !toScroll.isVisible()
|| e.isShiftDown()) {
toScroll = scrollpane.getHorizontalScrollBar();
if (toScroll == null || !toScroll.isVisible()) {
return;
}
orientation = SwingConstants.HORIZONTAL;
}
e.consume();
if (e.getScrollType() == MouseWheelEvent.WHEEL_UNIT_SCROLL) {
JViewport vp = scrollpane.getViewport();
if (vp == null) { return; }
Component comp = vp.getView();
int units = Math.abs(e.getUnitsToScroll());
// When the scrolling speed is set to maximum, it's possible
// for a single wheel click to scroll by more units than
// will fit in the visible area. This makes it
// hard/impossible to get to certain parts of the scrolling
// Component with the wheel. To make for more accurate
// low-speed scrolling, we limit scrolling to the block
// increment if the wheel was only rotated one click.
boolean limitScroll = Math.abs(e.getWheelRotation()) == 1;
// Check if we should use the visibleRect trick
Object fastWheelScroll = toScroll.getClientProperty(
"JScrollBar.fastWheelScrolling");
if (Boolean.TRUE == fastWheelScroll &&
comp instanceof Scrollable) {
// 5078454: Under maximum acceleration, we may scroll
// by many 100s of units in ~1 second.
//
// BasicScrollBarUI.scrollByUnits() can bog down the EDT
// with repaints in this situation. However, the
// Scrollable interface allows us to pass in an
// arbitrary visibleRect. This allows us to accurately
// calculate the total scroll amount, and then update
// the GUI once. This technique provides much faster
// accelerated wheel scrolling.
Scrollable scrollComp = (Scrollable) comp;
Rectangle viewRect = vp.getViewRect();
int startingX = viewRect.x;
boolean leftToRight =
comp.getComponentOrientation().isLeftToRight();
int scrollMin = toScroll.getMinimum();
int scrollMax = toScroll.getMaximum() -
toScroll.getModel().getExtent();
if (limitScroll) {
int blockIncr =
scrollComp.getScrollableBlockIncrement(viewRect,
orientation,
direction);
if (direction < 0) {
scrollMin = Math.max(scrollMin,
toScroll.getValue() - blockIncr);
}
else {
scrollMax = Math.min(scrollMax,
toScroll.getValue() + blockIncr);
}
}
for (int i = 0; i < units; i++) {
int unitIncr =
scrollComp.getScrollableUnitIncrement(viewRect,
orientation, direction);
// Modify the visible rect for the next unit, and
// check to see if we're at the end already.
if (orientation == SwingConstants.VERTICAL) {
if (direction < 0) {
viewRect.y -= unitIncr;
if (viewRect.y <= scrollMin) {
viewRect.y = scrollMin;
break;
}
}
else { // (direction > 0
viewRect.y += unitIncr;
if (viewRect.y >= scrollMax) {
viewRect.y = scrollMax;
break;
}
}
}
else {
// Scroll left
if ((leftToRight && direction < 0) ||
(!leftToRight && direction > 0)) {
viewRect.x -= unitIncr;
if (leftToRight) {
if (viewRect.x < scrollMin) {
viewRect.x = scrollMin;
break;
}
}
}
// Scroll right
else if ((leftToRight && direction > 0) ||
(!leftToRight && direction < 0)) {
viewRect.x += unitIncr;
if (leftToRight) {
if (viewRect.x > scrollMax) {
viewRect.x = scrollMax;
break;
}
}
}
else {
assert false : "Non-sensical ComponentOrientation / scroll direction";
}
}
}
// Set the final view position on the ScrollBar
if (orientation == SwingConstants.VERTICAL) {
toScroll.setValue(viewRect.y);
}
else {
if (leftToRight) {
toScroll.setValue(viewRect.x);
}
else {
// rightToLeft scrollbars are oriented with
// minValue on the right and maxValue on the
// left.
int newPos = toScroll.getValue() -
(viewRect.x - startingX);
if (newPos < scrollMin) {
newPos = scrollMin;
}
else if (newPos > scrollMax) {
newPos = scrollMax;
}
toScroll.setValue(newPos);
}
}
}
else {
// Viewport's view is not a Scrollable, or fast wheel
// scrolling is not enabled.
scrollByUnits(toScroll, direction,
units, limitScroll);
}
}
else if (e.getScrollType() ==
MouseWheelEvent.WHEEL_BLOCK_SCROLL) {
scrollByBlock(toScroll, direction);
}
}
}
/*
* Method for scrolling by a unit increment.
* Added for mouse wheel scrolling support, RFE 4202656.
*
* If limitByBlock is set to true, the scrollbar will scroll at least 1
* unit increment, but will not scroll farther than the block increment.
* See BasicScrollPaneUI.Handler.mouseWheelMoved().
*/
static void scrollByUnits(JScrollBar scrollbar, int direction,
int units, boolean limitToBlock) {
// This method is called from BasicScrollPaneUI to implement wheel
// scrolling, as well as from scrollByUnit().
int delta;
int limit = -1;
if (limitToBlock) {
if (direction < 0) {
limit = scrollbar.getValue() -
scrollbar.getBlockIncrement(direction);
}
else {
limit = scrollbar.getValue() +
scrollbar.getBlockIncrement(direction);
}
}
for (int i=0; i<units; i++) {
if (direction > 0) {
delta = scrollbar.getUnitIncrement(direction);
}
else {
delta = -scrollbar.getUnitIncrement(direction);
}
int oldValue = scrollbar.getValue();
int newValue = oldValue + delta;
// Check for overflow.
if (delta > 0 && newValue < oldValue) {
newValue = scrollbar.getMaximum();
}
else if (delta < 0 && newValue > oldValue) {
newValue = scrollbar.getMinimum();
}
if (oldValue == newValue) {
break;
}
if (limitToBlock && i > 0) {
assert limit != -1;
if ((direction < 0 && newValue < limit) ||
(direction > 0 && newValue > limit)) {
break;
}
}
scrollbar.setValue(newValue);
}
}
/*
* Method for scrolling by a block increment.
* Added for mouse wheel scrolling support, RFE 4202656.
*/
static void scrollByBlock(JScrollBar scrollbar, int direction) {
// This method is called from BasicScrollPaneUI to implement wheel
// scrolling, and also from scrollByBlock().
int oldValue = scrollbar.getValue();
int blockIncrement = scrollbar.getBlockIncrement(direction);
int delta = blockIncrement * ((direction > 0) ? +1 : -1);
int newValue = oldValue + delta;
// Check for overflow.
if (delta > 0 && newValue < oldValue) {
newValue = scrollbar.getMaximum();
}
else if (delta < 0 && newValue > oldValue) {
newValue = scrollbar.getMinimum();
}
scrollbar.setValue(newValue);
}
public interface ScrollPane {
boolean isWheelScrollingEnabled();
JScrollBar getVerticalScrollBar();
JScrollBar getHorizontalScrollBar();
JViewport getViewport();
}
}