javafx自定义控件

oknrviil  于 2021-07-16  发布在  Java
关注(0)|答案(0)|浏览(289)

我将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.");
        }

暂无答案!

目前还没有任何答案,快来回答吧!

相关问题