سؤال

أحاول تعديل Jtree المتأرجح القياسي لتواصل العقد مع وبدون مربعات الاختيار. هذا مثال:

alt text

عندما أحاول التحقق/إلغاء تحديد أحد مربعات الاختيار (عقدة "المستخدم 01" في هذا المثال) ، تفقد الشجرة العقد:

alt text

أنا رمز بلدي هو تكيف لهذا المثال: http://forums.sun.com/thread.jspa؟threadid=5321084&start=13.

بدلاً من تضمين jCheckbox في defaultMutableTreenode مثل هذا:

new DefaultMutableTreeNode(new CheckBoxNode("Accessibility", true));

اعتقدت أنه من المنطقي إنشاء عقدة نموذجية مستمدة من DefaultMutableTreenode ، والتي أسميها JtreeNode. تقوم هذه الفئة تلقائيًا بتعيين DefaultMutAbleTreenode's UserObject على JCheckbox. يتم استخدام خاصية showcheckbox في الفصل من قبل TreecellRenderer لتحديد ما إذا كان يتم استخدام JCheckbox أو DefaultTreecellRenderer. يتم استخدام jtreenode مثل هذا:

    JTreeNode user01 = new JTreeNode("User 01");
    user01.setShowCheckBox(true);
    user01.setSelected(true);

أعتقد أن المشكلة هي مع الفصل الذي ينفذ treecelleditor ، وتحديداً في طرق getCelleditorValue () أو getTreecelleditorComponent (). أظن أن القضية لديها شيء مع getCelleditorValue () لإعادة مشتق من DefaultMutableTreenode ، بدلاً من مثيل نموذج أبسط.

public Object getCellEditorValue() {

    JCheckBox checkBox = renderer.getCheckBoxRenderer();

    JTreeNode node = new JTreeNode(checkBox.getText());
    node.setShowCheckBox(true);
    node.setSelected(checkBox.isSelected());
    return node;

}

public Component getTreeCellEditorComponent(JTree tree, Object value, boolean isSelected, boolean expanded, boolean leaf, int row) {

    Component editor = renderer.getTreeCellRendererComponent(tree, value, true, expanded, leaf, row, true);

    // editor always selected / focused
    ItemListener itemListener = new ItemListener() {
        public void itemStateChanged(ItemEvent itemEvent) {
            if (stopCellEditing()) {
                fireEditingStopped();
            }
        }
    };

    if (editor instanceof JCheckBox) {
        ((JCheckBox) editor).addItemListener(itemListener);
    }

    return editor;

}

إليكم طريقة GetTreecellRenderErencomponent () Treecellrender ():

public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {

    Component component;

    //if object being passed for rendering is a JTreeNode that should show a JCheckBox, attempt to render it so
    if (((JTreeNode) value).getShowCheckBox()) {

        String stringValue = tree.convertValueToText(value, selected, expanded, leaf, row, false);

        //set default JCheckBox rendering
        checkBoxRenderer.setText(stringValue);
        checkBoxRenderer.setSelected(false);    //not checked
        checkBoxRenderer.setEnabled(tree.isEnabled());

        if (selected) {
            //removed colorization
            //checkBoxRenderer.setForeground(selectionForeground);
            //checkBoxRenderer.setBackground(selectionBackground);
        }
        else {
            checkBoxRenderer.setForeground(textForeground);
            checkBoxRenderer.setBackground(textBackground);
        }

        //DefaultMutableTreeNode
        if ((value != null) && (value instanceof JTreeNode)) {

            //userObject should be a JTreeNode instance
            //DefaultMutableTreeNode
            //Object userObject = ((JTreeNode) value).getUserObject();

            //if it is
            //if (userObject instanceof JTreeNode) {
                //cast as a JTreeNode
                //JTreeNode node = (JTreeNode) userObject;
                JTreeNode node = (JTreeNode) value;

                //set JCheckBox settings to match JTreeNode's settings
                checkBoxRenderer.setText(node.getText());
                checkBoxRenderer.setSelected(node.isSelected());

            //}

        }

        component = checkBoxRenderer;

    }

    //if not, render the default
    else {

        component = defaultRenderer.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);

    }

    return component;

}

تحظى بتقدير كبير أي أفكار.

هل كانت مفيدة؟

المحلول

تمكنت من حل المشكلة.

alt text

لقد قمت بإنشاء فئة نموذجية (TreeNodeModel) للاحتفاظ ببيانات العقدة ذات الصلة: المفتاح ، القيمة ، Hascheckbox ، Isselected:

public class TreeNodeModel {

    int key;
    String value;
    boolean isSelected=false;
    boolean hasCheckBox=false;

    public TreeNodeModel() {
    }
    public TreeNodeModel(int key, String value) {
        this.key=key;
        this.value = value;
    }
    public TreeNodeModel(int key, String value, boolean hasCheckBox) {
        this.key=key;
        this.value = value;
        this.hasCheckBox = hasCheckBox;
    }
    public TreeNodeModel(int key, String value, boolean hasCheckBox, boolean isSelected) {
        this.key=key;
        this.value = value;
        this.hasCheckBox=hasCheckBox;
        this.isSelected = isSelected;
    }

    public boolean isSelected() {
        return this.isSelected;
    }
    public void setSelected(boolean newValue) {
        this.isSelected = newValue;
    }

    public boolean hasCheckBox() {
        return this.hasCheckBox;
    }
    public void setCheckBox(boolean newValue) {
        this.hasCheckBox=newValue;
    }

    public int getKey() {
        return this.key;
    }
    public void setKey(int newValue) {
        this.key = newValue;
    }

    public String getValue() {
        return this.value;
    }
    public void setValue(String newValue) {
        this.value = newValue;
    }

    @Override
    public String toString() {
        return getClass().getName() + "[" + this.value + "/" + this.isSelected + "]";
//        return this.text;
    }

}

لقد أنشأت تطبيقًا لواجهة Treecelleditor:

public class TreeNodeEditor  extends AbstractCellEditor implements TreeCellEditor {

    private JTree tree;
    private TreeNodeModel editedModel = null;

    TreeNodeRenderer renderer = new TreeNodeRenderer();

    public TreeNodeEditor(JTree tree) {
        this.tree=tree;
    }

    @Override
    public boolean isCellEditable(EventObject event) {

        boolean editable=false;

        if (event instanceof MouseEvent) {

            MouseEvent mouseEvent = (MouseEvent) event;
            TreePath path = tree.getPathForLocation(mouseEvent.getX(),mouseEvent.getY());

            if (path != null) {

                Object node = path.getLastPathComponent();

                if ((node != null) && (node instanceof DefaultMutableTreeNode)) {

                    DefaultMutableTreeNode editedNode = (DefaultMutableTreeNode) node;
                    TreeNodeModel model = (TreeNodeModel) editedNode.getUserObject();
                    editable = model.hasCheckBox;

                }   //if (node)
            }   //if (path)
        }   //if (MouseEvent)

        return editable;

    }

    public Object getCellEditorValue() {

        JCheckBox checkbox = renderer.getCheckBoxRenderer();

        TreeNodeModel model = new TreeNodeModel(editedModel.getKey(), checkbox.getText(), true, checkbox.isSelected());
        return model;

    }

    public Component getTreeCellEditorComponent(JTree tree, Object value, boolean isSelected, boolean expanded, boolean leaf, int row) {

        if (((DefaultMutableTreeNode) value).getUserObject() instanceof TreeNodeModel) {
            editedModel = (TreeNodeModel) ((DefaultMutableTreeNode) value).getUserObject();
        }

        Component editor = renderer.getTreeCellRendererComponent(tree, value, true, expanded, leaf, row, true);

        // editor always selected / focused
        ItemListener itemListener = new ItemListener() {
            public void itemStateChanged(ItemEvent itemEvent) {
                if (stopCellEditing())
                    fireEditingStopped();
            }
        };

        if (editor instanceof JCheckBox) {
            ((JCheckBox) editor).addItemListener(itemListener);
        }

        return editor;
    }

}

كان المفتاح هو التقاط النموذج في طريقة getTreEcellEditorComponent () واستخدام مفتاحه في طريقة getCelleditorValue ().

كان بناء الشجرة سهلاً:

DefaultMutableTreeNode server = new DefaultMutableTreeNode(new TreeNodeModel(0,"Server 01", false));

DefaultMutableTreeNode userFolder = new DefaultMutableTreeNode(new TreeNodeModel(1, "User Folders", false));
server.add(userFolder);

DefaultMutableTreeNode user01 =  new DefaultMutableTreeNode(new TreeNodeModel(2, "User 01", true, true));
userFolder.add(user01);

DefaultMutableTreeNode clientA = new DefaultMutableTreeNode(new TreeNodeModel(3, "Client A", true, true));
user01.add(clientA);

DefaultMutableTreeNode clientB = new DefaultMutableTreeNode(new TreeNodeModel(4, "Client B", true, true));
user01.add(clientB);

DefaultMutableTreeNode publicFolder = new DefaultMutableTreeNode(new TreeNodeModel(5, "Public Folders", false));
server.add(publicFolder);

DefaultMutableTreeNode clientC = new DefaultMutableTreeNode(new TreeNodeModel(6, "Client C", true));
publicFolder.add(clientC);
        Tree_Nodes.setCellRenderer(new TreeNodeRenderer());
        Tree_Nodes.setCellEditor(new TreeNodeEditor(Tree_Nodes));
Tree_Nodes.setModel(new DefaultTreeModel(server);

أخيرًا ، تحديد العقد التي تم فحصها كانت مسألة فحص مجموعة عقدة النموذج (عبر زر):

private Map<Integer, String> checked = new HashMap<Integer, String>();

private void Button_CheckedActionPerformed(java.awt.event.ActionEvent evt) {

    DefaultTableModel tableModel = ((DefaultTableModel) Table_Nodes.getModel());
    tableModel.getDataVector().removeAllElements();
    tableModel.fireTableDataChanged();

    checked.clear();

    DefaultTreeModel treeModel = (DefaultTreeModel) Tree_Nodes.getModel();
    DefaultMutableTreeNode root = (DefaultMutableTreeNode) treeModel.getRoot();

    getChildNodes(root);

    for (Iterator it=checked.entrySet().iterator(); it.hasNext(); ) {
        Map.Entry entry = (Map.Entry)it.next();
        tableModel.addRow(new Object[] {entry.getKey(), entry.getValue()});
    }

    Button_Checked.requestFocus();


}

private void getChildNodes(DefaultMutableTreeNode parentNode) {

    for (Enumeration e=parentNode.children(); e.hasMoreElements();) {

        DefaultMutableTreeNode childNode = (DefaultMutableTreeNode) e.nextElement();
        TreeNodeModel model = (TreeNodeModel) childNode.getUserObject();

        if (model.hasCheckBox && model.isSelected()) {
            checked.put(model.getKey(), model.getValue());
        }

        //recurse
        if (childNode.getChildCount()>0) getChildNodes(childNode);

    }

}

نصائح أخرى

فيما يلي بعض "gotchas" التي تسببت في تقديم مشاكل بالنسبة لي:

  1. قد لا يشارك TreeCellEditor مثيل TreecellRenderer الذي ينتقل إليه JTree.setCellRenderer(). إذا TreeCellEditor.getTreeCellEditorComponent() يعيد نفس مثيل الشجرة TreeCellRenderer.getTreeCellRendererComponent() سوف ينتهي بك المطاف مع المشاكل. ستحاول تحرير خلية واحدة ، ولكن يتم تشغيل العارض ضد 5 خلايا غير ذات صلة. عندما يحاول المحرر استرداد حالة jcheckbox ، فإنها ستحصل على القيمة من الخلية الأخيرة المقدمة (على عكس الخلية الأخيرة التي تم تحريرها) والتي من الواضح أنها خاطئة.

  2. يستخدم TreeCellEditor.getCellEditorValue() لتعديل قيمة الخلية ، بدلاً من إضافة مستمعي الماوس مباشرة على خانة الاختيار. يتم استدعاء هذه الطريقة فقط إذا تم حفظ القيمة. إذا كنت تتصرف فورًا على أحداث الماوس ، فلن تتراجع القيمة CellEditor.cancelCellEditing().

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top