如何扩展使用FXML的自定义JavaFX组件

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

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

SpecializedButton.java(控制器)

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(查看)

           

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)并充当它的控制器。

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


问题

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

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

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

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

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


在这种情况下,FXML视图是如此“愚蠢”,每当我想从自定义组件inheritance时,我必须创建一个全新的FXML视图吗?

或者,如果我误解了真正的问题,那么使用或不使用FXML创建可扩展自定义JavaFX组件的正确方法是什么?

我非常感谢任何见解。 提前致谢!

根据我的理解,您希望能够扩展现有组件并避免复制和粘贴新组件的整个标记。

您可以使用@DefaultProperty批注为组件定义扩展点。 查看ex javafx.scene.layout.Pane :使用@DefaultProperty("children")定义了一个ObservableList getChildren() @DefaultProperty("children") 。 这样,当您使用ex HBox (扩展Pane)作为组件的根元素时,所有子组件都将添加到Pane定义的children属性中。

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

SpecializedButton.fxml (我为这个例子简化了一点)

          

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

 @DefaultProperty(value = "extension") public class SpecializedButton extends HBox { @FXML private HBox extension; public ObservableList getExtension() { return extension.getChildren(); } // ... more component specific code } 

SuperSpecializedButton.fxml

    

和:

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

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

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

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

我之前没有这样做,但是在实例化新的自定义组件时,您可以实现Initializable接口来设置视图组件。

要添加新组件(标签,按钮,img等等),我会将所有子组件包装在视图文件中,在AnchorPane,GridPane,VBox中,或者您希望以编程方式添加更多组件。 既然您正在从HBox扩展您的课程,您可以这样做。

这就是我要做的事情:

 public class SpecializedButton extends HBox implements Initializable{ @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!" ); } @Override public void initialize(URL url, ResourceBundle rb) { button.setText("Initialized Text"); } } 

所以对于HighlySpecializedButton类:

 public class HighlySpecializedButton extends SpecializedButton { public HighlySpecializedButton (){ super(); } // HighlySpecializedButton methods @Override public void initialize(URL url, ResourceBundle rb) { this.getChildren().add(new Button("New Button")); } } 

希望这可以帮到你