当前位置: 首页 > 知识库问答 >
问题:

JavaFx ImageView通过fxml表达式绑定绑定图像

闻人修平
2023-03-14

我知道有很多javafx教程。但其中99%没有提供好的fxml内容。在fxml中,我们可以按照JavaFX调用它的方式进行数据绑定或“表达式绑定”。

class MyController {
    private Image _imageA;
    private Image_ imageB;
    private Image_ image;

    public MyController(){
        _imageA = new Image(this.getClass().getResourceAsStream("imageA.png"));
        _imageB = new Image(this.getClass().getResourceAsStream("imageB.png"));
        _image = _imageA;
    }

    public getImage(){
        return _image;
    }

    public void mouseEnter(MouseEvent mouseEvent){
        _image = _imageA;
    }

    public void mouseLeave(MouseEvent mouseEvent){
        _image = _imageB;
    }
}
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.image.*?>
<?import javafx.scene.layout.*?>
<AnchorPane fx:id="_anchorPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="868.0" prefWidth="1124.0" xmlns="http://javafx.com/javafx/10.0.2-internal" xmlns:fx="http://javafx.com/fxml/1" fx:controller="MyController">

   <ImageView fx:id="_imgview" image="${controller.image}" onMouseEnter="#mouseEnter" onMouseExited="#mouseLeave"/>


</AnchorPane>

当应用程序启动时,将显示图像。但是当鼠标光标移动到图像上时,就会调用getImage方法,但是图像不会改变。有没有一种最小代码隐藏的方法来解决这个问题?

我不想做的是这里

class MyController implements Initializable {
    //..other stuff
    @FXML
    private ImageView _imgview;
    SimpleObjectProperty<Image> _propertyImage = new SimpleObjectProperty<>();

    public void initialize(URL url, ResourceBundle resourceBundle) {
        _imageViewSettings.imageProperty().bind(_propertySettingsImage);
    }

    public void mouseEnter(MouseEvent mouseEvent){
        _imageProperty.setValue(_imageB);
    }

    public void mouseLeave(MouseEvent mouseEvent){
        _imageProperty.setValue(_imageA);
    }
}

使用TableView,可以通过可观察的集合绑定数据。如果列表内容更改,tableview也会更改。所以在这里起作用了。

<TableView items="${controller.items}">
<!-- other stuff-->
 </TableView>

class TableController{

   private ObservableList<Integer> _list = FXCollections.observableArrayList();

   ObservableList<Integer> getItems(){
        return _list;
   }
}
GridPane p = new GridPane();;
p.setAlignment(...);
p.setChildren(...);

亲切的问候,鲍勃。

共有1个答案

顾永福
2023-03-14

TL;DR:要使FXML文件中的绑定具有可观察性,需要使图像属性具有可观察性(例如,通过objectproperty)。

FXML本身并没有什么特别之处。它只是定义了一种以XML语法描述对象图的方法,该对象图由fxmlloader解释并转换为普通的Java对象。它使用相对基本的规则和Java(FX)Bean约定来实现这一点。更多信息可以在FXML简介文档中找到。

当您使用表达式绑定时,您使用的是JavaFXproperty接口的绑定API。换句话说,当您有:

<ImageView image="${controller.image}"/>
public class FooController {

  private final ObjectProperty<Image> image = new SimpleObjectProperty<>(this, "image");
  // property-getter, getter, and setter omitted for brevity

  @FXML private ImageView imageView; // corresponding fx:id="imageView" in FXML file

  @FXML
  private void initialize() {
    // the "expression binding"
    imageView.imageProperty().bind(imageProperty());
  }
}

这就是你的例子中的问题的来源。您的控制器不公开可观察的图像属性;您只有getImage()方法。由于没有任何可以观察到的东西,ImageViewImage更改时无法自动更新(即没有任何可绑定的东西)。

下面是控制器公开ObjectProperty的示例。

app.fxml:

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

<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.StackPane?>

<BorderPane xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml/1"
            fx:controller="Controller" prefWidth="1000" prefHeight="650">

  <top>
    <Button text="Browse..." onAction="#handleBrowse" BorderPane.alignment="CENTER_RIGHT">
      <BorderPane.margin>
        <Insets topRightBottomLeft="5"/>
      </BorderPane.margin>
    </Button>
  </top>

  <center>
    <ScrollPane fitToHeight="true" fitToWidth="true" vbarPolicy="NEVER" hbarPolicy="NEVER" 
                pannable="true">
      <StackPane minWidth="-Infinity" minHeight="-Infinity">
        <ImageView image="${controller.image}"/>
      </StackPane>
    </ScrollPane>
  </center>

</BorderPane>
import java.io.File;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.image.Image;
import javafx.stage.FileChooser;
import javafx.stage.FileChooser.ExtensionFilter;
import javafx.stage.Window;

public class Controller {

  private final ObjectProperty<Image> image = new SimpleObjectProperty<>(this, "image");
  public final void setImage(Image image) { this.image.set(image); }
  public final Image getImage() { return image.get(); }
  public final ObjectProperty<Image> imageProperty() { return image; }

  @FXML
  private void handleBrowse(ActionEvent event) {
    event.consume();

    Window window = ((Button) event.getSource()).getScene().getWindow();

    FileChooser chooser = new FileChooser();
    chooser
        .getExtensionFilters()
        .addAll(new ExtensionFilter("Image Files", "*.png", "*.jpg", "*.jpeg", "*.gif"));
    File file = chooser.showOpenDialog(window);
    if (file != null) {
      setImage(new Image(file.toURI().toString()));
    }
  }
}

main.java

import java.io.IOException;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class Main extends Application {

  @Override
  public void start(Stage primaryStage) throws IOException {
    Parent root = FXMLLoader.load(Main.class.getResource("App.fxml"));
    primaryStage.setScene(new Scene(root));
    primaryStage.show();
  }
}

顺便说一句,请遵循Java命名惯例,至少在向公共论坛发帖时是这样。变量/字段名中的下划线(_)不是常规的,会使其他Java程序员更难理解您的代码。

 类似资料:
  • 问题内容: 我的FXML注入有问题。据我所知,我已经设置了程序,但似乎缺少了一些东西。我的代码如下: 主要: 控制器: FXML文件: 识别我正在注入 noteTree,sp和newNoteButton的字段 。但是,当我尝试将项目加载到树形视图时,我得到了NPE。我确认使用if语句表明我的3个字段是。堆栈跟踪如下: 事实证明我和我的功能都可以通过。 谁能指出我缺少/做错了什么? 问题答案: 您试

  • 我正在试用新的数据绑定库。我有一个奇怪的问题,属性的绑定没有编译。 这是xml文件的简化版本: 编译时收到以下消息: java.lang.RuntimeException:发现数据绑定错误. ****/ 数据绑定错误****msg:标识符必须具有XML文件中用户定义的类型。视图缺少它 当我删除声明时,一切都会编译(并正常工作!)。 我不知道我错过了什么

  • 问题内容: 自1.3.0-beta.10版本以来,AngularJS具有一项新功能:“懒惰的一次性绑定”。 可以在简单表达式的前面加上,告诉angular在首次评估表达式后停止观看。给出的常见示例如下所示: 类似以下表达式的语法是否类似? 问题答案: 是。您可以在每个表达式前添加,甚至可以在或中添加前缀: 实际上,代码只是检查表达式中的前两个字符是为了激活一次性绑定(然后将其删除,因此甚至不需要括

  • 因此,我在这里询问绑定表的概念。通常,只需对所有行/列使用ngFor即可。 然而,我想做的是,对于每个单元格,它应该绑定到一个具有两个属性的对象: <李>细胞内容李< / ><李>坳的头 在我的表中,我应该能够根据需要添加行或列。这很简单,但所有共享column_header的单元格都是棘手的部分。 现在这个表代表一个表单,所以我可以在用户单击submit后进行处理并解决问题。 我只是寻找其他聪明

  • 我使用Spring boot和Thymeleaf模板引擎,并尝试使用th:classappend属性为添加可选的“has error”类 但是我有这个错误 无法使用表达式“*”绑定表单错误。请检查此表达式是否在适当的上下文中执行(例如,具有th:object属性的a) 我的控制器方法 我做错了什么?

  • 我正在使用spring boot 2.0.0.M2遵循Simon Basle的“Reactor by example”中的代码。它就像一个魅力。但是,当我试图将path变量绑定到Mono并发送请求http://localhost:8080/monohello/hero时,它的响应如下: