GoXr3Plus GoXr3Plus - 3 months ago 49
Java Question

JavaFX TabPane,Tab.setContent() doesn't work

The problem is that i want to transfer an item between a

GridPane
and a
Tab

so i am adding the item to the tab first.

Then i am adding the same item to the GridPane.Its works well until here.But then i want to add the item back to the tab and i am using

tab.setContent(item);


But it doesn't work.Neither the item is removed from the GridPane neither the item is added to the tab as content.Why is this happening??


The .java file:


package pack;

import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;

import javafx.application.Application;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Tab;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;

public class Starter extends Application {

@Override
public void start(Stage primaryStage) throws Exception {
primaryStage.setScene(new Scene(new UI()));
primaryStage.centerOnScreen();
primaryStage.show();
}

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

/**
* This class contains the graphical interface
*
* @author Alexander
*
*/
public class UI extends BorderPane implements Initializable {

@FXML
private Tab tab;

@FXML
private Button item;

@FXML
private GridPane gridPane;

@FXML
private Button transferButton;

boolean onGridPane = false;

/**
* Constructor
*/
public UI() {
FXMLLoader loader = new FXMLLoader(getClass().getResource("UI.fxml"));
loader.setController(this);
loader.setRoot(this);

try {
loader.load();
} catch (IOException e) {
e.printStackTrace();
}
}

@Override
public void initialize(URL location, ResourceBundle resources) {
System.out.println("Main Controller has been initialized....");

transferButton.setOnAction(a -> {
if (!onGridPane) {
gridPane.add(item, 0, 0);
onGridPane = true;
transferButton.setText("<-Move to Tab");
} else {
tab.setContent(item);
onGridPane = false;
transferButton.setText("Move to GridPane->");
}
});
}

}

}



And the .fxml file:


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

<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.Tab?>
<?import javafx.scene.control.TabPane?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.text.Font?>

<fx:root prefHeight="322.0" prefWidth="538.0" type="BorderPane" xmlns="http://javafx.com/javafx/8.0.60" xmlns:fx="http://javafx.com/fxml/1">
<top>
<TabPane prefHeight="141.0" prefWidth="538.0" style="-fx-border-color: red;" tabClosingPolicy="UNAVAILABLE" BorderPane.alignment="CENTER">
<tabs>
<Tab fx:id="tab" text="Tab">
<content>
<Button fx:id="item" mnemonicParsing="false" text="Moving Item" />
</content>
</Tab>
</tabs>
</TabPane>
</top>
<bottom>
<GridPane fx:id="gridPane" gridLinesVisible="true" style="-fx-border-color: red;" BorderPane.alignment="CENTER">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
</GridPane>
</bottom>
<right>
<Button fx:id="transferButton" mnemonicParsing="false" text="Move to GridPane-&gt;" BorderPane.alignment="CENTER">
<font>
<Font size="16.0" />
</font></Button>
</right>
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</padding>
<center>
<Label prefHeight="82.0" prefWidth="340.0" style="-fx-font-weight: bold; -fx-font-size: 15;" text="Above is a [TabPane] and Below is a [GridPane]" BorderPane.alignment="CENTER" />
</center>
</fx:root>

Answer

Nodes cannot appear twice in the scene graph; adding a node that is already part of the scene graph to the scene graph again is explicitly forbidden by the API, so the behavior if you try to do so is undefined.

You need to remove the button from the scene graph before adding it elsewhere:

transferButton.setOnAction(a -> {
    if (!onGridPane) {
        tab.setContent(null);
        gridPane.add(item, 0, 0);
        onGridPane = true;
        transferButton.setText("<-Move to Tab");
    } else {
        gridPane.getChildren().remove(item);
        tab.setContent(item);
        onGridPane = false;
        transferButton.setText("Move to GridPane->");
    }
});
Comments