- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我正在尝试将一些组件放置在 ScrollPane
中。这些组件应该能够通过鼠标(单击并拖动)在该 Pane 中移动。 ScrollPane
本身可平移和缩放。
现在,如果我选择其中一个并将其拖动到新位置,如果我缩小了鼠标,则鼠标比组件更快。放大时,组件的移动速度比鼠标移动的速度快。
如果不缩放,它会一直工作,直到我到达 ScrollPane
自动平移的特定位置。
它必须对确定的节点坐标做一些事情。有谁知道我必须添加什么才能使其正常工作?
我的 Controller 类:
public class MainWindowController implements Initializable {
private final double SCALE_DELTA = 1.1;
private final StackPane zoomPane = new StackPane();
private Group group = new Group();
@FXML
private ScrollPane scrollPane;
@Override
public void initialize(URL url, ResourceBundle rb) {
Node node1 = new Node("Test");
Node node2 = new Node("Test2", 100, 200);
group.getChildren().addAll(node1, node2);
zoomPane.getChildren().add(group);
Group scrollContent = new Group(zoomPane);
scrollPane.setContent(scrollContent);
scrollPane.viewportBoundsProperty().addListener((ObservableValue<? extends Bounds> observable,
Bounds oldValue, Bounds newValue) -> {
zoomPane.setMinSize(newValue.getWidth(), newValue.getHeight());
});
zoomPane.setOnScroll(
(ScrollEvent event) -> {
event.consume();
if (event.getDeltaY() == 0) {
return;
}
double scaleFactor = (event.getDeltaY() > 0) ? SCALE_DELTA : 1 / SCALE_DELTA;
Point2D scrollOffset = figureScrollOffset(scrollContent, scrollPane);
group.setScaleX(group.getScaleX() * scaleFactor);
group.setScaleY(group.getScaleY() * scaleFactor);
repositionScroller(scrollContent, scrollPane, scaleFactor, scrollOffset);
}
);
group.getChildren()
.add(new Node("Test3", 500, 500));
}
private Point2D figureScrollOffset(javafx.scene.Node scrollContent, ScrollPane scroller) {
double extraWidth = scrollContent.getLayoutBounds().getWidth() - scroller.getViewportBounds().getWidth();
double hScrollProportion = (scroller.getHvalue() - scroller.getHmin()) / (scroller.getHmax() - scroller.getHmin());
double scrollXOffset = hScrollProportion * Math.max(0, extraWidth);
double extraHeight = scrollContent.getLayoutBounds().getHeight() - scroller.getViewportBounds().getHeight();
double vScrollProportion = (scroller.getVvalue() - scroller.getVmin()) / (scroller.getVmax() - scroller.getVmin());
double scrollYOffset = vScrollProportion * Math.max(0, extraHeight);
return new Point2D(scrollXOffset, scrollYOffset);
}
private void repositionScroller(javafx.scene.Node scrollContent, ScrollPane scroller, double scaleFactor, Point2D scrollOffset) {
double scrollXOffset = scrollOffset.getX();
double scrollYOffset = scrollOffset.getY();
double extraWidth = scrollContent.getLayoutBounds().getWidth() - scroller.getViewportBounds().getWidth();
if (extraWidth > 0) {
double halfWidth = scroller.getViewportBounds().getWidth() / 2;
double newScrollXOffset = (scaleFactor - 1) * halfWidth + scaleFactor * scrollXOffset;
scroller.setHvalue(scroller.getHmin() + newScrollXOffset * (scroller.getHmax() - scroller.getHmin()) / extraWidth);
} else {
scroller.setHvalue(scroller.getHmin());
}
double extraHeight = scrollContent.getLayoutBounds().getHeight() - scroller.getViewportBounds().getHeight();
if (extraHeight > 0) {
double halfHeight = scroller.getViewportBounds().getHeight() / 2;
double newScrollYOffset = (scaleFactor - 1) * halfHeight + scaleFactor * scrollYOffset;
scroller.setVvalue(scroller.getVmin() + newScrollYOffset * (scroller.getVmax() - scroller.getVmin()) / extraHeight);
} else {
scroller.setHvalue(scroller.getHmin());
}
}
}
节点类:
public class Node extends Parent {
private NodeStatus status = NodeStatus.OK;
private final Image okImage = new Image(getClass().getResourceAsStream("/images/MasterOK.png"));
private ImageView image = new ImageView(okImage);
private final Text label = new Text();
private final Font font = Font.font("Courier", 20);
double orgSceneX, orgSceneY;
double layoutX, layoutY;
public Node(String labelText) {
this(labelText, 0, 0);
}
public Node(String labelText, double x, double y) {
label.setText(labelText);
label.setFont(font);
label.setLayoutX(okImage.getWidth() + 10);
label.setLayoutY(okImage.getHeight() / 2 + 10);
getChildren().add(image);
getChildren().add(label);
setLayoutX(x);
setLayoutY(y);
setCursor(Cursor.MOVE);
setOnMousePressed(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent t) {
orgSceneX = t.getSceneX();
orgSceneY = t.getSceneY();
layoutX = getLayoutX();
layoutY = getLayoutY();
}
});
setOnMouseDragged(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent t) {
setLayoutX(layoutX + t.getSceneX() - orgSceneX);
setLayoutY(layoutY + t.getSceneY() - orgSceneY);
}
});
}
public NodeStatus getStatus() {
return status;
}
public void setStatus(NodeStatus status) {
this.status = status;
}
}
class Delta {
double x, y;
}
和 fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import nodes.*?>
<AnchorPane id="AnchorPane" prefHeight="600.0" prefWidth="800.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="cqsmonitor.MainWindowController">
<children>
<Pane layoutX="666.0" layoutY="14.0" prefHeight="572.0" prefWidth="114.0" AnchorPane.bottomAnchor="14.0" AnchorPane.rightAnchor="14.0" AnchorPane.topAnchor="14.0">
<children>
<TextField layoutY="30.0" prefHeight="25.0" prefWidth="114.0" />
<Label layoutY="12.0" text="Search:" />
<ChoiceBox layoutY="90.0" prefHeight="25.0" prefWidth="114.0" />
<Label layoutY="73.0" text="View:" />
</children>
</Pane>
<ScrollPane fx:id="scrollPane" layoutX="14.0" layoutY="14.0" pannable="true" prefHeight="571.0" prefWidth="644.0" AnchorPane.bottomAnchor="15.0" AnchorPane.leftAnchor="14.0" AnchorPane.rightAnchor="142.0" AnchorPane.topAnchor="14.0">
</ScrollPane>
</children>
</AnchorPane>
最佳答案
由于还没有人回答,这里有一些代码。我不想深入研究你的问题并重新发明轮子。
您可以使用鼠标左键拖动来移动节点,使用鼠标滚轮缩放 Pane ,使用鼠标右键平移 Pane 。不需要 ScrollPane。但是,如果您想要 ScrollBars,您可以根据需要随时添加它们。
代码:
import javafx.application.Application;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.Label;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.ScrollEvent;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
/**
* The canvas which holds all of the nodes of the application.
*/
class PannableCanvas extends Pane {
DoubleProperty myScale = new SimpleDoubleProperty(1.0);
public PannableCanvas() {
setPrefSize(600, 600);
setStyle("-fx-background-color: lightgrey; -fx-border-color: blue;");
// add scale transform
scaleXProperty().bind(myScale);
scaleYProperty().bind(myScale);
// logging
addEventFilter(MouseEvent.MOUSE_PRESSED, event -> {
System.out.println(
"canvas event: " + ( ((event.getSceneX() - getBoundsInParent().getMinX()) / getScale()) + ", scale: " + getScale())
);
System.out.println( "canvas bounds: " + getBoundsInParent());
});
}
/**
* Add a grid to the canvas, send it to back
*/
public void addGrid() {
double w = getBoundsInLocal().getWidth();
double h = getBoundsInLocal().getHeight();
// add grid
Canvas grid = new Canvas(w, h);
// don't catch mouse events
grid.setMouseTransparent(true);
GraphicsContext gc = grid.getGraphicsContext2D();
gc.setStroke(Color.GRAY);
gc.setLineWidth(1);
// draw grid lines
double offset = 50;
for( double i=offset; i < w; i+=offset) {
// vertical
gc.strokeLine( i, 0, i, h);
// horizontal
gc.strokeLine( 0, i, w, i);
}
getChildren().add( grid);
grid.toBack();
}
public double getScale() {
return myScale.get();
}
/**
* Set x/y scale
* @param myScale
*/
public void setScale( double scale) {
myScale.set(scale);
}
/**
* Set x/y pivot points
* @param x
* @param y
*/
public void setPivot( double x, double y) {
setTranslateX(getTranslateX()-x);
setTranslateY(getTranslateY()-y);
}
}
/**
* Mouse drag context used for scene and nodes.
*/
class DragContext {
double mouseAnchorX;
double mouseAnchorY;
double translateAnchorX;
double translateAnchorY;
}
/**
* Listeners for making the nodes draggable via left mouse button. Considers if parent is zoomed.
*/
class NodeGestures {
private DragContext nodeDragContext = new DragContext();
PannableCanvas canvas;
public NodeGestures( PannableCanvas canvas) {
this.canvas = canvas;
}
public EventHandler<MouseEvent> getOnMousePressedEventHandler() {
return onMousePressedEventHandler;
}
public EventHandler<MouseEvent> getOnMouseDraggedEventHandler() {
return onMouseDraggedEventHandler;
}
private EventHandler<MouseEvent> onMousePressedEventHandler = new EventHandler<MouseEvent>() {
public void handle(MouseEvent event) {
// left mouse button => dragging
if( !event.isPrimaryButtonDown())
return;
nodeDragContext.mouseAnchorX = event.getSceneX();
nodeDragContext.mouseAnchorY = event.getSceneY();
Node node = (Node) event.getSource();
nodeDragContext.translateAnchorX = node.getTranslateX();
nodeDragContext.translateAnchorY = node.getTranslateY();
}
};
private EventHandler<MouseEvent> onMouseDraggedEventHandler = new EventHandler<MouseEvent>() {
public void handle(MouseEvent event) {
// left mouse button => dragging
if( !event.isPrimaryButtonDown())
return;
double scale = canvas.getScale();
Node node = (Node) event.getSource();
node.setTranslateX(nodeDragContext.translateAnchorX + (( event.getSceneX() - nodeDragContext.mouseAnchorX) / scale));
node.setTranslateY(nodeDragContext.translateAnchorY + (( event.getSceneY() - nodeDragContext.mouseAnchorY) / scale));
event.consume();
}
};
}
/**
* Listeners for making the scene's canvas draggable and zoomable
*/
class SceneGestures {
private static final double MAX_SCALE = 10.0d;
private static final double MIN_SCALE = .1d;
private DragContext sceneDragContext = new DragContext();
PannableCanvas canvas;
public SceneGestures( PannableCanvas canvas) {
this.canvas = canvas;
}
public EventHandler<MouseEvent> getOnMousePressedEventHandler() {
return onMousePressedEventHandler;
}
public EventHandler<MouseEvent> getOnMouseDraggedEventHandler() {
return onMouseDraggedEventHandler;
}
public EventHandler<ScrollEvent> getOnScrollEventHandler() {
return onScrollEventHandler;
}
private EventHandler<MouseEvent> onMousePressedEventHandler = new EventHandler<MouseEvent>() {
public void handle(MouseEvent event) {
// right mouse button => panning
if( !event.isSecondaryButtonDown())
return;
sceneDragContext.mouseAnchorX = event.getSceneX();
sceneDragContext.mouseAnchorY = event.getSceneY();
sceneDragContext.translateAnchorX = canvas.getTranslateX();
sceneDragContext.translateAnchorY = canvas.getTranslateY();
}
};
private EventHandler<MouseEvent> onMouseDraggedEventHandler = new EventHandler<MouseEvent>() {
public void handle(MouseEvent event) {
// right mouse button => panning
if( !event.isSecondaryButtonDown())
return;
canvas.setTranslateX(sceneDragContext.translateAnchorX + event.getSceneX() - sceneDragContext.mouseAnchorX);
canvas.setTranslateY(sceneDragContext.translateAnchorY + event.getSceneY() - sceneDragContext.mouseAnchorY);
event.consume();
}
};
/**
* Mouse wheel handler: zoom to pivot point
*/
private EventHandler<ScrollEvent> onScrollEventHandler = new EventHandler<ScrollEvent>() {
@Override
public void handle(ScrollEvent event) {
double delta = 1.2;
double scale = canvas.getScale(); // currently we only use Y, same value is used for X
double oldScale = scale;
if (event.getDeltaY() < 0)
scale /= delta;
else
scale *= delta;
scale = clamp( scale, MIN_SCALE, MAX_SCALE);
double f = (scale / oldScale)-1;
double dx = (event.getSceneX() - (canvas.getBoundsInParent().getWidth()/2 + canvas.getBoundsInParent().getMinX()));
double dy = (event.getSceneY() - (canvas.getBoundsInParent().getHeight()/2 + canvas.getBoundsInParent().getMinY()));
canvas.setScale( scale);
// note: pivot value must be untransformed, i. e. without scaling
canvas.setPivot(f*dx, f*dy);
event.consume();
}
};
public static double clamp( double value, double min, double max) {
if( Double.compare(value, min) < 0)
return min;
if( Double.compare(value, max) > 0)
return max;
return value;
}
}
/**
* An application with a zoomable and pannable canvas.
*/
public class ZoomAndScrollApplication extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage stage) {
Group group = new Group();
// create canvas
PannableCanvas canvas = new PannableCanvas();
// we don't want the canvas on the top/left in this example => just
// translate it a bit
canvas.setTranslateX(100);
canvas.setTranslateY(100);
// create sample nodes which can be dragged
NodeGestures nodeGestures = new NodeGestures( canvas);
Label label1 = new Label("Draggable node 1");
label1.setTranslateX(10);
label1.setTranslateY(10);
label1.addEventFilter( MouseEvent.MOUSE_PRESSED, nodeGestures.getOnMousePressedEventHandler());
label1.addEventFilter( MouseEvent.MOUSE_DRAGGED, nodeGestures.getOnMouseDraggedEventHandler());
Label label2 = new Label("Draggable node 2");
label2.setTranslateX(100);
label2.setTranslateY(100);
label2.addEventFilter( MouseEvent.MOUSE_PRESSED, nodeGestures.getOnMousePressedEventHandler());
label2.addEventFilter( MouseEvent.MOUSE_DRAGGED, nodeGestures.getOnMouseDraggedEventHandler());
Label label3 = new Label("Draggable node 3");
label3.setTranslateX(200);
label3.setTranslateY(200);
label3.addEventFilter( MouseEvent.MOUSE_PRESSED, nodeGestures.getOnMousePressedEventHandler());
label3.addEventFilter( MouseEvent.MOUSE_DRAGGED, nodeGestures.getOnMouseDraggedEventHandler());
Circle circle1 = new Circle( 300, 300, 50);
circle1.setStroke(Color.ORANGE);
circle1.setFill(Color.ORANGE.deriveColor(1, 1, 1, 0.5));
circle1.addEventFilter( MouseEvent.MOUSE_PRESSED, nodeGestures.getOnMousePressedEventHandler());
circle1.addEventFilter( MouseEvent.MOUSE_DRAGGED, nodeGestures.getOnMouseDraggedEventHandler());
Rectangle rect1 = new Rectangle(100,100);
rect1.setTranslateX(450);
rect1.setTranslateY(450);
rect1.setStroke(Color.BLUE);
rect1.setFill(Color.BLUE.deriveColor(1, 1, 1, 0.5));
rect1.addEventFilter( MouseEvent.MOUSE_PRESSED, nodeGestures.getOnMousePressedEventHandler());
rect1.addEventFilter( MouseEvent.MOUSE_DRAGGED, nodeGestures.getOnMouseDraggedEventHandler());
canvas.getChildren().addAll(label1, label2, label3, circle1, rect1);
group.getChildren().add(canvas);
// create scene which can be dragged and zoomed
Scene scene = new Scene(group, 1024, 768);
SceneGestures sceneGestures = new SceneGestures(canvas);
scene.addEventFilter( MouseEvent.MOUSE_PRESSED, sceneGestures.getOnMousePressedEventHandler());
scene.addEventFilter( MouseEvent.MOUSE_DRAGGED, sceneGestures.getOnMouseDraggedEventHandler());
scene.addEventFilter( ScrollEvent.ANY, sceneGestures.getOnScrollEventHandler());
stage.setScene(scene);
stage.show();
canvas.addGrid();
}
}
如果这对您一点帮助都没有,请告诉我,然后我会删除帖子。我对赏金不感兴趣。
关于java - 在可平移/可缩放 Pane 中选取并移动节点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32220042/
我在 div 和 jquery ui slider 中有一个图像列表,当用户滑动栏时,图像应该调整大小/缩放(无论你想怎么调用它),我尝试选择所有图像并更改 css 的宽度和使用 jquery 的高度
我正在制作一张具有缩放和平移功能的世界地图。我在某些城市上画了圆圈,圆圈的半径由数据决定。当鼠标悬停在这些圆圈上时,将出现一个工具提示来显示数据。 代码结构为 //在此选择上调用缩放行为 - 让我们调
我正在使用 jquery UI slider (http://jqueryui.com/slider/)。 我需要对整个站点进行缩放。使用 css 样式在 IE+Chrome im 中缩放 - “缩放
我花了很多时间试图找到一种使用 CGAffineScale 将 View 转换为给定点的方法,包括摆弄 anchor 、在转换前后移动 View 的中心以及全面的谷歌搜索。我知道使用 UIScroll
我希望能够用手指旋转和缩放/缩放我的位图,我已经为此寻找了所有示例项目,但它们都与我的代码不匹配。这是我的 onTouchListener 代码。 public class MyView extend
在我的页面中间,我有一个 div 元素,其中包含一些内容(其他 div、图像等)。 before something inside another something
我一直在尝试使用 google maps API V3 的绘图管理器(绘制矩形)。使用 -webkit-transform 缩放谷歌地图 Canvas (包含 div)后像这样 var transf
这个问题在这里已经有了答案: How to resize the iPhone/iPad Simulator? (12 个答案) 关闭 5 年前。 我正在编写 iOS 应用 我使用 Xcode 6.
这几天一直在研究微服务,我想知道人们是如何着手自动化负载平衡和扩展这些东西的? 我心中有一个特定的场景,我想实现什么,但不确定是否可行,或者我的想法有误。就这样吧…… 假设我有一个由 3 台名为 A、
我正在使用 ffmpeg for android 来制作 mp4 格式的视频。我无法让这个命令在 FFMPEG 中工作,基本上我正在尝试添加两个图像,缩放它们,添加缩放效果,最后将结果连接到一个视频文
使用 OpenGL 我正在尝试绘制我校园的原始 map 。 谁能向我解释一下平移、缩放和旋转通常是如何实现的? 例如,通过平移和缩放,这仅仅是我调整我的视口(viewport)吗?所以我绘制并绘制了构
我需要在 iphone sdk 界面生成器中将按钮旋转 30 度,该怎么做? 最佳答案 您无法在 Interface Builder 中执行此操作,但代码非常简单。 确保您已将 IB 中的按钮连接到
假设默认级别等于“1”,是否可以检测触摸设备的捏合(缩放)级别?原因是我希望根据捏合级别禁用页面元素(显示:无)。 如果可以将其放在一个设置缩放级别值的函数中,那就太好了,例如: var ZOOM =
我正在努力找出并确定如何根据这个例子放大我的鼠标位置。 (https://stackblitz.com/edit/js-fxnmkm?file=index.js) let node, scal
我已将 UIWebView 的“scalesPageToFit”属性设置为 YES。 它正在缩放,但是当页面加载时,内容的字体很小,不捏就无法阅读。我们可以将缩放比例设置为默认值吗? 最佳答案 这更多
我仍在学习 jQuery mobile 的技巧,并且在 data-role="page"上放大和缩小图片/图像时遇到问题。有没有办法使用 jquery mobile 在 iPhone 上的图像上进行捏
给定一组 n 个维度为 d 的向量,存储在 (n,d) 数组中,以及第二组 m 相同维度的向量(存储在 (m,d) 数组中)我想计算向量之间的平方点距离,由大小为 的某个矩阵 A 缩放>(d,d)。
我想知道是否有人可以指出我正确的方向。 我使用 CSS3 过渡创建了缩放效果。将鼠标悬停在该对象上,它会转换为更大的版本。这看起来很棒并且效果很棒,但问题是这种效果在 IE 中不起作用,所以我需要在
mapbox-gl-js 版本:0.38.0在 ionic 2.2.11 上通过 npm repo 使用 正如您在这张 gif 上看到的 https://giphy.com/gifs/ionic-an
所以我花了几个小时在网上搜索帮助,但所有论坛和文档都没有向我正确解释我应该采取的最佳方式。 目前我有一个具有 XML 相对布局的 Activity (背景设置为 map 图片),我想实现多手势缩放功能
我是一名优秀的程序员,十分优秀!