首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么我的Spinner在第一次初始化时不更新它的绑定属性?

为什么我的Spinner在第一次初始化时不更新它的绑定属性?
EN

Stack Overflow用户
提问于 2016-09-11 14:56:09
回答 1查看 1.2K关注 0票数 3

我在控制器中有一个Spinner

代码语言:javascript
复制
@FXML
private Spinner<Integer> spnMySpinner;

和控制器中的SimpleIntegerProperty

代码语言:javascript
复制
private static final SimpleIntegerProperty myValue = 
new SimpleIntegerProperty(3); //load a default value

我在控制器的initialize方法中将它们绑定在一起:

代码语言:javascript
复制
spnMySpinner.getValueFactory().valueProperty().bindBidirectional(myValueProperty().asObject());

但是,只有在控制器第二次初始化之后,绑定才能正常工作。以下是我如何复制它的方法:

  1. 我用关联的控制器打开这个阶段,它加载在myValue属性中指定的默认值(一个数字3)。
  2. 我单击旋转器上的增量按钮,使其变为4。它更改了自旋器值属性中的值,但是绑定属性myValue与数字3保持不变。
  3. 我关上舞台/窗户。
  4. 我重新打开它,旋转器的值又是3。
  5. 我再增加一次。Boom现在的绑定工作,我有一个"4“内的旋转器和绑定属性。

整个简约的,但可启动/可复制的代码:

Main.java:

代码语言:javascript
复制
package spinnerpoc;

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 stage) throws IOException {
        Parent root  = FXMLLoader.load(getClass().getResource("MainWindow.fxml"));
        Scene scene = new Scene(root);
        stage.setScene(scene);
        stage.show();
    }

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

}

MainWindow.fxml:

代码语言:javascript
复制
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.AnchorPane?>


<AnchorPane fx:id="myRoot" id="AnchorPane" prefHeight="231.0" prefWidth="337.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8.0.60" fx:controller="spinnerpoc.MainWindowController">
    <children>
        <Button fx:id="btnOpenSpinnerWindow" layoutX="102.0" layoutY="103.0" mnemonicParsing="false" text="Open SpinnerWindow" onAction="#onOpenSpinnerWindow"/>
    </children>
</AnchorPane>

MainWindowController.java:

代码语言:javascript
复制
package spinnerpoc;

import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Modality;
import javafx.stage.Stage;

public class MainWindowController implements Initializable {

    @FXML
    private Button btnOpenSpinnerWindow;
    @FXML
    private AnchorPane myRoot;

    @Override
    public void initialize(URL url, ResourceBundle rb) {
    }

    @FXML
    private void onOpenSpinnerWindow(ActionEvent event) throws IOException{
        FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("SpinnerWindow.fxml"));
        Parent root = (Parent) fxmlLoader.load();
        Stage stage = new Stage();
        stage.initOwner(myRoot.getScene().getWindow());
        stage.initModality(Modality.WINDOW_MODAL);
        stage.setTitle("SpinnerWindow");
        stage.setScene(new Scene(root));
        stage.show();
    }

}

SpinnerWindow.fxml:

代码语言:javascript
复制
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.RadioButton?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.control.Slider?>
<?import javafx.scene.control.Spinner?>
<?import javafx.scene.control.SpinnerValueFactory.DoubleSpinnerValueFactory?>
<?import javafx.scene.control.TitledPane?>
<?import javafx.scene.control.ToggleGroup?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>


<ScrollPane xmlns:fx="http://javafx.com/fxml/1" fitToWidth="true" prefHeight="200.0" prefWidth="200.0" xmlns="http://javafx.com/javafx/8.0.60" fx:controller="spinnerpoc.SpinnerWindowController">
    <content>
        <VBox maxWidth="1.7976931348623157E308">
            <children>
                <Spinner fx:id="spnMySpinner" editable="true" prefWidth="50.0" max="10" min="1" />
            </children>
        </VBox>
    </content>
</ScrollPane>

SpinnerWindowController.java:

代码语言:javascript
复制
package spinnerpoc;

import java.net.URL;
import java.util.ResourceBundle;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Spinner;

public class SpinnerWindowController implements Initializable {

    private static final SimpleIntegerProperty myValue = new SimpleIntegerProperty(3);

    public static SimpleIntegerProperty myValueProperty() {
        return myValue;
    }

    public static Integer getMyValue() {
        return myValue.getValue();
    }

    public static void setMyValue(int value) {
        myValue.set(value);
    }

    @FXML
    private Spinner<Integer> spnMySpinner;

    @Override
    public void initialize(URL url, ResourceBundle rb) {
        spnMySpinner.getValueFactory().valueProperty().bindBidirectional(myValueProperty().asObject());
    }

}

(代码也可在BitBucket回购上使用。)

我遗漏了什么?

EN

回答 1

Stack Overflow用户

发布于 2016-09-11 16:56:28

您正遇到“过早的垃圾收集”问题。请参阅对此这里的描述。您可能会发现,并不是每隔一次都会向旋转器显示它失败,而只是零星的,而且行为会因机器而异。如果您限制了JVM可用的内存,您可能会发现它从未起作用。

当你打电话给IntegerProperty.asObject(),它

创建一个双向绑定到此ObjectPropertyIntegerProperty

现在请注意,双向绑定具有此功能可防止意外内存泄漏。

JavaFX双向绑定实现使用弱侦听器。这意味着双向绑定不会阻止垃圾收集属性。

因此,您显式创建的双向绑定不会阻止它绑定到的东西(由ObjectProperty<Integer>创建的asObject())被垃圾收集。由于不保留对它的引用,因此一旦退出initialize()方法,它就有资格进行垃圾回收。显然,一旦您的旋转器值双向绑定的值被垃圾收集,绑定将不再工作。

只是为了演示起见,您可以通过放入一个钩子来强制垃圾收集来看到这一点。例如,做

代码语言:javascript
复制
<ScrollPane onMouseClicked="#gc" xmlns:fx="http://javafx.com/fxml/1" ...>

在SpinnerWindow.fxml和

代码语言:javascript
复制
@FXML
private void gc() {
    System.out.println("Invoking GC");
    System.gc();
}

在SpinnerWindowController中。如果这样做,则在滚动窗格中单击将强制垃圾收集,而更改自旋器值将不会更新该属性。

要解决这个问题,请保留对从asObject()获得的属性的引用。

代码语言:javascript
复制
public class SpinnerWindowController implements Initializable {

    private static final SimpleIntegerProperty myValue = new SimpleIntegerProperty(3);

    public static SimpleIntegerProperty myValueProperty() {
        return myValue;
    }

    public static Integer getMyValue() {
        return myValue.getValue();
    }

    public static void setMyValue(int value) {
        myValue.set(value);
    }

    @FXML
    private Spinner<Integer> spnMySpinner;

    private ObjectProperty<Integer> spinnerValue = myValueProperty().asObject();

    @Override
    public void initialize(URL url, ResourceBundle rb) {
        spnMySpinner.getValueFactory().valueProperty().bindBidirectional(spinnerValue);
    }

}
票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/39437360

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档