我正在用简单的图像查看器试验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>
答案 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
包裹Group
,ScrollPane
仍然可以用作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();
这将更新您的滚动条。 不需要解决方法。