我希望有一个焦点侦听器作为一个静态变量来传递抛出静态方法,它的功能是在这个阶段上的焦点丢失时关闭一个阶段。
我有密码:
主班
public class Main extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
FXMLLoader loader = new FXMLLoader(getClass().getResource("sample.fxml"));
Scene scene = new Scene(loader.load(), 565, 551);
primaryStage.setScene(scene);
Controller controller = loader.getController();
primaryStage.show();
controller.setStage1InitOwner();
}
public static void main(String[] args) {
launch(args);
}
}控制器类
public class Controller implements Initializable {
@FXML
private AnchorPane anchorPane;
// stage1 suppose to be a small dialogs
private final Stage stage1 = new Stage();
@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
stage1.setScene(new Scene(new Pane(new Label("a Dialog")), 200, 200));
// giving the listener to stage1 from static method
stage1.focusedProperty().addListener(Prepare.getFocusListener());
stage1.initStyle(StageStyle.TRANSPARENT);
}
public void setStage1InitOwner() {
stage1.initOwner(anchorPane.getScene().getWindow());
stage1.show();
}
}准备类(内部的静态方法和变量)
public class Prepare {
public static ChangeListener<Boolean> focusListener = new ChangeListener<Boolean>() {
@Override
public void changed(ObservableValue<? extends Boolean> observableValue, Boolean aBoolean, Boolean t1) {
if (!t1) ;
// get the stage from observableValue and close it when focus is lost.
}
};
public static ChangeListener<Boolean> getFocusListener()
{
return focusListener;
}
}fxml文件
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.*?>
<AnchorPane fx:id="anchorPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="551.0" prefWidth="565.0" style="-fx-background-color: #fffe00;" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.Controller">
<children>
</children>
</AnchorPane>现在,我想从ObservableValue获得ChangeListener中的调用方级。我尝试将其转换为BooleanProperty,然后使用getBean()
if (!t1) {
BooleanProperty booleanProperty = (BooleanProperty) observableValue;
Stage stage = (Stage) booleanProperty.getBean();
stage.close();
},但我得到了以下错误:
Exception in thread "JavaFX Application Thread" java.lang.ClassCastException: class javafx.beans.property.ReadOnlyBooleanWrapper$ReadOnlyPropertyImpl cannot be cast to class javafx.beans.property.BooleanProperty (javafx.beans.property.ReadOnlyBooleanWrapper$ReadOnlyPropertyImpl and javafx.beans.property.BooleanProperty are in module javafx.base of loader 'app')
at sample.Prepare$1.changed(Prepare.java:13)
at sample.Prepare$1.changed(Prepare.java:9)
at javafx.base/com.sun.javafx.binding.ExpressionHelper$Generic.fireValueChangedEvent(ExpressionHelper.java:360)
at javafx.base/com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:80)
at javafx.base/javafx.beans.property.ReadOnlyBooleanPropertyBase.fireValueChangedEvent(ReadOnlyBooleanPropertyBase.java:78)
at javafx.base/javafx.beans.property.ReadOnlyBooleanWrapper.fireValueChangedEvent(ReadOnlyBooleanWrapper.java:103)
at javafx.base/javafx.beans.property.BooleanPropertyBase.markInvalid(BooleanPropertyBase.java:111)
at javafx.base/javafx.beans.property.BooleanPropertyBase.set(BooleanPropertyBase.java:145)
at javafx.graphics/javafx.stage.Window.setFocused(Window.java:678)
at javafx.graphics/javafx.stage.Window$1.setFocused(Window.java:150)
at javafx.graphics/com.sun.javafx.stage.WindowHelper.setFocused(WindowHelper.java:112)
at javafx.graphics/com.sun.javafx.stage.WindowPeerListener.changedFocused(WindowPeerListener.java:64)
at javafx.graphics/com.sun.javafx.tk.quantum.GlassWindowEventHandler.run(GlassWindowEventHandler.java:126)
at javafx.graphics/com.sun.javafx.tk.quantum.GlassWindowEventHandler.run(GlassWindowEventHandler.java:40)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
at javafx.graphics/com.sun.javafx.tk.quantum.GlassWindowEventHandler.lambda$handleWindowEvent$4(GlassWindowEventHandler.java:178)
at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:424)
at javafx.graphics/com.sun.javafx.tk.quantum.GlassWindowEventHandler.handleWindowEvent(GlassWindowEventHandler.java:176)
at javafx.graphics/com.sun.glass.ui.Window.handleWindowEvent(Window.java:1336)
at javafx.graphics/com.sun.glass.ui.Window.notifyFocus(Window.java:1315)
at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:184)
at java.base/java.lang.Thread.run(Thread.java:833)
Exception in thread "JavaFX Application Thread" java.lang.ClassCastException: class javafx.beans.property.ReadOnlyBooleanWrapper$ReadOnlyPropertyImpl cannot be cast to class javafx.beans.property.BooleanProperty (javafx.beans.property.ReadOnlyBooleanWrapper$ReadOnlyPropertyImpl and javafx.beans.property.BooleanProperty are in module javafx.base of loader 'app')
at sample.Prepare$1.changed(Prepare.java:13)
at sample.Prepare$1.changed(Prepare.java:9)
at javafx.base/com.sun.javafx.binding.ExpressionHelper$Generic.fireValueChangedEvent(ExpressionHelper.java:360)
at javafx.base/com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:80)
at javafx.base/javafx.beans.property.ReadOnlyBooleanPropertyBase.fireValueChangedEvent(ReadOnlyBooleanPropertyBase.java:78)
at javafx.base/javafx.beans.property.ReadOnlyBooleanWrapper.fireValueChangedEvent(ReadOnlyBooleanWrapper.java:103)
at javafx.base/javafx.beans.property.BooleanPropertyBase.markInvalid(BooleanPropertyBase.java:111)
at javafx.base/javafx.beans.property.BooleanPropertyBase.set(BooleanPropertyBase.java:145)
at javafx.graphics/javafx.stage.Window.setFocused(Window.java:678)
at javafx.graphics/javafx.stage.Window$1.setFocused(Window.java:150)
at javafx.graphics/com.sun.javafx.stage.WindowHelper.setFocused(WindowHelper.java:112)
at javafx.graphics/com.sun.javafx.stage.WindowPeerListener.changedFocused(WindowPeerListener.java:64)
at javafx.graphics/com.sun.javafx.tk.quantum.GlassWindowEventHandler.run(GlassWindowEventHandler.java:126)
at javafx.graphics/com.sun.javafx.tk.quantum.GlassWindowEventHandler.run(GlassWindowEventHandler.java:40)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
at javafx.graphics/com.sun.javafx.tk.quantum.GlassWindowEventHandler.lambda$handleWindowEvent$4(GlassWindowEventHandler.java:178)
at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:424)
at javafx.graphics/com.sun.javafx.tk.quantum.GlassWindowEventHandler.handleWindowEvent(GlassWindowEventHandler.java:176)
at javafx.graphics/com.sun.glass.ui.Window.handleWindowEvent(Window.java:1336)
at javafx.graphics/com.sun.glass.ui.Window.notifyFocus(Window.java:1315)
at javafx.graphics/com.sun.glass.ui.win.WinWindow._close(Native Method)
at javafx.graphics/com.sun.glass.ui.Window.close(Window.java:352)
at javafx.graphics/com.sun.glass.ui.win.WinWindow.close(WinWindow.java:316)
at javafx.graphics/com.sun.javafx.tk.quantum.WindowStage.lambda$close$4(WindowStage.java:824)
at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.runWithRenderLock(QuantumToolkit.java:442)
at javafx.graphics/com.sun.javafx.tk.quantum.WindowStage.close(WindowStage.java:817)
at javafx.graphics/javafx.stage.Window$12.invalidated(Window.java:1157)
at javafx.base/javafx.beans.property.BooleanPropertyBase.markInvalid(BooleanPropertyBase.java:110)
at javafx.base/javafx.beans.property.BooleanPropertyBase.set(BooleanPropertyBase.java:145)
at javafx.graphics/javafx.stage.Window.setShowing(Window.java:1190)
at javafx.graphics/javafx.stage.Window.hide(Window.java:1215)
at javafx.graphics/com.sun.javafx.stage.WindowCloseRequestHandler.dispatchBubblingEvent(WindowCloseRequestHandler.java:45)
at javafx.base/com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at javafx.base/com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at javafx.base/com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
at javafx.base/javafx.event.Event.fireEvent(Event.java:198)
at javafx.graphics/com.sun.javafx.stage.WindowPeerListener.closing(WindowPeerListener.java:93)
at javafx.graphics/com.sun.javafx.tk.quantum.GlassWindowEventHandler.run(GlassWindowEventHandler.java:147)
at javafx.graphics/com.sun.javafx.tk.quantum.GlassWindowEventHandler.run(GlassWindowEventHandler.java:40)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
at javafx.graphics/com.sun.javafx.tk.quantum.GlassWindowEventHandler.lambda$handleWindowEvent$4(GlassWindowEventHandler.java:178)
at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:424)
at javafx.graphics/com.sun.javafx.tk.quantum.GlassWindowEventHandler.handleWindowEvent(GlassWindowEventHandler.java:176)
at javafx.graphics/com.sun.glass.ui.Window.handleWindowEvent(Window.java:1336)
at javafx.graphics/com.sun.glass.ui.Window.notifyClose(Window.java:1241)
at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:184)
at java.base/java.lang.Thread.run(Thread.java:833)所以什么是问题,什么是获得舞台的最佳方式。
非常感谢StackOverflow团队。
发布于 2022-06-30 14:56:31
错误告诉您出了什么问题:
javafx.beans.property.ReadOnlyBooleanWrapper$ReadOnlyPropertyImpl类不能转换为类javafx.beans.property.BooleanProperty (javafx.beans.property.ReadOnlyBooleanWrapper$ReadOnlyPropertyImpl和javafx.beans.property.BooleanProperty在加载程序的模块javafx.base中)
您正在尝试将ReadOnlyBooleanProperty实例转换为BooleanProperty,这显然是不可能的。但是,您实际上并不需要处理这种“狭窄”的实现。您所关心的只是获取"bean",这只需要类型为ReadOnlyProperty (它是属性类层次结构的顶部)。
ChangeListener<Boolean> listener = (obs, wasFocused, isFocused) -> {
if (!isFocused) {
var property = (ReadOnlyProperty<?>) obs;
var stage = (Stage) property.getBean();
stage.close();
}
};然而,你根本不需要处理演员的问题。如果您的目标是简单地避免代码重复,那么只需创建一个接受Stage并向其focused属性添加侦听器的实用方法。
例如:
import javafx.beans.value.ChangeListener;
import javafx.stage.Stage;
public final class CloseOnFocusLost {
private static final Object KEY = new Object();
public static void installListener(Stage stage) {
@SuppressWarnings("unchecked")
var listener = (ChangeListener<Boolean>) stage.getProperties().get(KEY);
if (listener == null) {
listener = (obs, wasFocused, isFocused) -> {
if (!isFocused) {
stage.close();
}
};
stage.getProperties().put(KEY, listener);
stage.focusedProperty().addListener(listener):
}
}
public static void uninstallListener(Stage stage) {
@SuppressWarnings("unchecked")
var listener = (ChangeListener<Boolean>) stage.getProperties().remove(KEY);
if (listener != null) {
stage.focusedProperty().removeListener(listener):
}
}
// prevent instantiation of utility class
private CloseOnFocusLost() {}
}与您的代码相比,上面有一些优点:
ClassCastException的攻击,因为侦听器可以添加到不属于Stage的属性中。Stage实例。focused属性添加多个侦听器的安全措施。如果您不关心最后一点,也不需要删除侦听器,那么可以将代码简化为以下内容:
import javafx.stage.Stage;
public final class CloseOnFocusLost {
public static void installListener(Stage stage) {
stage.focusedProperty().addListener((obs, wasFocused, isFocused) -> {
if (!isFocused) {
stage.close();
}
});
}
// prevent instantiation of utility class
private CloseOnFocusLost() {}
}在任何一种情况下,您都可以将您的近焦点丢失侦听器添加到:
CloseOnFocusLost.installListener(theStageInstance);发布于 2022-06-30 19:21:25
一个简单的可执行应用程序,它演示了来自斯劳的回答的一些技术,再加上一两个技术。我不会对这些技术添加任何额外的解释,因为这已经在Slaw的回答中得到了很好的介绍。
只有本示例中的最后一个选项以编程方式演示如何确保侦听器不会多次添加到同一阶段。
import javafx.application.Application;
import javafx.beans.property.ReadOnlyProperty;
import javafx.beans.value.ChangeListener;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.stage.Stage;
public class StageClosureApp extends Application {
private static final ChangeListener<Boolean> CLOSE_ON_FOCUS_LOSS_USING_BEAN_LISTENER =
(o, wasFocused, isFocused) -> {
if (!isFocused) ((Stage) ((ReadOnlyProperty<?>) o).getBean()).close();
};
private static ChangeListener<Boolean> closeOnFocusLossListener(Stage stage) {
return (o, wasFocused, isFocused) -> {
if (!isFocused) stage.close();
};
}
private static void closeOnFocusLoss(Stage stage) {
stage.focusedProperty().removeListener(CLOSE_ON_FOCUS_LOSS_USING_BEAN_LISTENER);
stage.focusedProperty().addListener(CLOSE_ON_FOCUS_LOSS_USING_BEAN_LISTENER);
}
@Override
public void start(Stage stage) {
// all options perform the same function (close the stage on losing focus).
// when testing, only enable one option, commenting the others out.
// option 1: use a closure to reference the stage in a lambda function defined inline.
stage.focusedProperty().addListener((o, wasFocused, isFocused) -> {
if (!isFocused) stage.close();
});
// option 2: pass the stage instance to a static listener generation function.
stage.focusedProperty().addListener(closeOnFocusLossListener(stage));
// option 3: get the stage from the bean in an inline lambda function.
stage.focusedProperty().addListener((o, wasFocused, isFocused) -> {
if (!isFocused) ((Stage) ((ReadOnlyProperty<?>) o).getBean()).close();
});
// option 4: use a single instance static change listener that get the stage from the bean.
stage.focusedProperty().addListener(CLOSE_ON_FOCUS_LOSS_USING_BEAN_LISTENER);
// option 5: update stage to add a focus loss listener when it is not focused (can safely be called multiple time for a stage)
closeOnFocusLoss(stage);
stage.setScene(new Scene(new Label("hello, world")));
stage.show();
}
public static void main(String[] args) {
launch();
}
}如果阶段丢失焦点是应用程序中显示的唯一阶段(就像在这些测试用例中一样),那么,根据应用生命周期的说法,在默认情况下,一旦失去对阶段的关注,应用程序就会自动关闭。
我不确定这个例子对Slaw的回答有多大帮助,但它可能是有用的,所以我暂时保留这个帖子。
https://stackoverflow.com/questions/72810442
复制相似问题