Events 是否可以从JavaFXFileChooser窗口使用事件?
我有一个JavaFX按钮,当用户按下enter键时触发。这会导致文件选择器打开。有些人(比如我)可能会在文件选择器中按enter键来保存文件。但是,这会导致“保存”按钮再次触发,并再次打开文件选择器以保存新文件。用鼠标单击按钮(在文件选择器中)没有此问题 我认为从按钮中使用事件可以解决这个问题,但它只使用GUI事件上的按钮,而不是FileChooser按钮。我试图寻找方法修改FileChooser的EventHandler以使用enter键,但没有成功。Events 是否可以从JavaFXFileChooser窗口使用事件?,events,button,javafx,event-handling,filechooser,Events,Button,Javafx,Event Handling,Filechooser,我有一个JavaFX按钮,当用户按下enter键时触发。这会导致文件选择器打开。有些人(比如我)可能会在文件选择器中按enter键来保存文件。但是,这会导致“保存”按钮再次触发,并再次打开文件选择器以保存新文件。用鼠标单击按钮(在文件选择器中)没有此问题 我认为从按钮中使用事件可以解决这个问题,但它只使用GUI事件上的按钮,而不是FileChooser按钮。我试图寻找方法修改FileChooser的EventHandler以使用enter键,但没有成功。 我还尝试过将焦点从按钮上移开,并将其移动
我还尝试过将焦点从按钮上移开,并将其移动到父级(一个窗格),以便不能再次单击。但是,有一些按钮可以多次单击而无需重新聚焦 我的代码示例如下所示(显然这将是扩展应用程序的更大类的一部分):
我为打开的文件选择器添加了一个布尔值,它似乎对我有效,但我必须将事件拆分,否则它只会每隔一次触发打印按钮
public class Main extends Application {
private boolean fileChooserOpen = false;
@Override
public void start(Stage stage) throws Exception{
/* EventHandler to be used with multiple buttons */
EventHandler<KeyEvent> enterWithFileChooser = event -> {
if (!fileChooserOpen && event.getCode() == KeyCode.ENTER && event.getSource() instanceof Button) {
Button src = (Button) event.getSource();
src.fire();
fileChooserOpen = true;
}else {
fileChooserOpen = false;
}
event.consume();
};
EventHandler<KeyEvent> enter = event -> {
if (event.getCode() == KeyCode.ENTER && event.getSource() instanceof Button) {
Button src = (Button) event.getSource();
src.fire();
}
event.consume();
};
/* Create a new button */
Button b1 = new Button("Save");
Button b2 = new Button("Print");
/* Add event handlers */
b1.setOnKeyReleased(enterWithFileChooser);
b2.setOnKeyReleased(enter);
/* Called by .fire method of save button */
b1.setOnAction(event -> {
/* Create the save dialog box */
FileChooser saveDialog = new FileChooser();
saveDialog.setTitle("Save");
/* Get file */
File f = saveDialog.showSaveDialog(stage);
/* ... do stuff with file ... */
});
/* Called by .fire method of print button */
b2.setOnAction(event -> System.out.println("Pressed"));
Scene scene = new Scene(new HBox(b1, b2));
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) { launch(args); }
}
public类主扩展应用程序{
private boolean fileChooserOpen=false;
@凌驾
public void start(Stage)引发异常{
/*与多个按钮一起使用的EventHandler*/
EventHandler enterWithFileChooser=事件->{
如果(!filechooseOpen&&event.getCode()==KeyCode.ENTER&&event.getSource()instanceof按钮){
Button src=(Button)event.getSource();
src.fire();
fileChooserOpen=true;
}否则{
fileChooserOpen=false;
}
event.consume();
};
EventHandler enter=事件->{
if(event.getCode()==KeyCode.ENTER&&event.getSource()instanceof按钮){
Button src=(Button)event.getSource();
src.fire();
}
event.consume();
};
/*创建一个新按钮*/
按钮b1=新按钮(“保存”);
按钮b2=新按钮(“打印”);
/*添加事件处理程序*/
b1.setOnKeyReleased(使用文件选择器输入);
b2.setOnKeyReleased(输入);
/*保存按钮的.fire方法调用*/
b1.设置动作(事件->{
/*创建“保存”对话框*/
FileChooser saveDialog=新建FileChooser();
saveDialog.setTitle(“保存”);
/*获取文件*/
文件f=saveDialog.showsavedilog(stage);
/*…处理文件*/
});
/*打印按钮的.fire方法调用*/
b2.设置操作(事件->系统输出打印项次(“按下”);
场景=新场景(新HBox(b1,b2));
舞台场景;
stage.show();
}
公共静态void main(字符串[]args){launch(args);}
}
我为打开的文件选择器添加了一个布尔值,它似乎对我有效,但我必须将事件拆分,否则它只会每隔一段时间触发打印按钮
public class Main extends Application {
private boolean fileChooserOpen = false;
@Override
public void start(Stage stage) throws Exception{
/* EventHandler to be used with multiple buttons */
EventHandler<KeyEvent> enterWithFileChooser = event -> {
if (!fileChooserOpen && event.getCode() == KeyCode.ENTER && event.getSource() instanceof Button) {
Button src = (Button) event.getSource();
src.fire();
fileChooserOpen = true;
}else {
fileChooserOpen = false;
}
event.consume();
};
EventHandler<KeyEvent> enter = event -> {
if (event.getCode() == KeyCode.ENTER && event.getSource() instanceof Button) {
Button src = (Button) event.getSource();
src.fire();
}
event.consume();
};
/* Create a new button */
Button b1 = new Button("Save");
Button b2 = new Button("Print");
/* Add event handlers */
b1.setOnKeyReleased(enterWithFileChooser);
b2.setOnKeyReleased(enter);
/* Called by .fire method of save button */
b1.setOnAction(event -> {
/* Create the save dialog box */
FileChooser saveDialog = new FileChooser();
saveDialog.setTitle("Save");
/* Get file */
File f = saveDialog.showSaveDialog(stage);
/* ... do stuff with file ... */
});
/* Called by .fire method of print button */
b2.setOnAction(event -> System.out.println("Pressed"));
Scene scene = new Scene(new HBox(b1, b2));
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) { launch(args); }
}
public类主扩展应用程序{
private boolean fileChooserOpen=false;
@凌驾
public void start(Stage)引发异常{
/*与多个按钮一起使用的EventHandler*/
EventHandler enterWithFileChooser=事件->{
如果(!filechooseOpen&&event.getCode()==KeyCode.ENTER&&event.getSource()instanceof按钮){
Button src=(Button)event.getSource();
src.fire();
fileChooserOpen=true;
}否则{
fileChooserOpen=false;
}
event.consume();
};
EventHandler enter=事件->{
if(event.getCode()==KeyCode.ENTER&&event.getSource()instanceof按钮){
Button src=(Button)event.getSource();
src.fire();
}
event.consume();
};
/*创建一个新按钮*/
按钮b1=新按钮(“保存”);
按钮b2=新按钮(“打印”);
/*添加事件处理程序*/
b1.setOnKeyReleased(使用文件选择器输入);
b2.setOnKeyReleased(输入);
/*保存按钮的.fire方法调用*/
b1.设置动作(事件->{
/*创建“保存”对话框*/
FileChooser saveDialog=新建FileChooser();
saveDialog.setTitle(“保存”);
/*获取文件*/
文件f=saveDialog.showsavedilog(stage);
/*…处理文件*/
});
/*打印按钮的.fire方法调用*/
b2.设置操作(事件->系统输出打印项次(“按下”);
场景=新场景(新HBox(b1,b2));
舞台场景;
stage.show();
}
公共静态void main(字符串[]args){launch(args);}
}
问题是从onkeyreased
处理程序中启动按钮。当您松开ENTER键时,文件选择器
已被隐藏,阶段
已恢复焦点,这意味着按键释放事件将被赋予您的阶段
/按钮
。显然,这将导致一个循环
一种可能的解决方案是从按下键的处理程序内部启动按钮。但是,这会使您的用户产生与其他应用程序稍有不同的行为,而您的用户可能并不期望/欣赏这些行为
另一种可能的解决方案是跟踪文件选择器
在启动按钮之前是否已打开,就像Matt在中所做的那样
您试图做的是允许用户使用ENTER键启动按钮
;这应该是Windows等平台上的默认行为
不适合我。空间是o
public class Main extends Application {
private boolean fileChooserOpen = false;
@Override
public void start(Stage stage) throws Exception{
/* EventHandler to be used with multiple buttons */
EventHandler<KeyEvent> enterWithFileChooser = event -> {
if (!fileChooserOpen && event.getCode() == KeyCode.ENTER && event.getSource() instanceof Button) {
Button src = (Button) event.getSource();
src.fire();
fileChooserOpen = true;
}else {
fileChooserOpen = false;
}
event.consume();
};
EventHandler<KeyEvent> enter = event -> {
if (event.getCode() == KeyCode.ENTER && event.getSource() instanceof Button) {
Button src = (Button) event.getSource();
src.fire();
}
event.consume();
};
/* Create a new button */
Button b1 = new Button("Save");
Button b2 = new Button("Print");
/* Add event handlers */
b1.setOnKeyReleased(enterWithFileChooser);
b2.setOnKeyReleased(enter);
/* Called by .fire method of save button */
b1.setOnAction(event -> {
/* Create the save dialog box */
FileChooser saveDialog = new FileChooser();
saveDialog.setTitle("Save");
/* Get file */
File f = saveDialog.showSaveDialog(stage);
/* ... do stuff with file ... */
});
/* Called by .fire method of print button */
b2.setOnAction(event -> System.out.println("Pressed"));
Scene scene = new Scene(new HBox(b1, b2));
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) { launch(args); }
}
protected static final List<KeyBinding> BUTTON_BINDINGS = new ArrayList<KeyBinding>();
static {
BUTTON_BINDINGS.add(new KeyBinding(SPACE, KEY_PRESSED, PRESS_ACTION));
BUTTON_BINDINGS.add(new KeyBinding(SPACE, KEY_RELEASED, RELEASE_ACTION));
}
public ButtonBehavior(C control) {
super(control);
/* SOME CODE OMITTED FOR BREVITY */
// then button-specific mappings for key and mouse input
addDefaultMapping(buttonInputMap,
new KeyMapping(SPACE, KeyEvent.KEY_PRESSED, this::keyPressed),
new KeyMapping(SPACE, KeyEvent.KEY_RELEASED, this::keyReleased),
new MouseMapping(MouseEvent.MOUSE_PRESSED, this::mousePressed),
new MouseMapping(MouseEvent.MOUSE_RELEASED, this::mouseReleased),
new MouseMapping(MouseEvent.MOUSE_ENTERED, this::mouseEntered),
new MouseMapping(MouseEvent.MOUSE_EXITED, this::mouseExited),
// on non-Mac OS platforms, we support pressing the ENTER key to activate the button
new KeyMapping(new KeyBinding(ENTER, KeyEvent.KEY_PRESSED), this::keyPressed, event -> PlatformUtil.isMac()),
new KeyMapping(new KeyBinding(ENTER, KeyEvent.KEY_RELEASED), this::keyReleased, event -> PlatformUtil.isMac())
);
/* SOME CODE OMITTED FOR BREVITY */
}
import com.sun.javafx.PlatformUtil;
import com.sun.javafx.scene.control.behavior.ButtonBehavior;
import com.sun.javafx.scene.control.behavior.KeyBinding;
import java.lang.reflect.Field;
import java.util.List;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
public final class ButtonUtils {
public static void installEnterFiresButtonFix() throws ReflectiveOperationException {
if (PlatformUtil.isMac()) {
return;
}
Field bindingsField = ButtonBehavior.class.getDeclaredField("BUTTON_BINDINGS");
Field pressedActionField = ButtonBehavior.class.getDeclaredField("PRESS_ACTION");
Field releasedActionField = ButtonBehavior.class.getDeclaredField("RELEASE_ACTION");
bindingsField.setAccessible(true);
pressedActionField.setAccessible(true);
releasedActionField.setAccessible(true);
@SuppressWarnings("unchecked")
List<KeyBinding> bindings = (List<KeyBinding>) bindingsField.get(null);
String pressedAction = (String) pressedActionField.get(null);
String releasedAction = (String) releasedActionField.get(null);
bindings.add(new KeyBinding(KeyCode.ENTER, KeyEvent.KEY_PRESSED, pressedAction));
bindings.add(new KeyBinding(KeyCode.ENTER, KeyEvent.KEY_RELEASED, releasedAction));
}
private ButtonUtils() {}
}
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
public class Main extends Application {
@Override
public void start(Stage primaryStage) {
try {
ButtonUtils.installEnterFiresButtonFix();
} catch (ReflectiveOperationException ex) {
ex.printStackTrace();
}
Button button = new Button("Save");
button.setOnAction(event -> {
event.consume();
System.out.println(new FileChooser().showSaveDialog(primaryStage));
});
Scene scene = new Scene(new StackPane(button), 300, 150);
primaryStage.setScene(scene);
primaryStage.setTitle("Workshop");
primaryStage.show();
}
}