From a4f08dcb02bfec117b3ad1767a40c2dac2bc53db Mon Sep 17 00:00:00 2001 From: Starryi Date: Thu, 23 Sep 2021 16:25:11 +0800 Subject: [PATCH] =?UTF-8?q?REPORT-55989=20mac=E7=9A=84=E8=A7=A6=E6=8E=A7?= =?UTF-8?q?=E6=9D=BF=E5=B7=A6=E5=8F=B3=E6=BB=91=E5=8A=A8=E6=97=B6=EF=BC=8C?= =?UTF-8?q?=E8=AE=BE=E8=AE=A1=E5=99=A8=E7=9A=84=E8=AE=BE=E8=AE=A1=E4=B8=BB?= =?UTF-8?q?=E4=BD=93=E9=9D=A2=E6=9D=BF=E6=98=AF=E4=B8=8A=E4=B8=8B=E6=BB=9A?= =?UTF-8?q?=E5=8A=A8=E7=9A=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 【问题原因】 1. 移植JScrollPane的触摸板滚轮交互逻辑到表单布局和报表网格面板中 2. 复用表单和报表的滚轮处理逻辑, 表单和报表各自实现所需的接口即可 【改动思路】 同上 --- .../DesignerScaleMouseWheelHandler.java | 31 ++ .../DesignerTranslateMouseWheelHandler.java | 279 ++++++++++++++++++ .../com/fr/design/mainframe/FormArea.java | 31 +- .../mainframe/FormAreaMouseWheelHandler.java | 75 +++++ .../mainframe/ReportComponentComposite.java | 17 +- ...rtComponentCompositeMouseWheelHandler.java | 75 +++++ 6 files changed, 480 insertions(+), 28 deletions(-) create mode 100644 designer-form/src/main/java/com/fr/design/mainframe/DesignerScaleMouseWheelHandler.java create mode 100644 designer-form/src/main/java/com/fr/design/mainframe/DesignerTranslateMouseWheelHandler.java create mode 100644 designer-form/src/main/java/com/fr/design/mainframe/FormAreaMouseWheelHandler.java create mode 100644 designer-realize/src/main/java/com/fr/design/mainframe/ReportComponentCompositeMouseWheelHandler.java diff --git a/designer-form/src/main/java/com/fr/design/mainframe/DesignerScaleMouseWheelHandler.java b/designer-form/src/main/java/com/fr/design/mainframe/DesignerScaleMouseWheelHandler.java new file mode 100644 index 000000000..15aec31d5 --- /dev/null +++ b/designer-form/src/main/java/com/fr/design/mainframe/DesignerScaleMouseWheelHandler.java @@ -0,0 +1,31 @@ +package com.fr.design.mainframe; + +import java.awt.event.MouseWheelEvent; +import java.awt.event.MouseWheelListener; + +/** + * @author Starryi + * @version 1.0 + * Created by Starryi on 2021/9/23 + */ +public class DesignerScaleMouseWheelHandler implements MouseWheelListener { + private final ScalePane scalePane; + private final int step; + + public DesignerScaleMouseWheelHandler(ScalePane scalePane, int step) { + this.scalePane = scalePane; + this.step = step; + } + + @Override + public void mouseWheelMoved(MouseWheelEvent e) { + int dir = e.getWheelRotation(); + JFormSliderPane slidePane = this.scalePane.getSlidePane(); + int old_resolution = slidePane.getShowValue(); + slidePane.setShowValue(old_resolution - (dir * step)); + } + + public interface ScalePane { + JFormSliderPane getSlidePane(); + } +} diff --git a/designer-form/src/main/java/com/fr/design/mainframe/DesignerTranslateMouseWheelHandler.java b/designer-form/src/main/java/com/fr/design/mainframe/DesignerTranslateMouseWheelHandler.java new file mode 100644 index 000000000..82d2cb1b8 --- /dev/null +++ b/designer-form/src/main/java/com/fr/design/mainframe/DesignerTranslateMouseWheelHandler.java @@ -0,0 +1,279 @@ +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 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(); + } +} \ No newline at end of file diff --git a/designer-form/src/main/java/com/fr/design/mainframe/FormArea.java b/designer-form/src/main/java/com/fr/design/mainframe/FormArea.java index 648a2845d..d7a8e1d2a 100644 --- a/designer-form/src/main/java/com/fr/design/mainframe/FormArea.java +++ b/designer-form/src/main/java/com/fr/design/mainframe/FormArea.java @@ -74,8 +74,8 @@ public class FormArea extends JComponent implements ScrollRulerComponent { private static final String SCALE_MINUS_COMMAND = "scale_minus"; public static final double DEFAULT_SLIDER = 100.0; private static final int ROTATIONS = 50; - private static final int SHOWVALMAX = 400; - private static final int SHOWVALMIN = 10; + public static final int SHOWVALMAX = 400; + public static final int SHOWVALMIN = 10; private static final int RESIZE_PANE_GAP = 8; private static final int MOBILE_ONLY_WIDTH = 375; private static final int MOBILE_ONLY_HEIGHT = 560; @@ -132,10 +132,24 @@ public class FormArea extends JComponent implements ScrollRulerComponent { addFormRuler(); } this.setFocusTraversalKeysEnabled(false); - this.designer.addMouseWheelListener(showValSpinnerMouseWheelListener); + + + this.designer.addMouseWheelListener(new FormAreaMouseWheelHandler(this)); registerShortCutKey(); } + public FormScrollBar getVerticalScrollBar() { + return verScrollBar; + } + + public FormScrollBar getHorizontalScrollBar() { + return horScrollBar; + } + + public JFormSliderPane getSlidePane() { + return slidePane; + } + /** * 注册缩放快捷键 * mac: command + 和 command - @@ -169,17 +183,6 @@ public class FormArea extends JComponent implements ScrollRulerComponent { widthPane.setEnabled(!formMobileAttr.isMobileOnly()); } - MouseWheelListener showValSpinnerMouseWheelListener = new MouseWheelListener() { - @Override - public void mouseWheelMoved(MouseWheelEvent e) { - if (InputEventBaseOnOS.isControlDown(e)) { - int dir = e.getWheelRotation(); - int old_resolution = slidePane.getShowValue(); - slidePane.setShowValue(old_resolution - (dir * SHOWVALMIN)); - } - } - }; - private UIButton createFixLayoutSwitchButton(){ UIButton button = new UIButton(com.fr.design.i18n.Toolkit.i18nText("Fine-Design_Form_Layout_No_Fix_Layout")); button.setIcon(IOUtils.readIcon("/com/fr/base/images/share/filter_combo.png")); diff --git a/designer-form/src/main/java/com/fr/design/mainframe/FormAreaMouseWheelHandler.java b/designer-form/src/main/java/com/fr/design/mainframe/FormAreaMouseWheelHandler.java new file mode 100644 index 000000000..6c4095a45 --- /dev/null +++ b/designer-form/src/main/java/com/fr/design/mainframe/FormAreaMouseWheelHandler.java @@ -0,0 +1,75 @@ +package com.fr.design.mainframe; + +import com.fr.common.inputevent.InputEventBaseOnOS; + +import javax.swing.JScrollBar; +import javax.swing.JViewport; +import java.awt.event.MouseWheelEvent; +import java.awt.event.MouseWheelListener; + +/** + * @author Starryi + * @version 1.0 + * Created by Starryi on 2021/9/24 + */ +public class FormAreaMouseWheelHandler implements MouseWheelListener { + private final DesignerTranslateMouseWheelHandler translateMouseWheelHandler; + private final DesignerScaleMouseWheelHandler scaleMouseWheelHandler; + + public FormAreaMouseWheelHandler(FormArea formArea) { + translateMouseWheelHandler = new DesignerTranslateMouseWheelHandler(new FormAreaScrollPaneAdapter(formArea)); + scaleMouseWheelHandler = new DesignerScaleMouseWheelHandler(new FormAreaScalePaneAdapter(formArea), FormArea.SHOWVALMIN); + } + + @Override + public void mouseWheelMoved(MouseWheelEvent e) { + if (InputEventBaseOnOS.isControlDown(e)) { + scaleMouseWheelHandler.mouseWheelMoved(e); + } else { + translateMouseWheelHandler.mouseWheelMoved(e); + } + } + + private static class FormAreaScalePaneAdapter implements DesignerScaleMouseWheelHandler.ScalePane { + private final FormArea formArea; + + public FormAreaScalePaneAdapter(FormArea formArea) { + this.formArea = formArea; + } + + @Override + public JFormSliderPane getSlidePane() { + return formArea.getSlidePane(); + } + } + + private static class FormAreaScrollPaneAdapter implements DesignerTranslateMouseWheelHandler.ScrollPane { + private final FormArea formArea; + private final JViewport viewport; + + public FormAreaScrollPaneAdapter(FormArea formArea) { + this.formArea = formArea; + this.viewport = new JViewport(); + } + + @Override + public boolean isWheelScrollingEnabled() { + return true; + } + + @Override + public JScrollBar getVerticalScrollBar() { + return formArea.getVerticalScrollBar(); + } + + @Override + public JScrollBar getHorizontalScrollBar() { + return formArea.getHorizontalScrollBar(); + } + + @Override + public JViewport getViewport() { + return this.viewport; + } + } +} diff --git a/designer-realize/src/main/java/com/fr/design/mainframe/ReportComponentComposite.java b/designer-realize/src/main/java/com/fr/design/mainframe/ReportComponentComposite.java index b412d724d..5fe561829 100644 --- a/designer-realize/src/main/java/com/fr/design/mainframe/ReportComponentComposite.java +++ b/designer-realize/src/main/java/com/fr/design/mainframe/ReportComponentComposite.java @@ -34,7 +34,7 @@ public class ReportComponentComposite extends JComponent implements RemoveListen private static final int MAX = 400; private static final int HUND = 100; private static final int MIN = 10; - private static final int DIR = 10; + public static final int DIR = 10; private JWorkBook parent; private UIModeControlContainer parentContainer = null; @@ -66,17 +66,6 @@ public class ReportComponentComposite extends JComponent implements RemoveListen jSliderContainer.addValueChangeListener(showValSpinnerChangeListener); } - MouseWheelListener showValSpinnerMouseWheelListener = new MouseWheelListener() { - @Override - public void mouseWheelMoved(MouseWheelEvent e) { - if (InputEventBaseOnOS.isControlDown(e)) { - int dir = e.getWheelRotation(); - int old_resolution = jSliderContainer.getShowValue(); - jSliderContainer.setShowValue(old_resolution - (dir * DIR)); - } - } - }; - ChangeListener showValSpinnerChangeListener = new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { @@ -130,12 +119,12 @@ public class ReportComponentComposite extends JComponent implements RemoveListen } if (centerCardPane.editingComponet.elementCasePane == null) { - centerCardPane.getPolyDezi().polyArea.addMouseWheelListener(showValSpinnerMouseWheelListener); + centerCardPane.getPolyDezi().polyArea.addMouseWheelListener(new ReportComponentCompositeMouseWheelHandler(this)); return; } Grid grid = centerCardPane.editingComponet.elementCasePane.getGrid(); - this.centerCardPane.editingComponet.elementCasePane.getGrid().addMouseWheelListener(showValSpinnerMouseWheelListener); + this.centerCardPane.editingComponet.elementCasePane.getGrid().addMouseWheelListener(new ReportComponentCompositeMouseWheelHandler(this)); if (!grid.hasFocus() && grid.isRequestFocusEnabled()) { grid.requestFocus(); diff --git a/designer-realize/src/main/java/com/fr/design/mainframe/ReportComponentCompositeMouseWheelHandler.java b/designer-realize/src/main/java/com/fr/design/mainframe/ReportComponentCompositeMouseWheelHandler.java new file mode 100644 index 000000000..e8b41afac --- /dev/null +++ b/designer-realize/src/main/java/com/fr/design/mainframe/ReportComponentCompositeMouseWheelHandler.java @@ -0,0 +1,75 @@ +package com.fr.design.mainframe; + +import com.fr.common.inputevent.InputEventBaseOnOS; + +import javax.swing.JScrollBar; +import javax.swing.JViewport; +import java.awt.event.MouseWheelEvent; +import java.awt.event.MouseWheelListener; + +/** + * @author Starryi + * @version 1.0 + * Created by Starryi on 2021/9/24 + */ +public class ReportComponentCompositeMouseWheelHandler implements MouseWheelListener { + private final DesignerTranslateMouseWheelHandler translateMouseWheelHandler; + private final DesignerScaleMouseWheelHandler scaleMouseWheelHandler; + + public ReportComponentCompositeMouseWheelHandler(ReportComponentComposite componentComposite) { + translateMouseWheelHandler = new DesignerTranslateMouseWheelHandler(new ScrollPaneAdapter(componentComposite)); + scaleMouseWheelHandler = new DesignerScaleMouseWheelHandler(new ScalePaneAdapter(componentComposite), ReportComponentComposite.DIR); + } + + @Override + public void mouseWheelMoved(MouseWheelEvent e) { + if (InputEventBaseOnOS.isControlDown(e)) { + scaleMouseWheelHandler.mouseWheelMoved(e); + } else { + translateMouseWheelHandler.mouseWheelMoved(e); + } + } + + private static class ScrollPaneAdapter implements DesignerTranslateMouseWheelHandler.ScrollPane { + private final ReportComponentComposite componentComposite; + private JViewport viewport; + + public ScrollPaneAdapter(ReportComponentComposite componentComposite) { + this.componentComposite = componentComposite; + this.viewport = new JViewport(); + } + + @Override + public boolean isWheelScrollingEnabled() { + return true; + } + + @Override + public JScrollBar getVerticalScrollBar() { + return componentComposite.getEditingReportComponent().getVerticalScrollBar(); + } + + @Override + public JScrollBar getHorizontalScrollBar() { + return componentComposite.getEditingReportComponent().getHorizontalScrollBar(); + } + + @Override + public JViewport getViewport() { + return viewport; + } + } + + private static class ScalePaneAdapter implements DesignerScaleMouseWheelHandler.ScalePane { + private final ReportComponentComposite componentComposite; + + public ScalePaneAdapter(ReportComponentComposite componentComposite) { + this.componentComposite = componentComposite; + } + + @Override + public JFormSliderPane getSlidePane() { + return componentComposite.getjSliderContainer(); + } + } +}