关闭另一个控制器中的选项卡-JavaFX

关闭另一个控制器中的选项卡-JavaFX,java,model-view-controller,javafx,fxml,Java,Model View Controller,Javafx,Fxml,我正在用Java设计一个简单的电子邮件客户端。我使用两个FXML文件作为视图,当然,还有两个Java控制器,每个都用于正确的视图 我的目标是关闭WriteView选项卡,单击WriteView中的“删除”按钮,但我有一些问题,因为我创建了一个新选项卡,在MainVIewController中加载了WriteView,现在我没有任何id或引用来关闭选项卡,除非选项卡名称旁边的“x”按钮 代码如下: MainView.FXML <?xml version="1.0" encoding="UTF

我正在用Java设计一个简单的电子邮件客户端。我使用两个FXML文件作为视图,当然,还有两个Java控制器,每个都用于正确的视图

我的目标是关闭WriteView选项卡,单击WriteView中的“删除”按钮,但我有一些问题,因为我创建了一个新选项卡,在MainVIewController中加载了WriteView,现在我没有任何id或引用来关闭选项卡,除非选项卡名称旁边的“x”按钮

代码如下:

MainView.FXML

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

<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.control.cell.*?>
<?import javafx.collections.*?>

<TabPane fx:id="root" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" tabClosingPolicy="ALL_TABS" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="controller.MainViewController">
<tabs>
    <Tab text="Mailbox" closable="false">
        <content>
            <BorderPane prefHeight="200.0" prefWidth="200.0">
            <top>
                <ToolBar prefHeight="40.0" prefWidth="200.0" BorderPane.alignment="CENTER">
                    <items>
                    <Button fx:id="update" mnemonicParsing="false" onAction="#updateButton" text="Update" />
                        <Button fx:id="write" mnemonicParsing="false" onAction="#writeButton" text="Write" />
                        <Button fx:id="reply" mnemonicParsing="false" onAction="#replyButton" text="Reply" />
                        <Button fx:id="replyToAll" mnemonicParsing="false" onAction="#replyToAllButton" text="Reply to All" />
                        <Button fx:id="forward" mnemonicParsing="false" onAction="#forwardButton" text="Forward" />
                        <Button fx:id="delete" mnemonicParsing="false" onAction="#deleteButton" text="Delete" />
                    </items>
                </ToolBar>
            </top>
            <bottom>
                <HBox prefHeight="19.0" prefWidth="600.0" BorderPane.alignment="CENTER">
                    <children>
                        <Label text="Client Status:" />
                        <Label fx:id="status" text="" />
                    </children>
                </HBox>
            </bottom>
            <left>
                <Accordion BorderPane.alignment="CENTER">
                    <panes>
                    <TitledPane fx:id="mailboxName" animated="false" text="Inbox: ">
                        <content>
                            <VBox prefHeight="200.0" prefWidth="100.0">
                                <children>
                                    <Label fx:id="inbox" text="Inbox" />
                                    <Label fx:id="drafts" text="Drafts" />
                                    <Label fx:id="bin" text="Bin" />
                                </children>
                            </VBox>
                        </content>
                        </TitledPane>
                    </panes>
                </Accordion>
            </left>
            <center>
                <TableView fx:id="table" prefHeight="200.0" prefWidth="200.0" BorderPane.alignment="CENTER">

                    <columns>
                        <TableColumn prefWidth="247.0" text="Subject">
                            <cellValueFactory><PropertyValueFactory property="subject" /></cellValueFactory>
                        </TableColumn>

                        <TableColumn prefWidth="131.0" text="From">
                            <cellValueFactory><PropertyValueFactory property="receiver" /></cellValueFactory>
                        </TableColumn>

                        <TableColumn minWidth="3.0" prefWidth="118.0" text="Date">
                            <cellValueFactory><PropertyValueFactory property="date" /></cellValueFactory>
                        </TableColumn>
                    </columns>
                    <items>
                        <FXCollections fx:factory="observableArrayList">
                        </FXCollections>
                    </items>
                </TableView>
            </center>
            </BorderPane>
        </content>
    </Tab>
</tabs>
</TabPane>

您可以将事件处理程序传递给控制器,单击“删除”按钮时会触发该事件处理程序:

private Runnable tabCloseHandler;

public void setTabCloseHandler(Runnable handler) {
    tabCloseHandler = handler;
}

@FXML
public void deleteButton(ActionEvent e) {
    // you don't set the handler here; this method is invoked as handler
    String mess = "You clicked: " + e.getSource() + "!";
    System.out.println(mess);

    if (handler != null) {
        handler.run();
    }
}

旁白:您的所有处理程序都未正确实现。看@James\u D你是对的!谢谢大家!@洛伦佐塔巴索:如果它回答了你的问题,你应该这样做。@James_完成了!谢谢!
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.text.*?>
<?import java.lang.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<VBox fx:id="root" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="controller.WriteViewController">
<children>
    <GridPane fx:id="table">
        <columnConstraints>
        <ColumnConstraints hgrow="SOMETIMES" maxWidth="296.0" minWidth="10.0" prefWidth="57.0" />
        <ColumnConstraints hgrow="SOMETIMES" maxWidth="543.0" minWidth="10.0" prefWidth="543.0" />
        </columnConstraints>
        <rowConstraints>
        <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
        <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
        <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
        </rowConstraints>
        <children>
            <Label text="To:" />
            <Label text="From:" GridPane.rowIndex="1" />
            <Label text="Subject:" GridPane.rowIndex="2" />
            <TextField fx:id="to" GridPane.columnIndex="1" />
            <TextField fx:id="from" GridPane.columnIndex="1" GridPane.rowIndex="1" />
            <TextField fx:id="subject" GridPane.columnIndex="1" GridPane.rowIndex="2" />
        </children>
    </GridPane>
    <Pane prefHeight="272.0" prefWidth="600.0">
        <children>
            <TextArea fx:id="text" prefHeight="277.0" prefWidth="600.0" />
        </children>
    </Pane>
    <ToolBar fx:id="toolbar" nodeOrientation="RIGHT_TO_LEFT" prefHeight="40.0" prefWidth="200.0">
        <items>
            <Button fx:id="send" mnemonicParsing="false" onAction="#sendButton" text="Send" />
            <Button fx:id="saveAsDraft" mnemonicParsing="false" onAction="#saveButton" text="Save as draft" />
        <Button fx:id="delete" mnemonicParsing="false" onAction="#deleteButton" text="Delete" />
        </items>
    </ToolBar>
</children>
</VBox>
package controller;

import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.*;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.VBox;
import model.Account;
import model.Email;

import java.net.URL;
import java.util.Observable;
import java.util.Observer;
import java.util.ResourceBundle;

public class WriteViewController implements Initializable, Observer{

    public WriteViewController() {

    }

    @FXML
    public VBox root;
    public GridPane table;
    public TextField to;
    public TextField from;
    public TextField subject;
    public TextArea text;
    public ToolBar toolbar;
    public Button send;
    public Button saveAsDraft;
    public Button delete;

    // BUTTONS ---------------------------------------------------------------------------------------------------------

    /**
    * On click on Update button do something
    */
    @FXML
    public void sendButton() {
        send.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                Account reciver = new Account(to.getText());
                Account sender = new Account(from.getText());

                Email toSend = new Email(sender, reciver, subject.getText(), text.getText());

                toSend.writeEmail(reciver, subject.getText(), text.getText());

                // Is not necessary to set the state, because, when a new Email is created, it has already the
                // state of new (2). For further information, see Email constructor.
            }
        });
    }

    @FXML
    public void saveButton() {
        saveAsDraft.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                Account reciver = new Account(to.getText());
                Account sender = new Account(from.getText());

                Email toSend = new Email(sender, reciver, subject.getText(), text.getText());

                toSend.setState(0); // the email is a draft
            }
        });
    }

    @FXML
    public void deleteButton() {
        delete.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                Account reciver = new Account(to.getText());
                Account sender = new Account(from.getText());

                Email toSend = new Email(sender, reciver, subject.getText(), text.getText());

                // here is the problem, Goal: close this tab!

                System.out.println(root.getParent()); // DEBUG
            }
        });
    }

    // INITIALIZING ----------------------------------------------------------------------------------------------------

    /**
    * It initialize all the event of the buttons
    */
    private void initializeButtons(){
        sendButton();
        saveButton();
        deleteButton();
    }

    /**
    * It call all the methods that initialize a category of components
    */
    private void initializeAll() {
        initializeButtons();

    }

    // IMPLEMENTATIONS -------------------------------------------------------------------------------------------------

    /**
    * It initialize all the necessary for the GUI
    * @param location: The location used to resolve relative paths for the root object, or null if the location is not known.
    * @param resources: The resources used to localize the root object, or null if the root object was not localized.
    */
    @Override
    public void initialize(URL location, ResourceBundle resources) {
        initializeAll();
    }

    /**
    * Implementation of update method in Observer interface
    * @param o:  the observable object.
    * @param arg: (optional) an argument passed to the notifyObservers method.
    */
    @Override
    public void update(Observable o, Object arg) {

    }
}
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

import java.io.IOException;

/**
*
* @author lorenzotabasso
*/

public class Client extends Application{

    @Override
    public void start(Stage primaryStage) throws IOException{
        Parent root = FXMLLoader.load(getClass().getResource("view/MainView.fxml"));
        Scene scene = new Scene(root);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    /**
    * @param args the command line arguments
    */
    public static void main(String[] args) {
        launch(args);
    }

}
private Runnable tabCloseHandler;

public void setTabCloseHandler(Runnable handler) {
    tabCloseHandler = handler;
}

@FXML
public void deleteButton(ActionEvent e) {
    // you don't set the handler here; this method is invoked as handler
    String mess = "You clicked: " + e.getSource() + "!";
    System.out.println(mess);

    if (handler != null) {
        handler.run();
    }
}
final Tab tab = new Tab("Write");
FXMLLoader loader = new FXMLLoader(getClass().getResource("/view/WriteView.fxml"));
tab.setContent(loader.load());
loader.<WriteViewController>getController().setTabCloseHandler(() -> root.getTabs().remove(tab));
public static TabPane findEnclosingTabPane(Node n) {
    while (n != null && !(n instanceof TabPane)) {
        n = n.getParent();
    }
    return (TabPane) n;
}
TabPane tabPane = findEnclosingTabPane(root);
tabPane.getTabs().remove(tabPane.getSelectionModel().getSelectedItem());