??xml version="1.0" encoding="utf-8" standalone="yes"?> 树遍历这个概念先提一下:遍历即逐个讉KQ对于树而言主要有三U:前序Q后序,中序遍历树的每个节点。遍历一般是用递归法来实现的Q三U遍历法区别于先讉K树的那个部分。树遍历也是比较隄一个技术,不好掌握Q我在大学时用汇~实现过q三U算法,到现在还记忆ҎQ完全自己找到的规律Q,一下来和朋友们分n一下?br />
对于一个有两个子节点的树(或多个子节点Q,请你沿着树的外围M个轮廓线Q?/p>
——?gt; >—————?br />
/ \ q是大致l树行走的轮廓线Q大安知道Q或怽q不知道Q函数的调用时控制流的传递就是这个样子的。(控制是U程执行Ҏ时的形象表述Q比如一下函敎ͼ main(){ f1(); return出口?nbsp; } 中序遍历Q亦U广度优先遍历,L先遍历树的根Q?/p>
traversTree(Node root){ } 后序遍历Q亦U深度优先搜索)Q?br />
traversTree(Node root){ } 以上三个法Q可能有点不正确Q我没测试过Q时间太久了有点忘了QM为大家做个参考吧Q?br />
因ؓ树结构典型的是应用了l合设计模式Q所以只要涉及到树肯定涉及遍历,和递归。所以这里罗嗦一下?nbsp; 所有的树都是节?nbsp; JTree的构造:可用默认的构造方法,提供一个TreeNode作ؓ其根节点Q提供一个TreeModel包含所有其它的节点Q或提供一个一l数l,向量Q或对象的哈希表Q对于这些集合中的单个元素,如果它又是一个集合,那么他们会被解释昄为子树,该功能由JTree的内部类DynamicUtilTreeNode完成?br />
*** 因ؓ模型和视N能够触发事gQ比如视图(JTree{控Ӟ是触发用戯入导致的事gQ而模型触发的事g是因为模型中l护的数据有所变动才触发的Q比如,树模型中树节点的增删Q改Q或树\径的变动Q。而他们都使用了观察者模式,了不多说了Q到时全弄成模式了,会搞昏大家的。l?... JTree的setModel和getModelҎ是用来更?讄和获取模型的Ҏ。你可替换现有JTree的模型,或者你惌LQ两个模型,一个用Q一个备。如果构造模型复杂耗时的话Q先在后台构造好一个在换掉原先的。就如同双缓冲技术的思\那样?br />
**** TreePathQ该cȝ一pd节点表示一个从树根C个节点的路径Q它是只ȝQ提供与其他路径比较的能力?br />
TreeCellRenderrer接口Q渲染tree的一个单元的lgQ我们自己实现该接口q用jtree的setCellRendererQ)Ҏ替换原先的渲染器Q可以是树节点在选中Q获取焦点,不同的树状态(叶子或父节点Q展开Q或收羃Q等不同的状态下的外观?br />
DefaultTreeCellRenderercLTreeCellRenderrer接口的默认实玎ͼ它扩展了JLabelQƈZ以上描述的树状态来渲染树节点,其提供的属性包括图标,背景Ԍ前景色等Q其get和setҎ是我们可以访问的Q通过q些Ҏ你当然可以换掉树节点的图标了?/p>
CellEditor接口Q定义了控制何时~辑开始,l束Q提取一个新的结果,是否~辑h改变当前lg的选择Q请参考API文档看该接口的方法。该接口在JTree和JTable中都有用到。,该接口也可以d监听器,当编辑停止或取消时会Ȁ发ChangeEvents到其所有的注册处理器哪里?br />
TreeCellEditor接口扩展了CellEditor接口Qjtree的setCellEditor()使得我们可以用Q何一个可充当~辑器的lg替换掉原来的那个。DefaultCellEditor实现了该接口Q这个编辑器允许使用JTextFieldQJComboBox或是JCheckBoxlg来编辑数据,其保护的内部cEditorDelegate会响应getCellEditorValueQ)Ҏ把当前D回。DefaultCellEditor仅基于以上三个J控g作ؓ~辑器,其clickCountToStartҎ军_鼠标单击几次会触发编辑。默认对于JTextField是两ơ,JComboBox和JCheckBox是一ơ,changeEvents会在stopCellEditingQ)和cancelCellEditingQ)时激发?br />
DefaultTreeCellEditor扩展了DefaultCellEditorcdƈ且是TreeCellEditor的默认实现类Q他使用JTextField来编辑节Ҏ据,在键入ENTER键后stopCellEditingQ)会被调用。对于树节点的编辑我们可d自己的时间监听器来处理他们。默认时~辑开始于节点被单Mơ或两次Q时间间隔在内部会用一个定时器来决定)Q也可以改变他们的数目setClickCountToStart()Q?br />
JTree的选择是基于行和树路径的,我们可以选择使用那个?/p>
TreeSelectionModel接口用于树选择模型Q支持三U选择QSINGLE_TREE_SELECTIONQ?br />
DISCONTIGUOUS_TREE_SELECTIONQCONTIGUOUS_TREE_SELECTIONQset/getSelectionMode()可以讉K择模型。getSelectionPath『s?)会返回一个当前选中的树路径。DefaultTreeSelectionModel默认实现了该接口Q该cL供TreeSelectionlistener通知Q当树\径选择发生变化时?/p>
TreeModelListener实现者可以侦听模型变化,TreeSelectionListener用来侦听视图JTree的selectionQ仅有一个方法valueChanged(TreeSlectcionEvent tsEvt)Q? TreeModelEventQ用来通知模型的监听器QJTree的数据部分或全部发生了变化。该事g对象装了源lg的引用,装了一个TreePath或一个用来表C\径的数组?br />
TreeselectionEventQ视图会用其通知所有视囄听器TreeSelectionListenersQ选择发生了变化?br />
TreeExpansionEventQ用来封装相应最q或可能展开或收~的TreePathQ用getPath()Ҏ讉K树\径?br />
ExpandVetoException异常可由TreeWillExpandListener抛出Q来否决树\径的展开和收~?/p>
JTree提供的现成方便的UI属性: 其他控制TreeQテ昄的方法: ***** import java.awt.Container; public static void main(String[] args){ private void biuldFrame(){ ****** 在实际开发过E中会经怋用JTreelgQ^时会遇到q样或那L问题Q在此将偶得一点经验写下来Q与大家׃nQ希望对大家有所帮助?/p>
private JTree jtNetDevice;//数组件申?br />
private JScrollPane jspTree;//滚动面板x 2、三个经怋用的取值函?/strong> private DefaultMutableTreeNode getRootNode(){ 3、根据node得到pathQ?br />
TreePath visiblePath = new TreePath(getTreeModel().getPathToRoot(node)); 4、根据Path展开到该节点 5、根据path讑֮该节炚w定 6、选中节点的方?br />
首先Q根据节点得到树路径Q其中chosen为需要选中的节?br />
TreePath visiblePath = new TreePath( ( (DefaultTreeModel) jtNetDevice.getModel()). 7、滚动到可见位置 8、给JTreed右键弹出菜单 9、关于JTree的展开 10、如何遍历JTree
**
关于树的术语如根Q节点,叶子Q深度,路径Q^衡性,边,子树Q不需要我q里q多的解释,M一本数据结构的书籍都会介绍他们。我q里主要是讲q树控g?
/ \
/_____>____\
f2();
}//该函数的控制向是:先传lmainQ再由mainQ)传给f1,之后退回到mianQ)Q在传给f2()在由f2退回给main之后l束E序。异步方法调用时才会从这个封闭的轮廓中分Z个分支来。现在来谈你如何设计一个树遍历ҎQ?br />
我们来看一个函数的几个关键部位Q?
funcQ){
entry入口?br />
中间部位
}也许你很qhq与树遍历算法有和关p,告诉你吧q三个特D部位就是你在设计递归Ӟ递归函数应该出现的位|,他们出现在不同的位置是不同?#8220;?#8221;,伪码如:
先序遍历
traversTree(Node root){
if(root !=null){
if(root.isLeaf()){//当是叶子Ӟ
visitQrootQ?//前序遍历是先遍历节?br />
}
Node[] children=root.getChildren();//获取所有子?
for(Node n:children){
traversTree(n);//递归遍历所有子树,注意子树可能为空?br />
}
}
if(root !=null){
//树非I?br />
visit(root); //q是中序遍历 visit出现与递归函数之前?br />
Node[] children=root.getChildren();//获取所有子?
for(Node n:children){
traversTree(n);//递归遍历所有子树,注意子树可能为空?br />
}
}
if(root !=null){
Node[] children=root.getChildren();//获取所有子?
for(Node n:children){
traversTree(n);//递归遍历所有子树,注意子树可能为空?br />
}
visit(root); //q是后序遍历 visit出现在递归函数之后?br />
}
**
***
swing中Jtree处理树结构是通过树模型接口,它实CTreeNode接口Q在api文档中竟看不到此信息Q)QDefaultMutableTreeNodecdCTreeNode接口Qƈ提供了前,?后序的树遍历能力?br />
JTree囑Ş化的昄了树l构的每一个节点,所有的UI控g都有两个目的Q显C和输入Q输入包括数据的输入如JTextField和命令输入如菜单Q按钮等Q,JTree既可以用于树l构的显C,也可以用于命令的输入Q或使得我们~辑树节炏V?br />
树节点可以被选中Q它由TreeSelectionModel来控Ӟ选择涉及到维护作为TreeNode实例的树节点间的路径轨迹。树控g典型的可以激发两cMӞTreeModelEvent和TreeExpansionEventQ当然其他Awt和Swing事g也可由树控gȀ发(看其l承层次l构卛_知)比如MouseListener可用来截取鼠标事件。JTree扩展了Scrollable接口Q可被放在一个滚动面板中?/p>
****
TreeModel接口Q?br />
该接口的实现者ؓJTree提供昄的数据,如果你熟悉MVC模式Q你应该明白所有的swing或awt控g中模型的作用是为相应的控g提供数据。当模型的数据结构有所变化时它会通知视图Q这里就是JTreeQ来更新昄。当然模型也可以d其他的监听器如Jtree的addTreeModelListenerQ你可以实现该监听器Q来使你自己的类接收模型变化l你的通知。如果你不熟悉MVC模式Q请参考POSA卷一或其他资料,Z提一下在我们学校GUI旉知道有MVC模式的应用,往往不知道那个Controller是什么类Q其实就是视囄监听器,比如ActionListenerQ注意别被众多的监听器弄昏了Q一cL模型需要添加的Q一cL视图Q比如JComponent的子c)需要添加的。控制的向或数据的向是相反的Q视N要添加的监听器(我们常常实现他们Q才是控制器?/p>
*****
杂项Q?br />
DefultTreeModel是对TreeModel接口的默认实现类Q?br />
TreeNode接口可告诉你改实现者是否ؓ一个叶子,一个父节点{。MutalbeTreeNode接口扩展了TreeNode接口Q我们可在该实现者中存放一个我们自qcd例(setUserObjectQ)/getUserObjectQ?
defaultMutableTreeNode 实现了MutableTreeNode接口Qchildren()Ҏq回以一l向量Ş式存攄直接子节点的枚DQ也可以使用getChildAt()q回特定索引位置的子节点Q注意子节点完全可以是一颗子树)该类提供了前中后序访问树的能力:preorderEnumeration()Q?breadthFirstEnumeration()QdepthFirstEnumeration(QpostorderEnumeration()最后两个方法同行ؓQ只不过是不同的U号而已?/p>
TreeExpansionListener用来Ҏ展开收羃q行处理?br />
TreeW illExpandListener在树“要”展开和收~时得到通知Q你可截获处理,ExpandVetoException异常如果抛出Q那么树不会展开和收~?/p>
myJTree.putClientProperty("JTree.lineStyle", "Angled");//更改U型?br />
如同其他SwinglgQ我们也可以改变默认的用于JTree的UQ资源(全局性的Q:
UIManager.put("Tree.hash",
new ColorUIResource(Color.lightGray));Q/改变渲染节点间edges边的颜色?br />
UIManager.put("Tree.openIcon", new IconUIResource(
new ImageIcon("myOpenIcon.gif")));//改变一个打开的树节点的图标。同理可用于其它情况QTree.leafIcon, Tree.expandedIconQ和Tree.closedIconQ?Tree.collapsedIcon?/p>
myTree.setRowHeight()Q/控制树节点的行高Q?br />
JTree的UI委托也提供了更改树外观的ҎQ相比于QテQanager的ҎQ这里是局部的Q?br />
BasicTreeUI basicTreeUI = (BasicTreeUI) myJTree.getUI();
basicTreeUI.setRightChildIndent(10);
basicTreeUI.setLeftChildIndent(8);
以上要提及了QTree的Ҏ面面,许多的事Ӟ听器模型,请仔l分析,一定要分清哪些是针Ҏ型的那些是针对视囄?/p>
******
单的CZQ我q里仅用C最单的树构造方法,和一个监听器Q在
以后我的自学q程中,我会l箋试用其他的JTree知识Q我的JTree学习
最l都是想实现那个QUQ上的授权控制系l,请参考其他篇章,
至于q里用到的LAndFSysMenuc,在我的其他篇章中有该cȝ实现?br />
package jTreeDemo;
import javax.swing.*;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import lookAndFeelSys.*;
import userInterfaces.UIUtil;
import java.awt.*;
import java.util.Hashtable;
import java.util.Vector;
import javax.swing.tree.*;
public class JTreeTest extends JFrame{
new JTreeTest("试");
}
public JTreeTest(String title){
super(title);
biuldFrame();
}
JMenuBar jmb=new JMenuBar();
JMenu jm=new LAndFSysMenu();
//JMenu jm=new JMenu("hello");
jmb.add(jm);
this.setJMenuBar(jmb);
buildFrmContent();
UIUtil.SetComponentDimension(this,0.5,0.6);
UIUtil.SetComponentToCenterOfScreen(this);
this.setVisible(true);
this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
}
private void buildFrmContent(){
Container root_c=this.getContentPane();
JTabbedPane jtp=new JTabbedPane();
Container c = new JPanel();
jtp.addTab("静态树lgl习",c );
jtp.addTab("事g监听",this.treeDemo2());
root_c.add(jtp);
c.setLayout(new GridLayout(2,4));
JScrollPane jsp_1=new JScrollPane();
JScrollPane jsp_2=new JScrollPane();
JScrollPane jsp_3=new JScrollPane();
JScrollPane jsp_4=new JScrollPane();
/*为JTree准备昄的模?/
Object[] m1=new String[]{"节点1","节点2","节点3"};
Object[] m2=new String[][]{
{"1.1","1.2","1.3"},
{"2.1","2.2","2.3"},
{"3.1","3.2","3.3"}
};
Vector<Object> m3=new Vector<Object>();
m3.add("1");
m3.add("2");
m3.add(m1);
m3.add(m2);
Hashtable<String,Object> m4=new Hashtable<String,Object>();
m4.put("子一","叶子");
m4.put("子二", m1);
m4.put("子三",m3);
JTree jtr_1=new JTree(m1);
jsp_1.getViewport().add(jtr_1);
JTree jtr_2=new JTree(m2);
jsp_2.getViewport().add(jtr_2);
JTree jtr_3=new JTree(m3);
jsp_3.getViewport().add(jtr_3);
JTree jtr_4=new JTree(m4);
jsp_4.getViewport().add(jtr_4);
c.add(jsp_1);
c.add(jsp_2);
c.add(jsp_3);
c.add(jsp_4);
/*jsp_1.getViewport().add(jtr_1);
c.add(jsp_1);*/
}
/*<< 另一lJTree实例Q?/
private JPanel treeDemo2(){
JPanel rsltPanel=new JPanel();
rsltPanel.setLayout(new BorderLayout());
JLabel jl_msg=new JLabel("此标{来显C树选择情况");
JScrollPane jsp_1=new JScrollPane();
Object[] m=new String[]{"节点1","节点2","节点3"};
JTree jtr=new JTree(m);
jtr.getSelectionModel()
.addTreeSelectionListener(new MySelectionLstnr(
jl_msg));
jsp_1.getViewport().add(jtr);
rsltPanel.add(jsp_1,BorderLayout.CENTER);
rsltPanel.add(jl_msg,BorderLayout.SOUTH);
return rsltPanel;
}
class MySelectionLstnr implements TreeSelectionListener{
//该内部类实现树监听器Q在树被选中后将选中的节?br />
//信息打印C个Label?br />
private JLabel jl_msg=null;
public MySelectionLstnr(JLabel msgLabel){
this.jl_msg=msgLabel;
}
@Override
public void valueChanged(TreeSelectionEvent e) {
// 凡是树选择的处理都涉及到树路径的处理:
TreePath path = e.getPath();
Object[] nodes = path.getPath();
//当前选中的节Ҏ树\径上最后一个节?br />
Object selectedNode=nodes[nodes.length-1 ];
if(this.jl_msg!=null){
this.jl_msg.setText("选中的节点上的文本是Q?+
selectedNode.toString());
}
}
}
/*另一lJTree实例Q?gt;>*/
}
参考Java Swing QManning出版C)swing hack Qorelly出版C)?
]]>
import java.awt.Color;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.BoxLayout;
import javax.swing.tree.TreePath;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
/*
JTree的构造函?
JTree()
JTree(Hashtable value)
JTree(Object[] value)//只有q个构造函数可以创建多个根l点
JTree(TreeModel newModel)
JTree(TreeNode root)
JTree(TreeNode root, boolean asksAllowsChildren)
JTree(Vector value)
*/
public class JTreeDemo
{
public static void main (String[] args)
{
// 构造函敎ͼJTree()
JTree example1 = new JTree();
// 构造函敎ͼJTree(Object[] value)
Object[] letters = { " a " , " b " , " c " , " d " , " e " };
JTree example2 = new JTree (letters);
// 构造函敎ͼJTree(TreeNode root)(TreeNodeI?
// 用空l点创徏?/span>
DefaultMutableTreeNode node1 = new DefaultMutableTreeNode(); // 定义树结?/span>
JTree example3 = new JTree (node1); // 用此树结点做参数调用 JTree的构造函数创建含有一个根l点的树
// 构造函敎ͼJTree(TreeNode root)(同上,只是TreeNode非空)
// 用一个根l点创徏?/span>
DefaultMutableTreeNode node2 = new DefaultMutableTreeNode( " Color " );
JTree example4 = new JTree (node2); // l点不可以颜?默认为白面黑?/span>
example4.setBackground (Color.lightGray);
// 构造函敎ͼJTree(TreeNode root, boolean asksAllowsChildren)(同上,只是TreeNode又有不同)
// 使用DefaultMutableTreeNodecd用一个根l点创徏树,讄为可d孩子l点,再添加孩子结?/span>
DefaultMutableTreeNode color = new DefaultMutableTreeNode( " Color " , true );
DefaultMutableTreeNode gray = new DefaultMutableTreeNode ( " Gray " );
color.add (gray);
color.add ( new DefaultMutableTreeNode ( " Red " ));
gray.add ( new DefaultMutableTreeNode ( " Lightgray " ));
gray.add ( new DefaultMutableTreeNode ( " Darkgray " ));
color.add ( new DefaultMutableTreeNode ( " Green " ));
JTree example5 = new JTree (color);
// 构造函敎ͼJTree(TreeNode root)(同上,只是TreeNode非空)
// 通过逐个dl点创徏?/span>
DefaultMutableTreeNode biology = new DefaultMutableTreeNode ( " Biology " );
DefaultMutableTreeNode animal = new DefaultMutableTreeNode ( " Animal " );
DefaultMutableTreeNode mammal = new DefaultMutableTreeNode ( " Mammal " );
DefaultMutableTreeNode horse = new DefaultMutableTreeNode ( " Horse " );
mammal.add (horse);
animal.add (mammal);
biology.add (animal);
JTree example6 = new JTree (biology);
horse.isLeaf();
horse.isRoot();
// 构造函?JTree(TreeModel newModel)
// 用DefaultMutableTreeNodelcd义一个结点再用这个结点做参数定义一个用DefaultTreeMode
// 创徏一个树的模?再用JTree的构造函数创Z个树
DefaultMutableTreeNode root = new DefaultMutableTreeNode ( " Root1 " );
DefaultMutableTreeNode child1 = new DefaultMutableTreeNode ( " Child1 " );
DefaultMutableTreeNode child11 = new DefaultMutableTreeNode ( " Child11 " );
DefaultMutableTreeNode child111 = new DefaultMutableTreeNode ( " Child111 " );
root.add (child1); child1.add (child11); child11.add (child111);
DefaultTreeModel model = new DefaultTreeModel (root);
JTree example7 = new JTree (model);
JPanel panel = new JPanel();
panel.setLayout ( new BoxLayout (panel, BoxLayout.X_AXIS));
panel.setPreferredSize ( new Dimension ( 700 , 400 ));
panel.add ( new JScrollPane (example1)); // JTree必须攑֜JScrollPane?/span>
panel.add ( new JScrollPane (example2));
panel.add ( new JScrollPane (example3));
panel.add ( new JScrollPane (example4));
panel.add ( new JScrollPane (example5));
panel.add ( new JScrollPane (example6));
panel.add ( new JScrollPane (example7));
JFrame frame = new JFrame ( " JTreeDemo " );
frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
frame.setContentPane (panel);
frame.pack();
frame.show();
}
} ××××××××××××××××××××××××××××××××××××××××××××××
1、初始化
DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode("root");
jtNetDevice = new JTree(rootNode);
jtNetDevice.setAutoscrolls(true);
getTreeSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);//讄单选模?br />
jspTree = new JScrollPane();
jspTree.getViewport().add(jtNetDevice, null);
private DefaultTreeModel getTreeModel(){
return (DefaultTreeModel)jtNetDevice.getModel();
}
return (DefaultMutableTreeNode)getTreeModel().getRoot();
}
private TreeSelectionModel getTreeSelectionModel(){
return jtNetDevice.getSelectionModel();
}
jtNetDevice.makeVisible(visiblePath);
jtNetDevice.setSelectionPath(visiblePath);
getPathToRoot(chosen));
然后ҎPath选中该节?br />
jtNetDevice.setSelectionPath(visiblePath);
jtNetDevice.scrollPathToVisible(visiblePath);
void jtNetDevice_mouseReleased(MouseEvent e) {
if (e.isPopupTrigger()) {
jPopupMenu1.show(e.getComponent(), e.getX(), e.getY());//弹出右键菜单
}
}
// If expand is true, expands all nodes in the tree.
// Otherwise, collapses all nodes in the tree.
public void expandAll(JTree tree, boolean expand) {
TreeNode root = (TreeNode)tree.getModel().getRoot();
// Traverse tree from root
expandAll(tree, new TreePath(root), expand);
}
private void expandAll(JTree tree, TreePath parent, boolean expand) {
// Traverse children
TreeNode node = (TreeNode)parent.getLastPathComponent();
if (node.getChildCount() >= 0) {
for (Enumeration e=node.children(); e.hasMoreElements(); ) {
TreeNode n = (TreeNode)e.nextElement();
TreePath path = parent.pathByAddingChild(n);
expandAll(tree, path, expand);
}
}
// Expansion or collapse must be done bottom-up
if (expand) {
tree.expandPath(parent);
} else {
tree.collapsePath(parent);
}
}
// 创徏?br />
JTree tree = new JTree();
// d树节?.....
// 遍历所有节?br />
visitAllNodes(tree);
// 仅遍历展开的节?br />
visitAllExpandedNodes(tree);
// Traverse all nodes in tree
public void visitAllNodes(JTree tree) {
TreeNode root = (TreeNode)tree.getModel().getRoot();
visitAllNodes(root);
}
public void visitAllNodes(TreeNode node) {
// node is visited exactly once
process(node);
if (node.getChildCount() >= 0) {
for (Enumeration e=node.children(); e.hasMoreElements(); ) {
TreeNode n = (TreeNode)e.nextElement();
visitAllNodes(n);
}
}
}
// Traverse all expanded nodes in tree
public void visitAllExpandedNodes(JTree tree) {
TreeNode root = (TreeNode)tree.getModel().getRoot();
visitAllExpandedNodes(tree, new TreePath(root));
}
public void visitAllExpandedNodes(JTree tree, TreePath parent) {
// Return if node is not expanded
if (!tree.isVisible(parent)) {
return;
}
// node is visible and is visited exactly once
TreeNode node = (TreeNode)parent.getLastPathComponent();
process(node);
// Visit all children
if (node.getChildCount() >= 0) {
for (Enumeration e=node.children(); e.hasMoreElements(); ) {
TreeNode n = (TreeNode)e.nextElement();
TreePath path = parent.pathByAddingChild(n);
visitAllExpandedNodes(tree, path);
}
}
}
]]>
今天l于耐着性子弄懂了GridBagLayout是怎么使用的?br />
构造函敎ͼ
GirdBagLayout()建立一个新的GridBagLayout理器?br />
GridBagConstraints()建立一个新的GridBagConstraints对象?br />
GridBagConstraints(int gridx,int gridy,
int gridwidth,int gridheight,
double weightx,double weighty,
int anchor,int fill, Insets insets,
int ipadx,int ipady)建立一个新的GridBagConstraints对象Qƈ指定其参数的倹{?br />
看着q一堆的参数快烦死了,下面׃解一下参数的意思:
参数说明Q?br />
gridx,gridy —?nbsp; 讄lg的位|,
gridx讄为GridBagConstraints.RELATIVE代表此组件位于之前所加入lg的右辏V?br />
gridy讄为GridBagConstraints.RELATIVE代表此组件位于以前所加入lg的下面?br />
定义出gridx,gridy的位|以便以后维护程序。gridx=0,gridy=0时放??列?/p>
gridwidth,gridheight —?nbsp; 用来讄lg所占的单位长度与高度,默认值皆??br /> 你可以用GridBagConstraints.REMAINDER帔RQ代表此lg为此行或此列的最后一个组Ӟ而且会占据所有剩余的I间?/p>
weightx,weighty —?nbsp; 用来讄H口变大Ӟ各组件跟着变大的比例?br /> 当数字越大,表示lg能得到更多的I间Q默认值皆??/p>
anchor —?nbsp; 当组件空间大于组件本w时Q要组件置于何处?br /> 有CENTER(默认?、NORTH、NORTHEAST、EAST、SOUTHEAST、WEST、NORTHWEST选择?/p>
insets —?nbsp; 讄lg之间彼此的间距?br /> 它有四个参数Q分别是上,左,下,叻I默认?0,0,0,0)?/p>
ipadx,ipady —?nbsp; 讄lg间距Q默认gؓ0?/p>
GridBagLayout里的各种讄都必通过GridBagConstraintsQ因此当我们GridBagConstraints的参数都讄
好了之后Q必new一个GridBagConstraints的对象出来,以便GridBagLayout使用?/p>
代码片断Q?br />
JButton b;
GridBagConstraints c;
int gridx,gridy,gridwidth,gridheight,anchor,fill,ipadx,ipady;
double weightx,weighty;
Insets inset;
JFrame f=new JFrame();
GridBagLayout gridbag=new GridBagLayout();
Container contentPane=f.getContentPane();
contentPane.setLayout(gridbag);
b=new JButton("first");
gridx=0;
gridy=0;
gridwidth=1;
gridheight=1;
weightx=10;
weighty=1;
anchor=GridBagConstraints.CENTER;
fill=GridBagConstraints.HORIZONTAL;
inset=new Insets(0,0,0,0);
ipadx=0;
ipady=0;
c=new GridBagConstraints(gridx,gridy,gridwidth,gridheight,weightx,weighty,anchor,fill,inset,ipadx,ipady);
gridbag.setConstraints(b,c);
contentPane.add(b);
GridBagLayoutq种理器是十分灉|的,只不q他写v来比较麻烦,不过用了之后才发C对界面的部v帮助很大?br />
本文来自CSDN博客Q{载请标明出处Qhttp://blog.csdn.net/dracularking/archive/2008/04/22/2314336.aspx
正如你所看到的,最l的l果看上d计划的想法完全一栗?/p>
你应该能看到在草N有一些线Q这些线是用来把ȝ面分成若q行和列的,q样你就很清楚每一个组件放|的格子位置。这是GridBagLayout??的那一部分Q而图上的数字是格的L?/p>
在某U意义上? 我们可以把GridBagLayout惌成ؓ早些q的HTML3?Q它们都是基于表的布局QGrid的概念就cMrowspan和colspan的意思,只不q换了个名字|了?/p>
随着我们的界面和表格的设|完成,是时候该q行界面布局q开始写代码了?/p>
工作q程
q一节我假定你已l了解了基本的窗口和lg创徏知识?/p>
通过q篇文章我们最l能在一个frame中布局lgQ我们将在以后的文章对界面进行改q它更适用。因?Z了解q整个工作的q程Q我们列Z所有的目标代码?/p>
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class GridBagWindow extends JFrame {
private JButton searchBtn;
private JComboBox modeCombo;
private JLabel tagLbl;
private JLabel tagModeLbl;
private JLabel previewLbl;
private JTable resTable;
private JTextField tagTxt;
public GridBagWindow() {
Container contentPane = getContentPane();
GridBagLayout gridbag = new GridBagLayout();
contentPane.setLayout(gridbag);
GridBagConstraints c = new GridBagConstraints();
//setting a default constraint value
c.fill =GridBagConstraints.HORIZONTAL;
tagLbl = new JLabel("Tags");
c.gridx = 0; //x grid position
c.gridy = 0; //y grid position
gridbag.setConstraints(tagLbl, c); //associate the label with a constraint object
contentPane.add(tagLbl); //add it to content pane
tagModeLbl = new JLabel("Tag Mode");
c.gridx = 0;
c.gridy = 1;
gridbag.setConstraints(tagModeLbl, c);
contentPane.add(tagModeLbl);
tagTxt = new JTextField("plinth");
c.gridx = 1;
c.gridy = 0;
c.gridwidth = 2;
gridbag.setConstraints(tagTxt, c);
contentPane.add(tagTxt);
String[] options = {"all", "any"};
modeCombo = new JComboBox(options);
c.gridx = 1;
c.gridy = 1;
c.gridwidth = 1;
gridbag.setConstraints(modeCombo, c);
contentPane.add(modeCombo);
searchBtn = new JButton("Search");
c.gridx = 1;
c.gridy = 2;
gridbag.setConstraints(searchBtn, c);
contentPane.add(searchBtn);
resTable = new JTable(5,3);
c.gridx = 0;
c.gridy = 3;
c.gridwidth = 3;
gridbag.setConstraints(resTable, c);
contentPane.add(resTable);
previewLbl = new JLabel("Preview goes here");
c.gridx = 0;
c.gridy = 4;
gridbag.setConstraints(previewLbl, c);
contentPane.add(previewLbl);
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
public static void main(String args[]) {
GridBagWindow window = new GridBagWindow();
window.setTitle("GridBagWindow");
window.pack();
window.setVisible(true);
}
}
构造方法前的代码都不是很特D,都是一些相当标准的import和变量定义。但是进入构造方法后Q事情就变得有趣了?/p>
Container contentPane = getContentPane();
GridBagLayout gridbag = new GridBagLayout();
contentPane.setLayout(gridbag);
我们以GridBagWindow的内定w板作为开始来创徏一个GridBagLayout对象Q准地_q个Ҏ与过L们所创徏 GridLayout对象和BorderLayout对象的方法是一L。那么,现在我们开始来讄GridBagLayout对象使它作ؓ内容面板?布局?/p>
GridBagConstraints c = new GridBagConstraints();
然后我要提到q整个进E中的一个独特的对象Q那是GridBagConstraints。这个对象在GridBagLayout中控制所 有被安置在其中组件的U束。ؓ了把一个组件增加到你的GridBagLayout中去Q你首先必须它与一个GridBagConstraints对象?立连接?/p>
GridBagConstraints可以?1个方面来q行控制和操U,也可以给你提供一些帮助。这些内ҎQ?/p>
可能对于一个组件的每一个实例你都需要ؓ它徏立一个单独的GridBagConstraintsQ然而,q种Ҏ我们q不推荐使用。最好的Ҏ是,当你调用它的时候把对象讄为默认|然后针对于每一个组件改变其相应的域?/p>
q个Ҏh通用性,因ؓ在一些域中,比如insets、padx、pady和fillq些域,对于每一个组件来说一般都是相同的Q因此这样对一个域q行讄׃更轻松了Q也能更L的在另外的组件中改变某些域的倹{?/p>
如果在改变了某些域g后,你想回到原始的域值的话,你应该在增加下一个组件之前进行改变。这U方法你更Ҏ明白你正在修改的内容Q也能你更Ҏ明白在一q串对象中的q?1个参数的作用?/p>
也许你现在对q些内容q是一知半解,不过事实上一旦你理解了GridBagConstraintsQ值得安慰的是你以后做再困隄工作都会游刃有余了?/p>
所以,如果我们已经明白了GridBagConstraints的详l用法了Q那么现在就让我们来看看在实际应用中应该如何来实现它Q?/p>
tagLbl = new JLabel("Tags");
c.gridx = 0; //x grid position
c.gridy = 0; //y grid position
gridbag.setConstraints(tagLbl, c); //讄标签的限?/p>
contentPane.add(tagLbl); //增加到内定w?/p>
我们所做的是示例我们的标签、分配给它一个格位置Q将它与一个约束对象联pv来ƈ把它增加到我们的内容面板中?/p>
tagModeLbl = new JLabel("Tag Mode");
c.gridx = 0;
c.gridy = 1;
gridbag.setConstraints(tagModeLbl, c);
contentPane.add(tagModeLbl);
h意,虽然我们已经在我们的U束对象中把gridx的D|ؓ0Q但是在q里我们仍然要对它进行重新设|——这样做没有其它原因Q只是ؓ了增加可L?/p>
下面Q我们增加一个文本域以便能存储我们希望能搜烦到的关键字,再增加一个组合框以便用来搜烦多个关键字。除了我们希望的文本域有两列之外Q这个概念其他的斚w都与上面所说的是相同的Q所以,我们需要在增加l合框之前重新设|文本域的倹{?/p>
tagTxt = new JTextField("plinth");
c.gridx = 1;
c.gridy = 0;
c.gridwidth = 2;
gridbag.setConstraints(tagTxt, c);
contentPane.add(tagTxt);
String[] options = {"all", "any"};
modeCombo = new JComboBox(options);
c.gridx = 1;
c.gridy = 1;
c.gridwidth = 1;
gridbag.setConstraints(modeCombo, c);
contentPane.add(modeCombo);
做了q些之后Q我们再在内定w板中增加一些其余的单组Ӟq时候我们就能够览它了Q其余的代码应该不会出现M问题了?/p>
到这个阶D,我们应该已经得到了一个类g我们先前所设计的界面了?/p>
DefaultTableModel model = new DefaultTableModel(cellData, headers) {
public boolean isCellEditable(int row, int column) { return false; } };
table = new JTable(model);
?对表格列的控?/pre>0)获取JTable中特定单元格的位|?/pre>table.addMouseListener(new MouseListener() {public void mouseClicked(MouseEvent e) {int row = jt.rowAtPoint(e.getPoint()); int col = jt.columnAtPoint(e.getPoint());}});1) 讄列不可随容器lg大小变化自动调整宽度. table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); 2) 限制某列的宽? TableColumn firsetColumn = table.getColumnModel().getColumn(0); firsetColumn.setPreferredWidth(30); firsetColumn.setMaxWidth(30); firsetColumn.setMinWidth(30); 3) 讄当前列数. DefaultTableModel tableModel = (DefaultTableModel) table.getModel(); int count=5; tableModel.setColumnCount(count); 4) 取得表格列数 int cols = table.getColumnCount(); 5) d? DefaultTableModel tableModel = (DefaultTableModel) table.getModel(); tableModel.addColumn("新列?); 6) 删除? table.removeColumn(table.getColumnModel().getColumn(columnIndex));// columnIndex是要删除的列序号 ?对表D的控? 1) 讄行高 table.setRowHeight(20); 2) 讄当前航数 DefaultTableModel tableModel = (DefaultTableModel) table.getModel(); int n=5; tableModel.setRowCount(n); 3) 取得表格行数 int rows = table.getRowCount();4) d表格? DefaultTableModel tableModel = (DefaultTableModel) table.getModel(); tableModel.addRow(new Object[]{"sitinspring", "35", "Boss"}); 5) 删除表格? DefaultTableModel tableModel = (DefaultTableModel) table.getModel(); model.removeRow(rowIndex);// rowIndex是要删除的行序号 ?存取表格单元格的数据 1) 取单元格数据 DefaultTableModel tableModel = (DefaultTableModel) table.getModel(); String cellValue=(String) tableModel.getValueAt(row, column);// 取单元格数据,row是行?column是列? 2) 填充数据到表? ?数据是Membercd的链?Membercd? public class Member{ // 名称 private String name; // q龄 private String age; // 职务 private String title; } 填充数据的代? public void fillTable(List<Member> members){ DefaultTableModel tableModel = (DefaultTableModel) table.getModel(); tableModel.setRowCount(0);// 清除原有? // 填充数据 for(Member member:members){ String[] arr=new String[3]; arr[0]=member.getName(); arr[1]=member.getAge(); arr[2]=member.getTitle(); // d数据到表? tableModel.addRow(arr); } // 更新表格 table.invalidate(); } 2) 取得表格中的数据 public List<Member> getShowMembers(){ List<Member> members=new ArrayList<Member>(); DefaultTableModel tableModel = (DefaultTableModel) table.getModel(); int rowCount=tableModel.getRowCount(); for(int i=0;i<rowCount;i++){ Member member=new Member(); member.setName((String)tableModel.getValueAt(i, 0));// 取得Wi行第一列的数据member.setAge((String)tableModel.getValueAt(i, 1));// 取得Wi行第二列的数? member.setTitle((String)tableModel.getValueAt(i, 2));// 取得Wi行第三列的数? members.add(member); } return members; } ?取得用户所选的? 1) 取得用户所选的单行 int selectRows=table.getSelectedRows().length;// 取得用户所选行的行? DefaultTableModel tableModel = (DefaultTableModel) table.getModel();if(selectRows==1){ int selectedRowIndex = table.getSelectedRow(); // 取得用户所选单? .// q行相关处理 } 2) 取得用户所选的多行 int selectRows=table.getSelectedRows().length;// 取得用户所选行的行? DefaultTableModel tableModel = (DefaultTableModel) table.getModel();if(selectRows>1) int[] selRowIndexs=table.getSelectedRows();// 用户所选行的序? for(int i=0;i<selRowIndexs.length;i++){ // 用tableModel.getValueAt(row, column)取单元格数据 String cellValue=(String) tableModel.getValueAt(i, 1); } } ?d表格的事件处?/pre>view.getTable().addMouseListener(new MouseListener() { public void mousePressed(MouseEvent e) { // 鼠标按下时的处理 }public void mouseReleased(MouseEvent e) { // 鼠标村ּ时的处理 }public void mouseEntered(MouseEvent e) { // 鼠标q入表格时的处理 }public void mouseExited(MouseEvent e) { // 鼠标退格时的处? }public void mouseClicked(MouseEvent e) { // 鼠标点击时的处理 } });
]]>