TimerTask更新ComboBox下拉选项后输入字符出现镜像问题排查
问题原因
- UI操作线程违规:你代码中的
((TextInputControl)combo.getEditor()).end()、combo.show()两个UI操作写在了Platform.runLater()的run()方法外部,等于在后台线程直接修改UI,违反JavaFX单线程规则,直接导致光标位置异常。 - 多余的输入框赋值操作:更新下拉列表不会清空ComboBox输入框的内容,你主动调用
combo.getEditor().setText(actualValue)完全多余,反复覆盖输入框内容会打断用户输入状态,导致新输入的字符插入位置错乱,呈现出镜像反转的效果。 - 防抖逻辑完全失效:你每次按键都会新建一个
Timer实例,没有取消之前的待执行任务,会出现多个请求并发执行的情况,后返回的旧请求会用历史输入内容覆盖用户当前的新输入。 - 列表数据累加问题:全局的
listItems每次请求前没有清空,旧的下拉选项会不断累加,导致下拉列表内容错乱。
修复方案
1. 直接修正现有代码的异常点
combo.getEditor().setOnKeyPressed(new EventHandler<KeyEvent>() { // 全局持有Timer和TimerTask实例,不要每次按键新建 private Timer timer; private TimerTask currentTask; public void handle(KeyEvent ke) { // 每次按键先取消之前的待执行任务,实现防抖 if (timer != null) { timer.cancel(); } if (currentTask != null) { currentTask.cancel(); } last = System.currentTimeMillis(); timer = new Timer("Timer"); currentTask = new TimerTask() { public void run() { if (System.currentTimeMillis() - last > 1500) { String query = combo.getEditor().getText(); if (query.length() <= 3 || stopFlag) { return; } String search = query.replace(" ", "%20"); HttpRequest request = // 你的请求逻辑 try { HttpResponse<String> responses = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString()); String jsonString = responses.body(); JSONObject obj = new JSONObject(jsonString); JSONArray arr = obj.getJSONArray("d"); // 每次请求新建列表,不要用全局list,避免并发修改 List<String> newItems = new ArrayList<>(); for (Object itemObj : arr) { JSONObject itemJSON = (JSONObject) itemObj; String nazev = itemJSON.getString("l"); try { int ro = itemJSON.getInt("y"); String res = nazev + " (" + ro + ")"; newItems.add(res); } catch (JSONException je) { continue; } } Platform.runLater(() -> { combo.getItems().setAll(newItems); // 删掉多余的setText操作!!! combo.show(); }); } catch (IOException | InterruptedException e1) { e1.printStackTrace(); } } } }; timer.schedule(currentTask, 1500); } });
2. 更优的防抖实现方案
推荐用JavaFX原生的PauseTransition实现防抖,不需要自己处理线程安全问题,代码更简洁稳定:
// 全局只初始化一次防抖实例 private final PauseTransition searchDebounce = new PauseTransition(Duration.millis(1500)); // 初始化组件时绑定逻辑 private void initSearch() { searchDebounce.setOnFinished(e -> { String input = combo.getEditor().getText(); if (input.length() < 3) { combo.hide(); combo.getItems().clear(); return; } // 后台线程发请求 new Thread(() -> { List<String> newItems = new ArrayList<>(); // 你的HTTP请求、JSON解析逻辑 // ... Platform.runLater(() -> { combo.getItems().setAll(newItems); combo.show(); }); }).start(); }); // 按键时重置防抖计时 combo.getEditor().setOnKeyTyped(e -> searchDebounce.playFromStart()); }
内容的提问来源于stack exchange,提问作者user7303261
相关产品推荐
相关产品推荐

