You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Outliner应用添加节点时点击OK输入框重复弹出问题求助

Outliner应用添加节点对话框重复弹出问题修复

问题描述

开发一款类似待办清单的Outliner应用,支持添加和编辑节点。添加节点时点击“OK”按钮后,输入对话框会重复弹出;已用布尔值修复“取消”按钮的问题,但OK按钮和对话框右上角的X按钮仍会导致输入框重新弹出。

控制器类代码

public class OutlinerController implements ActionListener {

    private OutlinerModel model;
    private OutlinerView view;

    public OutlinerController(OutlinerModel model, OutlinerView view) {
        this.model = model;
        this.view = view;

        // 注册控制器为视图中按钮的监听器
        view.addButtonListener(this);
        view.addEditButtonListener(this);
        view.addDeleteButtonListener(this);
        view.addCompleteButtonListener(this);
        view.addSearchButtonListener(this);
    }

    public void actionPerformed(ActionEvent e) {
        DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) view.getTree().getLastSelectedPathComponent();
        if (e.getSource() == view.getAddButton()) {
            boolean adding = true;
            while (adding) {
                // 向选中节点添加新节点
                String nodeName = JOptionPane.showInputDialog("Enter node name:");
                if (nodeName == null) { // 点击取消按钮或右上角X
                    adding = false;
                } else if (nodeName.trim().equals("")) { // 输入空名称
                    JOptionPane.showMessageDialog(view.getTree(), "Node name cannot be empty.", "Error", JOptionPane.ERROR_MESSAGE);
                } else {
                    DefaultMutableTreeNode newNode = new DefaultMutableTreeNode(nodeName);
                    model.getTreeModel().insertNodeInto(newNode, selectedNode, selectedNode.getChildCount());
                    // 展开选中节点以显示新添加的节点
                    view.getTree().expandPath(new TreePath(selectedNode.getPath()));
                    // 添加成功后退出循环
                    adding = false;
                }
            }
        } 
        if (e.getSource() == view.getEditButton()) {
            // 编辑选中节点的名称
            String nodeName = JOptionPane.showInputDialog("Enter new node name:");
            selectedNode.setUserObject(nodeName);
            model.getTreeModel().nodeChanged(selectedNode);
        }  
        if (e.getSource() == view.getDeleteButton()) {
            // 从JTree中移除选中节点
            model.getTreeModel().removeNodeFromParent(selectedNode);
        }  
        if (e.getSource() == view.getCompleteButton()) {
            // 将选中节点标记为已完成
            selectedNode.setUserObject(selectedNode.getUserObject() + " [Complete]");
            model.getTreeModel().nodeChanged(selectedNode);
        }  
        if (e.getSource() == view.getSearchButton()) {
            // 获取用户输入的搜索词
            String searchTerm = JOptionPane.showInputDialog("Enter search term:");
            DefaultMutableTreeNode searchResult = searchNode(model.getRoot(), searchTerm);
            // 如果找到匹配节点,选中并滚动到该节点
            if (searchResult != null) {
                TreePath path = new TreePath(searchResult.getPath());
                view.getTree().setSelectionPath(path);
                view.getTree().scrollPathToVisible(path);
            } else {
                // 未找到匹配节点时显示提示
               view.displayErrorMessage("No node found with the given search term");
            }
        }
    }

    private DefaultMutableTreeNode searchNode(DefaultMutableTreeNode node, String searchTerm) {
        // 检查当前节点是否匹配搜索词
        if (node.getUserObject().toString().toLowerCase().contains(searchTerm.toLowerCase())) {
            return node;
        }
        // 递归搜索当前节点的子节点
        for (int i = 0; i < node.getChildCount(); i++) {
            DefaultMutableTreeNode childNode = (DefaultMutableTreeNode) node.getChildAt(i);
            DefaultMutableTreeNode result = searchNode(childNode, searchTerm);
            if (result != null) {
                return result;
            }
        }

        // 未找到匹配节点时返回null
        return null;

    }
    private void searchNode(String searchString) {
        // 获取JTree的根节点
        DefaultMutableTreeNode rootNode = (DefaultMutableTreeNode) view.getTree().getModel().getRoot();

        // 遍历JTree查找匹配搜索字符串的节点
        searchNodeHelper(searchString, rootNode);
    }

    private void searchNodeHelper(String searchString, DefaultMutableTreeNode node) {

        // 获取节点的用户对象并转换为小写
        String nodeString = node.getUserObject().toString().toLowerCase();

        // 检查节点字符串是否包含搜索字符串
        if (nodeString.contains(searchString)) {

            // 如果匹配,展开路径并高亮节点
            TreePath path = new TreePath(node.getPath());
            view.getTree().expandPath(path);
            view.getTree().setSelectionPath(path);
            return;

        }

        // 如果不匹配,递归检查子节点
        for (int i = 0; i < node.getChildCount(); i++) {
            DefaultMutableTreeNode childNode = (DefaultMutableTreeNode) node.getChildAt(i);
            searchNodeHelper(searchString, childNode);
        }

    }

}

问题分析与修复

核心问题

添加节点的while(adding)循环中,当用户输入有效名称并成功添加节点后,未将adding设为false,导致循环持续执行,重复弹出输入对话框。

额外排查点

若点击对话框右上角X按钮仍出现重复弹出,需检查视图层OutlinerView中的addButtonListener方法是否被多次调用,导致监听器重复注册,进而多次触发actionPerformed方法。

修复步骤

  1. 在添加节点成功的分支中添加adding = false;,确保完成一次添加后退出循环(已在上述代码中标记)。
  2. 检查OutlinerView类,确保addButtonListener仅被调用一次,避免重复注册监听器。

内容的提问来源于stack exchange,提问作者Aaron

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 15:23:11