我试图在一个简单的JavaFX应用程序中将键事件处理程序添加到可编辑的ComboBox中。由于Scene Builder不提供对ComboBox中TextField的访问,因此我必须在代码中添加事件处理程序。
这是我尝试添加处理程序。
主班
package sample;
import javafx.application.Application;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.stage.Stage;
public class Main extends Application {
@FXML
private ComboBox combo;
@Override
public void start(Stage primaryStage) throws Exception{
FXMLLoader loader = new FXMLLoader(getClass().getResource("sample.fxml"));
Parent root = loader.load();
primaryStage.setTitle("Hello World");
primaryStage.setScene(new Scene(root, 400, 300));
primaryStage.show();
Controller c = loader.getController();
combo.getEditor().setOnKeyTyped(c::handleComboKeyPress);
}
public static void main(String[] args) {
launch(args);
}
}
控制器类
package sample;
import javafx.fxml.FXML;
import javafx.scene.control.ComboBox;
import javafx.scene.input.KeyEvent;
public class Controller {
@FXML
private ComboBox combo;
public void handleComboKeyPress(KeyEvent ke)
{
System.out.print("key press. "); // debugging
String query = combo.getEditor().getText();
System.out.println(query); // debugging
}
}
FXML(sample.fxml)
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.ComboBox?>
<?import javafx.scene.layout.Pane?>
<Pane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="300.0" prefWidth="400.0" xmlns="http://javafx.com/javafx/10.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.Controller">
<children>
<ComboBox fx:id="combo" editable="true" layoutX="75.0" layoutY="34.0" prefWidth="150.0" promptText="City, State" visibleRowCount="5" />
</children>
</Pane>
这会在start方法的最后一行出现空指针异常而崩溃。问题是
combo
还没有值,因为(我假设)FXML加载程序在单独的线程中运行,并且在我的代码尝试调用getEditor时还没有完成。设置事件处理程序的更合适的方法是什么?
编辑:添加了完整的源代码
最佳答案
start
方法需要访问在Controller类中声明的ComboBox变量。仅在Main类中用@FXML
注释ComboBox变量是不够的。
我通过向Controller类添加getComboBox
方法解决了该问题。这将返回由combo
变量引用的ComboBox实例。
public ComboBox getComboBox()
{
return combo;
}
在Main类中,使用此方法进入ComboBox基础的编辑器:
Controller c = loader.getController();
c.getComboBox().getEditor().setOnTyped(c::handleComboKeyPress);
这是修改后的主类:
public class Main extends Application {
@Override
public void start(Stage primaryStage) throws Exception{
FXMLLoader loader = new FXMLLoader(getClass().getResource("sample.fxml"));
Parent root = loader.load();
primaryStage.setTitle("Hello World");
primaryStage.setScene(new Scene(root, 400, 300));
primaryStage.show();
Controller c = loader.getController();
c.getComboBox().getEditor().setOnKeyTyped(c::handleComboKeyPress);
}
更好的解决方案
如下面的@Slaw所建议的,另一种(更好的)解决方案是在Controller中设置keyTyped处理程序。使用
initialize
方法,该方法会由加载程序自动调用(如果存在)。public void initialize()
{
combo.getEditor().setOnKeyTyped(this::handleComboKeyPress);
}
这是整个Controller类(减去导入):
public class Controller {
@FXML
private ComboBox combo;
public void handleComboKeyPress(KeyEvent ke)
{
// Do stuff
System.out.println("key pressed.");
}
public void initialize()
{
combo.getEditor().setOnKeyTyped(this::handleComboKeyPress);
}
}