ビューに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ビューは、2つのAnchorPanesと、左側と右側にそれぞれLabelとButtonを持つHBoxを作成するだけです。ボタンがクリックされると、SpecializedButtonコントローラークラスのdoSomething()が呼び出されます。
問題
この設定では、FXMLを使用してビューをアプリケーションロジックから分離しています。
ただし、SpecializedButtonを拡張する新しいHighlySpecializedButtonクラスを作成したい場合は、ビューを「拡張」する方法もわかりません。
SpecializedButtonビューを使用したいが、HighlySpecializedButton用に変更したい場合は、ビューコードを新しいFXMLファイルにコピーする必要があり、適切な継承ではなく重複したコードになります。
FXMLを使用しておらず、代わりにJavaクラス内でGUIコンポーネントを作成していた場合、そのクラスを拡張すると、スーパークラスからコンポーネントを適切に継承および追加/変更できるようになります。 。
私はJavaFXに関するいくつかの非常に重要な概念を明らかに誤解しています。
質問
この場合のFXMLビューは非常に「ダム」なので、カスタムコンポーネントから継承するたびに、まったく新しいFXMLビューを作成する必要がありますか?
または、実際の問題を誤解している場合、FXMLの有無にかかわらず、拡張可能なカスタムJavaFXコンポーネントを作成する適切な方法は何ですか?
洞察をいただければ幸いです。前もって感謝します!
私が理解していることから、既存のコンポーネントを拡張し、新しいコンポーネントのマークアップ全体をコピーして貼り付けることを避けたいと考えています。
_@DefaultProperty
_アノテーションを使用して、コンポーネントの拡張ポイントを定義できます。 e.xを見てください。 _javafx.scene.layout.Pane
_:ObservableList getChildren()
で定義された@DefaultProperty("children")
があります。このように、e.xをコンポーネントのルート要素としてHBox
(ペインを拡張)として使用すると、すべての子コンポーネントがペインで定義された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"));
}
}
これがあなたを助けることができることを願っています