用javafx创建等待/通知window有什么用?
What is the good use to create a wait / notify window with javafx?
我只想创建一次弹出窗口并通过for循环更改内容; (对于每个丢弃的文件)。我要回答yes/no/noAll/yesAll。所以我需要一个 wait() 来显示第一部电影内容的弹出窗口。例如,如果我说 "no",我希望 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(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;");
您必须在同步块中嵌入等待和通知:
synchronized( dialog)
{
dialog.wait();
}
和
synchronized( dialog)
{
dialog.notify();
}
顺便说一句:只通知()就足够了。 notifyAll(() 只有在有多个线程在等待时才有意义。
有比您的方法更好的解决问题的方法:
使有关需要询问的元素和当前元素的数据可供事件处理程序使用,并修改这些值和UI 事件发生时.
让您为某些项目选择 Yes
或 No
的简化示例:
@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();
}
}
我只想创建一次弹出窗口并通过for循环更改内容; (对于每个丢弃的文件)。我要回答yes/no/noAll/yesAll。所以我需要一个 wait() 来显示第一部电影内容的弹出窗口。例如,如果我说 "no",我希望 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(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;");
您必须在同步块中嵌入等待和通知:
synchronized( dialog)
{
dialog.wait();
}
和
synchronized( dialog)
{
dialog.notify();
}
顺便说一句:只通知()就足够了。 notifyAll(() 只有在有多个线程在等待时才有意义。
有比您的方法更好的解决问题的方法:
使有关需要询问的元素和当前元素的数据可供事件处理程序使用,并修改这些值和UI 事件发生时.
让您为某些项目选择 Yes
或 No
的简化示例:
@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();
}
}