JXTreeTable中的复选框

时间:2014-02-21 03:42:45

标签: java swing jcheckbox swingx jxtreetable

这里还是一个Java新手,为了自己的利益而尝试过于先进。不过,这就是我需要做的:JXTreeTable中的一个复选框。我的主要课程:

package info.chrismcgee.sky.production;

import info.chrismcgee.sky.production.treetable.NoRootTreeTableModel;

import java.awt.Checkbox;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ScrollPaneConstants;
import javax.swing.border.EmptyBorder;
import javax.swing.border.EtchedBorder;

import net.miginfocom.swing.MigLayout;

import org.jdesktop.swingx.JXTreeTable;

public class TestFrame extends JFrame {

    /**
     * 
     */
    private static final long serialVersionUID = -1899673458785493250L;
    private JXTreeTable treeTable;

    /**
     * Launch the application.
     */
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    TestFrame frame = new TestFrame();
                    frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    /**
     * Create the frame.
     */
    public TestFrame() {
        setMinimumSize(new Dimension(600, 600));
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setBounds(100, 100, 546, 600);
        JPanel contentPane = new JPanel();
        contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
        setContentPane(contentPane);
        contentPane.setLayout(new MigLayout("", "[grow][grow][grow][100px:n,grow][grow][grow][grow]", "[][251.00,grow][]"));

        List<Job> jobList = new ArrayList<Job>();

        List<ItemDetail> itemList = new ArrayList<ItemDetail>();
        itemList.add(new ItemDetail("N10", "N10", 2, 1000, PrintType.PAD, true));
        itemList.add(new ItemDetail("N13", "N13", 2, 2000, PrintType.PAD, true));

        // create and add the first job with its list of ItemDetail objects
        jobList.add(new Job(new Checkbox("Print Solutions"), "123456", ShipDate.getDate("02/28/14"), itemList));

        List<ItemDetail> itemList2 = new ArrayList<ItemDetail>();
        itemList2.add(new ItemDetail("P12", "Green", 1, 250, PrintType.SCREEN, true));
        itemList2.add(new ItemDetail("P12", "Purple", 1, 250, PrintType.SCREEN, true));
        itemList2.add(new ItemDetail("P12", "Gray", 1, 250, PrintType.SCREEN, true));

        // create and add a second job with its list of ItemDetail objects
        jobList.add(new Job(new Checkbox("Innovators Inc"), "246801", ShipDate.getDate("03/10/14"), itemList2));

        // we use a no root model
        NoRootTreeTableModel noRootTreeTableModel = new NoRootTreeTableModel(jobList);
        treeTable = new JXTreeTable(noRootTreeTableModel);
        treeTable.setEditable(false);
        treeTable.setRootVisible(false);
        treeTable.setBorder(new EtchedBorder(EtchedBorder.LOWERED, null, null));
        treeTable.getTableHeader().setReorderingAllowed(false);
        treeTable.getColumn(0).setPreferredWidth(200);
        treeTable.getColumn(1).setPreferredWidth(75);
        treeTable.getColumn(2).setPreferredWidth(15);
            treeTable.getColumn(2).setMinWidth(15);
            treeTable.getColumn(2).setMaxWidth(15);
        treeTable.getColumn(3).setPreferredWidth(50);
            treeTable.getColumn(3).setMaxWidth(50);
        treeTable.getColumn(4).setPreferredWidth(25);
        JScrollPane scrollPane = new JScrollPane(treeTable);
        scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
        contentPane.add(scrollPane, "cell 0 1 7 1,grow");

    }       
}

Job类(TreeTable中的分支):

package info.chrismcgee.sky.production;

import java.awt.Checkbox;
import java.util.List;

import org.joda.time.LocalDate;

public class Job {

    private Checkbox cbJob;
    private String idNumber;
    private LocalDate shipDate;
    private List<ItemDetail> itemList;

    public Job(Checkbox cbJob, String idNumber, LocalDate shipDate, List<ItemDetail> itemList)
    {
        this.cbJob = cbJob;
        this.idNumber = idNumber;
        this.shipDate = shipDate;
        this.itemList = itemList;
    }

    public List<ItemDetail> getItemList()
    {
        return itemList;
    }

    public void setItemList(List<ItemDetail> itemList)
    {
        this.itemList = itemList;
    }

    /**
     * @return the cbJob
     */
    public Checkbox getCbJob() {
        return cbJob;
    }

    /**
     * @param cbJob the cbJob to set
     */
    public void setCbJob(Checkbox cbJob) {
        this.cbJob = cbJob;
    }

    /**
     * @return the idNumber
     */
    public String getIdNumber() {
        return idNumber;
    }

    /**
     * @param idNumber the idNumber to set
     */
    public void setIdNumber(String idNumber) {
        this.idNumber = idNumber;
    }

    /**
     * @return the shipDate
     */
    public LocalDate getShipDate() {
        return shipDate;
    }

    /**
     * @param shipDate the shipDate to set
     */
    public void setShipDate(LocalDate shipDate) {
        this.shipDate = shipDate;
    }

}

OrderDetail类(在TreeTable中留下):

package info.chrismcgee.sky.production;


public class ItemDetail {

    private String productId;
    private String detail;
    private long numColors;
    private long numQuantity;
    private PrintType printType;
    private boolean active;

    public ItemDetail(String productId, String detail, long numColors, long numQuantity, PrintType printType, boolean active)
    {
        this.productId = productId;
        this.detail = detail;
        this.numColors = numColors;
        this.numQuantity = numQuantity;
        this.printType = printType;
        this.active = active;
    }

    /**
     * @return the productId
     */
    public String getProductId() {
        return productId;
    }

    /**
     * @param productId the productId to set
     */
    public void setProductId(String productId) {
        this.productId = productId;
    }

    /**
     * @return the detail
     */
    public String getDetail() {
        return detail;
    }

    /**
     * @param detail the detail to set
     */
    public void setDetail(String detail) {
        this.detail = detail;
    }

    /**
     * @return the numColors
     */
    public long getNumColors() {
        return numColors;
    }

    /**
     * @param numColors the numColors to set
     */
    public void setNumColors(long numColors) {
        this.numColors = numColors;
    }

    /**
     * @return the numQuantity
     */
    public long getNumQuantity() {
        return numQuantity;
    }

    /**
     * @param numQuantity the numQuantity to set
     */
    public void setNumQuantity(long numQuantity) {
        this.numQuantity = numQuantity;
    }

    /**
     * @return the printType
     */
    public PrintType getPrintType() {
        return printType;
    }

    /**
     * @param printType the printType to set
     */
    public void setPrintType(PrintType printType) {
        this.printType = printType;
    }

    /**
     * @return the active
     */
    public boolean isActive() {
        return active;
    }

    /**
     * @param active the active to set
     */
    public void setActive(boolean active) {
        this.active = active;
    }

}

,最后是NoRootTreeTableModel类,它扩展了AbstractTreeTableModel类,以便不显示树的根目录:

package info.chrismcgee.sky.production.treetable;

import info.chrismcgee.sky.production.ItemDetail;
import info.chrismcgee.sky.production.Job;

import java.util.List;

import org.jdesktop.swingx.treetable.AbstractTreeTableModel;

public class NoRootTreeTableModel extends AbstractTreeTableModel {

    private final static String[] COLUMN_NAMES = {"Name/Product", "Job # / Detail", "T",
        "Colors", "Quantity", "Total"};

    private List<Job> jobList;

    public NoRootTreeTableModel(List<Job> jobList)
    {
        super(new Object());
        this.jobList = jobList;
    }

    @Override
    public int getColumnCount() {
        return COLUMN_NAMES.length;
    }

    @Override
    public String getColumnName(int column)
    {
        return COLUMN_NAMES[column];
    }

    @Override
    public boolean isCellEditable(Object node, int column)
    {
        return false;
    }

    @Override
    public boolean isLeaf(Object node)
    {
        return node instanceof ItemDetail;
    }

    @Override
    public int getChildCount(Object parent) {
        if (parent instanceof Job) {
            Job job = (Job) parent;
            return job.getItemList().size();
        }
        return jobList.size();
    }

    @Override
    public Object getChild(Object parent, int index) {
        if (parent instanceof Job) {
            Job job = (Job) parent;
            return job.getItemList().get(index);
        }
        return jobList.get(index);
    }

    @Override
    public int getIndexOfChild(Object parent, Object child) {
        Job job = (Job) parent;
        ItemDetail item = (ItemDetail) child;
        return job.getItemList().indexOf(item);
    }

    @Override
    public Object getValueAt(Object node, int column) {
        if (node instanceof Job) {
            Job job = (Job) node;
            switch (column) {
                case 0:
                    return job.getCbJob();
                case 1:
                    return job.getIdNumber();
            }
        } else if (node instanceof ItemDetail) {
            ItemDetail item = (ItemDetail) node;
            switch (column) {
                case 0:
                    return item.getProductId();
                case 1:
                    return item.getDetail();
                case 2:
                    return item.getPrintType();
                case 3:
                    return item.getNumColors();
                case 4:
                    return item.getNumQuantity();
                case 5:
                    return item.getNumColors() * item.getNumQuantity();
            }
        }
        return null;
    }

}

我知道这是很多代码,但我想不出一个快速的方法来削减它仍然让它按照我需要的方式工作。实际上,它已经减少了很多。 (我遗漏了一些通常也在JFrame中的东西。)

运行代码时,我没有得到分支的复选框;相反,我得到的似乎是复选框代码的字符串表示: Checkbox in a TreeTable http://imageshack.com/a/img713/250/dl87.jpg

咦?这是怎么发生的,更重要的是,我怎样才能让复选框显示出来?

3 个答案:

答案 0 :(得分:6)

您永远不应该向模型添加组件,而应该提供TreeCellRenderer来呈现节点的值。节点可能正在使用分配给它的用户对象的toString值...

请查看How to Use TreesCustomizing a Tree's Display了解详情

示例直接从Customizing a Tree's Display

撕开

Check Boxes

我将把它留给你创建编辑器并确定如何选中复选框

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
import javax.swing.ButtonGroup;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.TreeModelEvent;
import javax.swing.event.TreeModelListener;
import javax.swing.tree.TreeCellRenderer;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;

public class TreeExample {

    public static void main(String[] args) {
        //Schedule a job for the event-dispatching thread:
        //creating and showing this application's GUI.
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {

                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());

                    //Create and set up the window.
                    JFrame frame = new JFrame("GenealogyExample");
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

                    //Create and set up the content pane.
                    GenealogyExample newContentPane = new GenealogyExample();
                    newContentPane.setOpaque(true); //content panes must be opaque
                    frame.setContentPane(newContentPane);

                    //Display the window.
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }
            }
        });
    }

    public static class GenealogyExample extends JPanel
            implements ActionListener {

        private JTree tree;
        private static String SHOW_ANCESTOR_CMD = "showAncestor";

        public GenealogyExample() {
            super(new BorderLayout());

            //Construct the panel with the toggle buttons.
            JRadioButton showDescendant
                    = new JRadioButton("Show descendants", true);
            final JRadioButton showAncestor
                    = new JRadioButton("Show ancestors");
            ButtonGroup bGroup = new ButtonGroup();
            bGroup.add(showDescendant);
            bGroup.add(showAncestor);
            showDescendant.addActionListener(this);
            showAncestor.addActionListener(this);
            showAncestor.setActionCommand(SHOW_ANCESTOR_CMD);
            JPanel buttonPanel = new JPanel();
            buttonPanel.add(showDescendant);
            buttonPanel.add(showAncestor);

            //Construct the tree.
            tree = new JTree(new GenealogyModel(getGenealogyGraph()));
      tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
            tree.setCellRenderer(new CheckBoxTreeCellRenderer());

            JScrollPane scrollPane = new JScrollPane(tree);
            scrollPane.setPreferredSize(new Dimension(200, 200));

            //Add everything to this panel.
            add(buttonPanel, BorderLayout.PAGE_START);
            add(scrollPane, BorderLayout.CENTER);
        }

        /**
         * Required by the ActionListener interface. Handle events on the
         * showDescendant and showAncestore buttons.
         */
        public void actionPerformed(ActionEvent ae) {
            if (ae.getActionCommand() == SHOW_ANCESTOR_CMD) {
                showAncestor(true);
            } else {
                showAncestor(false);
            }
        }

        public void showAncestor(boolean b) {
        Object newRoot = null;
        TreePath path = tree.getSelectionModel().getSelectionPath();
        if (path != null) {
            newRoot = path.getLastPathComponent();
        }
        ((GenealogyModel)tree.getModel()).showAncestor(b, newRoot);
    }

        /**
         * Constructs the genealogy graph used by the model.
         */
        public Person getGenealogyGraph() {
            //the greatgrandparent generation
            Person a1 = new Person("Jack (great-granddaddy)");
            Person a2 = new Person("Jean (great-granny)");
            Person a3 = new Person("Albert (great-granddaddy)");
            Person a4 = new Person("Rae (great-granny)");
            Person a5 = new Person("Paul (great-granddaddy)");
            Person a6 = new Person("Josie (great-granny)");

            //the grandparent generation
            Person b1 = new Person("Peter (grandpa)");
            Person b2 = new Person("Zoe (grandma)");
            Person b3 = new Person("Simon (grandpa)");
            Person b4 = new Person("James (grandpa)");
            Person b5 = new Person("Bertha (grandma)");
            Person b6 = new Person("Veronica (grandma)");
            Person b7 = new Person("Anne (grandma)");
            Person b8 = new Person("Renee (grandma)");
            Person b9 = new Person("Joseph (grandpa)");

            //the parent generation
            Person c1 = new Person("Isabelle (mom)");
            Person c2 = new Person("Frank (dad)");
            Person c3 = new Person("Louis (dad)");
            Person c4 = new Person("Laurence (dad)");
            Person c5 = new Person("Valerie (mom)");
            Person c6 = new Person("Marie (mom)");
            Person c7 = new Person("Helen (mom)");
            Person c8 = new Person("Mark (dad)");
            Person c9 = new Person("Oliver (dad)");

            //the youngest generation
            Person d1 = new Person("Clement (boy)");
            Person d2 = new Person("Colin (boy)");

            Person.linkFamily(a1, a2, new Person[]{b1, b2, b3, b4});
            Person.linkFamily(a3, a4, new Person[]{b5, b6, b7});
            Person.linkFamily(a5, a6, new Person[]{b8, b9});
            Person.linkFamily(b3, b6, new Person[]{c1, c2, c3});
            Person.linkFamily(b4, b5, new Person[]{c4, c5, c6});
            Person.linkFamily(b8, b7, new Person[]{c7, c8, c9});
            Person.linkFamily(c4, c7, new Person[]{d1, d2});

            return a1;
        }

    }

    public static class CheckBoxTreeCellRenderer implements TreeCellRenderer {

        private JCheckBox cb = new JCheckBox();

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

            cb.setText(value.toString());
            cb.setOpaque(selected);
            if (selected) {
                cb.setBackground(UIManager.getColor("Tree.selectionBackground"));
                cb.setForeground(UIManager.getColor("Tree.selectionForeground"));
            } else {
                cb.setBackground(tree.getBackground());
                cb.setForeground(tree.getForeground());
            }

            return cb;

        }

    } 

    public static class GenealogyModel implements TreeModel {

        private boolean showAncestors;
        private Vector<TreeModelListener> treeModelListeners
                = new Vector<TreeModelListener>();
        private Person rootPerson;

        public GenealogyModel(Person root) {
            showAncestors = false;
            rootPerson = root;
        }

        /**
         * Used to toggle between show ancestors/show descendant and to change the
         * root of the tree.
         */
        public void showAncestor(boolean b, Object newRoot) {
            showAncestors = b;
            Person oldRoot = rootPerson;
            if (newRoot != null) {
                rootPerson = (Person) newRoot;
            }
            fireTreeStructureChanged(oldRoot);
        }

//////////////// Fire events //////////////////////////////////////////////
        /**
         * The only event raised by this model is TreeStructureChanged with the root
         * as path, i.e. the whole tree has changed.
         */
        protected void fireTreeStructureChanged(Person oldRoot) {
            int len = treeModelListeners.size();
            TreeModelEvent e = new TreeModelEvent(this,
                    new Object[]{oldRoot});
            for (TreeModelListener tml : treeModelListeners) {
                tml.treeStructureChanged(e);
            }
        }

//////////////// TreeModel interface implementation ///////////////////////
        /**
         * Adds a listener for the TreeModelEvent posted after the tree changes.
         */
        public void addTreeModelListener(TreeModelListener l) {
            treeModelListeners.addElement(l);
        }

        /**
         * Returns the child of parent at index index in the parent's child array.
         */
        public Object getChild(Object parent, int index) {
            Person p = (Person) parent;
            if (showAncestors) {
                if ((index > 0) && (p.getFather() != null)) {
                    return p.getMother();
                }
                return p.getFather();
            }
            return p.getChildAt(index);
        }

        /**
         * Returns the number of children of parent.
         */
        public int getChildCount(Object parent) {
            Person p = (Person) parent;
            if (showAncestors) {
                int count = 0;
                if (p.getFather() != null) {
                    count++;
                }
                if (p.getMother() != null) {
                    count++;
                }
                return count;
            }
            return p.getChildCount();
        }

        /**
         * Returns the index of child in parent.
         */
        public int getIndexOfChild(Object parent, Object child) {
            Person p = (Person) parent;
            if (showAncestors) {
                int count = 0;
                Person father = p.getFather();
                if (father != null) {
                    count++;
                    if (father == child) {
                        return 0;
                    }
                }
                if (p.getMother() != child) {
                    return count;
                }
                return -1;
            }
            return p.getIndexOfChild((Person) child);
        }

        /**
         * Returns the root of the tree.
         */
        public Object getRoot() {
            return rootPerson;
        }

        /**
         * Returns true if node is a leaf.
         */
        public boolean isLeaf(Object node) {
            Person p = (Person) node;
            if (showAncestors) {
                return ((p.getFather() == null)
                        && (p.getMother() == null));
            }
            return p.getChildCount() == 0;
        }

        /**
         * Removes a listener previously added with addTreeModelListener().
         */
        public void removeTreeModelListener(TreeModelListener l) {
            treeModelListeners.removeElement(l);
        }

        /**
         * Messaged when the user has altered the value for the item identified by
         * path to newValue. Not used by this model.
         */
        public void valueForPathChanged(TreePath path, Object newValue) {
            System.out.println("*** valueForPathChanged : "
                    + path + " --> " + newValue);
        }
    }

    public static class Person {

        Person father;
        Person mother;
        List<Person> children;
        private String name;

        public Person(String name) {
            this.name = name;
            mother = father = null;
            children = new ArrayList<Person>();
        }

        /**
         * Link together all members of a family.
         *
         * @param pa the father
         * @param ma the mother
         * @param kids the children
         */
        public static void linkFamily(Person pa,
                Person ma,
                Person[] kids) {
            for (Person kid : kids) {
                pa.children.add(kid);
                ma.children.add(kid);
                kid.father = pa;
                kid.mother = ma;
            }
        }

/// getter methods ///////////////////////////////////
        public String toString() {
            return name;
        }

        public String getName() {
            return name;
        }

        public Person getFather() {
            return father;
        }

        public Person getMother() {
            return mother;
        }

        public int getChildCount() {
            return children.size();
        }

        public Person getChildAt(int i) {
            return (Person) children.get(i);
        }

        public int getIndexOfChild(Person kid) {
            return children.indexOf(kid);
        }
    }
}

答案 1 :(得分:2)

Sturm提供了大部分解决方案。

这个难题的缺失部分是你可以从JTree得到JXTreeTable,如下所示:

JTree tree = (JTree) treeTable.getCellRenderer(0, treeTable.getHierarchicalColumn())

这有点像黑客,但我不知道他们是否有更好的API来实现它。

答案 2 :(得分:1)

通过几分钟的Google搜索,我发现了这个CheckBox node tree sampleblog post about JXTreeTable with CheckBoxes以及此very simple solution

这不是你想要的吗?