如何在控制器类中打开JavaFX文件选择器?

40

我的问题是所有使用FileChooser的例子都需要传入一个舞台(stage)。唯一的问题是,我的UI是在一个fxml文件中定义的,它使用一个与主舞台不同的控制器类。

@FXML protected void locateFile(ActionEvent event) {
    FileChooser chooser = new FileChooser();
    chooser.setTitle("Open File");
    chooser.showOpenDialog(???);
}

我应该在???处放什么才能使其工作?就像我说的,我没有对控制器类中任何阶段的引用,那我该怎么办呢?

4个回答

70

对于场景中的任何节点(例如根节点;但是任何您已注入 @FXML 的节点都可以),请执行

chooser.showOpenDialog(node.getScene().getWindow());

我应该从哪里获取根节点?我需要定义一个fx:id吗,还是我完全没有理解这个想法? - Electric Coffee
7
是的,请定义一个 fx:id。但是您不必使用根节点,只需使用任何已经具有 fx:id 并且已注入到控制器中的内容(所有节点都在同一场景中...)。您还可以执行 Node node = (Node) event.getSource();,但我不太喜欢它,因为这会导致向下转换。 - James_D
1
请您能否详细解释一下这个答案?首先,在这个上下文中,“node”是什么意思?我该如何“定义fx:id”,在哪里进行操作?我已经复制了上面的那行代码,但是“node”部分仍然无法解析。 - Sargon1
回复@Sargon1的请求: 节点是UI中从Node继承的任何小部件。 “fx:id”是您类中Java UI对象的名称。您可以通过[Scenebuilder App](http://gluonhq.com/labs/scene-builder/)连接相关的fxml组件(当然也可以直接在fxml代码中进行):当您打开一个fxml文件并选择所需的小部件时,您只需在正确的手风琴菜单“代码”下设置id(对象名称)和出现的字段“fx:id”。 - David Artmann

19

您不必继续使用应用程序中创建的舞台,您可以选择:

@FXML protected void locateFile(ActionEvent event) {
    FileChooser chooser = new FileChooser();
    chooser.setTitle("Open File");
    File file = chooser.showOpenDialog(new Stage());
}

或者,如果你想继续使用同一个阶段(stage),那么你需要先将阶段传递给控制器(controller):

    FXMLLoader loader = new FXMLLoader(getClass().getResource("yourFXMLDocument.fxml"));
    Parent root = (Parent)loader.load();
    MyController myController = loader.getController();
    myController.setStage(stage);

而你将拥有主要的应用程序舞台,可随意使用。


7
我认为将对话框的所有者设置为正确的舞台而不是一些虚构的舞台会更好。请参见showOpenDialog javadoc,“如果为文件对话框设置了所有者窗口,则在显示文件对话框时,所有者链中所有窗口的输入都会被阻止。” 如果未指定正确的舞台,则FileChooser的模态对话框阻止功能将无法启用。在FileChooser中通常希望有模态阻止。 - jewelsea
3
保持使用同一阶段是更好的做法,这就是为什么我在回答中展示了一种方法。但需要注意的是,最佳实践并不是唯一的实践方式。 - Mansueli

2

另外,对我而言行之有效的方法是:直接输入null

@FXML
private void onClick(ActionEvent event) {
    File file = fileChooser.showOpenDialog(null);
    if (file != null) {
       //TODO
    }
}

好奇心.... null 不会创建一个非模态对话框吗?在大多数情况下,文件打开对话框通常是模态的。 - GoldBishop

1

从菜单项中

public class SerialDecoderController implements Initializable {

  @FXML
  private MenuItem fileOpen;

  @Override
  public void initialize(URL url, ResourceBundle rb) {
    // TODO
 }    


public void fileOpen (ActionEvent event) {

    FileChooser fileChooser = new FileChooser();
    fileChooser.setTitle("Open Resource File"); 
    fileChooser.showOpenDialog(fileOpen.getParentPopup().getScene().getWindow());

}

fileOpen.getParentPopup 在给定的上下文中对我来说很奇怪。fileOpen 是该方法的名称。 - Alexander

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接