2017-01-20 2 views
1

になっていないFXMLボタンをハードコードされたように動作させるために、以下のことがなぜ必要なのかを説明してください。FXMLボタンがnullpointerにつながり、ハードコードされたボタンが

ボタンを押して、オンザフライでアプリケーションのCSSを変更しようとしています。 コントローラのボタンをハードコードすると、すべてが正常に機能していますが、FXMLを使用すると、同じ関数呼び出しによってnullpointerが発生します。

完全なコードを表示するように更新しました(とにかく小さなテストプログラム)。私はいくつかの名前を変更して読みやすくしました。機能が変更されませんが、一方で弱い回避策として役立つ機能が追加されましたいいえ: コントローラ:私のFXMLの

public class SoC extends Application 
{ 
public Scene myScene; 
Button   btn  = new Button(); 
@FXML 
Button   btnFXHack; 
@FXML 
Button   btnFXFail; 
boolean   flipIt = false; 

// basic function i want to use 
public void changeCSS() 
{ 
    if (!flipIt) 
    { 
     myScene.getStylesheets().remove(0); 
     myScene.getStylesheets().add(getClass().getResource("styleTwo.css").toExternalForm()); 
    } 
    else 
    { 
     myScene.getStylesheets().remove(0); 
     myScene.getStylesheets().add(getClass().getResource("styleOne.css").toExternalForm()); 
    } 
    flipIt = !flipIt; 
} 

// workaround that is fine unless there are more then one scene 
public void changeCSSHack(Scene s) 
{ 
    if (!flipIt) 
    { 
     s.getStylesheets().remove(0); 
     s.getStylesheets().add(getClass().getResource("styleTwo.css").toExternalForm()); 
    } 
    else 
    { 
     s.getStylesheets().remove(0); 
     s.getStylesheets().add(getClass().getResource("styleOne.css").toExternalForm()); 
    } 
    flipIt = !flipIt; 
} 

/** 
* Button one changes CSS on his own scene only, which feels kinda hacked and lame. 
* 
* @param event 
*/ 
@FXML 
private void handleCSSHack(ActionEvent event) 
{ 
    // this button can access his own scene AND use it,.... 
    changeCSSHack(btnFXHack.getScene()); 
} 

/** 
* Button two tries to change CSS with saved values in the mainController... 
* ...and fails. 
* 
* @param event 
*/ 
@FXML 
private void handleCSSFail(ActionEvent event) 
{ 
    // ...yet this button tells me the SAME scene is null. Yes, the one he is on himself. 
    changeCSS(); 
} 

@Override 
public void start(Stage primaryStage) 
{ 
    try 
    { 
     BorderPane pane = (BorderPane) FXMLLoader.load(getClass().getResource("SoC.fxml")); 
     myScene = new Scene(pane); 
     myScene.getStylesheets().add(getClass().getResource("styleOne.css").toExternalForm()); 

     btn = new Button("hardcoded"); 
     btn.setOnAction(new EventHandler<ActionEvent>() 
     { 
      @Override 
      public void handle(ActionEvent event) 
      { 
       changeCSS(); 
      } 
     }); 
     pane.setCenter(btn); 

     primaryStage.setScene(myScene); 
     primaryStage.show(); 
     System.out.println("Started"); 
    } 
    catch (Exception e) 
    { 
     e.printStackTrace(); 
    } 
} 

public static void main(String[] args) 
{ 
    launch(args); 
} 
} 

パート(ボードはFXMLを好きとは思われないので、フルに貼り付けることはできません)

<Button fx:id="btnFXHack" mnemonicParsing="false" onAction="#handleCSSHack" text="FX Button Hack" BorderPane.alignment="CENTER" /> 
    <Button fx:id="btnFXFail" mnemonicParsing="false" onAction="#handleCSSFail" text="FX Button Fail" BorderPane.alignment="CENTER" /> 

サイドノート:「children()。add(btnFX)」を使用してFXMLボタンをペインに追加するだけで、今は2倍になりますが、これも機能します。 Idは本当に私のコードから自分のGUIのものを保つことを好むので、IDは本当にこの問題を解決する方法を聞くのが大好きです。

ありがとうございました。

編集私の構成を示す:

programmfolder 
-src 
--mainpackage 
---controller.java 
---.fxml-file 
-themes folder 
--default.css 
--SciFi.css 

そうです、 "/" .cssファイルに到達するために必要とされています。そしてもう一度:ハードコードボタンによって呼び出されると、changeCSS()は実際に動作しています。だから私はこの問題がこの目的のためにあるのではないかと疑う。

また、println(「stuff」)のためにFXMLボタンを押すこともできます。今私は彼がmySceneを見ないので、nullpointerを取得するという気持ちを得る。単純なsystem.out.println(myScene.toString())でも、FXMLボタンのnullポインタが返されます。問題は、どこから呼び出されているのかによって同じオブジェクトが突然nullになるのはなぜですか?

+0

関連性があるかどうかわかりませんが、changeCssメソッドの前に "@FXML"と入力する必要があります。さらに、btnFXはコード内で初期化する必要はありません。単に "@FXMl Button btnFX;"を使用してください。 –

+0

悲しいことに、FXML表記は何も変更しません。私は前にそれを試みた。 – Rattenmann

+0

ボタンはfxmlの唯一のコンポーネントですか?他の要素はどうですか?彼らは働きますか?コントローラがfxmlに正しく設定されていない可能性があります。 –

答えて

1

ああ、今、私は問題を知っている。あなたのコントローラーもメインのアプリケーションクラスです!

アプリケーションを起動すると、 "SoC"のインスタンスが作成され、 "start()"が呼び出されます。したがって、mySceneはこのインスタンスで初期化されます。

JavaFxがfxmlファイルのコントローラを作成すると、新しいインスタンスが作成されます。その場合、mySceneはnullです。 メインアプリケーションクラスとは別のコントローラクラスを作成する必要があります。 また、mySceneをstaticに設定します。

+0

それを静的に設定すると、そのトリックがうまくいきます。シーンを「他のシーン」に渡すにはどうすればいいですか?またはそれらを同期する?私は別々のコントローラを持っていて、mySceneをパラメータとして渡しました。それはまだnull thoになった。隠されたシーンがどこにあるのか分かりません。実際に最初に作成された理由については分かりません。 – Rattenmann

+0

自分でコントローラを作成して初期化することはできません。 JavaFXはそのインスタンスを作成します。さまざまなコントローラーでシーンを設定するには、シーンを静的にする必要もあります。しかし、私はそれが良くないと思う。私は最良の方法はbutton.getScene()を使うことだと思います。この記事を参照してください:http://stackoverflow.com/questions/26060859/javafx-getting-scene-from-a-controller –

+0

それは私が恐れていたものです。したがって、button.getScene()では、単一のシーンにしかアクセスすることができず、静的な使用は間違っていると感じます。私がJavaに戻ったときは、なぜ私は他の言語を好むのか覚えている!いずれにせよ、答えが好きではないということは、それが間違っていることを意味するものではありません。ありがとう! – Rattenmann

0

ここで、関数changeCSSを保存しますか?プロジェクトの構造を見せてください。

この関数は、ボタンが表示されているビューに割り当てられたコントローラの内側にある必要があります。

+0

コントローラーが正しく割り当てられていて、実際にボタンを押すだけでsystem.out.printlnが正常に実行されます。私の質問を編集して私の構造を含めてください。 – Rattenmann

関連する問題