绑定到 GraphicPropety 的 JavaFX ImageView 未显示在多个视图上
JavaFX ImageView bound to GraphicPropety not showing on multiple Views
这个问题建立在我之前问过的一个问题的基础上:
但涉及到一个单独的问题。我正在尝试创建一个 Play/Pause 按钮,只要单击该按钮,它就会将图形交换到适当的 > 播放和 ||暂停图片
ButtonModel.java
public class ButtonModel {
private final ObjectProperty<ImageView> playImage = new SimpleObjectProperty<ImageView>();
private boolean paused;
public final ObjectProperty<ImageView> playImageProperty() {
return this.playImage;
}
//... Other Getters and Setters...
}
ButtonPanelController.java
public class ButtonPanelController implements Initializable {
@FXML
Button myButton
ButtonModel model
public ButtonPanelController(ButtonModel model) {
this.model = model;
}
@Override
public void initialize(URL location, ResourceBundle resources) {
model.setPaused(true);
myButton.graphicProperty().bind(model.playImageProperty());
}
public void buttonClickedAction(ActionEvent e) {
Image image = null;
if(model.isPaused()) {
image = new Image(this.getClass().getResourceAsStream("play.png"));
} else {
image = new Image(this.getClass().getResourceAsStream("pause.png"));
}
model.setPlayImage(new ImageView(image));
model.togglePaused();
}
}
我正在使用相同的 .fxml 创建两个场景,并将模型的单个实例传递给两个控制器以控制状态。
我遇到的问题是,当我更改 ImageView 属性 时,图像只显示在我的第二阶段的按钮上。我的第一个阶段的按钮正在调整大小以适应图像,当我放置断点并查看第一个按钮的 'graphic' 属性时,我可以看到它的 'observable' 属性设置为我的 ObjectProperty参考,但是图像本身没有显示在按钮上。第二阶段的按钮按预期工作,但第一阶段的按钮不是。
我已经能够使用相同的体系结构成功绑定 RadioButton 的 SelectedProperty,所以我不确定为什么 Button 的 graphicProperty 有问题。
这里的概念性问题是您正在使用模型存储 UI 个组件(例如 ImageView
)。模型应该存储应用程序的状态,而不是应用程序的视图。
它实际上不起作用的技术原因是一个节点只能出现在一个场景中,并且在任何场景图中最多出现一次。由于您在两个控制器视图对之间共享模型,因此您试图在每个视图中显示相同的 ImageView
实例,这是不允许的。 (例如,由于您只有一个 ImageView
实例,您希望通过 playImage.get().getScene()
或 playImage.get().getLayoutX()
等方法调用返回什么?)
您的模型应该只存储状态(即数据):
public class ButtonModel {
private final BooleanProperty paused = new SimpleBooleanProperty();
public final BooleanProperty pausedProperty() {
return paused ;
}
public final boolean isPaused() {
return pausedProperty().get();
}
public final void setPaused(boolean paused) {
pausedProperty().set(paused);
}
public void togglePaused() {
setPaused(! isPaused());
}
//... Other Getters and Setters...
}
并且您的控制器应该关注根据模型中的数据更新自己的视图(以及响应用户输入更新模型):
public class ButtonPanelController implements Initializable {
// We can use a single instance of each image (which is not a node)
// and share it between
// multiple image views, so we can make the images static
// to conserve memory. Note that fairly spectacularly bad things
// will happen if there is an exception thrown loading these images...
private static Image playImage =
new Image(ButtonPanelController.class.getResource("play.png").toExternalForm());
private static Image pauseImage =
new Image(ButtonPanelController.class.getResource("pause.png").toExternalForm());
// But each controller *must* have its own imageview to display in
// the button in its view:
private ImageView buttonGraphic ;
@FXML
Button myButton
ButtonModel model
public ButtonPanelController(ButtonModel model) {
this.model = model;
}
@Override
public void initialize(URL location, ResourceBundle resources) {
buttonGraphic = new ImageView();
myButton.setGraphic(buttonGraphic);
model.setPaused(true);
buttonGraphic.imageProperty().bind(Bindings
.when(model.pausedProperty())
.then(playImage)
.otherwise(pauseImage));
}
public void buttonClickedAction(ActionEvent e) {
model.togglePaused();
}
}
请注意,您可以改为在 FXML 中定义 ImageView
并将其注入控制器:
<Button fx:id="myButton" onAction="#handleButtonAction">
<graphic>
<ImageView fx:id="buttonGraphic"/>
</graphic>
</Button>
然后当然去掉 initialize
方法的前两行并用 @FXML
注释 buttonGraphic
字段。 (主要思想基本一致。)
这个问题建立在我之前问过的一个问题的基础上:
但涉及到一个单独的问题。我正在尝试创建一个 Play/Pause 按钮,只要单击该按钮,它就会将图形交换到适当的 > 播放和 ||暂停图片
ButtonModel.java
public class ButtonModel {
private final ObjectProperty<ImageView> playImage = new SimpleObjectProperty<ImageView>();
private boolean paused;
public final ObjectProperty<ImageView> playImageProperty() {
return this.playImage;
}
//... Other Getters and Setters...
}
ButtonPanelController.java
public class ButtonPanelController implements Initializable {
@FXML
Button myButton
ButtonModel model
public ButtonPanelController(ButtonModel model) {
this.model = model;
}
@Override
public void initialize(URL location, ResourceBundle resources) {
model.setPaused(true);
myButton.graphicProperty().bind(model.playImageProperty());
}
public void buttonClickedAction(ActionEvent e) {
Image image = null;
if(model.isPaused()) {
image = new Image(this.getClass().getResourceAsStream("play.png"));
} else {
image = new Image(this.getClass().getResourceAsStream("pause.png"));
}
model.setPlayImage(new ImageView(image));
model.togglePaused();
}
}
我正在使用相同的 .fxml 创建两个场景,并将模型的单个实例传递给两个控制器以控制状态。
我遇到的问题是,当我更改 ImageView 属性 时,图像只显示在我的第二阶段的按钮上。我的第一个阶段的按钮正在调整大小以适应图像,当我放置断点并查看第一个按钮的 'graphic' 属性时,我可以看到它的 'observable' 属性设置为我的 ObjectProperty参考,但是图像本身没有显示在按钮上。第二阶段的按钮按预期工作,但第一阶段的按钮不是。
我已经能够使用相同的体系结构成功绑定 RadioButton 的 SelectedProperty,所以我不确定为什么 Button 的 graphicProperty 有问题。
这里的概念性问题是您正在使用模型存储 UI 个组件(例如 ImageView
)。模型应该存储应用程序的状态,而不是应用程序的视图。
它实际上不起作用的技术原因是一个节点只能出现在一个场景中,并且在任何场景图中最多出现一次。由于您在两个控制器视图对之间共享模型,因此您试图在每个视图中显示相同的 ImageView
实例,这是不允许的。 (例如,由于您只有一个 ImageView
实例,您希望通过 playImage.get().getScene()
或 playImage.get().getLayoutX()
等方法调用返回什么?)
您的模型应该只存储状态(即数据):
public class ButtonModel {
private final BooleanProperty paused = new SimpleBooleanProperty();
public final BooleanProperty pausedProperty() {
return paused ;
}
public final boolean isPaused() {
return pausedProperty().get();
}
public final void setPaused(boolean paused) {
pausedProperty().set(paused);
}
public void togglePaused() {
setPaused(! isPaused());
}
//... Other Getters and Setters...
}
并且您的控制器应该关注根据模型中的数据更新自己的视图(以及响应用户输入更新模型):
public class ButtonPanelController implements Initializable {
// We can use a single instance of each image (which is not a node)
// and share it between
// multiple image views, so we can make the images static
// to conserve memory. Note that fairly spectacularly bad things
// will happen if there is an exception thrown loading these images...
private static Image playImage =
new Image(ButtonPanelController.class.getResource("play.png").toExternalForm());
private static Image pauseImage =
new Image(ButtonPanelController.class.getResource("pause.png").toExternalForm());
// But each controller *must* have its own imageview to display in
// the button in its view:
private ImageView buttonGraphic ;
@FXML
Button myButton
ButtonModel model
public ButtonPanelController(ButtonModel model) {
this.model = model;
}
@Override
public void initialize(URL location, ResourceBundle resources) {
buttonGraphic = new ImageView();
myButton.setGraphic(buttonGraphic);
model.setPaused(true);
buttonGraphic.imageProperty().bind(Bindings
.when(model.pausedProperty())
.then(playImage)
.otherwise(pauseImage));
}
public void buttonClickedAction(ActionEvent e) {
model.togglePaused();
}
}
请注意,您可以改为在 FXML 中定义 ImageView
并将其注入控制器:
<Button fx:id="myButton" onAction="#handleButtonAction">
<graphic>
<ImageView fx:id="buttonGraphic"/>
</graphic>
</Button>
然后当然去掉 initialize
方法的前两行并用 @FXML
注释 buttonGraphic
字段。 (主要思想基本一致。)