锁定老帖子 主题:Swing界面优化进阶五
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2015-05-31
最后修改:2015-06-07
http://www.iteye.com/topic/1137293 http://www.iteye.com/topic/1138102 JTree 一个给我印象最深刻的东西。 刚参加工作的时候那会儿,公司让我做一个即时通讯软件,当时真是被jtree玩死了,后来干脆自己用jlabel重新写了一个好友列表,说起来都是泪啊。。。 好了,不扯了,先来说一下优化思路: 1、重写cellRenderer渲染器; 2、消除节点之前的连线; 3、构建自己的Node节点(重绘UI); 4、居左对齐; 5、加上鼠标效果。 老规矩,还是先上图 看完大家没感觉吧,因为他这个排版还可以,勉强能接受。 接下来,我们需要将其原始图标给替换掉 上代码:继承DefaultTreeCellRenderer重写里面的getTreeCellRendererComponent方法,并调用重写的渲染器JTree.setCellRenderer(new DemoRenderer()); public class DemoRenderer extends DefaultTreeCellRenderer { // 大家可以将其看成一个jlabel @Override public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) { DefaultMutableTreeNode node = (DefaultMutableTreeNode) value; // 设置图标 this.setIcon(new ImageIcon(getClass().getClassLoader().getResource("qq_icon.png"))); // 设置文字 this.setText(value.toString()); return this; } } 但是大家发现,这不是我们要的效果,我们想要灵活的控制图标 OK,我们来看下代码,思路就是根据不同级别控制一下图标 public class DemoRenderer extends DefaultTreeCellRenderer { @Override public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) { DefaultMutableTreeNode node = (DefaultMutableTreeNode) value; // 根节点从0开始,依次往下 // 分组 if (node.getLevel() == 1) { if (expanded) { this.setIcon(new ImageIcon(getClass().getClassLoader().getResource("arrow_down.png"))); } else { this.setIcon(new ImageIcon(getClass().getClassLoader().getResource("arrow_left.png"))); } } // 好友 if (node.getLevel() == 2) { this.setIcon(new ImageIcon(getClass().getClassLoader().getResource("qq_icon.png"))); } this.setText(value.toString()); return this; } } 看着前面的线条不太美观,咱们干掉它。很简单,有现成API:JTree.putClientProperty("JTree.lineStyle", "None"); 效果图: 看起来好友头像有了,昵称也有了,可是个性签名呢?原始的node节点,我们可以将其看做一个jlabel,只有一张图表和一行文字,所以我们需要重新绘制节点UI了 主要是cellRender渲染器和node节点,上代码: package course; import java.awt.Component; import javax.swing.ImageIcon; import javax.swing.JTree; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeCellRenderer; /** * 自定义CellRenderer * @author sf_dream * @date 2015年5月24日 */ @SuppressWarnings("serial") public class DemoRenderer extends DefaultTreeCellRenderer { @Override public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) { // 大家这里注意,我为了节省时间,所以就没有写两个node类 // 所有的代码写在了同一个类中,然后根据不同的节点来调用相应的方法 DemoNode node = (DemoNode) value; if (node.getLevel() == 1) { if (expanded) { node.iconLabel.setIcon(new ImageIcon(getClass().getClassLoader().getResource("arrow_down.png"))); } else { node.iconLabel.setIcon(new ImageIcon(getClass().getClassLoader().getResource("arrow_left.png"))); } return node.getCateView(); } if (node.getLevel() == 2) { node.iconLabel.setIcon(new ImageIcon(getClass().getClassLoader().getResource("qq_icon.png"))); return node.getNodeView(); } return this; } } package course; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import javax.swing.BorderFactory; import javax.swing.Icon; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.tree.DefaultMutableTreeNode; /** * 自定义Node <br/> * 继承节点类DefaultMutableTreeNode <br/> * 在这里自定义我们自己的UI,以便cellRenderer中调用 * * @author sf_dream * @date 2015年5月24日 */ @SuppressWarnings("serial") public class DemoNode extends DefaultMutableTreeNode { /** 图片 */ private Icon icon; /** 文字 */ private String name; /** 签名 */ private String sign; public JPanel cateContent; public JPanel nodeContent; public JLabel iconLabel; public JLabel nameLabel; public JLabel signLabel; /** * 初始化分组节点 * @param name 名称 */ public DemoNode(Icon icon, String name) { this.icon = icon; this.name = name; // 初始化UI initCateGUI(); } /** * 初始化好友节点 * @param icon 头像 * @param nick 昵称 * @param sign 签名 */ public DemoNode(Icon icon, String nick, String sign) { this.icon = icon; this.name = nick; this.sign = sign; // 初始化UI initNodeGUI(); } /** * 自定义分组UI */ private void initCateGUI() { cateContent = new JPanel(); cateContent.setLayout(null); cateContent.setOpaque(false); cateContent.setPreferredSize(new Dimension(258, 25)); //cateContent.setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY)); iconLabel = new JLabel(icon); iconLabel.setBounds(6, 5, 20, 16); cateContent.add(iconLabel); nameLabel = new JLabel(name); nameLabel.setBounds(23, 0, 132, 28); cateContent.add(nameLabel); } /** * 自定义好友UI */ private void initNodeGUI() { nodeContent = new JPanel(); nodeContent.setLayout(null); nodeContent.setOpaque(false); nodeContent.setPreferredSize(new Dimension(258, 50)); //nodeContent.setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY)); iconLabel = new JLabel(icon); iconLabel.setBounds(8, 4, 39, 42); nodeContent.add(iconLabel); nameLabel = new JLabel(name); nameLabel.setBounds(59, 5, 132, 19); nodeContent.add(nameLabel); signLabel = new JLabel(sign); signLabel.setBounds(59, 28, 132, 17); nodeContent.add(signLabel); } /** * 将自定义UI返回给渲染器 <br/> * 供渲染器调用,返回的必须是一个Component * @return */ public Component getCateView() { return cateContent; } /** * 将自定义UI返回给渲染器 <br/> * 供渲染器调用,返回的必须是一个Component * @return */ public Component getNodeView() { return nodeContent; } public Icon getIcon() { return icon; } public void setIcon(Icon icon) { this.icon = icon; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSign() { return sign; } public void setSign(String sign) { this.sign = sign; } } 看完大家是不是觉着大功告成了呢,咱再来整个边框看看到底好了没有。 线去掉了,但是位置么有让出来(先前因为背景都是白色,所以我们看的不太明显) 解决办法:继承BasicTreeUI,重写里面的左右对齐方法, 调用:JTree.setUI(new DemoTreeUI()); package course; import java.awt.Graphics; import javax.swing.JComponent; import javax.swing.plaf.basic.BasicTreeUI; /** * 重写UI,主要为了左对齐 * @author sf_dream * @date 2015年5月25日 */ public class DemoTreeUI extends BasicTreeUI { // 去除JTree的垂直线 @Override protected void paintVerticalLine(Graphics g, JComponent c, int x, int top, int bottom) { } // 去除JTree的水平线 @Override protected void paintHorizontalLine(Graphics g, JComponent c, int y, int left, int right) { } // 实现父节点与子节点左对齐 @Override public void setLeftChildIndent(int newAmount) { } // 实现父节点与子节点右对齐 @Override public void setRightChildIndent(int newAmount) { } } 大家似乎有什么新发现?对,没错,去除节点前面的线条,我们也可以在这里一并处理,就不再需要JTree.putClientProperty("JTree.lineStyle", "None")了 再来看看效果,对齐了有木有 现在我们只需要将宽度跟界面匹配起来,就是在我们重绘的节点UI里面设置宽度,可以设置宽一点儿都没事,反正超出界面的部分也看不到,所以不用担心 好了,我们的界面基本上已经优化完毕,再来加点儿鼠标特效,我这里就简单点儿,鼠标滑入显示边框,点击选中变色。大家这里注意一下,事件还是放在jtree上处理,而不是放在我们重绘的UI上面,当时我就掉到这个坑里面了 特效: 1、鼠标滑入,当前三级(好友)节点显示边框,其他节点去掉边框; 2、鼠标点击,当前三节(好友)几点显示边框并且改变背景颜色,其他节点去掉边框并恢复颜色; 思路很简单,上面说过大家应该都能明白,有一个问题,大家帮忙思考一下,若是大家有更好的办法,可以教我一下,大家看到这些特效,改变自己就要恢复其他,所以这里就涉及到循环了,循环中除去根节点还有二三级节点,在节点过多的情况下,嵌套for循环十分影响效率,但是自己重绘UI的时候又加不上事件,非得加在jtree上,很让人头疼。。。 上图: 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2015-06-01
楼主厉害!学习!
|
|
返回顶楼 | |
发表时间:2015-06-02
写的挺不错,希望楼主能持续更新
|
|
返回顶楼 | |
发表时间:2015-06-04
小湿妹,加油
|
|
返回顶楼 | |
发表时间:2015-06-05
必须得顶。。。。。。
|
|
返回顶楼 | |
发表时间:2015-06-05
swing功力深厚!
|
|
返回顶楼 | |
发表时间:2015-06-06
cyberniuniu 写道 楼主厉害!学习!
大神,我还是比较佩服你的QQ气泡啊 |
|
返回顶楼 | |
发表时间:2015-06-06
jiangchao419 写道 swing功力深厚!
一点儿都不深厚,还要你们帮忙思考问题。。。 |
|
返回顶楼 | |
发表时间:2015-06-06
godtiger 写道 写的挺不错,希望楼主能持续更新
这个jtree组件讲解的差不多了,感觉没啥多说的了 |
|
返回顶楼 | |
发表时间:2015-06-06
gao_xianglong 写道 必须得顶。。。。。。
谢赞 |
|
返回顶楼 | |