【问题标题】:What is the good use to create a wait / notify window with javafx?用 javafx 创建等待/通知窗口有什么好处?
【发布时间】:2016-10-11 18:47:01
【问题描述】:

我只想创建一个弹出窗口并通过 for 循环更改内容; (对于每个删除的文件)。我想回答yes/no/noAll/yesAll。所以我需要一个 wait() 来显示带有第一部电影内容的弹出窗口。例如,如果我说“不”,我希望将 notify() 线程解锁,以达到第二部电影的目标。在这种情况下,弹出内容会随着第二部电影而变化,我再次等待(),直到我通过按钮等回答。

我尝试了很多东西都没有成功:/ 我得到这个错误:

Exception in thread "JavaFX Application Thread" java.lang.IllegalMonitorStateException
    at java.lang.Object.notifyAll(Native Method)
    at controllers.HomeController.notifyPopup(HomeController.java:150)
    at controllers.HomeController.lambda$1(HomeController.java:208)
    at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)

我在dialog.notify() 遇到问题 也许我没有在同一个对话框对象上应用 notify() 但确实如此,不是吗?

提前感谢您的帮助

这是我的部分代码:在代码中搜索// LOOK HERE以查看主要行

public class HomeController {


  @FXML
  private Label home;

  @FXMLViewFlowContext
  private ViewFlowContext context;

  RenameFiles film;
  SimpleBooleanProperty  noAllProperty = new SimpleBooleanProperty(false);
  SimpleBooleanProperty  yesAllProperty = new SimpleBooleanProperty(false);
  SimpleBooleanProperty  continuePopup = new SimpleBooleanProperty(false);
  ArrayList<Path> arrayFile = new ArrayList<Path>();
  Stage stage;
  Boolean firstFile = false;
  JFXDialogLayout content;
  JFXDialog dialog;

  @PostConstruct
  public void init() throws FlowException, VetoException {
    Settings settings = (Settings) context.getRegisteredObject("Settings");
    content = new JFXDialogLayout();
    dialog = new JFXDialog((StackPane) context.getRegisteredObject("ROOT"), content, JFXDialog.DialogTransition.CENTER);

    home.setOnDragOver(new EventHandler<DragEvent>() {
      @Override
      public void handle(DragEvent event) {
        Dragboard dragboard = event.getDragboard();
        if (dragboard.hasFiles()) {
          event.acceptTransferModes(TransferMode.ANY);
        } else {
          event.consume();
        }
      }
    });

    // Dropping over surface
    home.setOnDragDropped(new EventHandler<DragEvent>() {
      @Override
      public void handle(DragEvent event) {
        Dragboard dragboard = event.getDragboard();
        boolean success = false;
        if (dragboard.hasFiles()) {
          arrayFile = new ArrayList<Path>();
          success = true;
          noAllProperty.set(false);
          yesAllProperty.set(false);
          dragboard.getFiles().forEach(file -> {
            if(Files.isDirectory(file.toPath())){
              try(Stream<Path> paths = Files.walk(Paths.get(file.toURI()))) {
                paths.forEach(filePath -> {
                  if (Files.isRegularFile(filePath)) 
                  arrayFile.add(filePath);
                });
              } catch (IOException e) {
                e.printStackTrace();
              } 
            }else if (Files.isRegularFile(file.toPath()))
            arrayFile.add(file.toPath());

          });
        }
        event.setDropCompleted(success);
        event.consume();

        arrayFile.forEach(file -> {
          film = new RenameFiles(new File(file.toString()), settings);
          if(!noAllProperty.getValue()){
            if(film.getNameWithoutExt().length() > 0){
              if(!yesAllProperty.getValue()){
                    try {
                        firstFile = true;
                        contentPopup();

                        if(firstFile) {
                          dialog.show();
                          dialog.setOverlayClose(false);
                          firstFile = false;
                        }
                 // LOOK HERE
                        waitPopup(dialog);

                    } catch (FlowException | InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }           
              }else{
                film.applyRename(film.getCleanName());
              }
            }
          }
        });
      }
    });
  }
  public synchronized void waitPopup(JFXDialog dialog) {
        // This guard only loops once for each special event, which may not
        // be the event we're waiting for.
        while(!continuePopup.getValue()) {
            try {
                dialog.wait();
            } catch (InterruptedException e) {}
        }
    }

  public synchronized void notifyPopup(JFXDialog dialog) {
        continuePopup.setValue(true);
        dialog.notifyAll();
    }

  private void contentPopup() throws FlowException, InterruptedException{

    JFXButton buttonYesPopupRename = new JFXButton("Yes");
    buttonYesPopupRename.setPrefHeight(30);
    buttonYesPopupRename.setPrefWidth(70);
    buttonYesPopupRename.setId("buttonYesPopupRename");
    buttonYesPopupRename.setButtonType(ButtonType.RAISED);
    buttonYesPopupRename.setOnAction(e -> { film.applyRename(film.getCleanName());continuePopup.setValue(true);notifyPopup(dialog); });  // LOOK HERE
    buttonYesPopupRename.setStyle("-fx-text-fill:WHITE;-fx-background-color:#5264AE;-fx-font-size:14px;");

    JFXButton buttonNoPopupRename = new JFXButton("No");
    buttonNoPopupRename.setPrefHeight(30);
    buttonNoPopupRename.setPrefWidth(70);
    buttonNoPopupRename.setId("buttonNoPopupRename");
    buttonNoPopupRename.setButtonType(ButtonType.RAISED);
    buttonNoPopupRename.setOnAction(e -> { continuePopup.setValue(true); notifyPopup(dialog); });  // LOOK HERE
    buttonNoPopupRename.setStyle("-fx-text-fill:WHITE;-fx-background-color:#5264AE;-fx-font-size:14px;");

【问题讨论】:

  • 您需要拥有wait()/notify() 的对象监视器。你不会在这两个地方这样做。你甚至不应该尝试使用wait()/notify() 来做这样的事情。您是如何想到这个想法的?
  • 您是否碰巧在网上搜索“java.lang.IllegalMonitorStateException”?
  • @Kayaman,如果我不这样做,可以使用什么解决方案来等待用户对弹出窗口的回答?也许我错过了一些非常简单的事情。我从来没有使用过等待和通知,所以我今天尝试应用它。我也是,我不喜欢这种方式,但目前我没有看到其他我想要的方式:/。
  • @kevincaradant 如果您从未使用过wait()/notify(),请不要从这里开始。您不太可能在第一次尝试时就将它们做好。它们是用于线程控制的非常低级的构造,但不是以这种方式。
  • @Kayaman,哦,好的,我会寻找一种新的方式来获得我想要的。对不起,如果我不应该问这个问题。谢谢

标签: java multithreading javafx wait


【解决方案1】:

有比你的方法更好的解决问题的方法:

使有关需要询问的元素和当前元素的数据可供事件处理程序使用,并在事件发生时修改这些值和 UI

让您为某些项目选择YesNo 的简化示例:

@Override
public void start(Stage primaryStage) {
    Button btn = new Button("Dialog");
    List<String> list = Arrays.asList("A", "B", "C", "D");
    btn.setOnAction((ActionEvent event) -> {
        displayDialog(list.iterator());
    });

    StackPane root = new StackPane();
    root.getChildren().add(btn);

    Scene scene = new Scene(root);

    primaryStage.setScene(scene);
    primaryStage.show();
}

public static void displayDialog(Iterator<String> iterator) {
    if (iterator.hasNext()) {
        Button yes = new Button("Yes");
        Button no = new Button("No");
        Label text = new Label(iterator.next());
        Stage stage = new Stage();
        stage.setScene(new Scene(new VBox(text, yes, no)));
        EventHandler<ActionEvent> handler = evt -> {
            Labeled source = (Labeled) evt.getSource();
            System.out.println("You chose \"" + source.getText() + "\" for \"" + text.getText() + "\"");

            // procede to next state
            if (iterator.hasNext()) {
                // display next item
                text.setText(iterator.next());
            } else {
                // close "dialog" when no more elements available
                stage.close();
            }
        };
        yes.setOnAction(handler);
        no.setOnAction(handler);
        stage.show();
    }
}

【讨论】:

  • 我赞成你的回答,这正是我想要的。它完美地工作。非常感谢这种在我看来很好的方式!
【解决方案2】:

您必须在同步块中嵌入等待和通知:

synchronized( dialog)
{
    dialog.wait();
}

synchronized( dialog)
{
    dialog.notify();
}

顺便说一句:只需要 notify() 就足够了。只有当有多个线程在等待时,notifyAll(() 才有意义。

【讨论】:

  • 我已经尝试过您的解决方案,但在这种情况下,我的应用程序冻结了。我很惊讶,因为我认为同步块在第二个线程中,但如果所有应用程序都被冻结,那会说它在主线程上?我在方法 waitPopup 和通知弹出窗口中应用您的同步块。我应该在等待时继续使用循环吗?这是我不明白的部分。提前谢谢你
  • 因为我几乎不知道 FX,所以我不知道 GUI 回调发生在哪个线程上下文中。在旧的摇摆中,它是一个单独的线程(不是主线程),但所有 GUI 操作都发生在同一个线程中。如果 FX 表现类似,则通过等待函数阻塞该线程不是一个好主意。正如 Kayaman 在她的评论中指出的那样,您应该寻找另一种方式。据我所知,FX 是事件驱动的(请参阅您的回调),所以只需执行所需的操作并返回。 FX 框架正在等待您的下一个事件。
  • 好的,谢谢。我用 JAVAFX 编辑了这个问题,以便更清楚。我会检查你的建议。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-03
  • 1970-01-01
相关资源
最近更新 更多