我试图在Kotlin的TableView上使用MapValueFactory.我在Java中找到了一个https://jenkov.com/tutorials/javafx/tableview.html岁的好例子

以下Java代码运行良好:

package com.example.tableview;

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.MapValueFactory;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

public class HelloApplication extends Application {
    @Override
    public void start(Stage stage) throws IOException {

        var tableView = new TableView();

        TableColumn<Map, String> firstNameColumn = new TableColumn<>("firstName");
        firstNameColumn.setCellValueFactory(new MapValueFactory<>("firstName"));

        TableColumn<Map, String> lastNameColumn = new TableColumn<>("lastName");
        lastNameColumn.setCellValueFactory(new MapValueFactory<>("lastName"));

        tableView.getColumns().add(firstNameColumn);
        tableView.getColumns().add(lastNameColumn);

        ObservableList<Map<String, Object>> items = FXCollections.<Map<String, Object>>observableArrayList();

        Map<String, Object> item1 = new HashMap<>();
        item1.put("firstName", "Randall");
        item1.put("lastName" , "Kovic");

        items.add(item1);

        Map<String, Object> item2 = new HashMap<>();
        item2.put("firstName", "Irmelin");
        item2.put("lastName" , "Satoshi");

        items.add(item2);

        tableView.getItems().addAll(items);
        Scene scene = new Scene(tableView, 320, 240);
        stage.setTitle("Hello!");
        stage.setScene(scene);
        stage.show();
    }

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

当我将代码剪切并粘贴到IntelliJ中的Kotlin项目中时,它会try 自动将Java转换为Kotlin.但是,生成的代码不会编译.它表示,试图将firstNameColumn添加到tableView时存在类型不匹配.柱.

Type mismatch.
Required: Nothing!
Found: TableColumn<Map<*, *>, String>

以下是生成的未编译Kotlin代码:

package com.example.tableview

import javafx.application.Application
import javafx.collections.FXCollections
import javafx.scene.Scene
import javafx.scene.control.TableColumn
import javafx.scene.control.TableView
import javafx.scene.control.cell.MapValueFactory
import javafx.stage.Stage

class HelloApplication : Application() {

    override fun start(stage: Stage) {

        val tableView: TableView<*> = TableView<Any?>()

        val firstNameColumn = TableColumn<Map<*, *>, String>("firstName")
        firstNameColumn.setCellValueFactory(MapValueFactory("firstName"))

        val lastNameColumn = TableColumn<Map<*, *>, String>("lastName")
        lastNameColumn.setCellValueFactory(MapValueFactory("lastName"))

        tableView.columns.add(firstNameColumn)
        tableView.columns.add(lastNameColumn)

        val items = FXCollections.observableArrayList<Map<String, Any>>()

        val item1: MutableMap<String, Any> = HashMap()
        item1["firstName"] = "Randall"
        item1["lastName"] = "Kovic"

        items.add(item1)

        val item2: MutableMap<String, Any> = HashMap()
        item2["firstName"] = "Irmelin"
        item2["lastName"] = "Satoshi"

        items.add(item2)

        tableView.items.addAll(items)
        val scene = Scene(tableView, 320.0, 240.0)
        stage.title = "Hello!"
        stage.scene = scene
        stage.show()

    }

    fun main() {
        Application.launch(HelloApplication::class.java)
    }
}

任何帮助都将不胜感激.我在这件事上做了好几次调查,试图找出正确的类型...

推荐答案

Compiler Error

你的编译器错误源于你把tableView变成了TableView<*>.它对类型了解不够,无法向列列表中添加任何内容.只需更改这一行:

val tableView: TableView<*> = TableView<Any?>()

致下列其中一项:

val tableView: TableView<Map<*, *>> = TableView()
// or
val tableView = TableView<Map<*, *>>()

将允许您的Kotlin代码编译并按预期运行.

Java代码有问题吗

您的Java代码可以编译,因为在这里您将原始类型TableView设置为tableView.这意味着没有使用与TableView相关的泛型.除非与Java 5之前的遗留代码交互,否则永远不要使用原始类型.

你应该改变:

var tableView = new TableView();

致:

var tableView = new TableView<Map<?, ?>>();

请注意,在参数化TableColumns时,也使用原始类型.该修复类似,但不幸的是,它 destruct 了使用MapValueFactory的能力,因为它在实现Callback时声明了一个原始类型.真正的解决办法是不使用MapValueFactory(见下文).


Don't Use *ValueFactory Classes

PropertyValueFactoryMapValueFactory这样的类是在lambda表达式(在Java中)不存在的时候添加的.这意味着使用匿名类.匿名类可能非常冗长,因此它们添加了方便类,以使开发人员更容易编写代码.但它们有两个缺点:它们依赖于反射,更重要的是,会丢失所有编译时验证(例如,属性是否存在,属性的类型等).

在Java和Kotlin中,我建议使用lambda表达式(同时也从不使用原始类型).

Java :

// Note everywhere is using a Map<String, String> now
var tableView = new TableView<Map<String, String>>();

TableColumn<Map<String, String>, String> firstNameColumn = new TableColumn<>("firstName");
firstNameColumn.setCellValueFactory(data -> new SimpleStringProperty(data.getValue().get("firstName")));

TableColumn<Map<String, String>, String> lastNameColumn = new TableColumn<>("lastName");
lastNameColumn.setCellValueFactory(data -> new SimpleStringProperty(data.getValue().get("lastName")));

锅炉:

// Again, note everywhere is using Map<String, String>
val tableView = TableView<Map<String, String>>()

val firstNameColumn = TableColumn<Map<String, String>, String>("firstName")
firstNameColumn.setCellValueFactory { SimpleStringProperty(it.value["firstName"]) }

val lastNameColumn = TableColumn<Map<String, String>, String>("lastName")
lastNameColumn.setCellValueFactory { SimpleStringProperty(it.value["lastName"]) }

虽然我在两个版本中都使用了Map<String, String>,但显然可以根据需要对Map进行不同的参数化.

Kotlin相关问答推荐

何时使用figureEach

如何修改muableStateMapOf的值?

仅某些用户出现 DateTimeFormatter 错误

为什么Kotlin不用static inner class来实现带有object关键字的单例呢?

如何将光标从一个文本字段传递到 Jetpack Compose 中的其他文本字段?

通用接口继承

如何在 Kotlin 中将with代码转换为完整代码?

为什么 KFunction2 在 Kotlin 中不是可表示类型?

类型不匹配:Required: Context, Found: Intent

TestContainers PostgreSQLContainer 与 Kotlin 单元测试:Not enough information to infer type variable SELF

Kotlin:泛型、反射以及类型 T 和 T:Any 之间的区别

如何从 Java 中隐藏 Kotlin 的 lateinit var 支持字段?

Kotlin 单元测试 - 如何模拟 Companion 对象的组件?

Kotlin 具体化的泛型不会按计划保持类型

Android EditText 协程go 抖操作符,如 RxJava

kotlin 委托有什么用?

Kotlin - 具有私有构造函数的类的工厂函数

Lint 错误:可疑的相等判断:在 Object DiffUtilEquals 中未实现 equals()

Kotlin中对象和数据类的区别是什么?

如何在 kotlin 中创建重复对象数组?