【发布时间】:2018-11-20 04:16:23
【问题描述】:
我想设置 Scrollpane H 和 V 值,但在调整内部内容大小后。
一些上下文 - 我得到以下结构:
我将.setOnScroll(...)(鼠标)事件附加到 StackPane,当它发生时,内部内容的大小(图像)被调整为某些值(也称为缩放)。我想补充一点,StackPane min size 绑定到滚动窗格视口大小,Pane size 绑定到图像大小,以保持一切正常工作。
到目前为止,一切正常,当内容更改大小时,滚动条会更新,并且一切都会按预期进行调整,但我想保留或将滚动条位置设置为某些值以保持缩放到上一个中间点(类似于放大 Photoshop)。在这种情况下,我在回调中添加了这一行来测试它:
scrollPane.setHvalue(0.5);
该函数本身可以工作,但稍后会被覆盖(可能在重新计算布局时),这样总是错误的。我通过事件测试了值
scrollPane.hvalueProperty().addListener((observable, oldvalue, newvalue) -> {
System.out.println(newvalue);
});
输出有点像
0.5
0.45172283226050736
0.5
0.45196805476326296
0.5
0.4522703818369453
// or this when scaled down
0.5
0.5591296121097445
0.5
0.5608324439701174
这就是为什么我的结论是我成功设置了0.5,但后来的布局可能为调整大小的内容设置了不同的值,因为我将大小限制更改为Pane 和StackPane。
我的问题然后我应该怎么做?
是否有任何 onResize 事件来纠正或强制我自己的值?或其他方式来安排滚动事件或在重新计算布局时完成我的更新?
// 编辑
我清理了代码,这里是示例:
Main.java
package application;
import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.fxml.FXMLLoader;
public class Main extends Application {
@Override
public void start(Stage primaryStage) {
try {
BorderPane root = (BorderPane)FXMLLoader.load(getClass().getResource("Sample.fxml"));
Scene scene = new Scene(root,800,600);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
application.css为空
/* JavaFX CSS - Leave this comment until you have at least create one rule which uses -fx-Property */
Sample.fxml(替换图片网址)
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.Pane?>
<?import javafx.scene.layout.StackPane?>
<BorderPane xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.SampleController">
<center>
<ScrollPane fx:id="scrollPane" prefHeight="600.0" prefWidth="800.0" BorderPane.alignment="CENTER">
<content>
<StackPane fx:id="stackPane">
<children>
<Pane fx:id="clipContainer">
<children>
<ImageView fx:id="img" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="@../../../../Desktop/sample.jpg" />
</image>
</ImageView>
</children>
</Pane>
</children>
</StackPane>
</content>
</ScrollPane>
</center>
</BorderPane>
和SampleController.java
package application;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.beans.binding.Bindings;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.ScrollPane;
import javafx.scene.image.ImageView;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
public class SampleController implements Initializable {
@FXML
private Pane clipContainer;
@FXML
private StackPane stackPane;
@FXML
private ImageView img;
@FXML
private ScrollPane scrollPane;
final double SCALE_DELTA = 1.1;
private double imgW;
private double imgH;
private double scale = 1;
@Override
public void initialize(URL location, ResourceBundle resources) {
clipContainer.setStyle("-fx-background-color: #999999");
stackPane.setStyle("-fx-background-color: #CCCCCC");
imgW = img.getImage().getWidth();
imgH = img.getImage().getHeight();
// bind max and min to adjust to new image bounds
stackPane.minWidthProperty().bind(Bindings.createDoubleBinding(() ->
scrollPane.getViewportBounds().getWidth(), scrollPane.viewportBoundsProperty()
));
stackPane.minHeightProperty().bind(Bindings.createDoubleBinding(() ->
scrollPane.getViewportBounds().getHeight(), scrollPane.viewportBoundsProperty()
));
clipContainer.maxWidthProperty().bind(Bindings.createDoubleBinding(() ->
img.getFitWidth(), img.fitWidthProperty()
));
clipContainer.maxHeightProperty().bind(Bindings.createDoubleBinding(() ->
img.getFitHeight(), img.fitHeightProperty()
));
// initial scale
img.setFitWidth(imgW * 1);
img.setFitHeight(imgH * 1);
// on mouse scroll
stackPane.setOnScroll(event -> {
event.consume();
if (event.getDeltaY() == 0) {
return;
}
double scaleFactor =
(event.getDeltaY() > 0)
? SCALE_DELTA
: 1/SCALE_DELTA;
scale *= scaleFactor;
img.setFitWidth(imgW * scale);
img.setFitHeight(imgH * scale);
// HERE i want to do something to keep my image where it was
scrollPane.setHvalue(0.5);
});
scrollPane.hvalueProperty().addListener((observable, oldvalue, newvalue) -> {
System.out.println(newvalue);
});
}
}
【问题讨论】:
-
你为什么还要使用
ScrollPane?使用ScrollPane调整大小而不是向上/向下/向左/向右滚动对我来说听起来很糟糕。setOnScroll()可以在任何节点上使用。 -
@Jai 我不使用 ScrollPane 来调整大小,而是使用鼠标滚动事件来调整内部图像的大小。滚动窗格用于导航缩放的图像 - 这与 Photoshop 中的缩放画布完全相同,您可以通过滚动条进行导航。我遇到的问题是我想在缩放之前将图像保持在适当位置,这就是为什么我尝试将滚动条设置到某个位置但无论我设置什么都会在稍后更改,可能在布局意识到内部内容更改大小和滚动条最大、最小和我相信价值必须更新。
-
请提供一个minimal reproducible example 来说明问题。
-
@kleopatra 对不起,我以前没有这样做,代码一团糟,我不得不清理很多。我认为这是一个相当简单的问题,并且很容易解决它 - 我的错。我编辑了问题并添加了示例代码,如果可以,请检查一下,谢谢。
标签: java javafx layout scrollbar