调整内容大小时保留或设置JavaFX滚动窗格位置
我想设置滚动窗格的H和V值,但在调整内部内容的大小之后。 一些上下文-我得到了以下结构: 我将调整内容大小时保留或设置JavaFX滚动窗格位置,java,javafx,layout,scrollbar,Java,Javafx,Layout,Scrollbar,我想设置滚动窗格的H和V值,但在调整内部内容的大小之后。 一些上下文-我得到了以下结构: 我将.setOnScroll(…)(鼠标)事件附加到StackPane,当它发生时,内部内容的大小(图像)将调整为某些值(也称为缩放)。我想添加StackPane最小大小绑定到滚动窗格视口大小,窗格大小绑定到图像大小,以保持一切正常工作 到目前为止,一切都很好,当内容改变大小时,滚动条会更新,所有内容都会按预期进行调整,但我想保持或更确切地说,将滚动条位置设置为一些值,以保持缩放到上一个中间点(类似于ph
.setOnScroll(…)
(鼠标)事件附加到StackPane,当它发生时,内部内容的大小(图像)将调整为某些值(也称为缩放)。我想添加StackPane最小大小绑定到滚动窗格视口大小,窗格大小绑定到图像大小,以保持一切正常工作
到目前为止,一切都很好,当内容改变大小时,滚动条会更新,所有内容都会按预期进行调整,但我想保持或更确切地说,将滚动条位置设置为一些值,以保持缩放到上一个中间点(类似于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);
}
}
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);
});
}
}
应用程序。css为空
/* JavaFX CSS - Leave this comment until you have at least create one rule which uses -fx-Property */
Sample.fxml(替换图像url)
虽然我不熟悉JavaFX,但有人会认为只要滚动条边界发生变化,就可以通过调整滚动条边界的大小来“强制您自己的值”。因此,在回调中执行
scrollPane.setHvalue(0.5)
:
scrollPane.hvalueProperty().addListener((DoubleProperty observable, double oldvalue, double newvalue) -> {
if (newvalue != 0.5) {
scrollPane.setHvalue(0.5);
}
});
这是大约一年半前提出的问题,但对于仍在寻找答案的任何人来说--布局只覆盖hvalue和vvalue属性一次。这意味着,您可以附加一个侦听器,在否决更改值的尝试后自行处理,而不是直接设置值 也就是说,给定自动注销侦听器的包装类
导入javafx.beans.value.ChangeListener;
导入javafx.beans.value.observeValue;
公共类ChangeOnceListener实现ChangeListener{
私有化;
公共变更监听器(变更监听器包装){
this.wrapped=wrapped;
}
@凌驾
更改公众假期(ObservalEvalue我不确定这是否是个好主意。这是否会造成一些问题?调用setHValue将触发另一个事件+回调属性的描述说,通常认为在这种方法中修改观察值是不好的做法。
@Griva这就是为什么我在强制使用您自己的值时加粗并引用了您。I agree当API希望您以另一种方式执行任何操作时,强制执行任何操作都不被视为良好做法,但出于您的目的,“强制”是唯一的解决方案。JavaFX UI系统试图以一种方式排列UI,而您正试图改变这种排列方式并手动创建自己的。您唯一的选择是实现自己的滚动窗格,直至覆盖您的更改的类。@Griva查看我的编辑,以确保setHvalue
不会自行循环。为什么您是否使用了滚动窗格
?使用滚动窗格
来调整大小,而不是向上/向下/向左/向右滚动,这对我来说听起来很糟糕。setOnScroll()
可以在任何节点上使用。@Jai我不使用滚动窗格来调整大小,而是使用鼠标滚动事件来调整内部图像的大小。滚动窗格用于导航缩放后的图像-这与photoshop中缩放后的画布完全相同,您可以通过滚动条进行导航。我遇到的问题是,我想在缩放前保持图像的位置不变,这就是我尝试的原因要将滚动条设置到某个位置,但无论我设置了什么,它都会在以后更改,可能是在布局意识到内部内容更改了大小,并且滚动条的最大、最小和值必须更新后,我相信。请提供一个例子来说明问题。@kleopatra抱歉,我以前没有这样做,代码太乱了,我不得不清除它。我想这是一个相当简单的问题,并且将是一个很容易解决的任务-我的错。我编辑了问题并添加了示例代码,所以如果可以,请检查它,谢谢。
scrollPane.hvalueProperty().addListener((DoubleProperty observable, double oldvalue, double newvalue) -> {
if (newvalue != 0.5) {
scrollPane.setHvalue(0.5);
}
});