调用setImage()后,包含ImageView的ScrollPane不会更新其滚动条

时间:2013-12-16 12:26:47

标签: javafx javafx-2

我正在用简单的图像查看器试验JavaFX。我希望它显示图像,如果它不适合窗口,则显示滚动条。要显示的图片使用FileChooser加载,并使用ImageView设置为imageView.setImage(image)

问题是,在调用ScrollPane后,包含imageView.setImage(image) 的滚动条不会更新。相反,我需要执行一个改变场景的动作(例如调整窗口大小)。当显示图像而另一个图像被加载时,它的行为相同,即滚动条的大小反映了前一图像的大小。


使用以下代码的简化版本可以重现该错误:

(Java)的

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

import javafx.application.Application;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.BorderPane;
import javafx.stage.FileChooser;
import javafx.stage.Stage;

public class ImageViewerBug extends Application
{
    @FXML private ImageView imageView;

    @Override
    public void start(Stage primaryStage) throws Exception {
        FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("ImageViewerBug.fxml"));
        fxmlLoader.setController(this);
        try {
            BorderPane borderPane = (BorderPane) fxmlLoader.load();
            Scene scene = new Scene(borderPane);
            primaryStage.setScene(scene);
            primaryStage.show();
        }
        catch( IOException e ) {
            throw new RuntimeException(e);
        }
    }

    public void loadClicked() {
        FileChooser fileChooser = new FileChooser();
        File f = fileChooser.showOpenDialog(null);
        if( f != null ) {
            try( InputStream is = new FileInputStream(f) ) {
                Image image = new Image(is);
                imageView.setImage(image);
            }
            catch( IOException e ) {
                e.printStackTrace();
            }
        }
    }

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

(FXML)

<?xml version="1.0" encoding="UTF-8"?>

<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.Group?>
<?import javafx.scene.control.*?>
<?import javafx.scene.image.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.paint.*?>

<BorderPane id="BorderPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns:fx="http://javafx.com/fxml">
  <center>
    <ScrollPane prefHeight="200.0" prefWidth="200.0">
      <content>
        <Group>
          <ImageView fx:id="imageView" pickOnBounds="true" preserveRatio="true" />
        </Group>
      </content>
    </ScrollPane>
  </center>
  <top>
    <ToolBar>
      <items>
        <Button mnemonicParsing="false" onAction="#loadClicked" text="Load" />
      </items>
    </ToolBar>
  </top>
</BorderPane>

3 个答案:

答案 0 :(得分:4)

我可以确认这个错误。一个快速而肮脏的解决方法,为我修复它:

    public void loadClicked() {
    FileChooser fileChooser = new FileChooser();
    File f = fileChooser.showOpenDialog(null);
    if( f != null ) {
        try( InputStream is = new FileInputStream(f) ) {
            Image image = new Image(is);
            imageView.setImage(image);
            imageView.snapshot(new SnapshotParameters(), new WritableImage(1, 1));
            double rnd = new Random().nextInt(10);
            imageView.setX(rnd/1000);
            imageView.setY(rnd/1000);
        }
        catch( IOException e ) {
            e.printStackTrace();
        }
    }
}

每当某个UI元素未更新或正确显示时,snapshot()方法有时会像魅力一样工作。但是不要问我为什么会这样,也许它与渲染过程有关,因为snapshots迫使JavaFX渲染场景图或目标元素。在ImageView已经部分之后添加新图像时,需要随机填充以创建正确的滚动条大小。 也许这与strange behaviour i found some weeks earlier有关。解决方法也解决了我当时的问题。

(真的很晚)编辑

问题是由包裹Group的{​​{1}}引起的。如果您使用继承自ImageView的节点,即使没有解决方法,Pane的行为也应符合预期。只要ScrollPane包裹GroupScrollPane仍然可以用作Pane的直接子项。

示例:

ImageView

答案 1 :(得分:1)

我对图像有同样的问题......而不是

Image image = new Image(is);

你应该写:

Image image = new Image("file:" + ABSOLUTE_PATH_TO_FILE);

图像会自动刷新,您无需执行任何操作。对我来说,它的工作原理

答案 2 :(得分:0)

使用命令:

Scrollbar scrollbar
// ...
// Some activities with children that extends canvas, so scrollbar is needed.
// ...    
scrollbar.layout();

这将更新您的滚动条。 不需要解决方法。