【问题标题】:Mysterious " The color components or name must be specified " error in JavaFX ListViewJavaFX ListView 中出现神秘的“必须指定颜色组件或名称”错误
【发布时间】:2019-12-09 04:21:12
【问题描述】:

我尝试通过显示彩色矩形而不是字符串本身来自定义 Javafx 中的 ListView。

public class Main extends Application {
@Override
public void start(Stage primaryStage)
{
    VBox vBox = new VBox();
    ListView<String> listView = new ListView<>();
    vBox.getChildren().add(listView);
    ObservableList<String> list = FXCollections.observableArrayList("black" , "blue" , "brown" , "gold");
    listView.setItems(list);
    listView.setCellFactory(new Callback<ListView<String>, ListCell<String>>() {
        @Override
        public ListCell<String> call(ListView<String> stringListView) {
            return new cell();
        }
    });

    primaryStage.setScene(new Scene(vBox,400 , 400));
    primaryStage.show();
}


public class cell extends ListCell<String>
{
    Rectangle rect;

    cell() {
        super();
        this.rect = new Rectangle(20,20);
        this.rect.setFill(Color.web(getItem()));      // ERROR  ERROR  ERROR
        setGraphic(this.rect);
    }

    @Override
    protected void updateItem(String s, boolean empty) {
        super.updateItem(s, empty);
        if(empty)
            setGraphic(null);
        else 
            setGraphic(this.rect);
    }
}

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

}

显然错误出现在我已指示为错误的行中。我稍微操纵了细胞类,它起作用了。下面是被操纵的细胞类:

public class cell extends ListCell<String>
{
    Rectangle rect;

    cell() {
        super();
        this.rect = new Rectangle(20,20);
       // this.rect.setFill(Color.web(getItem()));
        setGraphic(this.rect);
    }

    @Override
    protected void updateItem(String s, boolean empty) {
        super.updateItem(s, empty);
        if(empty)
            setGraphic(null);
        else {
            rect.setFill(Color.web(getItem()));
            setGraphic(this.rect);
        }
    }

我知道 updateItem() 会被调用很多次。我的第一种方法确实减少了 updateItem() 所做的工作,但由于某种原因,它在该行中抛出了错误。以前的方法中的错误可能是什么原因

【问题讨论】:

  • 您认为getItem() 在列表单元的初始创建过程中会返回什么?
  • 它从对应于该ListCell的“列表”中返回该字符串
  • 不在构造函数中。根据定义,在构造函数执行期间,该类之外的任何代码都无法访问该对象,因此此时没有 ListView 或任何其他代码将项目设置为任何内容。

标签: java javafx desktop-application


【解决方案1】:

ListCellitem 属性最初是 nullColor.web 不接受 null 作为参数。此外,您需要能够处理以下事实:ListCell 的项目可以在其生命周期内被替换,并且同一项目可能被分配给不同的单元格。 ListView 仅创建填充视图所需的单元格,例如可滚动区域的视口发生变化,不同的项目需要可见,并且单元格被重用以显示更改的项目集。

如果您担心updateItem 中某些计算的性能,您可以将结果缓存在地图中(如果您担心内存消耗,可能会将值包装在SoftReferences 中)。

在这种情况下,这是不必要的,因为:

  1. Color.web不贵,
  2. 无论如何,命名颜色(如您使用的物品)都存储在Map 中;无论您多久将相同的参数传递给Color.web,每种不同的命名颜色都只会创建一个Color 实例。

顺便说一句:我不建议以不能是updateItem 调用结果的方式初始化单元格。在您的情况下,空单元格的graphic 属性为null,初始状态除外。如果您担心单元格大小一致,最好始终保留图形并设置其可见性:

public class cell extends ListCell<String> {
    private final Rectangle rect;

    cell() {
        super();
        this.rect = new Rectangle(20,20);
        setGraphic(this.rect);
    }

    @Override
    protected void updateItem(String s, boolean empty) {
        super.updateItem(s, empty);
        if(empty)
            rect.setVisible(false);
        else {
            rect.setFill(Color.web(getItem()));
            rect.setVisible(true);
        }
    }
}

【讨论】:

  • 与您回答的要点无关:请学习 java 命名约定并遵守它们 您知道我认为传播错误是一个非常糟糕的主意(而且它们只是违反约定)来自问题:典型的读者往往比正确的代码更容易记住错误......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-07
  • 2018-04-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多