Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
JavaFX ChoiceBox添加具有类型安全性的分隔符_Javafx_Javafx 2_Javafx 8 - Fatal编程技术网

JavaFX ChoiceBox添加具有类型安全性的分隔符

JavaFX ChoiceBox添加具有类型安全性的分隔符,javafx,javafx-2,javafx-8,Javafx,Javafx 2,Javafx 8,我希望在选择框中添加分隔符,并且仍然保持类型安全性 在我所看到的所有示例中,它们只执行以下操作: ChoiceBox<Object> cb = new ChoiceBox<>(); cb.getItems().addAll("one", "two", new Separator(), "fadfadfasd", "afdafdsfas"); ChoiceBox<T> cb = new ChoiceBox<T>(); cb.getSeparato

我希望在选择框中添加分隔符,并且仍然保持类型安全性

在我所看到的所有示例中,它们只执行以下操作:

ChoiceBox<Object> cb =  new ChoiceBox<>();
cb.getItems().addAll("one", "two", new Separator(), "fadfadfasd", "afdafdsfas");
ChoiceBox<T> cb = new ChoiceBox<T>();
cb.getSeparators().add(1, new Separator()); // 1 is the index of where the separator should be
ChoiceBox cb=new ChoiceBox();
cb.getItems().addAll(“一”、“二”、新分隔符()、“fadfasd”、“afdafdsfas”);
是否有人想出了一个解决方案,能够添加分离器,但仍然保持类型安全

我希望,如果我想添加分隔符,我应该能够按照以下步骤进行操作:

ChoiceBox<Object> cb =  new ChoiceBox<>();
cb.getItems().addAll("one", "two", new Separator(), "fadfadfasd", "afdafdsfas");
ChoiceBox<T> cb = new ChoiceBox<T>();
cb.getSeparators().add(1, new Separator()); // 1 is the index of where the separator should be
ChoiceBox cb=new ChoiceBox();
cb.getSeparators().add(1,newseparator());//1是分隔符应位于何处的索引

我不应该为了添加分隔符而牺牲类型安全性。

您可以通过创建一个接口,然后子类化分隔符来实现此接口:

import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.ChoiceBox;
import javafx.scene.control.Separator;
import javafx.scene.layout.GridPane;
import javafx.scene.text.Text;
import javafx.stage.Stage;

public class ChoiceBoxIsSafe extends Application {

    interface FruitInterface { }

    static public class Fruit implements FruitInterface {
        private StringProperty name = new SimpleStringProperty();
        Fruit(String name) {
            this.name.set(name);
        }

        public StringProperty nameProperty() {
            return name;
        }

        @Override
        public String toString() {
            return name.get();
        }
    }

    static public class FruitySeparator extends Separator implements FruitInterface { }

    @Override
    public void start(Stage primaryStage) throws Exception {
        GridPane grid = new GridPane();
        grid.setHgap(10); grid.setVgap(10); grid.setPadding(new Insets(10));

        ChoiceBox<FruitInterface> cb = new ChoiceBox<>();
        cb.getItems().addAll(new Fruit("Apple"), new Fruit("Orange"), new FruitySeparator(), new Fruit("Peach"));

        Text text = new Text("");

        ReadOnlyObjectProperty<FruitInterface> selected = cb.getSelectionModel().selectedItemProperty();
        text.textProperty().bind(Bindings.select(selected, "name"));

        grid.add(cb, 0, 0);
        grid.add(text, 1, 0);

        Scene scene = new Scene(grid);
        primaryStage.setScene(scene);        
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}
导入javafx.application.application;
导入javafx.beans.binding.Bindings;
导入javafx.beans.property.ReadOnlyObject属性;
导入javafx.beans.property.SimpleStringProperty;
导入javafx.beans.property.StringProperty;
导入javafx.geometry.Insets;
导入javafx.scene.scene;
导入javafx.scene.control.ChoiceBox;
导入javafx.scene.control.Separator;
导入javafx.scene.layout.GridPane;
导入javafx.scene.text.text;
导入javafx.stage.stage;
公共类ChoiceBoxIsSafe扩展了应用程序{
接口{}
静态公共类接口{
私有StringProperty名称=新的SimpleStringProperty();
水果(字符串名称){
this.name.set(name);
}
公共字符串属性nameProperty(){
返回名称;
}
@凌驾
公共字符串toString(){
返回name.get();
}
}
静态公共类FruitySeparator扩展分隔符实现了FruitInterface{}
@凌驾
public void start(Stage primaryStage)引发异常{
GridPane grid=新建GridPane();
grid.setHgap(10);grid.setVgap(10);grid.setPadding(新插图(10));
ChoiceBox cb=新的ChoiceBox();
cb.getItems().addAll(新水果(“苹果”)、新水果(“橙色”)、新水果分离器()、新水果(“桃子”);
文本文本=新文本(“”);
ReadOnlyObjectProperty selected=cb.getSelectionModel().SelectEditeProperty();
text.textProperty().bind(Bindings.select(selected,“name”));
加(cb,0,0);
添加(文本,1,0);
场景=新场景(网格);
初级阶段。场景(场景);
primaryStage.show();
}
公共静态void main(字符串[]args){
发射(args);
}
}
但这并不是一个“优雅”的解决方案,不能在所有情况下都做到(例如,
ChoiceBox


从ChoiceBox的实现来看,将分隔符视为ChoiceBox中的项目显然不是一个好主意:-(.

如前所述,仅当添加到项目(脏的,脏的)时才支持分隔符。要按照问题中的预期来支持它们,我们需要:

  • 将分隔符列表的概念添加到choiceBox
  • 让它的皮肤知道这个列表
虽然前者不是什么大问题,但后者需要完全重写(主要是c&p),因为所有内容都被严格隐藏在隐私中。如果重写发生了,那么只需要再写几行:-)

只是为了好玩,我正在用它做实验,它解决了选择处理中的一些讨厌的错误,所以忍不住尝试

首先,添加对ChoiceBoxx本身的支持:

/**
 * Adds a separator index to the list. The separator is inserted 
 * after the item with the same index. Client code
 * must keep this list in sync with the data.
 * 
 * @param separator
 */
public final void addSeparator(int separator) {
    if (separatorsList.getValue() == null) {
        separatorsList.setValue(FXCollections.observableArrayList());
    }
    separatorsList.getValue().add(separator);
};
然后在ChoiceBoxXSkin中进行一些更改

  • 必须听分离列表
  • 必须预期menuItem的索引!=选择项目索引
  • menuItem必须保留其choiceItem索引
最简单的方法是,侦听器重新构建弹出窗口,menuItem将数据索引存储在其属性中,并且需要通过其数据索引访问弹出窗口的所有代码都被委托给一个方法,该方法在menuItems中循环,直到找到一个符合以下条件的方法:

protected RadioMenuItem getMenuItemFor(int dataIndex) {
    if (dataIndex < 0) return null;
    int loopIndex = dataIndex;
    while (loopIndex < popup.getItems().size()) {
        MenuItem item = popup.getItems().get(loopIndex);

        ObservableMap<Object, Object> properties = item.getProperties();
        Object object = properties.get("data-index");
        if ((object instanceof Integer) && dataIndex == (Integer) object) {
            return item instanceof RadioMenuItem ? (RadioMenuItem)item : null;
        }
        loopIndex++;
    }
    return null;
}
受保护的RadioMenuItem getMenuItemFor(int dataIndex){
if(dataIndex<0)返回null;
int loopIndex=数据索引;
while(loopIndex
对于我们其他人:

有一种更简单的方法可以使用代码实现(也有一些简单的方法可以使用FXML实现,在代码中实现提供了更大的灵活性)

您只需创建一个ObservableList,然后用您的项目(包括分隔符)填充它,然后将该列表分配给ChoiceBox,如下所示:

private void fillChoiceBox(ChoiceBox choiceBox) {

    ObservableList items = FXCollections.observableArrayList();

    items.add("one");
    items.add("two");
    items.add("three");
    items.add(new Separator());
    items.add("Apples");
    items.add("Oranges");
    items.add("Pears");

    choiceBox.getItems().clear();
    choiceBox.getItems().addAll(items);
}

有趣的想法:-)沉思:哪一方负责在数据修改时保持索引同步?可能是蒙皮(分隔符映射到分隔符numitems的位置)?我们不需要一个完整的分隔符,只需要一个标记(分隔符根本不用),也许你可以使用一个。创建一个自定义类型,例如
separablelement
,它保存类型
T
的元素,并知道分隔符应该放在哪里,然后定义一个自定义单元格工厂,根据需要呈现元素和不可选择的分隔符(可能很难很好地实现)。但这并不能满足问题的要求,即使用类型安全性将
分隔符添加到列表选项中。要实现类型安全,您需要这样做。我同意这种实现很简单,而且对大多数人来说,可能已经足够了。创建此问题的泛型类型安全解决方案所涉及的工作可能会超过