ObservableList中的粗体文本会破坏ChangeListener

时间:2016-06-02 04:11:46

标签: java listview javafx observablelist

我希望ObservableList中的标题是粗体。我已经把它变成了粗体,但是当它被选中时会遇到异常块,因为它不是一个字符串。我可以使其他项目文本,但然后ChangeListener想要一个字符串。我只想让例外消失。

有没有办法让它不能选择或粗体和字符串类型?

   ListView<String> list = new ListView<>();
   ObservableList items = FXCollections.observableArrayList();
   Task curr = tasklist.head;

   items.add(TextBuilder.create().text("Done Tasks").style("-fx-font-weight:bold;").build());
   items.add(curr.name + " - " + curr.description);
   //items.add(new Text(curr.name + " - " + curr.description));

   try {
        list.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<String>() {
            public void changed(ObservableValue<? extends String> ov,
                                final String oldvalue, final String newvalue) {
                if(newvalue != "Done Tasks")
                    selectedValue[0] = newvalue.split(" - ")[0];
                else
                    selectedValue[0] = "done";
            }
        });
    } catch(Exception e)
    {
        actiontarget.setFill(Color.FIREBRICK);
        actiontarget.setText("You must select a task.");
    }

1 个答案:

答案 0 :(得分:1)

快速而肮脏的答案

直接回答你的意愿“我可以创建其他项目Text但是ChangeListener想要一个字符串。我只想让异常消失。”,你可以改变ChangeListener的类型来接受Object而不是String:

new ChangeListener<Object>() {
    @Override
    public void changed(ObservableValue<? extends Object> observable, Object oldValue, Object newValue) {
        if(!(newvalue instanceof Text)) {
            String string = ((String) newvalue).split(" - ")[0];
            System.out.println(string);
        }
    }
}

但是,我不推荐上述方法,因为您失去了Java环境提供的一些先天类型的安全性。

编码建议

根据您的代码段提供一些建议。

  1. 使用cell factories从ListView的基础项目模型数据生成ListView单元节点。
  2. 不要将Text等节点直接放入ListView项目列表中。 ListView项列表用于表示不是节点的模型对象。我知道ListView javadoc没有明确说明这一点,但是,尽管如此,这仍然是我的最佳建议。每当您认为某个节点非常适合ListView时,您通常会选择使用单元工厂。
  3. 当您将items放入ListView时,它们应该与ListView的项目类型匹配(ListView的javadoc确实说明了这一点。)
  4. 对于像这里一样的非常重要的用例,使用更复杂的数据结构来表示列表中的项目,这样您就可以将语义数据(例如项目是否是标题)直接编码到项目,而不是硬编码字符串,如“完成任务”。
  5. 不要使用Builder类,例如TextBuilder,它们已被弃用,将从未来的JavaFX运行时发行版中删除。
  6. 使用外部样式表并通过设置和取消设置样式类来操作样式,而不是在代码中内联样式定义。
  7. 包含建议的示例

    根据建议,您可以将问题编码为类似下面的应用程序(注意它仍然没有将样式信息提取到外部样式表,我会将该部分作为练习):

    screenshot

    import javafx.application.Application;
    import javafx.beans.property.SimpleBooleanProperty;
    import javafx.beans.value.ChangeListener;
    import javafx.beans.value.ObservableValue;
    import javafx.collections.FXCollections;
    import javafx.scene.Scene;
    import javafx.scene.control.*;
    import javafx.stage.Stage;
    
    public class ListDisplay extends Application {
        @Override
        public void start(Stage stage) {
            ListView<TaskItem> listView = new ListView<>(
                    FXCollections.observableArrayList(
                            new TaskItem("Todo Tasks", null, true, true),
                            new TaskItem("Senility", "The Autumn Years", false, false),
                            new TaskItem("Death", "But I didn't eat the salmon mousse", false, false),
                            new TaskItem("Done Tasks", null, true, true),
                            new TaskItem("Birth", "The Miracle of Life", true, false),
                            new TaskItem("School", "Growth and Learning", true, false),
                            new TaskItem("Middle Age", "Stagnation", true, false),
                            new TaskItem("Live Organ Transplants", "The Machine that goes 'Ping'", true, false)
                    )
            );
    
            listView.setCellFactory(param -> new ListCell<TaskItem>() {
                @Override
                protected void updateItem(TaskItem item, boolean empty) {
                    super.updateItem(item, empty);
    
                    if (!empty && item != null) {
                        if (item.isHeader()) {
                            setText(item.getName());
                            setStyle("-fx-font-weight: bold;");
                        } else {
                            setText(item.getName() + " - " + item.getDescription());
                            setStyle(null);
                        }
                    } else {
                        setText(null);
                    }
                }
            });
    
            listView.setPrefHeight(200);
    
            listView.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
                if (!newValue.isHeader()) {
                    System.out.println("Selected: " + newValue.getName());
                }
            });
    
            stage.setTitle("Monty Python's Meaning of Life");
            stage.setScene(new Scene(listView));
            stage.show();
        }
    
        public static void main(String[] args) {
            launch(args);
        }
    
        private static class TaskItem {
            private final String name;
            private final String description;
            private final SimpleBooleanProperty completed;
            private final boolean header;
    
            public TaskItem(String name, String description, boolean completed, boolean header) {
                this.name = name;
                this.description = description;
                this.completed = new SimpleBooleanProperty(completed);
                this.header = header;
            }
    
            public boolean isHeader() {
                return header;
            }
    
            public boolean isCompleted() {
                return completed.get();
            }
    
            public SimpleBooleanProperty completedProperty() {
                return completed;
            }
    
            public String getName() {
                return name;
            }
    
            public String getDescription() {
                return description;
            }
        }
    }