javafxcustomcontrol<;T>;:这可能吗?
我想在JavaFX中创建一个简单的可重用自定义控件,它只不过是一个带有标签的组合框,可以设置文本 我希望它在JavaFX场景生成器中可用 我还希望它能够采用单个通用参数javafxcustomcontrol<;T>;:这可能吗?,java,generics,custom-controls,javafx-8,scenebuilder,Java,Generics,Custom Controls,Javafx 8,Scenebuilder,我想在JavaFX中创建一个简单的可重用自定义控件,它只不过是一个带有标签的组合框,可以设置文本 我希望它在JavaFX场景生成器中可用 我还希望它能够采用单个通用参数,尽可能地模拟可用的标准组合框的行为 我遇到的问题是,当我尝试在SceneBuilder中将Controls Controller设置为Controller时,我收到一个错误,告诉我:控制器对于控制器类无效 这就像调用fxmloader.load()(在设置根、类加载器和位置之后)时,无法(我可以找到)告诉加载器“哦,这是一个Cu
,尽可能地模拟可用的标准组合框的行为
我遇到的问题是,当我尝试在SceneBuilder中将Controls Controller设置为Controller
时,我收到一个错误,告诉我:控制器对于控制器类无效
这就像调用fxmloader.load()
(在设置根、类加载器和位置之后)时,无法(我可以找到)告诉加载器“哦,这是一个CustomControl。”
这是我对控件的代码:
public class LabeledComboBox<T> extends VBox {
private final LCBController<T> Controller;
public LabeledComboBox(){
this.Controller = this.Load();
}
private LCBController Load(){
final FXMLLoader loader = new FXMLLoader();
loader.setRoot(this);
loader.setClassLoader(this.getClass().getClassLoader());
loader.setLocation(this.getClass().getResource("LabeledComboBox.fxml"));
try{
final Object root = loader.load();
assert root == this;
} catch (IOException ex){
throw new IllegalStateException(ex);
}
final LCBController ctrlr = loader.getController();
assert ctrlr != null;
return ctrlr;
}
/*Methods*/
}
public类LabeledComboBox扩展了VBox{
专用最终LCB控制器;
公共标签mbobox(){
this.Controller=this.Load();
}
专用LCB控制器加载(){
最终FXMLLoader=新的FXMLLoader();
setRoot(this);
setClassLoader(this.getClass().getClassLoader());
setLocation(this.getClass().getResource(“LabeledComboBox.fxml”);
试一试{
最终对象根=loader.load();
断言根==this;
}捕获(IOEX异常){
抛出新的非法状态异常(ex);
}
最终LCBController ctrlr=loader.getController();
断言ctrlr!=null;
返回ctrlr;
}
/*方法*/
}
这是控制器类:
public class LCBController<T> implements Initializable {
//<editor-fold defaultstate="collapsed" desc="Variables">
@FXML private ResourceBundle resources;
@FXML private URL location;
@FXML private Label lbl; // Value injected by FXMLLoader
@FXML private ComboBox<T> cbx; // Value injected by FXMLLoader
//</editor-fold>
//<editor-fold defaultstate="collapsed" desc="Initialization">
@Override public void initialize(URL fxmlFileLocation, ResourceBundle resources) {
this.location = fxmlFileLocation;
this.resources = resources;
//<editor-fold defaultstate="collapsed" desc="Assertions" defaultstate="collapsed">
assert lbl != null : "fx:id=\"lbl\" was not injected: check your FXML file 'LabeledComboBox.fxml'.";
assert cbx != null : "fx:id=\"cbx\" was not injected: check your FXML file 'LabeledComboBox.fxml'.";
//</editor-fold>
}
//</editor-fold>
/*Methods*/
}
公共类LCBController实现可初始化{
//
@FXML私有资源包资源;
@FXML私有URL位置;
@FXML私有标签lbl;//FXMLLoader注入的值
@FXML专用组合框cbx;//FXMLLoader注入的值
//
//
@重写公共void初始化(URL fxmlFileLocation,ResourceBundle资源){
this.location=fxmlFileLocation;
这就是资源=资源;
//
assert lbl!=null:“fx:id=\“lbl\”未被注入:检查FXML文件“LabeledComboBox.FXML”;
assert cbx!=null:“fx:id=\“cbx\”未被注入:检查FXML文件“LabeledComboBox.FXML”;
//
}
//
/*方法*/
}
很明显,我在这里遗漏了一些东西。我真的希望这是可能的,而不必拿出我自己的FXMLLoader类实现(真的,真的,真的希望)
有人能告诉我我错过了什么,或者这是否可能
编辑1:
在有人给我指了一个链接之后,我可能已经知道了怎么做,但我仍然不是百分之百的确定。对我来说,它感觉控制器类本身不能用泛型参数创建(即:公共类控制器{…}
=不好)
这有点烦人,但我想是有道理的
那么,如何将泛型参数应用于自定义控件控制器内的方法,并使控件本身(而不是控制器)成为泛型:如是
控制:
public class LabeledComboBox<T> extends VBox {...}
package application;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.SingleSelectionModel;
import javafx.scene.layout.VBox;
public class LabeledComboBox<T> extends VBox {
private final LabeledComboBoxController<T> controller ;
public LabeledComboBox(ObservableList<T> items, String text) {
controller = load();
if (controller != null) {
setText(text);
setItems(items);
}
}
public LabeledComboBox(ObservableList<T> items) {
this(items, "");
}
public LabeledComboBox(String text) {
this(FXCollections.observableArrayList(), text);
}
public LabeledComboBox() {
this("");
}
private LabeledComboBoxController<T> load() {
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource(
"LabeledComboBox.fxml"));
loader.setRoot(this);
loader.load();
return loader.getController() ;
} catch (Exception exc) {
Logger.getLogger("LabeledComboBox").log(Level.SEVERE,
"Exception occurred instantiating LabeledComboBox", exc);
return null ;
}
}
// Expose properties, but just delegate to controller to manage them
// (by delegating in turn to the underlying controls):
public void setText(String text) {
controller.setText(text);
}
public String getText() {
return controller.getText();
}
public StringProperty textProperty() {
return controller.textProperty();
}
public boolean isWrapText() {
return controller.isWrapText();
}
public void setWrapText(boolean wrapText) {
controller.setWrapText(wrapText);
}
public BooleanProperty wrapTextProperty() {
return controller.wrapTextProperty();
}
public ObservableList<T> getItems() {
return controller.getItems();
}
public void setItems(ObservableList<T> items) {
controller.setItems(items);
}
public SingleSelectionModel<T> getSelectionModel() {
return controller.getSelectionModel();
}
}
public类LabeledComboBox扩展VBox{…}
控制器:
public class LCBController implements Initializable {
/*Stuff...*/
/**
* Set the ComboBox selected value.
* @param <T>
* @param Value
*/
public <T> void setValue(T Value){
this.cbx.setValue(Value);
}
/**
* Adds a single item of type T to the ComboBox.
* @param <T> ComboBox Type
* @param Item
*/
public <T> void Add(T Item){
this.cbx.getItems().add(Item);
}
/**
* Adds a list of items of type T to the ComboBox.
* @param <T> ComboBox Type
* @param Items
*/
public <T> void Add(ObservableList<T> Items){
this.cbx.getItems().addAll(Items);
}
/**
* Removes an item of type T from the ComboBox.
* @param <T> ComboBox Type
* @param Item
* @return True if successful(?)
*/
public <T> boolean Remove(T Item){
return this.cbx.getItems().remove(Item);
}
}
package application;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.control.SingleSelectionModel;
public class LabeledComboBoxController<T> {
@FXML
private Label label ;
@FXML
private ComboBox<T> comboBox ;
public void setText(String text) {
label.setText(text);
}
public String getText() {
return label.getText();
}
public StringProperty textProperty() {
return label.textProperty();
}
public ObservableList<T> getItems() {
return comboBox.getItems();
}
public void setItems(ObservableList<T> items) {
comboBox.setItems(items);
}
public boolean isWrapText() {
return label.isWrapText();
}
public void setWrapText(boolean wrapText) {
label.setWrapText(wrapText);
}
public BooleanProperty wrapTextProperty() {
return label.wrapTextProperty();
}
public SingleSelectionModel<T> getSelectionModel() {
return comboBox.getSelectionModel();
}
}
公共类LCBController实现可初始化{
/*东西*/
/**
*设置组合框的选定值。
*@param
*@param值
*/
公共无效设置值(T值){
此.cbx.setValue(值);
}
/**
*将类型为T的单个项添加到组合框中。
*@param组合框类型
*@param项目
*/
公共作废新增(T项){
this.cbx.getItems().add(Item);
}
/**
*将T类型的项目列表添加到组合框中。
*@param组合框类型
*@param项目
*/
公共作废添加(可观察列表项){
this.cbx.getItems().addAll(Items);
}
/**
*从组合框中删除T类型的项。
*@param组合框类型
*@param项目
*@如果成功返回True(?)
*/
公共布尔删除(T项){
返回此.cbx.getItems().remove(项);
}
}
这样行吗?这条路对吗?同样,我的愿望不过是一个带有标签的组合框,告诉用户它的全部内容。我确信这种构造是不可能的,因为FXML是在运行时评估的。和泛型已在运行时删除
但是可以做的是为控制器分配一个泛型
FXML实现了模型视图控制器(MVC)设计,该设计受以下主题约束:
您的问题也是以下主题中的一个问题:
这对我很有效,当我将库导入到SceneBuilder中时,效果很好:
(非常基本)FXML:
控制器:
public class LCBController implements Initializable {
/*Stuff...*/
/**
* Set the ComboBox selected value.
* @param <T>
* @param Value
*/
public <T> void setValue(T Value){
this.cbx.setValue(Value);
}
/**
* Adds a single item of type T to the ComboBox.
* @param <T> ComboBox Type
* @param Item
*/
public <T> void Add(T Item){
this.cbx.getItems().add(Item);
}
/**
* Adds a list of items of type T to the ComboBox.
* @param <T> ComboBox Type
* @param Items
*/
public <T> void Add(ObservableList<T> Items){
this.cbx.getItems().addAll(Items);
}
/**
* Removes an item of type T from the ComboBox.
* @param <T> ComboBox Type
* @param Item
* @return True if successful(?)
*/
public <T> boolean Remove(T Item){
return this.cbx.getItems().remove(Item);
}
}
package application;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.control.SingleSelectionModel;
public class LabeledComboBoxController<T> {
@FXML
private Label label ;
@FXML
private ComboBox<T> comboBox ;
public void setText(String text) {
label.setText(text);
}
public String getText() {
return label.getText();
}
public StringProperty textProperty() {
return label.textProperty();
}
public ObservableList<T> getItems() {
return comboBox.getItems();
}
public void setItems(ObservableList<T> items) {
comboBox.setItems(items);
}
public boolean isWrapText() {
return label.isWrapText();
}
public void setWrapText(boolean wrapText) {
label.setWrapText(wrapText);
}
public BooleanProperty wrapTextProperty() {
return label.wrapTextProperty();
}
public SingleSelectionModel<T> getSelectionModel() {
return comboBox.getSelectionModel();
}
}
包应用;
导入javafx.beans.property.BooleanProperty;
导入javafx.beans.property.StringProperty;
导入javafx.collections.ObservableList;
导入javafx.fxml.fxml;
导入javafx.scene.control.ComboBox;
导入javafx.scene.control.Label;
导入javafx.scene.control.SingleSelectionModel;
公共类LabeledBoxController{
@FXML
自有品牌;
@FXML
专用组合框组合框;
公共void setText(字符串文本){
label.setText(文本);
}
公共字符串getText(){
返回label.getText();
}
公共字符串属性textProperty(){
返回label.textProperty();
}
公共可观察列表getItems(){
返回comboBox.getItems();
}
公共无效集合项(可观察列表项){
comboBox.setItems(项目);
}
公共布尔值isWrapText(){
返回标签。isWrapText();
}
公共无效setWrapText(布尔wrapText){
label.setWrapText(wrapText);
}