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

JavaFx TableView显示列的长字符串表示

高高雅
2023-03-14

我刚启动JavaFx,有点拘泥于TableView,它显示了每个列的非常长的字符串表示,如:

StringProperty [bean: com.plcsim2.PlcSimModel$ErpSheet@2c1ffe7b, name:name, value: big]
IntegerProperty [bean: com.plcsim2.PlcSimModel$ErpSheet@2c1ffe7b, name:sheet_long, value: 5000]
IntegerProperty [bean: com.plcsim2.PlcSimModel$ErpSheet@2c1ffe7b, name:sheet_short, value: 3000]

而我预计细胞中只会出现“大”、“5000”、“3000”。

这是我的模型:

object PlcSimModel {
    class ErpSheet {
        val name = SimpleStringProperty(this, "name")
        val sheet_long = SimpleIntegerProperty(this, "sheet_long")
        val sheet_short = SimpleIntegerProperty(this, "sheet_short")
    }
    val erpSheets = ArrayList<ErpSheet>()
}

fxml:

<VBox alignment="CENTER" prefHeight="562.0" prefWidth="812.0" spacing="20.0"
  xmlns="http://javafx.com/javafx/18" xmlns:fx="http://javafx.com/fxml/1"
  fx:controller="com.plcsim2.PlcSimController">
<padding>
    <Insets bottom="20.0" left="20.0" right="20.0" top="20.0" />
</padding>
<TableView fx:id="table_1" prefHeight="400.0" prefWidth="200.0">
</TableView>
<Button onAction="#onHelloButtonClick" text="Hello!" />
</VBox>

最后是控制器:

@FXML
private fun onHelloButtonClick() {
    val rs = DB.populateSql("select name, sheet_long, sheet_short from erp_sheet")
    PlcSimModel.erpSheets.clear()
    if (rs != null) {
        while (rs.next()) {
            val sheet = PlcSimModel.ErpSheet()
            sheet.name.set(rs.getString("name"))
            sheet.sheet_long.set(rs.getInt("sheet_long"))
            sheet.sheet_short.set(rs.getInt("sheet_short"))
            PlcSimModel.erpSheets.add(sheet)
        }
    }
    table_1.columns.clear()
    val col0 = TableColumn<PlcSimModel.ErpSheet, String>("name")
    col0.cellValueFactory = PropertyValueFactory("name")
    table_1.columns.add(col0)
    val col1 = TableColumn<PlcSimModel.ErpSheet, Int>("sheet_long")
    col1.cellValueFactory = PropertyValueFactory("sheet_long")
    table_1.columns.add(col1)
    val col2 = TableColumn<PlcSimModel.ErpSheet, Int>("sheet_short")
    col2.cellValueFactory = PropertyValueFactory("sheet_short")
    table_1.columns.add(col2)
    table_1.items = FXCollections.observableArrayList(PlcSimModel.erpSheets)
}

看起来控制器很好,它能够从数据库中获取值并向TableView添加行,但为什么TableView显示属性对象的字符串表示,而不仅仅是显示值?

非常感谢!

共有2个答案

阴飞星
2023-03-14

现在我知道PropertyValueFactory使用反射来查找属性。我认为这是定义IntegerProperty或StringProperty的关键。因此,只需将模型类更改为以下类型即可解决问题:

class ErpSheet {
    var name = ""
    var sheet_long = 0
    var sheet_short = 0
}

成员变量名是PropertyVaueFactory的关键。

马权
2023-03-14

当类公开JavaFX属性时,它应该遵循以下模式:

import javafx.beans.property.SimpleStringProperty
import javafx.beans.property.StringProperty

public class Foo {

  // a field holding the property
  private final StringProperty name = new SimpleStringProperty(this, "name");
  
  // a setter method (but ONLY if the property is writable)
  public final void setName(String name) {
    this.name.set(name);
  }

  // a getter method
  public final String getName() {
    return name.get();
  }

  // a "property getter" method
  public final StringProperty nameProperty() {
    return name;
  }
}

请注意,属性的名称是name,以及在getter、setter和属性getter方法的名称中如何使用它。方法名称必须遵循该格式。

PropertyValueFactory类使用反射来获取所需的属性。它依赖于上述方法命名模式。您的ErpSheet类不遵循上述模式。隐式getter方法(不是属性getter方法)返回属性对象,而不是属性值。

Kotlin对JavaFX属性的处理效果并不特别好。您需要创建两个Kotlin属性,一个用于JavaFX属性对象,另一个作为JavaFX属性值的委托(手动或通过关键字)。

这里有一个例子:

import javafx.beans.property.IntegerProperty
import javafx.beans.property.SimpleIntegerProperty
import javafx.beans.property.SimpleStringProperty
import javafx.beans.property.StringProperty

class Person(name: String = "", age: Int = 0) {

    @get:JvmName("nameProperty")
    val nameProperty: StringProperty = SimpleStringProperty(this, "name", name)
    var name: String
        get() = nameProperty.get()
        set(value) = nameProperty.set(value)

    @get:JvmName("ageProperty")
    val ageProperty: IntegerProperty = SimpleIntegerProperty(this, "age", age)
    var age: Int
        get() = ageProperty.get()
        set(value) = ageProperty.set(value)
}

例如,您可以看到,nameKotlin属性将其getter和setter委托给namePropertyKotlin属性。

@get: JvmName("nameProperty")注解对于静态编程语言在Java端生成正确的"属性getter"方法(JVM字节码)是必要的。如果没有该注解,getter将被命名为getNameProperty(),这与JavaFX属性的模式不匹配。如果您从未打算使用来自Java的静态编程语言代码,或者使用任何依赖反射的类(例如,Property tyValueFactory)来获取属性,您可以不使用注解。

如果您想使用关键字而不是手动编写getter和setter(例如,var-name:String-by-nameProperty),请参阅关于委托属性的Kotlin文档。您可以编写扩展函数来实现这一点。

下面是一个使用上述Person类的可运行示例。它还周期性地增加每个人的年龄,以便您可以看到表视图正在观察模型项。

import javafx.animation.PauseTransition
import javafx.application.Application
import javafx.beans.property.IntegerProperty
import javafx.beans.property.SimpleIntegerProperty
import javafx.beans.property.SimpleStringProperty
import javafx.beans.property.StringProperty
import javafx.scene.Scene
import javafx.scene.control.TableColumn
import javafx.scene.control.TableView
import javafx.scene.control.cell.PropertyValueFactory
import javafx.stage.Stage
import javafx.util.Duration

fun main(args: Array<String>) = Application.launch(App::class.java, *args)

class App : Application() {

    override fun start(primaryStage: Stage) {
        val table = TableView<Person>()
        table.columnResizePolicy = TableView.CONSTRAINED_RESIZE_POLICY
        table.items.addAll(
            Person("John Doe", 35),
            Person("Jane Doe", 42)
        )

        val nameCol = TableColumn<Person, String>("Name")
        nameCol.cellValueFactory = PropertyValueFactory("name")
        table.columns += nameCol

        val ageCol = TableColumn<Person, Number>("Age")
        ageCol.cellValueFactory = PropertyValueFactory("age")
        table.columns += ageCol

        primaryStage.scene = Scene(table, 600.0, 400.0)
        primaryStage.show()

        PauseTransition(Duration.seconds(1.0)).apply {
            setOnFinished {
                println("Incrementing age of each person...")
                table.items.forEach { person -> person.age += 1 }
                playFromStart()
            }
            play()
        }
    }
}

class Person(name: String = "", age: Int = 0) {

    @get:JvmName("nameProperty")
    val nameProperty: StringProperty = SimpleStringProperty(this, "name", name)
    var name: String
        get() = nameProperty.get()
        set(value) = nameProperty.set(value)

    @get:JvmName("ageProperty")
    val ageProperty: IntegerProperty = SimpleIntegerProperty(this, "age", age)
    var age: Int
        get() = ageProperty.get()
        set(value) = ageProperty.set(value)
}

综上所述,无论您是用Java还是Kotlin编写应用程序,都应该避免使用PropertyValueFactory。它是在lambda表达式还不是Java的一部分时添加的,以帮助开发人员避免在任何地方编写冗长的匿名类。然而,它有两个缺点:它依赖于反射,更重要的是,您会丢失编译时验证(例如,属性是否确实存在)。

您应该用lambda替换PropertyValueFactory的用法。例如,从上述代码中,替换:

val nameCol = TableColumn<Person, String>("Name")
nameCol.cellValueFactory = PropertyValueFactory("name")
table.columns += nameCol

val ageCol = TableColumn<Person, Number>("Age")
ageCol.cellValueFactory = PropertyValueFactory("age")
table.columns += ageCol

使用:

val nameCol = TableColumn<Person, String>("Name")
nameCol.setCellValueFactory { it.value.nameProperty }
table.columns += nameCol

val ageCol = TableColumn<Person, Number>("Age")
ageCol.setCellValueFactory { it.value.ageProperty }
table.columns += ageCol

 类似资料:
  • 问题内容: 我正在做一个从列表中返回最长字符串值的函数。当只有一个包含最多字符的字符串时,我的代码有效。如果有多个字符串,我尝试使其打印所有最长的字符串,并且我不希望重复它们。当我运行它时,它只返回“ hello”,而我希望它也返回“ ohman”和“ yoloo”。我觉得问题就在眼前,但是我已经尝试了所有方法,但是没有用。 问题答案: 首先 ,我们可以在列表中找到任何字符串的最大长度: 一点解释

  • 问题内容: 我想打印一个字符或字符串,例如’-‘n次。 我可以不使用循环就做吗? ..这意味着打印3次,如下所示: 问题答案: Python 2.x: Python 3.x:

  • 我有代码在这里生成一个随机的名字给定音节点击一个动作按钮。但作为字符串currentName生成的名称会显示在TextView中。我需要使视图成为它自己的类吗?我是androidstudio的新手,来自eclipse,所以textviews对我来说也是新手。多谢了。 } 这也是我的activity_main.xml

  • 如果我有一个< code>ArrayList的单词,比如: 我想计算 4 5 6 3 3 3 作为 中每个字符串的长度之和加上单词之间的 5 个空格。我该怎么做?

  • 本文向大家介绍go语言按显示长度截取字符串的方法,包括了go语言按显示长度截取字符串的方法的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了go语言按显示长度截取字符串的方法。分享给大家供大家参考。具体分析如下: 根据显示长度截取字符串,之前php用的utf8编码,10个英文和10个汉字的显示长度差距太大,按字节截取的话又会出错出现截取半个汉字的情况,所以写了这两个函数. 这两天在折腾gol