【问题标题】:Handle multiple JavaFX application launches within a loop在一个循环中处理多个 JavaFX 应用程序启动
【发布时间】:2015-12-08 00:37:43
【问题描述】:

我的代码目前通过 IMAP (imaps) 和 javamail 读取我的 Gmail 收件箱,一旦找到带有 zip/xap 附件的电子邮件,它就会显示一个阶段(窗口)询问是否下载文件,是或否。

一旦我做出选择,我希望舞台关闭,然后返回到循环中调用的位置。我的问题出现是因为您不能多次启动应用程序,所以我读到here 我应该在start 方法中写Platform.setImplicitExit(false);,然后使用primartyStage.hide()(?),然后使用Platform.runLater(() -> primaryStage.show()); 之类的东西稍后我需要再次显示舞台。

现在出现的问题是命令流开始于 Mail.java 的 doit() 方法,该方法循环通过我的收件箱,launch(args) 出现在方法内的 for loop 中。这意味着launch(args) 然后调用start 设置场景并展示舞台。因为有一个Controller.javafxml 关联,所以Controller 类有一个用于舞台按钮的事件处理程序,一旦start 显示舞台,它就会“拦截”流。因此,当我单击“是”或“否”时,它会隐藏舞台,然后只是 挂在那里。 好像它无法返回到 start 方法以从发生启动(args)的地方继续循环。如何在必要时正确隐藏/显示舞台,无论单击是还是否,都允许循环继续。

这是 Mail.java 和 Controller.java 的代码。非常感谢!

Mail.java

 [Other variables set here]
    public static int launchCount = 0;@FXML public Text subjectHolder;

    public static ReceiveMailImap obj = new ReceiveMailImap();

    public static void main(String[] args) throws IOException,        MessagingException {
        ReceiveMailImap.doit();
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        loader = new FXMLLoader(getClass().getResource("prompts.fxml"));
        root = loader.load();
        controller = loader.getController();
        controller.setPrimaryStage(primaryStage);
        scene = new Scene(root, 450, 250);
        controller.setPrimaryScene(scene);
        scene.getStylesheets().add("styleMain.css");
        Platform.setImplicitExit(false);
        primaryStage.setTitle("Download this file?");
        primaryStage.initStyle(StageStyle.UNDECORATED);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static void doit() throws MessagingException, IOException {
        Folder inbox = null;
        Store store = null;

        try {
            Properties props = System.getProperties();
            Session session = Session.getDefaultInstance(props, null);
            store = session.getStore("imaps");
            store.connect("imap.gmail.com", "myAccount@gmail.com", "Password");
            inbox = store.getFolder("Inbox");
            inbox.open(Folder.READ_WRITE);
            Message[] messages = inbox.getMessages();
            FetchProfile fp = new FetchProfile();
            fp.add(FetchProfile.Item.ENVELOPE);
            fp.add(UIDFolder.FetchProfileItem.FLAGS);
            fp.add(UIDFolder.FetchProfileItem.CONTENT_INFO);
            fp.add("X-mailer");

            inbox.fetch(messages, fp);
            int doc = 0;
            int maxDocs = 400;
            for (int i = messages.length - 1; i >= 0; i--) {
                Message message = messages[i];
                if (doc < maxDocs) {
                    doc++;
                    message.getSubject();

                    if (!hasAttachments(message)) {
                        continue;
                    }
                    String from = "Sender Unknown";
                    if (message.getReplyTo().length >= 1) {
                        from = message.getReplyTo()[0].toString();
                    } else if (message.getFrom().length >= 1) {
                        from = message.getFrom()[0].toString();
                    }
                    subject = message.getSubject();
                    if (from.contains("myAccount@gmail.com")) {
                        saveAttachment(message.getContent());
                        message.setFlag(Flags.Flag.SEEN, true);
                    }
                }
            }
        } finally {
            if (inbox != null) {
                inbox.close(true);
            }
            if (store != null) {
                store.close();
            }
        }
    }

    public static boolean hasAttachments(Message msg) throws MessagingException, IOException {
        if (msg.isMimeType("multipart/mixed")) {
            Multipart mp = (Multipart) msg.getContent();
            if (mp.getCount() > 1) return true;
        }
        return false;
    }

    public static void saveAttachment(Object content)
    throws IOException, MessagingException {
        out = null; in = null;
        try {
            if (content instanceof Multipart) {
                Multipart multi = ((Multipart) content);
                parts = multi.getCount();
                for (int j = 0; j < parts; ++j) {
                    part = (MimeBodyPart) multi.getBodyPart(j);
                    if (part.getContent() instanceof Multipart) {
                        // part-within-a-part, do some recursion...
                        saveAttachment(part.getContent());
                    } else {
                        int allow = 0;
                        if (part.isMimeType("application/x-silverlight-app")) {
                            extension = "xap";
                            allow = 1;
                        } else {
                            extension = "zip";
                            allow = 1;
                        }
                        if (allow == 1) {
                            if (launchCount == 0) {
                                launch(args);
                                launchCount++;
                            } else {
                                Platform.runLater(() -> primaryStage.show());
                            }
                        } else {
                            continue;
                        }
                    }
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if ( in != null) { in .close();
            }
            if (out != null) {
                out.flush();
                out.close();
            }
        }
    }

    public static File createFolder(String subject) {
        JFileChooser fr = new JFileChooser();
        FileSystemView myDocs = fr.getFileSystemView();
        String myDocuments = myDocs.getDefaultDirectory().toString();
        dir = new File(myDocuments + "\\" + subject);
        savePathNoExtension = dir.toString();
        dir.mkdir();
        System.out.println("Just created: " + dir);
        return dir;
    }

}

Controller.java

public class Controller implements Initializable {

    @FXML
    private Text subjectHolder;
    public Button yesButton, noButton;
    public ReceiveMailImap subject;

    @Override
    public void initialize(URL url, ResourceBundle rb) {
        subject= new ReceiveMailImap();
        subjectHolder.setText(subject.returnSubject());
    }
    public Stage primaryStage;
    public Scene scene;

    @FXML
    ComboBox<String> fieldCombo;

    public void setPrimaryStage(Stage stage) {
        this.primaryStage = stage;
    }

    public void setPrimaryScene(Scene scene) {
        this.scene = scene;
    }

    public String buttonPressed(ActionEvent e) throws IOException, MessagingException {
        Object source = e.getSource();
        if(source==yesButton){
            System.out.println("How to tell Mail.java that user clicked Yes?");
            return "POSITIVE";}
        else{subject.dlOrNot("no");
            System.out.println("How to tell Mail.java that user clicked No?");
            primaryStage.hide();
            return "NEGATIVE";}
    }

}

【问题讨论】:

    标签: javafx controller jakarta-mail stage actionevent


    【解决方案1】:

    您发布的代码存在很多问题,但让我尝试解决您提出的问题。

    代码挂起的原因是Application.launch(...)

    在应用程序退出之前不会返回

    一般来说,您在这里有点误解了 JavaFX 应用程序的整个生命周期。您应该将start(...) 方法视为与“传统”Java 应用程序中的main(...) 方法等效。唯一需要注意的是start(...)是在FX应用线程上执行的,所以如果你需要执行任何阻塞代码,你需要把它放在后台线程中。

    为方便起见,start(...) 方法传递了一个Stage 实例,因为最常见的做法是创建一个场景图并将其显示在舞台上。不过,您没有义务使用此阶段,您可以忽略它,并在需要时创建自己的阶段。

    我认为您基本上可以按如下方式构建您的代码(但说实话,我很难理解您在做什么):

    public class Mail extends Application {
    
        @Override
        public void start(Stage ignored) throws Exception {
    
            Platform.setImplicitExit(false);
    
            Message[] messages = /* retrieve messages */ ;
            for (Message message : messages) {
                if ( /* need to display window */) {
                    showMessage(message);
                }
            }
        }
    
        private void showMessage(Message message) {
            FXMLLoader loader = new FXMLLoader(getClass().getResource("prompts.fxml"));
            Parent root = loader.load();
    
            Controller controller = loader.getController();
            Scene scene = new Scene(root, 450, 250);
            stage.setScene(scene);
            stage.initStyle(StageStyle.UNDECORATED);
            stage.setTitle(...);
    
            // showAndWait will block execution until the window is hidden, so 
            // you can query which button was pressed afterwards:
    
            stage.showAndWait();
    
            if (controller.wasYesPressed()) {
                // ...
            }
        }
    
        // for IDEs that don't support directly launching a JavaFX Application:
        public static void main(String[] args) { 
            launch(args);
        }
    }
    

    显然,您决定是否显示窗口的逻辑更复杂,但这将为您提供基本结构。

    要检查按下了哪个按钮,请如上所述使用showAndWait,然后在您的控制器中执行

    public class Controller {
    
        @FXML
        private Button yesButton ;
    
        private boolean yesButtonPressed = false ;
    
        public boolean wasYesPressed() {
            return yesButtonPressed ;
        }
    
        // use different handlers for different buttons:
        @FXML
        private void yesButtonPressed() {
            yesButtonPressed = true ;
            closeWindow();
        }
    
        @FXML
        private void noButtonPressed() {
            yesButtonPressed = false ; // not really needed, but makes things clearer
            closeWindow();
        }
    
        private void closeWindow() {
            // can use any @FXML-injected node here:
            yesButton.getScene().getWindow().hide();
        }
    }
    

    【讨论】:

    • 解决了!!詹姆斯,非常感谢!你为我提供了足够的细节来解决我的代码问题,并回答我的主要问题。我从你的帖子中学到了很多。非常感谢!保重。
    • 您在启动方法中传递了一些参数,如何接收该消息以显示在窗口中
    猜你喜欢
    • 1970-01-01
    • 2013-03-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-05
    • 1970-01-01
    相关资源
    最近更新 更多