簡體   English   中英

如何擴展使用FXML的自定義JavaFX組件

[英]How to extend custom JavaFX components that use FXML

如果為視圖使用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(查看)

<?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)並充當它的控制器。

SpecializedButton FXML視圖分別在左側和右側創建一個帶有兩個AnchorPanes和一個Label和Button的HBox。 單擊該按鈕時,它會調用SpecializedButton控制器類中的doSomething()。


問題

通過此設置,我使用FXML將視圖與應用程序邏輯分開。

但是,如果我想創建一個擴展SpecializedButton的新的HighlySpecializedButton類,我不知道如何“擴展”視圖。

如果我想使用SpecializedButton視圖,但是為HighlySpecializedButton修改它,我必須將視圖代碼復制到新的FXML文件中,導致重復的代碼而不是正確的繼承。

如果我沒有使用FXML,而是在Java類中創建GUI組件,那么擴展該類將使我能夠正確地繼承和添加/修改超類中的組件。

我顯然誤解了一些關於JavaFX的非常重要的概念。


在這種情況下,FXML視圖是如此“愚蠢”,每當我想從自定義組件繼承時,我必須創建一個全新的FXML視圖嗎?

或者,如果我誤解了真正的問題,那么使用或不使用FXML創建可擴展自定義JavaFX組件的正確方法是什么?

我非常感謝任何見解。 提前致謝!

根據我的理解,您希望能夠擴展現有組件並避免復制和粘貼新組件的整個標記。

您可以使用@DefaultProperty注釋為組件定義擴展點。 查看ex javafx.scene.layout.Pane :使用@DefaultProperty("children")定義了一個ObservableList getChildren() @DefaultProperty("children") 這樣,當您使用ex HBox (擴展Pane)作為組件的根元素時,所有子組件都將添加到Pane定義的children屬性中。

以同樣的方式,您可以在FXML中定義擴展點:

SpecializedButton.fxml (我為這個例子簡化了一點)

<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。

此代碼僅適用於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"));

}  
}

希望這可以幫到你

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM