我有一个表格视图。当我更新一行的属性时,我看不到修改?例如:
implicit class PersonView(p:Person) {
val fname = new ObjectProperty(this, "fname",p.name)
}
并在我的表格视图中
lazy val tableLines = ObservableBuffer(persView)
val personTable = new TableView[PersonView](tableLines) {
columns ++= List(
new TableColumn[PersonView, String] {
text = "Name"
cellValueFactory = _.value.fname
cellFactory = { _ =>
new TableCell[PersonView, String] {
item.onChange { (_, _, newValue) => text = newValue }
}
}
}
)
}
它运行正常,但是当我更新名称时,我无法在GUI中看到它。
答案 0 :(得分:2)
首先,我将尝试总结一下我所看到的内容,以及我认为您可以将其发挥作用:
PersonView
类通过提供Person
属性来装饰fname
实例,该属性已初始化为关联name
的{{1}}字段。在" Name"中创建每个单元格时在列中,您可以创建此类属性并将其与单元格的值相关联。此后,只要该属性的值发生更改,单元格将自动更改其Person
字段以显示该属性的新值。 (顺便说一下,item
属性是冗余且不必要的 - 当onChange
属性(即绑定的item
属性 - 更改时,它提供了执行某些其他操作的机会,因此单元格将在执行时更新。)
因此,如果您现在更改fname
实例的名称,那么"名称"中的Person
的单元格会发生什么?柱?什么都没有。
为什么?
首先,正如@James_D指出的那样,您尚未在Person
实例的name
与最初与之关联的Person
实例的值之间建立关系。也就是说,您所做的就是更改ObjectProperty
值。对于要更新的GUI,String
的值也需要更改。
添加到您的问题是ObjectProperty
与其关联的Person
之间没有任何关系。因此,当PersonView
Person
字段发生更改时,name
人无法通知其Person
。更糟糕的是,通过使PersonView
成为PersonView
类,您建议implicit
个实例本身并不重要且暂时存在,暂时仅用于装饰某些PersonView
实例额外的一组方法和/或属性。
那么,我们怎样才能改变事物,使它们像你期望的那样工作?有两种基本方法,您的选择将取决于您可以对Person
类施加多少控制。两种情况下的关键是确保只要Person
的{{1}},包含StringProperty
名称的ObjectProperty
(比Person
更好的选项)就会发生变化{1}}已更改...
首先,最简单的方法是完全取消name
类。显然,您需要能够编辑Person
来执行此操作;如果你不能,你将不得不尝试第二种方法。应修改PersonView
以添加Person
属性字段,并将Person
转换为报告fname
的当前值的函数:
name
在这种情况下,您的表初始化现在如下所示:
fname
现在,您可以更改// initName is the initial name of the Person, and may be changed later...
class Person(initName: String, /*Whatever other arguments you require*/) {
// String property storing this Person's name. Name is initialized to initName.
val fname = new StringProperty(this, "fname", initName)
// Report the current name of this Person.
def name = fname.value
// This function is not necessary, since we could change the value through fname directly
// but it does look better...
def name_=(newName: String): Unit = fname.value = newName
}
的名称:
val tableLines = ObservableBuffer(persView) // Of Person, not PersonView!
val personTable = new TableView[Person](tableLines) {
columns ++= List(
new TableColumn[Person, String] {
text = "Name"
cellValueFactory = _.value.fname
// No need for a cellFactory - default works fine.
}
)
}
一切都很好。 Person
属性,val someone = new Person("Bob"/*, etc...*/)
someone.name = "Fred"
字段和 GUI表中相应单元格的值现在都具有相同的值。
如果您无法修改fname
类型的定义,则需要第二种方法。在这里,我们使用name
更改Person
个实例的名称,并希望没有人更改我们控件之外的PersonView
个名称。 (也就是说,如果其他一些代码修改Person
实例的名称而不通过Person
,那么我们对它一无所知,GUI也不会相应更新。)< / p>
Person
,在这种情况下,不得为PersonView
类。我们希望保留PersonView
实例并使用它与关联的implicit
实例进行交互。 PersonView
现在看起来像这样:
Person
现在,假设您有一个PersonView
个实例列表,您需要将它们映射到class PersonView(p: Person) {
// String property initialized to the name of the associated person.
val fname = new StringProperty(this, "fname", p.name)
// Change the name of the person. Note that we MUST also change the name of the
// associated person instance.
def name_=(newName: String): Unit = {
// Change the name of the Person instance. Verify it has the value we think it has.
assert(p.name == fname.value)
p.name = newName // Might be p.setName(newName), etc. in your case
// Change the name of our property.
fname.value = newName
}
}
个实例,然后再使用这些实例。
您的GUI代码现在看起来像这样:
Person
现在更改人名更加复杂,因为我们需要能够找到正确的PersonView
实例,但它看起来像这样:
val tableLines = ObservableBuffer(persView)
val personTable = new TableView[PersonView](tableLines) {
columns ++= List(
new TableColumn[PersonView, String] {
text = "Name"
cellValueFactory = _.value.fname
// No need for a cellFactory - default works fine.
}
)
}
一切都好了。 PersonView
属性,val someone = new Person("Bob"/*, etc...*/)
val someoneView = new PersonView(someone)
someoneView.name = "Fred"
字段和 GUI表中相应单元格的值(PersonView.fname
一次添加到Person.name
可观察对象),现在都具有相同的价值。
但是,以下行只是更改someoneView
实例的名称。 tableLines
和GUI 不会更新:
Person