JavaFX更改imageView中的图像

6

基本上,我有一种方法可以从数据库中加载图像到imageView中,还有另一种方法可以更改图像。我成功地运行了这两种方法而没有出现异常,但是在changeImage()方法中的setImage之后,我需要更新什么以及如何更新(场景、舞台),这是否可能?我知道在JavaFX中没有类似于Swing中的repaint()方法,那么我该如何解决这个问题?

public class MainMenuController implements Initializable {

    /**
     * Initializes the controller class.
     */
    @Override
    public void initialize(URL url, ResourceBundle rb) {
        // TODO
    }

    private AnchorPane stck1;

 @FXML
    private AnchorPane openSecondWindow(ActionEvent event) throws Exception {
        GUIController ctrl = new GUIController();
        Stage stage = new Stage();
       setStck1((AnchorPane) FXMLLoader.load(InteractiveFictionGame2.class.getResource("GUI.fxml")));
        ImageView img_1 = new ImageView(ctrl.loadImg().getImage());
        img_1.setPreserveRatio(true);
        img_1.setSmooth(true);
        img_1.setCache(true);
        getStck1().getChildren().add(img_1);
        Scene scene = new Scene(getStck1());
        stage.setTitle("Interactive Fiction Game");
        stage.setScene(scene);
         stage.setFullScreen(true);
       // stage.sizeToScene();
        stage.show();
       return getStck1();
    }






public class GUIController implements Initializable {

    @FXML
    private TabPane tb1;

    /**
     * Initializes the controller class.
     *
     * @param url
     */
    @Override
    public void initialize(URL url, ResourceBundle rb) {
        // TODO
    }
    @FXML
    private ImageView img_1;





 public ImageView loadImg() {

        try {

            con = DriverManager.getConnection(host, unm, pswrd);
            stmnt = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY);
            rs = stmnt.executeQuery(SQL);
            rs.next();
            fis = rs.getBinaryStream(4);
            imgt = javax.imageio.ImageIO.read(fis);
            Image newImg = SwingFXUtils.toFXImage(imgt, null);
            img_1 = new ImageView();
            img_1.setImage(newImg);
            rs.close();
            stmnt.close();

            con.close();
        } catch (Exception e) {
            System.out.println("Not working");
        }
        return img_1;
    }


public void changeImage() {
..
            fis = rs.getBinaryStream(1);
            imgt = javax.imageio.ImageIO.read(fis);
            Image newImg = SwingFXUtils.toFXImage(imgt, null);
            img_1.setImage(newImg);
...
 } catch (Exception e) {
            System.out.println("Not working");
        }
        return img_1;
    }
2个回答

16

您的问题

如果您在控制器中有一个成员节点,您使用@FXML注入它,那么您永远不应该使用new构造函数创建一个新的对象实例,并将该新对象分配给现有引用。相反,只需使用FXML为您创建的对象即可。

您有:

@FXML
private ImageView img_1;

没问题。

然后在 loadImg 函数中,你有:

img_1 = new ImageView();
img_1.setImage(newImg);

这很糟糕。

当您加载FXML文档时,FXMLLoader已经为您创建了一个ImageView,并将其分配给了您的引用,因为您使用了@FXML注释。

如何解决

所以您只需要停止创建新的ImageView并且只需编写:

img_1.setImage(newImg);

完成了。

为什么有效

ImageView的Image属性是可观察的属性。JavaFX系统观察Image属性是否有任何更改,如果有更改,则自动更新在ImageView上显示的图像。您不需要执行任何重新绘制的调用(无论如何也没有这样的重新绘制例程要调用)。

背景阅读

如果您想更好地理解JavaFX场景图架构,请阅读Oracle教程:

一些提示

  • 您可以直接从InputStream创建JavaFX图像,无需使用ImageIO和SwingFXUtils来完成此任务。
  • 您可以使用Task与数据库通信,使应用程序更加响应。
  • 从文件或通过http读取图像可能比从数据库中读取简单。

免责声明

除了这里指出的问题之外,您未提供的代码中可能还有其他错误,这些错误可能会阻止您按照您希望的方式使应用程序正常工作。


0

我在这里毕业于Java I:
在我的JavaFX学期项目中,我必须在setOnAction事件(单击按钮)上更新imageView对象。这使程序用户可以通过一系列图片进行点击。

以下方法非常有效:
首先创建您的Image和ImageView实例:

Image imageObject = new Image();
ImageView imageViewObject = new ImageView();

然后在代码中,按钮事件会导致(下一个)图像被分配并更新如下:

btn.setOnAction(e -> {
    imageIndex++;
    imageFilename = imageNamesArray.get(imageIndex);
    imageObject = new Image(imageFilename);  
    imageViewObject.setImage(imageObject);
}

注意:我的项目中的文件名是作为字符串元素保存在ArrayList()中的jpg文件(名称)。按钮单击还会将数组索引递增到下一个jpg文件名(和路径或URL),新图像将出现。因此,如上述答案所述,您只创建一个ImageViewObject,但每次都会重新分配新图像给图像对象“imageObject”。

5
这个问题在四月份已经得到了充分的回答,我在这个答案中没有看到任何新的东西。实际上,你的代码示例有些误导性,因为没有理由用空白图像来初始化imageObject。 - mipa

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接