我将spring与javafx一起使用。要将springbean用作自定义控件,我需要使用builderfactory和一个builder从上下文中获取bean。否则我没有应用程序上下文
父.java
@Component
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class ParentControl extends VBox {
@Autowired
ControlFXMLLoader controlFXMLLoader;
@Value("classpath:/parent.fxml")
private Resource fxml;
@PostConstruct
void load() throws IOException {
controlFXMLLoader.load(fxml.getURL(), this);
}
public ParentControl() {
//no application context
}
public LocalDate getDate() {
return LocalDate.now();
}
}
beanbuilderfactory.java
@Component
public class BeanBuilderFactory implements BuilderFactory {
private Logger logger = LogManager.getLogger(BeanBuilderFactory.class);
@Autowired
private ConfigurableApplicationContext context;
public BeanBuilderFactory() {
}
private JavaFXBuilderFactory defaultBuilderFactory = new JavaFXBuilderFactory();
@Override
public Builder<?> getBuilder(Class<?> type) {
try {
String[] beanNames = context.getBeanNamesForType(type);
if (beanNames.length == 1) {
return new Builder<Object>() {
@Override
public Object build() {
return context.getBean(beanNames[0]);
}
};
} else {
return defaultBuilderFactory.getBuilder(type);
}
} catch (BeansException e) {
return defaultBuilderFactory.getBuilder(type);
}
}
}
然后我使用这个builderfactory为自定义控件加载fxml
controlfxmlloader.java文件
@Component
public class ControlFXMLLoader {
private Logger logger = LogManager.getLogger(ControlFXMLLoader.class);
@Autowired
protected ConfigurableApplicationContext context;
@Autowired
protected BeanBuilderFactory beanBuilderFactory;
public Object load(URL fxmlUrl, Parent root, Object controller) throws IOException {
logger.debug("load");
javafx.fxml.FXMLLoader loader = new javafx.fxml.FXMLLoader(fxmlUrl);
loader.setControllerFactory(context::getBean);
loader.setBuilderFactory(beanBuilderFactory);
loader.setRoot(root);
loader.setController(controller);
return loader.load();
}
public Object load(URL fxmlUrl, Parent root) throws IOException {
return load(fxmlUrl, root, root);
}
}
现在我有了一个子自定义控件
儿童控制.java
@Component
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class ChildControl extends VBox {
public ChildControl() {
}
@Autowired
ControlFXMLLoader controlFXMLLoader;
@Value("classpath:/child.fxml")
private Resource fxml;
@PostConstruct
void load() throws IOException {
controlFXMLLoader.load(fxml.getURL(), this);
}
ObjectProperty<LocalDate> date = new SimpleObjectProperty<LocalDate>();
public LocalDate getDate() {
return date.get();
}
public void setDate(LocalDate date) {
this.date.set(date);
}
public ObjectProperty<LocalDate> dateProperty() {
return date;
}
@FXML
protected void doSomething() {
System.out.println("The button was clicked! " + date.get().toString());
}
}
并希望将日期从父项fxml分配给子项
父.fxml
<fx:root type="com.example.javafx.ParentControl" xmlns:fx="http://javafx.com/fxml">
<ChildControl date="${controller.date}"/>
</fx:root>
子.fxml
<fx:root type="com.example.javafx.ChildControl" xmlns:fx="http://javafx.com/fxml">
<TextField fx:id="textField"/>
<Button text="Click Me" onAction="#doSomething"/>
</fx:root>
问题是fxmloader不允许将绑定表达式与生成器一起使用。我得到“无法绑定到生成器属性”异常。下面是fxmloader.java中的部分代码,以及最后一个导致问题的代码。
还有别的解决办法吗?
fxmlloader.java文件
public void processPropertyAttribute(Attribute attribute) throws IOException {
String value = attribute.value;
if (isBindingExpression(value)) {
// Resolve the expression
Expression expression;
if (attribute.sourceType != null) {
throw constructLoadException("Cannot bind to static property.");
}
if (!isTyped()) {
throw constructLoadException("Cannot bind to untyped object.");
}
// TODO We may want to identify binding properties in processAttribute()
// and apply them after build() has been called
if (this.value instanceof Builder) {
throw constructLoadException("Cannot bind to builder property.");
}
暂无答案!
目前还没有任何答案,快来回答吧!