Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/arduino/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么TableView';s change listener为ObjectProperty提供不同的结果<;T>;JavaFX8中的VSTProperty列?_Javafx_Tableview_Javafx 8_Propertychangelistener - Fatal编程技术网

为什么TableView';s change listener为ObjectProperty提供不同的结果<;T>;JavaFX8中的VSTProperty列?

为什么TableView';s change listener为ObjectProperty提供不同的结果<;T>;JavaFX8中的VSTProperty列?,javafx,tableview,javafx-8,propertychangelistener,Javafx,Tableview,Javafx 8,Propertychangelistener,一个相对的Java新手问题 我有一个带有提取器的TableView和一个添加到基础ObservableList的ListChangeListener 如果我在数据模型中有一个StringProperty列,那么如果我双击单元格,然后按ENTER键而不做任何更改,则更改侦听器不会检测到更改。那很好 但是,如果我将列定义为ObjectProperty,然后双击并单击ENTER,则即使未进行任何更改,更改侦听器也会始终检测到更改 为什么会这样?从更改侦听器的角度来看,ObjectProperty和St

一个相对的Java新手问题

我有一个带有提取器的TableView和一个添加到基础ObservableList的
ListChangeListener

如果我在数据模型中有一个
StringProperty
列,那么如果我双击单元格,然后按ENTER键而不做任何更改,则更改侦听器不会检测到更改。那很好

但是,如果我将列定义为
ObjectProperty
,然后双击并单击ENTER,则即使未进行任何更改,更改侦听器也会始终检测到更改

为什么会这样?从更改侦听器的角度来看,
ObjectProperty
StringProperty
之间有什么区别

我读过并认为我理解这些差异。但是我不明白为什么更改侦听器对
TProperty
/
SimpleTProperty
ObjectProperty
给出不同的结果

如果有帮助的话,这里有一个MVCE来解释我的一些荒谬的案例。实际上,我正试图让一个更改侦听器为
BigDecimal
LocalDate
列工作,并且已经在上面停留了5天。如果我能理解为什么变更监听器会给出不同的结果,我就可以让我的代码正常工作

我正在使用JavaFX8(JDK1.8.0µ)、NetBeans 8.2和Scene Builder 8.3

package test17;

import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.beans.Observable;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import javafx.util.converter.DefaultStringConverter;

public class Test17 extends Application {

    private Parent createContent() {

        ObservableList<TestModel> olTestModel = FXCollections.observableArrayList(testmodel -> new Observable[] {
                testmodel.strProperty(),
                testmodel.strObjectProperty()
        });

        olTestModel.add(new TestModel("A", "a"));
        olTestModel.add(new TestModel("B", "b"));

        olTestModel.addListener((ListChangeListener.Change<? extends TestModel > c) -> {
            while (c.next()) {
                if (c.wasUpdated()) {
                    System.out.println("===> wasUpdated() triggered");
                }
            }
        });

        TableView<TestModel> table = new TableView<>();

        TableColumn<TestModel, String> strCol = new TableColumn<>("strCol");
        strCol.setCellValueFactory(cellData -> cellData.getValue().strProperty());
        strCol.setCellFactory(TextFieldTableCell.forTableColumn(new DefaultStringConverter()));
        strCol.setEditable(true);
        strCol.setPrefWidth(100);
        strCol.setOnEditCommit((CellEditEvent<TestModel, String> t) -> {
                ((TestModel) t.getTableView().getItems().get(
                        t.getTablePosition().getRow())
                        ).setStr(t.getNewValue());
        });

        TableColumn<TestModel, String> strObjectCol = new TableColumn<>("strObjectCol");
        strObjectCol.setCellValueFactory(cellData -> cellData.getValue().strObjectProperty());
        strObjectCol.setCellFactory(TextFieldTableCell.forTableColumn(new DefaultStringConverter()));
        strObjectCol.setEditable(true);
        strObjectCol.setPrefWidth(100);
        strObjectCol.setOnEditCommit((CellEditEvent<TestModel, String> t) -> {
            ((TestModel) t.getTableView().getItems().get(
                    t.getTablePosition().getRow())
                    ).setStrObject(t.getNewValue());
        });

        table.getColumns().addAll(strCol, strObjectCol);
        table.setItems(olTestModel);
        table.getSelectionModel().setCellSelectionEnabled(true);
        table.setEditable(true);

        BorderPane content = new BorderPane(table);
        return content;
    }

    public class TestModel {

        private StringProperty str;
        private ObjectProperty<String> strObject;

        public TestModel(
            String str,
            String strObject
        ) {
            this.str = new SimpleStringProperty(str);
            this.strObject = new SimpleObjectProperty(strObject);
        }

        public String getStr() {
            return this.str.get();
        }

        public void setStr(String str) {
            this.str.set(str);
        }

        public StringProperty strProperty() {
            return this.str;
        }

        public String getStrObject() {
            return this.strObject.get();
        }

        public void setStrObject(String strObject) {
            this.strObject.set(strObject);
        }

        public ObjectProperty<String> strObjectProperty() {
            return this.strObject;
        }

    }

    @Override
    public void start(Stage stage) throws Exception {
        stage.setScene(new Scene(createContent()));
        stage.setTitle("Test");
        stage.setWidth(350);
        stage.show();
    }

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

}
包测试17;
导入javafx.application.application;
导入静态javafx.application.application.launch;
导入javafx.beans.Observable;
导入javafx.beans.property.ObjectProperty;
导入javafx.beans.property.SimpleObject属性;
导入javafx.beans.property.SimpleStringProperty;
导入javafx.beans.property.StringProperty;
导入javafx.collections.FXCollections;
导入javafx.collections.ListChangeListener;
导入javafx.collections.ObservableList;
导入javafx.scene.Parent;
导入javafx.scene.scene;
导入javafx.scene.control.TableColumn;
导入javafx.scene.control.TableView;
导入javafx.scene.control.cell.TextFieldTableCell;
导入javafx.scene.layout.BorderPane;
导入javafx.stage.stage;
导入javafx.util.converter.DefaultStringConverter;
公共类Test17扩展了应用程序{
私有父createContent(){
ObservableList olTestModel=FXCollections.observableArrayList(testmodel->new Observable[]{
testmodel.strProperty(),
testmodel.strObjectProperty()
});
添加(新的测试模型(“A”,“A”));
添加(新的测试模型(“B”、“B”);

olTestModel.addListener((ListChangeListener.Change通过查看
StringPropertyBase
ObjectPropertyBase
的源代码可以看出差异,特别是它们的
设置方法

StringPropertyBase
ObjectPropertyBase
请注意它们在检查新值是否等于旧值方面的差异。
StringPropertyBase
类使用
Object.equals
进行检查,而
ObjectPropertyBase
类使用引用相等(
==
/
!=

我不能肯定地回答为什么会存在这种差异,但我可以冒险猜测:一个
ObjectProperty
可以容纳任何东西,因此
Object.equals
可能很昂贵;比如当使用
List
Set
时。当编码
StringPropertyBase
时,我想他们决定tential不在那里,因为
String
equality的语义更重要,或者两者都重要。他们这样做可能有更多/更好的原因,但由于我没有参与开发,我不知道他们


有趣的是,如果你看看他们是如何处理听众的 (
com.sun.javafx.binding.ExpressionHelper
)您将看到它们使用
Object.equals
检查相等性。仅当当前注册了
ChangeListener
s,以便在没有
ChangeListener
s的情况下支持延迟计算时,才会发生此相等性检查

如果新值和旧值
等于
则不会通知
ChangeListener
s。但是,这不会阻止通知
InvalizationListener
s。因此,您的
ObservableList
将触发更新更改,因为该机制基于
InvalizationListener
s而不是
ChangeLi斯坦纳
s

以下是相关的源代码:

ExpressionHelper$Generic.fireValueChangedEvent

有趣的是…似乎没有指明身份或平等的变化是否构成了ObservalEvalue值的变化(至少我找不到任何东西)-并且实现没有指定它们是如何实现的。嗯…@Slaw非常感谢您的解释。至少我现在理解了为什么我无法让更改侦听器为
bigdecimic
LocalDate
列工作。我当前的解决方法是将它们定义为
StringProperty
并处理在我的代码中使用它们,但我现在将尝试编写自己的“ObjectProperty”类。我怀疑这超出了我目前的Java技能,但没有任何冒险,没有任何收获。再次感谢。@kleopatra我也找不到明确的规范。不过,我注意到,更改似乎是基于
equals
实现的,但无效似乎是通过引用相等实现的,除了
StringPropertyBase
。可能更改的引用是无效的?它似乎与
ObservalEvalue
的文档相符:“更改事件[…]值已更改。无效事件[…]值不再有效。此区别变得非常重要[…]因为对于延迟计算的值,在重新计算之前,不知道无效值是否真的发生了更改。”@GreenZebra我可以问一下有什么问题吗
@Override
public void set(String newValue) {
    if (isBound()) {
        throw new java.lang.RuntimeException((getBean() != null && getName() != null ?
                getBean().getClass().getSimpleName() + "." + getName() + " : ": "") + "A bound value cannot be set.");
    }
    if ((value == null)? newValue != null : !value.equals(newValue)) {
        value = newValue;
        markInvalid();
    }
}
@Override
public void set(T newValue) {
    if (isBound()) {
        throw new java.lang.RuntimeException((getBean() != null && getName() != null ?
                getBean().getClass().getSimpleName() + "." + getName() + " : ": "") + "A bound value cannot be set.");
    }
    if (value != newValue) {
        value = newValue;
        markInvalid();
    }
}
@Override
protected void fireValueChangedEvent() {
    final InvalidationListener[] curInvalidationList = invalidationListeners;
    final int curInvalidationSize = invalidationSize;
    final ChangeListener<? super T>[] curChangeList = changeListeners;
    final int curChangeSize = changeSize;

    try {
        locked = true;
        for (int i = 0; i < curInvalidationSize; i++) {
            try {
                curInvalidationList[i].invalidated(observable);
            } catch (Exception e) {
                Thread.currentThread().getUncaughtExceptionHandler().uncaughtException(Thread.currentThread(), e);
            }
        }
        if (curChangeSize > 0) {
            final T oldValue = currentValue;
            currentValue = observable.getValue();
            final boolean changed = (currentValue == null)? (oldValue != null) : !currentValue.equals(oldValue);
            if (changed) {
                for (int i = 0; i < curChangeSize; i++) {
                    try {
                        curChangeList[i].changed(observable, oldValue, currentValue);
                    } catch (Exception e) {
                        Thread.currentThread().getUncaughtExceptionHandler().uncaughtException(Thread.currentThread(), e);
                    }
                }
            }
        }
    } finally {
        locked = false;
    }
}
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;

public class Main {

  public static void main(String[] args) {
    ObjectProperty<String> property = new SimpleObjectProperty<>("Hello, World!");
    property.addListener(obs -> System.out.printf("Property invalidated: %s%n", property.get()));
    property.addListener((obs, ov, nv) -> System.out.printf("Property changed: %s -> %s%n", ov, nv));
    property.get(); // ensure valid

    property.set(new String("Hello, World!")); // must not use interned String
    property.set("Goodbye, World!");
  }

}