如何扩展使用FXML的自定义JavaFX组件 [英] How to extend custom JavaFX components that use FXML

查看:168
本文介绍了如何扩展使用FXML的自定义JavaFX组件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果为视图使用FXML,如何正确扩展自定义JavaFX组件以添加或修改其GUI组件?

How do I properly extend a custom JavaFX component to add or modify its GUI components if it uses FXML for the view?

作为示例场景,假设我使用以下创建自定义JavaFX组件的方法:

As an example scenario, suppose I use the following approach of creating a custom JavaFX component:

SpecializedButton.java(Controller)

package test;

import java.io.IOException;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;

public class SpecializedButton extends HBox
{
    @FXML private Button button;
    @FXML private Label label;

    public SpecializedButton() 
    {
        FXMLLoader loader = new FXMLLoader( getClass().getResource( "SpecializedButton.fxml" ) );

        loader.setRoot( this );
        loader.setController( this );

        try {
            loader.load();
        } catch ( IOException e ) {
            throw new RuntimeException( e );
        }
    }

    // specialized methods for this specialized button
    // ...
    public void doSomething() {
        button.setText( "Did something!" );
    }
}

SpecializedButton.fxml(查看)

<?xml version="1.0" encoding="UTF-8"?>

<?import java.lang.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.control.Button?>

<fx:root type="HBox" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
   <children>
      <AnchorPane HBox.hgrow="ALWAYS">
         <children>
            <Label fx:id="label" text="Click to do something: " AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
         </children>
      </AnchorPane>
      <AnchorPane HBox.hgrow="ALWAYS">
         <children>
            <Button fx:id="button" onAction="#doSomething" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
         </children>
      </AnchorPane>
   </children>
</fx:root>

MyApp.java

package test;

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class MyApp extends Application
{
    public static void main( String[] args )
    {
        launch( args );
    }

    public void start( Stage stage ) throws Exception
    {
        stage.setScene( new Scene( new SpecializedButton(), 300, 50 ) );
        stage.show();
    }
}

SpecializedButton类加载FXML视图(SpecializedButton.fxml并且充当它的控制器。

The SpecializedButton class loads the FXML view (SpecializedButton.fxml) and acts as the controller for it.

SpecializedButton FXML视图分别在左侧和右侧创建一个带有两个AnchorPanes和一个Label和Button的HBox。单击该按钮时,它会调用SpecializedButton控制器类中的doSomething()。

The SpecializedButton FXML view just creates an HBox with two AnchorPanes and a Label and Button in the left and right sides, respectively. When the button is clicked, it calls doSomething() in the SpecializedButton controller class.

问题

通过此设置,我使用FXML将视图与应用程序逻辑分开。

With this setup, I am using FXML to separate the view from the application logic.

但是,如果我想创建一个扩展SpecializedButton的新 HighlySpecializedButton 类,我不知道如何扩展视图。

However, if I want to create a new HighlySpecializedButton class that extends SpecializedButton, I don't know how to go about "extending" the view as well.

如果我想使用SpecializedButton视图,但是为HighlySpecializedButton修改它,我必须将视图代码复制到新的FXML文件中,导致代码重复而不是正确的继承。

If I wanted to use the SpecializedButton view, but modify it for the HighlySpecializedButton, I'd have to copy the view code into a new FXML file, resulting in duplicate code instead of proper inheritance.

如果我没有使用FXML,而是在Java类中创建GUI组件,那么扩展该类将使我能够正确继承并添加/修改超类中的组件。

If I wasn't using FXML, and was creating the GUI components within a Java class instead, extending that class would give me the ability to properly inherit and add/modify the components from the super class.

我显然误解了一些关于JavaFX的非常重要的概念。

I am clearly misunderstanding some very important concepts about JavaFX.

问题

在这种情况下,FXML视图是如此愚蠢,以至于我每次我想从自定义组件继承时,都必须创建一个全新的FXML视图吗?

Are FXML views in this case so "dumb" that I'd have to create an entirely new FXML view every time I wanted to inherit from a custom component?

或者,如果我误解了真正的问题,在有或没有FXML的情况下创建可扩展自定义JavaFX组件的正确方法是什么?

Or, if I am misunderstanding the real issue, what is the proper way of creating extendable custom JavaFX components, with or without FXML?

我非常感谢任何见解。在此先感谢!

I'd greatly appreciate any insight. Thanks in advance!

推荐答案

据我所知,您希望能够扩展现有组件并避免
副本&安培;粘贴新组件的整个标记。

From what I understand, you want to be able to extend existing components and avoid copy & pasting the entire markup for the new component.

您可以使用 @DefaultProperty 为组件定义扩展点注解。
请看e.x. javafx.scene.layout.Pane ObservableList getChildren()
定义为 @DefaultProperty( 孩子)
这样,当您使用ex HBox (扩展Pane)作为组件的根元素时,所有子组件都会添加到儿童由窗格定义的属性。

You can define an extension point for the component with the @DefaultProperty annotation. Look at e.x. javafx.scene.layout.Pane: There is a ObservableList getChildren() defined with @DefaultProperty("children"). In this way, when you use e.x an HBox (extends Pane) as the root element for your component, all child components are added to the children property defined by the Pane.

以同样的方式,您可以在FXML中定义扩展点:

In the same way you can define extension points in FXML:

SpecializedButton.fxml (我在本例中简化了一点)

SpecializedButton.fxml (I simplified it a little for this example)

<fx:root type="HBox">
  <HBox>
    <Label fx:id="label" text="Click to do something: " />
    <HBox fx:id="extension"></HBox>
  </HBox>

  <HBox>
    <Button fx:id="button" onAction="#doSomething"/>
  </HBox>
</fx:root>

HBox fx:id =extension将是我的扩展点:

@DefaultProperty(value = "extension")
public class SpecializedButton extends HBox
{
    @FXML private HBox extension;

    public ObservableList<Node> getExtension() {
        return extension.getChildren();
    }
    // ... more component specific code
}

SuperSpecializedButton.fxml

<fx:root type="SpecializedButton">
  <Label text="EXTENDED HALLO"/>
</fx:root>

并且:

public class SuperSpecializedButton extends SpecializedButton
{
    // ... more component specific code
}

如您所见,我只需要为超级专用组件定义fxml。

As you can see, I need only to define fxml for the super-specialized component.

此代码仅适用于JavaFX> = 2.1 。事先,超类的组件注入不适用于FXMLLoader。

This code will work only on JavaFX >= 2.1. Beforehand the component injection for the super class didn't worked with the FXMLLoader.

我在github上添加了一个工作示例: https://github.com/matrak/javafx-extend-fxml

I added an working example on github: https://github.com/matrak/javafx-extend-fxml

这篇关于如何扩展使用FXML的自定义JavaFX组件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆