Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/google-cloud-platform/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
调整内容大小时保留或设置JavaFX滚动窗格位置_Java_Javafx_Layout_Scrollbar - Fatal编程技术网

调整内容大小时保留或设置JavaFX滚动窗格位置

调整内容大小时保留或设置JavaFX滚动窗格位置,java,javafx,layout,scrollbar,Java,Javafx,Layout,Scrollbar,我想设置滚动窗格的H和V值,但在调整内部内容的大小之后。 一些上下文-我得到了以下结构: 我将.setOnScroll(…)(鼠标)事件附加到StackPane,当它发生时,内部内容的大小(图像)将调整为某些值(也称为缩放)。我想添加StackPane最小大小绑定到滚动窗格视口大小,窗格大小绑定到图像大小,以保持一切正常工作 到目前为止,一切都很好,当内容改变大小时,滚动条会更新,所有内容都会按预期进行调整,但我想保持或更确切地说,将滚动条位置设置为一些值,以保持缩放到上一个中间点(类似于ph

我想设置滚动窗格的H和V值,但在调整内部内容的大小之后。

一些上下文-我得到了以下结构:

我将
.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);
    }

});