Java中带复选框的微信牛牛房卡开发的实现和应用

在使用Java Swing开发微信牛牛房卡开发(h5.fanshubbs.com)程序时,很有可能会遇到使用带复选框的微信牛牛房卡开发的需求,但是Java Swing并没有提供这个组件,因此如果你有这个需求,你就得自己动身实现带复选框的树。
CheckBoxTree与JTree在两个层面上存在差异:
[li]在模型层上,CheckBoxTree的每个结点需要一个成员来保存其是否被选中,但是JTree的结点则不需要。[/li][li]在视图层上,CheckBoxTree的每个结点比JTree的结点多显示一个微信牛牛房卡开发。[/li]

既然存在两个差异,那么只要我们把这两个差异部分通过自己的实现填补上,那么带复选框的微信牛牛房卡开发也就实现了。
现在开始解决第一个差异。为了解决第一个差异,需要定义一个新的结点类CheckBoxTreeNode,该类继承DefaultMutableTreeNode,并增加新的成员isSelected来表示该结点是否被选中。对于一颗CheckBoxTree,如果某一个结点被选中的话,其复选框会勾选上,并且使用CheckBoxTree的动机在于可以一次性地选中一颗微信牛牛房卡开发。那么,在选中或取消一个结点时,其祖先结点和子孙结点应该做出某种变化。在此,我们应用如下递归规则:
[li]如果某个结点被手动选中,那么它的所有子孙结点都应该被选中;如果选中该结点使其父节点的所有子结点都被选中,则选中其父结点。[/li][li]如果某个结点被手动取消选中,那么它的所有子孙结点都应该被取消选中;如果该结点的父结点处于选中状态,则取消选中其父结点。[/li]

注意:上面的两条规则是递归规则,当某个结点发生变化,导致另外的结点发生变化时,另外的结点也会导致其他的结点发生变化。在上面两条规则中,强调手动,是因为手动选中或者手动取消选中一个结点,会导致其他结点发生非手动的选中或者取消选中,这种非手动导致的选中或者非取消选中则不适用于上述规则。
按照上述微信牛牛房卡开发规则实现的CheckBoxTreeNode源代码如下:

[li]package demo;??[/li][li]??[/li][li]import javax.swing.tree.DefaultMutableTreeNode;??[/li][li]??[/li][li]public class CheckBoxTreeNode extends DefaultMutableTreeNode??[/li][li]{??[/li][li]? ? protected boolean isSelected;??[/li][li]? ?? ?[/li][li]? ? public CheckBoxTreeNode()??[/li][li]? ? {??[/li][li]? ?? ???this(null);??[/li][li]? ? }??[/li][li]? ?? ?[/li][li]? ? public CheckBoxTreeNode(Object userObject)??[/li][li]? ? {??[/li][li]? ?? ???this(userObject, true, false);??[/li][li]? ? }??[/li][li]? ?? ?[/li][li]? ? public CheckBoxTreeNode(Object userObject, boolean allowsChildren, boolean isSelected)??[/li][li]? ? {??[/li][li]? ?? ???super(userObject, allowsChildren);??[/li][li]? ?? ???this.isSelected = isSelected;??[/li][li]? ? }??[/li][li]??[/li][li]? ? public boolean isSelected()??[/li][li]? ? {??[/li][li]? ?? ???return isSelected;??[/li][li]? ? }??[/li][li]? ?? ?[/li][li]? ? public void setSelected(boolean _isSelected)??[/li][li]? ? {??[/li][li]? ?? ???this.isSelected = _isSelected;??[/li][li]? ?? ?? ? [/li][li]? ?? ???if(_isSelected)??[/li][li]? ?? ???{??[/li][li]? ?? ?? ?? ?// 如果选中,则将其所有的子结点都选中??[/li][li]? ?? ?? ?? ?if(children != null)??[/li][li]? ?? ?? ?? ?{??[/li][li]? ?? ?? ?? ?? ? for(Object obj : children)??[/li][li]? ?? ?? ?? ?? ? {??[/li][li]? ?? ?? ?? ?? ?? ???CheckBoxTreeNode node = (CheckBoxTreeNode)obj;??[/li][li]? ?? ?? ?? ?? ?? ???if(_isSelected != node.isSelected())??[/li][li]? ?? ?? ?? ?? ?? ?? ?? ?node.setSelected(_isSelected);??[/li][li]? ?? ?? ?? ?? ? }??[/li][li]? ?? ?? ?? ?}??[/li][li]? ?? ?? ?? ?// 向上检查,如果父结点的所有子结点都被选中,那么将父结点也选中??[/li][li]? ?? ?? ?? ?CheckBoxTreeNode pNode = (CheckBoxTreeNode)parent;??[/li][li]? ?? ?? ?? ?// 开始检查pNode的所有子节点是否都被选中??[/li][li]? ?? ?? ?? ?if(pNode != null)??[/li][li]? ?? ?? ?? ?{??[/li][li]? ?? ?? ?? ?? ? int index = 0;??[/li][li]? ?? ?? ?? ?? ? for(; index < pNode.children.size(); ++ index)??[/li][li]? ?? ?? ?? ?? ? {??[/li][li]? ?? ?? ?? ?? ?? ???CheckBoxTreeNode pChildNode = (CheckBoxTreeNode)pNode.children.get(index);??[/li][li]? ?? ?? ?? ?? ?? ???if(!pChildNode.isSelected())??[/li][li]? ?? ?? ?? ?? ?? ?? ?? ?break;??[/li][li]? ?? ?? ?? ?? ? }??[/li][li]? ?? ?? ?? ?? ? /??[/li][li]? ?? ?? ?? ?? ??? 表明pNode所有子结点都已经选中,则选中父结点, [/li][li]? ?? ?? ?? ?? ??? 该方法是一个递归方法,因此在此不需要进行迭代,因为 [/li][li]? ?? ?? ?? ?? ??? 当选中父结点后,父结点本身会向上检查的。 [/li][li]? ?? ?? ?? ?? ???/??[/li][li]? ?? ?? ?? ?? ? if(index == pNode.children.size())??[/li][li]? ?? ?? ?? ?? ? {??[/li][li]? ?? ?? ?? ?? ?? ???if(pNode.isSelected() != _isSelected)??[/li][li]? ?? ?? ?? ?? ?? ?? ?? ?pNode.setSelected(_isSelected);??[/li][li]? ?? ?? ?? ?? ? }??[/li][li]? ?? ?? ?? ?}??[/li][li]? ?? ???}??[/li][li]? ?? ???else? ?[/li][li]? ?? ???{??[/li][li]? ?? ?? ?? ?/ [/li][li]? ?? ?? ?? ? 如果是取消父结点导致子结点取消,那么此时所有的子结点都应该是选择上的; [/li][li]? ?? ?? ?? ? 否则就是子结点取消导致父结点取消,然后父结点取消导致需要取消子结点,但 [/li][li]? ?? ?? ?? ? 是这时候是不需要取消子结点的。 [/li][li]? ?? ?? ?? ? /??[/li][li]? ?? ?? ?? ?if(children != null)??[/li][li]? ?? ?? ?? ?{??[/li][li]? ?? ?? ?? ?? ? int index = 0;??[/li][li]? ?? ?? ?? ?? ? for(; index < children.size(); ++ index)??[/li][li]? ?? ?? ?? ?? ? {??[/li][li]? ?? ?? ?? ?? ?? ???CheckBoxTreeNode childNode = (CheckBoxTreeNode)children.get(index);??[/li][li]? ?? ?? ?? ?? ?? ???if(!childNode.isSelected())??[/li][li]? ?? ?? ?? ?? ?? ?? ?? ?break;??[/li][li]? ?? ?? ?? ?? ? }??[/li][li]? ?? ?? ?? ?? ? // 从上向下取消的时候??[/li][li]? ?? ?? ?? ?? ? if(index == children.size())??[/li][li]? ?? ?? ?? ?? ? {??[/li][li]? ?? ?? ?? ?? ?? ???for(int i = 0; i < children.size(); ++ i)??[/li][li]? ?? ?? ?? ?? ?? ???{??[/li][li]? ?? ?? ?? ?? ?? ?? ?? ?CheckBoxTreeNode node = (CheckBoxTreeNode)children.get(i);??[/li][li]? ?? ?? ?? ?? ?? ?? ?? ?if(node.isSelected() != _isSelected)??[/li][li]? ?? ?? ?? ?? ?? ?? ?? ?? ? node.setSelected(_isSelected);??[/li][li]? ?? ?? ?? ?? ?? ???}??[/li][li]? ?? ?? ?? ?? ? }??[/li][li]? ?? ?? ?? ?}??[/li][li]? ?? ?? ?? ???[/li][li]? ?? ?? ?? ?// 向上取消,只要存在一个子节点不是选上的,那么父节点就不应该被选上。??[/li][li]? ?? ?? ?? ?CheckBoxTreeNode pNode = (CheckBoxTreeNode)parent;??[/li][li]? ?? ?? ?? ?if(pNode != null ;; pNode.isSelected() != _isSelected)??[/li][li]? ?? ?? ?? ?? ? pNode.setSelected(_isSelected);??[/li][li]? ?? ???}??[/li][li]? ? }??[/li][li]}??[/li]
package demo;import javax.swing.tree.DefaultMutableTreeNode;public class CheckBoxTreeNode extends DefaultMutableTreeNode{protected boolean isSelected;public CheckBoxTreeNode(){this(null);}public CheckBoxTreeNode(Object userObject){this(userObject, true, false);}public CheckBoxTreeNode(Object userObject, boolean allowsChildren, boolean isSelected){super(userObject, allowsChildren);this.isSelected = isSelected;}public boolean isSelected(){return isSelected;}public void setSelected(boolean _isSelected){this.isSelected = _isSelected;if(_isSelected){// 如果选中,则将其所有的子结点都选中if(children != null){for(Object obj : children){CheckBoxTreeNode node = (CheckBoxTreeNode)obj;if(_isSelected != node.isSelected())node.setSelected(_isSelected);}}// 向上检查,如果父结点的所有子结点都被选中,那么将父结点也选中CheckBoxTreeNode pNode = (CheckBoxTreeNode)parent;// 开始检查pNode的所有子节点是否都被选中if(pNode != null){int index = 0;for(; index < pNode.children.size(); ++ index){CheckBoxTreeNode pChildNode = (CheckBoxTreeNode)pNode.children.get(index);if(!pChildNode.isSelected())break;}/* 表明pNode所有子结点都已经选中,则选中父结点, 该方法是一个递归方法,因此在此不需要进行迭代,因为 当选中父结点后,父结点本身会向上检查的。/if(index == pNode.children.size()){if(pNode.isSelected() != _isSelected)pNode.setSelected(_isSelected);}}}else{/* 如果是取消父结点导致子结点取消,那么此时所有的子结点都应该是选择上的; 否则就是子结点取消导致父结点取消,然后父结点取消导致需要取消子结点,但 是这时候是不需要取消子结点的。/if(children != null){int index = 0;for(; index < children.size(); ++ index){CheckBoxTreeNode childNode = (CheckBoxTreeNode)children.get(index);if(!childNode.isSelected())break;}// 从上向下取消的时候if(index == children.size()){for(int i = 0; i < children.size(); ++ i){CheckBoxTreeNode node = (CheckBoxTreeNode)children.get(i);if(node.isSelected() != _isSelected)node.setSelected(_isSelected);}}}// 向上取消,只要存在一个子节点不是选上的,那么父节点就不应该被选上。CheckBoxTreeNode pNode = (CheckBoxTreeNode)parent;if(pNode != null ;; pNode.isSelected() != _isSelected)pNode.setSelected(_isSelected);}}}
第一个差异通过继承DefaultMutableTreeNode定义CheckBoxTreeNode解决了,接下来需要解决第二个差异。第二个差异是外观上的差异,JTree的每个结点是通过TreeCellRenderer进行显示的。为了解决第二个差异,我们定义一个新的类CheckBoxTreeCellRenderer,该类实现了TreeCellRenderer接口。CheckBoxTreeRenderer的源代码如下:

[li]package demo;??[/li][li]??[/li][li]import java.awt.Color;??[/li][li]import java.awt.Component;??[/li][li]import java.awt.Dimension;??[/li][li]??[/li][li]import javax.swing.JCheckBox;??[/li][li]import javax.swing.JPanel;??[/li][li]import javax.swing.JTree;??[/li][li]import javax.swing.UIManager;??[/li][li]import javax.swing.plaf.ColorUIResource;??[/li][li]import javax.swing.tree.TreeCellRenderer;??[/li][li]??[/li][li]public class CheckBoxTreeCellRenderer extends JPanel implements TreeCellRenderer??[/li][li]{??[/li][li]? ? protected JCheckBox check;??[/li][li]? ? protected CheckBoxTreeLabel label;??[/li][li]? ?? ?[/li][li]? ? public CheckBoxTreeCellRenderer()??[/li][li]? ? {??[/li][li]? ?? ???setLayout(null);??[/li][li]? ?? ???add(check = new JCheckBox());??[/li][li]? ?? ???add(label = new CheckBoxTreeLabel());??[/li][li]? ?? ???check.setBackground(UIManager.getColor("Tree.textBackground"));??[/li][li]? ?? ???label.setForeground(UIManager.getColor("Tree.textForeground"));??[/li][li]? ? }??[/li][li]? ?? ?[/li][li]? ? /* [/li][li]? ??? 返回的是一个<code>JPanel</code>对象,该对象中包含一个<code>JCheckBox</code>对象 [/li][li]? ??? 和一个<code>JLabel</code>对象。并且根据每个结点是否被选中来决定<code>JCheckBox</code> [/li][li]? ??? 是否被选中。 [/li][li]? ???*/??[/li][li]? ? @Override??[/li][li]? ? public Component getTreeCellRendererComponent(JTree tree, Object value,??[/li][li]? ?? ?? ?? ?boolean selected, boolean expanded, boolean leaf, int row,??[/li][li]? ?? ?? ?? ?boolean hasFocus)??[/li][li]? ? {??[/li][li]? ?? ???String stringValue = tree.convertValueToText(value, selected, expanded, leaf, row, hasFocus);??[/li][li]? ?? ???setEnabled(tree.isEnabled());??[/li][li]? ?? ???check.setSelected(((CheckBoxTreeNode)value).isSelected());??[/li][li]? ?? ???label.setFont(tree.getFont());??[/li][li]? ?? ???label.setText(stringValue);??[/li][li]? ?? ???label.setSelected(selected);??[/li][li]? ?? ???label.setFocus(hasFocus);??[/li][li]? ?? ???if(leaf)??[/li][li]? ?? ?? ?? ?label.setIcon(UIManager.getIcon("Tree.leafIcon"));??[/li][li]? ?? ???else if(expanded)??[/li][li]? ?? ?? ?? ?label.setIcon(UIManager.getIcon("Tree.openIcon"));??[/li][li]? ?? ???else??[/li][li]? ?? ?? ?? ?label.setIcon(UIManager.getIcon("Tree.closedIcon"));??[/li][li]? ?? ?? ?? ???[/li][li]? ?? ???return this;??[/li][li]? ? }??[/li][li]??[/li][li]? ? @Override??[/li][li]? ? public Dimension getPreferredSize()??[/li][li]? ? {??[/li][li]? ?? ???Dimension dCheck = check.getPreferredSize();??[/li][li]? ?? ???Dimension dLabel = label.getPreferredSize();??[/li][li]? ?? ???return new Dimension(dCheck.width + dLabel.width, dCheck.height < dLabel.height ? dLabel.height: dCheck.height);??[/li][li]? ? }??[/li][li]? ?? ?[/li][li]? ? @Override??[/li][li]? ? public void doLayout()??[/li][li]? ? {??[/li][li]? ?? ???Dimension dCheck = check.getPreferredSize();??[/li][li]? ?? ???Dimension dLabel = label.getPreferredSize();??[/li][li]? ?? ???int yCheck = 0;??[/li][li]? ?? ???int yLabel = 0;??[/li][li]? ?? ???if(dCheck.height < dLabel.height)??[/li][li]? ?? ?? ?? ?yCheck = (dLabel.height - dCheck.height) / 2;??[/li][li]? ?? ???else??[/li][li]? ?? ?? ?? ?yLabel = (dCheck.height - dLabel.height) / 2;??[/li][li]? ?? ???check.setLocation(0, yCheck);??[/li][li]? ?? ???check.setBounds(0, yCheck, dCheck.width, dCheck.height);??[/li][li]? ?? ???label.setLocation(dCheck.width, yLabel);??[/li][li]? ?? ???label.setBounds(dCheck.width, yLabel, dLabel.width, dLabel.height);??[/li][li]? ? }??[/li][li]? ?? ?[/li][li]? ? @Override??[/li][li]? ? public void setBackground(Color color)??[/li][li]? ? {??[/li][li]? ?? ???if(color instanceof ColorUIResource)??[/li][li]? ?? ?? ?? ?color = null;??[/li][li]? ?? ???super.setBackground(color);??[/li][li]? ? }??[/li][li]}??[/li]
package demo;import java.awt.Color;import java.awt.Component;import java.awt.Dimension;import javax.swing.JCheckBox;import javax.swing.JPanel;import javax.swing.JTree;import javax.swing.UIManager;import javax.swing.plaf.ColorUIResource;import javax.swing.tree.TreeCellRenderer;public class CheckBoxTreeCellRenderer extends JPanel implements TreeCellRenderer{protected JCheckBox check;protected CheckBoxTreeLabel label;public CheckBoxTreeCellRenderer(){setLayout(null);add(check = new JCheckBox());add(label = new CheckBoxTreeLabel());check.setBackground(UIManager.getColor("Tree.textBackground"));label.setForeground(UIManager.getColor("Tree.textForeground"));}/** 返回的是一个<code>JPanel</code>对象,该对象中包含一个<code>JCheckBox</code>对象 和一个<code>JLabel</code>对象。并且根据每个结点是否被选中来决定<code>JCheckBox</code> 是否被选中。/@Overridepublic Component getTreeCellRendererComponent(JTree tree, Object value,boolean selected, boolean expanded, boolean leaf, int row,boolean hasFocus){String stringValue = tree.convertValueToText(value, selected, expanded, leaf, row, hasFocus);setEnabled(tree.isEnabled());check.setSelected(((CheckBoxTreeNode)value).isSelected());label.setFont(tree.getFont());label.setText(stringValue);label.setSelected(selected);label.setFocus(hasFocus);if(leaf)label.setIcon(UIManager.getIcon("Tree.leafIcon"));else if(expanded)label.setIcon(UIManager.getIcon("Tree.openIcon"));elselabel.setIcon(UIManager.getIcon("Tree.closedIcon"));return this;}@Overridepublic Dimension getPreferredSize(){Dimension dCheck = check.getPreferredSize();Dimension dLabel = label.getPreferredSize();return new Dimension(dCheck.width + dLabel.width, dCheck.height < dLabel.height ? dLabel.height: dCheck.height);}@Overridepublic void doLayout(){Dimension dCheck = check.getPreferredSize();Dimension dLabel = label.getPreferredSize();int yCheck = 0;int yLabel = 0;if(dCheck.height < dLabel.height)yCheck = (dLabel.height - dCheck.height) / 2;elseyLabel = (dCheck.height - dLabel.height) / 2;check.setLocation(0, yCheck);check.setBounds(0, yCheck, dCheck.width, dCheck.height);label.setLocation(dCheck.width, yLabel);label.setBounds(dCheck.width, yLabel, dLabel.width, dLabel.height);}@Overridepublic void setBackground(Color color){if(color instanceof ColorUIResource)color = null;super.setBackground(color);}}在CheckBoxTreeCellRenderer的实现中,为了处理背景色等问题,我们重新实现了微信牛牛房卡开发一个JLabel的子类CheckBoxTreeLabel,其源代码如下:
[li]package demo;??[/li][li]??[/li][li]import java.awt.Color;??[/li][li]import java.awt.Dimension;??[/li][li]import java.awt.Graphics;??[/li][li]??[/li][li]import javax.swing.Icon;??[/li][li]import javax.swing.JLabel;??[/li][li]import javax.swing.UIManager;??[/li][li]import javax.swing.plaf.ColorUIResource;??[/li][li]??[/li][li]public class CheckBoxTreeLabel extends JLabel??[/li][li]{??[/li][li]? ? private boolean isSelected;??[/li][li]? ? private boolean hasFocus;??[/li][li]? ?? ?[/li][li]? ? public CheckBoxTreeLabel()??[/li][li]? ? {??[/li][li]? ? }??[/li][li]? ?? ?[/li][li]? ? @Override??[/li][li]? ? public void setBackground(Color color)??[/li][li]? ? {??[/li][li]? ?? ???if(color instanceof ColorUIResource)??[/li][li]? ?? ?? ?? ?color = null;??[/li][li]? ?? ???super.setBackground(color);??[/li][li]? ? }??[/li][li]? ?? ?[/li][li]? ? @Override??[/li][li]? ? public void paint(Graphics g)??[/li][li]? ? {??[/li][li]? ?? ???String str;??[/li][li]? ?? ???if((str = getText()) != null)??[/li][li]? ?? ???{??[/li][li]? ?? ?? ?? ?if(0 < str.length())??[/li][li]? ?? ?? ?? ?{??[/li][li]? ?? ?? ?? ?? ? if(isSelected)??[/li][li]? ?? ?? ?? ?? ?? ???g.setColor(UIManager.getColor("Tree.selectionBackground"));??[/li][li]? ?? ?? ?? ?? ? else??[/li][li]? ?? ?? ?? ?? ?? ???g.setColor(UIManager.getColor("Tree.textBackground"));??[/li][li]? ?? ?? ?? ?? ? Dimension d = getPreferredSize();??[/li][li]? ?? ?? ?? ?? ? int imageOffset = 0;??[/li][li]? ?? ?? ?? ?? ? Icon currentIcon = getIcon();??[/li][li]? ?? ?? ?? ?? ? if(currentIcon != null)??[/li][li]? ?? ?? ?? ?? ?? ???imageOffset = currentIcon.getIconWidth() + Math.max(0, getIconTextGap() - 1);??[/li][li]? ?? ?? ?? ?? ? g.fillRect(imageOffset, 0, d.width - 1 - imageOffset, d.height);??[/li][li]? ?? ?? ?? ?? ? if(hasFocus)??[/li][li]? ?? ?? ?? ?? ? {??[/li][li]? ?? ?? ?? ?? ?? ???g.setColor(UIManager.getColor("Tree.selectionBorderColor"));??[/li][li]? ?? ?? ?? ?? ?? ???g.drawRect(imageOffset, 0, d.width - 1 - imageOffset, d.height - 1);??[/li][li]? ?? ?? ?? ?? ? }??[/li][li]? ?? ?? ?? ?}??[/li][li]? ?? ???}??[/li][li]? ?? ???super.paint(g);??[/li][li]? ? }??[/li][li]? ?? ?[/li][li]? ? @Override??[/li][li]? ? public Dimension getPreferredSize()??[/li][li]? ? {??[/li][li]? ?? ???Dimension retDimension = super.getPreferredSize();??[/li][li]? ?? ???if(retDimension != null)??[/li][li]? ?? ?? ?? ?retDimension = new Dimension(retDimension.width + 3, retDimension.height);??[/li][li]? ?? ???return retDimension;??[/li][li]? ? }??[/li][li]? ?? ?[/li][li]? ? public void setSelected(boolean isSelected)??[/li][li]? ? {??[/li][li]? ?? ???this.isSelected = isSelected;??[/li][li]? ? }??[/li][li]? ?? ?[/li][li]? ? public void setFocus(boolean hasFocus)??[/li][li]? ? {??[/li][li]? ?? ???this.hasFocus = hasFocus;??[/li][li]? ? }??[/li][li]}??[/li]
package demo;import java.awt.Color;import java.awt.Dimension;import java.awt.Graphics;import javax.swing.Icon;import javax.swing.JLabel;import javax.swing.UIManager;import javax.swing.plaf.ColorUIResource;public class CheckBoxTreeLabel extends JLabel{private boolean isSelected;private boolean hasFocus;public CheckBoxTreeLabel(){}@Overridepublic void setBackground(Color color){if(color instanceof ColorUIResource)color = null;super.setBackground(color);}@Overridepublic void paint(Graphics g){String str;if((str = getText()) != null){if(0 < str.length()){if(isSelected)g.setColor(UIManager.getColor("Tree.selectionBackground"));elseg.setColor(UIManager.getColor("Tree.textBackground"));Dimension d = getPreferredSize();int imageOffset = 0;Icon currentIcon = getIcon();if(currentIcon != null)imageOffset = currentIcon.getIconWidth() + Math.max(0, getIconTextGap() - 1);g.fillRect(imageOffset, 0, d.width - 1 - imageOffset, d.height);if(hasFocus){g.setColor(UIManager.getColor("Tree.selectionBorderColor"));g.drawRect(imageOffset, 0, d.width - 1 - imageOffset, d.height - 1);}}}super.paint(g);}@Overridepublic Dimension getPreferredSize(){Dimension retDimension = super.getPreferredSize();if(retDimension != null)retDimension = new Dimension(retDimension.width + 3, retDimension.height);return retDimension;}public void setSelected(boolean isSelected){this.isSelected = isSelected;}public void setFocus(boolean hasFocus){this.hasFocus = hasFocus;}}
通过定义CheckBoxTreeNode和CheckBoxTreeCellRenderer。我们解决了CheckBoxTree和JTree的两个根本差异,但是还有一个细节问题需要解决,就是CheckBoxTree可以响应用户事件决定是否选中某个结点。为此,我们为CheckBoxTree添加一个响应用户鼠标事件的监听器CheckBoxTreeNodeSelectionListener,该类的源代码如下:

[li]package demo;??[/li][li]??[/li][li]import java.awt.event.MouseAdapter;??[/li][li]import java.awt.event.MouseEvent;??[/li][li]??[/li][li]import javax.swing.JTree;??[/li][li]import javax.swing.tree.TreePath;??[/li][li]import javax.swing.tree.DefaultTreeModel;??[/li][li]??[/li][li]public class CheckBoxTreeNodeSelectionListener extends MouseAdapter??[/li][li]{??[/li][li]? ? @Override??[/li][li]? ? public void mouseClicked(MouseEvent event)??[/li][li]? ? {??[/li][li]? ?? ???JTree tree = (JTree)event.getSource();??[/li][li]? ?? ???int x = event.getX();??[/li][li]? ?? ???int y = event.getY();??[/li][li]? ?? ???int row = tree.getRowForLocation(x, y);??[/li][li]? ?? ???TreePath path = tree.getPathForRow(row);??[/li][li]? ?? ???if(path != null)??[/li][li]? ?? ???{??[/li][li]? ?? ?? ?? ?CheckBoxTreeNode node = (CheckBoxTreeNode)path.getLastPathComponent();??[/li][li]? ?? ?? ?? ?if(node != null)??[/li][li]? ?? ?? ?? ?{??[/li][li]? ?? ?? ?? ?? ? boolean isSelected = !node.isSelected();??[/li][li]? ?? ?? ?? ?? ? node.setSelected(isSelected);??[/li][li]? ?? ?? ?? ?? ? ((DefaultTreeModel)tree.getModel()).nodeStructureChanged(node);??[/li][li]? ?? ?? ?? ?}??[/li][li]? ?? ???}??[/li][li]? ? }??[/li][li]}??[/li]
package demo;import java.awt.event.MouseAdapter;import java.awt.event.MouseEvent;import javax.swing.JTree;import javax.swing.tree.TreePath;import javax.swing.tree.DefaultTreeModel;public class CheckBoxTreeNodeSelectionListener extends MouseAdapter{@Overridepublic void mouseClicked(MouseEvent event){JTree tree = (JTree)event.getSource();int x = event.getX();int y = event.getY();int row = tree.getRowForLocation(x, y);TreePath path = tree.getPathForRow(row);if(path != null){CheckBoxTreeNode node = (CheckBoxTreeNode)path.getLastPathComponent();if(node != null){boolean isSelected = !node.isSelected();node.setSelected(isSelected);((DefaultTreeModel)tree.getModel()).nodeStructureChanged(node);}}}}到此为止,CheckBoxTree所需要的所有组件都已经完成了,接下来就是如何使用这些组件。下面给出了使用微信牛牛房卡开发这些组件的源代码:

[li]package demo;??[/li][li]??[/li][li]import javax.swing.JFrame;??[/li][li]import javax.swing.JScrollPane;??[/li][li]import javax.swing.JTree;??[/li][li]import javax.swing.tree.DefaultTreeModel;??[/li][li]??[/li][li]public class DemoMain? ?[/li][li]{??[/li][li]? ? public static void main(String[] args)??[/li][li]? ? {??[/li][li]? ?? ???JFrame frame = new JFrame("CheckBoxTreeDemo");??[/li][li]? ?? ???frame.setBounds(200, 200, 400, 400);??[/li][li]? ?? ???JTree tree = new JTree();??[/li][li]? ?? ???CheckBoxTreeNode rootNode = new CheckBoxTreeNode("root");??[/li][li]? ?? ???CheckBoxTreeNode node1 = new CheckBoxTreeNode("node_1");??[/li][li]? ?? ???CheckBoxTreeNode node1_1 = new CheckBoxTreeNode("node_1_1");??[/li][li]? ?? ???CheckBoxTreeNode node1_2 = new CheckBoxTreeNode("node_1_2");??[/li][li]? ?? ???CheckBoxTreeNode node1_3 = new CheckBoxTreeNode("node_1_3");??[/li][li]? ?? ???node1.add(node1_1);??[/li][li]? ?? ???node1.add(node1_2);??[/li][li]? ?? ???node1.add(node1_3);??[/li][li]? ?? ???CheckBoxTreeNode node2 = new CheckBoxTreeNode("node_2");??[/li][li]? ?? ???CheckBoxTreeNode node2_1 = new CheckBoxTreeNode("node_2_1");??[/li][li]? ?? ???CheckBoxTreeNode node2_2 = new CheckBoxTreeNode("node_2_2");??[/li][li]? ?? ???node2.add(node2_1);??[/li][li]? ?? ???node2.add(node2_2);??[/li][li]? ?? ???rootNode.add(node1);??[/li][li]? ?? ???rootNode.add(node2);??[/li][li]? ?? ???DefaultTreeModel model = new DefaultTreeModel(rootNode);??[/li][li]? ?? ???tree.addMouseListener(new CheckBoxTreeNodeSelectionListener());??[/li][li]? ?? ???tree.setModel(model);??[/li][li]? ?? ???tree.setCellRenderer(new CheckBoxTreeCellRenderer());??[/li][li]? ?? ???JScrollPane scroll = new JScrollPane(tree);??[/li][li]? ?? ???scroll.setBounds(0, 0, 300, 320);??[/li][li]? ?? ???frame.getContentPane().add(scroll);??[/li][li]? ?? ?? ? [/li][li]? ?? ???frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);??[/li][li]? ?? ???frame.setVisible(true);??[/li][li]? ? }??[/li][li]}??[/li]
package demo;import javax.swing.JFrame;import javax.swing.JScrollPane;import javax.swing.JTree;import javax.swing.tree.DefaultTreeModel;public class DemoMain{public static void main(String[] args){JFrame frame = new JFrame("CheckBoxTreeDemo");frame.setBounds(200, 200, 400, 400);JTree tree = new JTree();CheckBoxTreeNode rootNode = new CheckBoxTreeNode("root");CheckBoxTreeNode node1 = new CheckBoxTreeNode("node_1");CheckBoxTreeNode node1_1 = new CheckBoxTreeNode("node_1_1");CheckBoxTreeNode node1_2 = new CheckBoxTreeNode("node_1_2");CheckBoxTreeNode node1_3 = new CheckBoxTreeNode("node_1_3");node1.add(node1_1);node1.add(node1_2);node1.add(node1_3);CheckBoxTreeNode node2 = new CheckBoxTreeNode("node_2");CheckBoxTreeNode node2_1 = new CheckBoxTreeNode("node_2_1");CheckBoxTreeNode node2_2 = new CheckBoxTreeNode("node_2_2");node2.add(node2_1);node2.add(node2_2);rootNode.add(node1);rootNode.add(node2);DefaultTreeModel model = new DefaultTreeModel(rootNode);tree.addMouseListener(new CheckBoxTreeNodeSelectionListener());tree.setModel(model);tree.setCellRenderer(new CheckBoxTreeCellRenderer());JScrollPane scroll = new JScrollPane(tree);scroll.setBounds(0, 0, 300, 320);frame.getContentPane().add(scroll);frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);frame.setVisible(true);}}其执行微信牛牛房卡开发结果:

原文地址:http://blog.51cto.com/13566796/2058685

时间: 2024-11-03 03:25:16

Java中带复选框的微信牛牛房卡开发的实现和应用的相关文章

如何在select下拉列表中添加复选框?

近来在给一个公司做考试系统的项目,遇到的问题不少,但其中的几个让我对表单的使用颇为感兴趣,前端程序员都知道,下拉列表有select标签,复选框有checkbox,但是两者合在一起却少有人去研究,当时接到这样的要求时我也蒙了,于是去网上查相关资料,查了好久,查不出个结果,只好自己用纯html css jq去做一个仿下拉列表中自带复选框的效果,代码如下,可直接复制去查看效果, 注:(以下代码为本人自己编写,只是一个小Demo,可以直接复制使用,但代码只是演示其效果和功能,告诉大家如何去写,所以界面可

在php中验证复选框

PHP接收多个同名复选框信息不像ASP那样自动转换成为数组,这给使用带来了一定不便.但是还是有解决办法的,就是利用javascript做一下预处理.多个同名复选框在javascript中还是以数组的形式存在的,所以在表单提交之前可以利用javascript把复选框中的信息组合成一个字符数组赋值给表单中的隐藏元素,然后用PHP中的explode函数解析此数组,这样就可以实现复选框信息的传递了.下面举例说明. 假设有这样一个表单: <form name="form1" id=&quo

QTableView中嵌入复选框CheckBox 的四种方法总结

搜索了一下,QTableView中嵌入复选框CheckBox方法有四种: 第一种不能之前显示,必须双击/选中后才能显示,不适用. 第二种比较简单,通常用这种方法. 第三种只适合静态显示静态数据用 第四种比较适合扩展,它除了可以嵌入复选框,还可以通过paint()绘制其它控件,图片等自定义风格. 第一种方法是:编辑委托法 这种方法直接利用委托中重载createEditor(),激活QCheckBox,这个缺点是必须双击/选中,才能显示CheckBox控件.一般不满足我们实际中的直接显示的需要.可以

C# Word中插入复选框选中符号

object fontname = "Wingdings 2";  object uic = true;    doc.Bookmarks.get_Item(ref lblmark).Range.InsertSymbol(-4014, ref fontname, ref uic, ref missing); C# Word中插入复选框选中符号,布布扣,bubuko.com

带复选框的下拉框

效果图: . css: <style type="text/css"> /* 带复选框的下拉框 */ ul li{ list-style: none; padding:0px; margin: 0px; } .select_checkBox{ border:0px solid red; position: relative; display:inline-block; } .chartQuota{ height:23px; float:left; display:inlin

jQuery+SpringMVC中的复选框选择与传值

一.checkbox选择 在jQuery中,选中checkbox通用的两种方式: $("#cb1").attr("checked","checked");$("#cb1").attr("checked",true); 对应的jQuery函数,主要完成三个功能: 1.第一个复选框选中或取消选中,则下面的复选框为全选或取消全选: 2.当下面的复选框全部选中时,则将第一个复选框设置为选中,当下面的复选框中有一个没

nodetree中 前面复选框禁用插件

nodetree中 前面复选框的去掉插件 extendTreeCheck.js 1 /** 2 * tree方法扩展 3 * 作者:小雪转中雪 4 */ 5 $.extend($.fn.tree.methods, { 6 /** 7 * 激活复选框 8 * @param {Object} jq 9 * @param {Object} target 10 */ 11 enableCheck : function(jq, target) { 12 return jq.each(function(){

Itext填写pdf中的复选框

使用Acrobat制作模板,在赋值的时候发现一个问题,对于模板中的复选框CheckBox,使用了默认导入值"是",结果复选框内显示的是一个叉而不是一个√. 翻看了很多的资料,也找不到解决的方法,如果有哪位大神知道的,能不能指导一下,不胜感激. 在这里说一下我自己的解决方法: 就是利用反向思维,不是需要在复选框内打勾吗?那么我就先将模板中的复选框全部打上√. 然后再赋值"否",问题可以解决,就是麻烦了很多. 原文地址:https://www.cnblogs.com/c

制作带复选框的ListView控件

实现效果: 知识运用   ListView控件的GridLines //设置是否在ListView控件中显示网格线 public bool GridLines{get;set} 和CheckBoxes属性 //设置listView控件中各数据项是否显示复选框 public bool CheckBoxes{get;set} 以及ListViewItem数据项的Checked属性 //判断是否选中此数据项中的复选框 public bool Checked{get;set} 实现代码: private