放大JavaFx:当内容大小超过ScrollPane视口时,将使用ScrollEvent [英] Zooming in JavaFx: ScrollEvent is consumed when content size exceeds ScrollPane viewport

查看:124
本文介绍了放大JavaFx:当内容大小超过ScrollPane视口时,将使用ScrollEvent的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个需要在ScrollPane内缩放的应用程序,但是按照我目前的方法,我仍然面临2个挑战。为了重现该问题,我编写了一个小的应用程序ZoomApp,您将在下面找到其代码。其有限的功能允许放大和缩小(使用Ctrl +鼠标滚轮)某些任意形状。当缩放的内容超出窗口范围时,滚动条应该朝上。



挑战1。
由于 innerGroup 的大小而出现,ScrollEvent不再到达我的ZoomHandler。取而代之的是,我们开始向下滚动窗口,直到到达底部为止。我以为

  scrollPane.setPannable(false); 

会有所作为,但不会。



挑战2。
我该如何以 innerGroup为中心在scrollPane中,而又不求在 innerGroup 的左上角绘制一个像素,该像素具有所需的正方形增量?



附带说明,根据ScrollPane的JavaDoc:如果应用程序希望滚动基于节点的可视范围(用于缩放内容等),则它们需要将滚动节点包装在Group中 / em>。这就是为什么在ScrollPane中有一个 innerGroup 一个 outerGroup 的原因。



  import javafx.application.Application;>任何指导我找到该解决方案的建议,都会受到JavaFX新手的赞赏。 
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.SceneBuilder;
import javafx.scene.control.ScrollPane;
import javafx.scene.input.ScrollEvent;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;

/ **
*我在{@code ScrollPane}中放大遇到的挑战演示。
*< br>
*我在Mac上运行JavaFx 2.2。 {@code java -version}产生:
*< pre>
* Java版本 1.7.0_09
* Java(TM)SE Runtime Environment(内部版本1.7.0_09-b05)
* Java HotSpot(TM)64位服务器VM(内部版本23.5) -b02,混合模式)
*< / pre>
*绘制了6个矩形,并且可以使用
*< pre>
* Ctrl +鼠标滚轮
*或Ctrl + 2个手指在键盘上。
*< / pre>
*它重现了我正在编写的应用程序中遇到的问题。
*如果您放大到{@link #MAX_SCALE},则尝试放大到{@link #MIN_SCALE}时会出现一个有趣的问题。在开始的
*中,您将看到{@code scrollPane}滚动并使用{@code ScrollEvent},直到我们滚动到窗口底部为止。
*一旦到达窗口的底部,它就会像预期的那样运行(或至少达到我的预期)。
*
* @author SkjalgBjørndal
* @自2012.11.05
* /
公共类ZoomApp扩展了应用程序{

private static final int WINDOW_WIDTH = 800;
private static final int WINDOW_HEIGHT = 600;

私人静态最终双精度MAX_SCALE = 2.5d;
private static final double MIN_SCALE = .5d;

私有类ZoomHandler实现了EventHandler< ScrollEvent> {

专用节点nodeToZoom;

private ZoomHandler(Node nodeToZoom){
this.nodeToZoom = nodeToZoom;
}

@Override
公共无效句柄(ScrollEvent scrollEvent){
if(scrollEvent.isControlDown()){
最终双倍缩放= calculateScale( scrollEvent);
nodeToZoom.setScaleX(scale);
nodeToZoom.setScaleY(scale);
scrollEvent.consume();
}
}

私人double computeScale(ScrollEvent scrollEvent){
double scale = nodeToZoom.getScaleX()+ scrollEvent.getDeltaY()/ 100;

if(scale< = MIN_SCALE){
scale = MIN_SCALE;
}否则,如果(scale> = MAX_SCALE){
scale = MAX_SCALE;
}
的回报比例;
}
}

public static void main(String [] args){
launch(args);
}

@Override
public void start(阶段)引发异常{

final Group innerGroup = createSixRectangles();
最终组externalGroup =新组(innerGroup);

最终ScrollPane scrollPane = new ScrollPane();
scrollPane.setContent(outerGroup);
scrollPane.setOnScroll(new ZoomHandler(innerGroup));

StackPane stackPane =新的StackPane();
stackPane.getChildren()。add(scrollPane);

场景= SceneBuilder.create()
.width(WINDOW_WIDTH)
.height(WINDOW_HEIGHT)
.root(stackPane)
.build( );

stage.setScene(scene);
stage.show();
}

private Group createSixRectangles(){
return new Group(
createRectangle(0,0),createRectangle(110,0),createRectangle(220,0 ),
createRectangle(0、110),createRectangle(110、110),createRectangle(220、110),
createRectangle(0、220),createRectangle(110、220),createRectangle(220、220 )
);
}

私人矩形createRectangle(int x,int y){
Rectangleangle = new Rectangle(x,y,100,100);
angle.setStroke(Color.ORANGERED);
angle.setFill(Color.ORANGE);
矩形.setStrokeWidth(3d);
返回矩形;
}
}


解决方案

OK ,所以我终于找到了解决问题的方法。


只需替换行

  scrollPane.setOnScroll (新的ZoomHandler(innerGroup)); 

with

  scrollPane.addEventFilter( ScrollEvent.ANY,新的ZoomHandler(innerGroup)); 

它现在可以正常工作了。不需要神秘的矩形或其他技巧。


所以下一个问题是为什么?根据这篇关于处理事件的出色文章


在事件捕获阶段执行事件过滤器。


while


在事件冒泡阶段执行一个事件处理程序。


我认为这是有区别的。


I have an application that requires zoom inside a ScrollPane, but with my current approach I'm still facing 2 challenges. In order to replicate the problem, I have written a small application ZoomApp that you will find the code for underneath. Its' limited functionality allows zooming in and out (using Ctrl + Mouse Wheel) on some arbitrary shapes. When the zoomed content grows outside the bounds of the window, scroll bars should apperar.

Challenge 1. When the scroll bars appears as a consequence of innerGroup scales up in size, the ScrollEvent no longer reach my ZoomHandler. Instead, we start scrolling down the window, until it reaches the bottom, when zooming again works as expect. I thought maybe

scrollPane.setPannable(false);

would make a difference, but no. How should this unwanted behaviour be avoided?

Challenge 2. How would I go about to center innerGroup inside the scrollPane, without resorting to paint a pixel in the upper left corner of innerGroup with the desired delta to the squares?

As a sidenote, according to the JavaDoc for ScrollPane: "If an application wants the scrolling to be based on the visual bounds of the node (for scaled content etc.), they need to wrap the scroll node in a Group". This is the reason why I have an innerGroup and an outerGroup inside ScrollPane.

Any suggestions that guides me to the solution is much appreciated by this JavaFX novice.

import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.SceneBuilder;
import javafx.scene.control.ScrollPane;
import javafx.scene.input.ScrollEvent;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;

/**
 * Demo of a challenge I have with zooming inside a {@code ScrollPane}.
 * <br>
 * I am running JavaFx 2.2 on a Mac. {@code java -version} yields:
 * <pre>
 * java version "1.7.0_09"
 * Java(TM) SE Runtime Environment (build 1.7.0_09-b05)
 * Java HotSpot(TM) 64-Bit Server VM (build 23.5-b02, mixed mode)
 * </pre>
 * 6 rectangles are drawn, and can be zoomed in and out using either
 * <pre>
 * Ctrl + Mouse Wheel
 * or Ctrl + 2 fingers on the pad.
 * </pre>
 * It reproduces a problem I experience inside an application I am writing.
 * If you magnify to {@link #MAX_SCALE}, an interesting problem occurs when you try to zoom back to {@link #MIN_SCALE}. In the beginning
 * you will see that the {@code scrollPane} scrolls and consumes the {@code ScrollEvent} until we have scrolled to the bottom of the window.
 * Once the bottom of the window is reached, it behaves as expected (or at least as I was expecting).
 *
 * @author Skjalg Bjørndal
 * @since 2012.11.05
 */
public class ZoomApp extends Application {

    private static final int WINDOW_WIDTH = 800;
    private static final int WINDOW_HEIGHT = 600;

    private static final double MAX_SCALE = 2.5d;
    private static final double MIN_SCALE = .5d;

    private class ZoomHandler implements EventHandler<ScrollEvent> {

        private Node nodeToZoom;

        private ZoomHandler(Node nodeToZoom) {
            this.nodeToZoom = nodeToZoom;
        }

        @Override
        public void handle(ScrollEvent scrollEvent) {
            if (scrollEvent.isControlDown()) {
                final double scale = calculateScale(scrollEvent);
                nodeToZoom.setScaleX(scale);
                nodeToZoom.setScaleY(scale);
                scrollEvent.consume();
            }
        }

        private double calculateScale(ScrollEvent scrollEvent) {
            double scale = nodeToZoom.getScaleX() + scrollEvent.getDeltaY() / 100;

            if (scale <= MIN_SCALE) {
                scale = MIN_SCALE;
            } else if (scale >= MAX_SCALE) {
                scale = MAX_SCALE;
            }
            return scale;
        }
    }

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage stage) throws Exception {

        final Group innerGroup = createSixRectangles();
        final Group outerGroup = new Group(innerGroup);

        final ScrollPane scrollPane = new ScrollPane();
        scrollPane.setContent(outerGroup);
        scrollPane.setOnScroll(new ZoomHandler(innerGroup));

        StackPane stackPane = new StackPane();
        stackPane.getChildren().add(scrollPane);

        Scene scene = SceneBuilder.create()
                .width(WINDOW_WIDTH)
                .height(WINDOW_HEIGHT)
                .root(stackPane)
                .build();

        stage.setScene(scene);
        stage.show();
    }

    private Group createSixRectangles() {
        return new Group(
                createRectangle(0, 0), createRectangle(110, 0), createRectangle(220, 0),
                createRectangle(0, 110), createRectangle(110, 110), createRectangle(220, 110),
                createRectangle(0, 220), createRectangle(110, 220), createRectangle(220, 220)
        );
    }

    private Rectangle createRectangle(int x, int y) {
        Rectangle rectangle = new Rectangle(x, y, 100, 100);
        rectangle.setStroke(Color.ORANGERED);
        rectangle.setFill(Color.ORANGE);
        rectangle.setStrokeWidth(3d);
        return rectangle;
    }
}

解决方案

OK, so I finally found a solution to my problem.

By merely substituting the line

   scrollPane.setOnScroll(new ZoomHandler(innerGroup));

with

    scrollPane.addEventFilter(ScrollEvent.ANY, new ZoomHandler(innerGroup));

it now works as expected. No mystic Rectangle or other hacks are needed.

So the next question is why? According to this excellent article on Processing Events,

An event filter is executed during the event capturing phase.

while

An event handler is executed during the event bubbling phase.

I assume this is what makes the difference.

这篇关于放大JavaFx:当内容大小超过ScrollPane视口时,将使用ScrollEvent的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆