目录

简介:

使用Swing的优势:

Swing的特征:

Swing基本组件的用法

Swing组件层次

AWT组件的Swing实现

简单了解swing(JFrame)

弹窗

标签:

面板

按钮

3.6 列表

3.7 文本框

JTree、TreeModel实现树

创建树

拖动、编辑树结点

监听结点事件

使用DefaultTreeCellRenderer改变结点外观

扩展DefaultTreeCellRenderer改变结点外观

实现TreeCellRenderer接口改变结点外观


简介:

己经介绍过AWT和Swing 的关系 , 因此不难知道 : 实际使用 Java 开发图形界面程序时 ,很少使用 AWT 组件,绝大部分时候都是用 Swing 组件开发的 。 Swing是由100%纯 Java实现的,不再依赖于本地平台的 GUI, 因此可以在所有平台上都保持相同的界面外观。独立于本地平台的Swing组件被称为轻量级组件;而依赖于本地平台的 AWT 组件被称为重量级组件。 ​ 由于 Swing 的所有组件完全采用 Java 实现,不再调用本地平台的 GUI,所以导致 Swing 图形界面的显示速度要比 AWT 图形界面的显示速度慢一些,但相对于快速发展的硬件设施而言,这种微小的速度差别无妨大碍。

使用Swing的优势:

1. Swing 组件不再依赖于本地平台的 GUI,无须采用各种平台的 GUI 交集 ,因此 Swing 提供了大量图形界面组件 , 远远超出了 AWT 所提供的图形界面组件集。 ​ 2. Swing 组件不再依赖于本地平台 GUI ,因此不会产生与平台 相关的 bug 。

3. Swing 组件在各种平台上运行时可以保证具有相同的图形界面外观。

Swing 提供的这些优势,让 Java 图形界面程序真正实现了 " Write Once, Run Anywhere" 的 目标。

Swing的特征:

1. Swing 组件采用 MVC(Model-View-Controller, 即模型一视图一控制器)设计模式:
​模型(Model): 用于维护组件的各种状态;
​视图(View): 是组件的可视化表现;控制器(Controller):用于控制对于各种事件、组件做出响应 。当模型发生改变时,它会通知所有依赖它的视图,视图会根据模型数据来更新自己。Swing使用UI代理来包装视图和控制器, 还有一个模型对象来维护该组件的状态。例如,按钮JButton有一个维护其状态信息的模型ButtonModel对象 。 Swing组件的模型是自动设置的,因此一般都使用JButton,而无须关心ButtonModel对象。
​
2. Swing在不同的平台上表现一致,并且有能力提供本地平台不支持的显示外观 。由于 Swing采用 MVC 模式来维护各组件,所以 当组件的外观被改变时,对组件的状态信息(由模型维护)没有任何影响 。因 此,Swing可以使用插拔式外观感觉 (Pluggable Look And Feel, PLAF)来控制组件外观,使得 Swing图形界面在同一个平台上运行时能拥有不同的外观,用户可以选择自己喜欢的外观 。相比之下,在 AWT 图形界面中,由于控制组件外观的对等类与具体平台相关 ,因此 AWT 组件总是具有与本地平台相同的外观 。   
 

Swing基本组件的用法

Swing组件层次

Swing组件继承体系图:

大部分Swing 组件都是 JComponent抽象类的直接或间接子类(并不是全部的 Swing 组件),JComponent 类定义了所有子类组件的通用方法 ,JComponent 类是 AWT 里 java.awt. Container 类的子类 ,这也是 AWT 和 Swing 的联系之一。 绝大部分 Swing 组件类继承了 Container类,所以Swing 组件都可作为 容器使用 ( JFrame继承了Frame 类)。

Swing组件和AWT组件的对应关系:

大部分情况下,只需要在AWT组件的名称前面加个J,就可以得到其对应的Swing组件名称,但有几个例外:

1. JComboBox: 对应于 AWT 里的 Choice 组件,但比 Choice 组件功能更丰富 。 ​ 2. JFileChooser: 对应于 AWT 里的 FileDialog 组件 。 ​ 3. JScrollBar: 对应于 AWT 里的 Scrollbar 组件,注意两个组件类名中 b 字母的大小写差别。 ​ 4. JCheckBox : 对应于 AWT 里的 Checkbox 组件, 注意两个组件类名中 b 字母的大小 写差别 。 ​ 5. JCheckBoxMenultem: 对应于 AWT 里的 CheckboxMenuItem 组件,注意两个组件类名中 b字母的大小写差别。

Swing组件按照功能来分类:

1. 顶层容器: JFrame、JApplet、JDialog 和 JWindow 。 ​ 2. 中间容器: JPanel 、 JScrollPane 、 JSplitPane 、 JToolBar 等 。 ​ 3. 特殊容器:在用户界面上具有特殊作用的中间容器,如 JIntemalFrame 、 JRootPane 、 JLayeredPane和 JDestopPane 等 。 ​ 4. 基本组件 : 实现人机交互的组件,如 JButton、 JComboBox 、 JList、 JMenu、 JSlider 等 。 ​ 5. 不可编辑信息的显示组件:向用户显示不可编辑信息的组件,如JLabel 、 JProgressBar 和 JToolTip等。 ​ 6. 可编辑信息的显示组件:向用户显示能被编辑的格式化信息的组件,如 JTable 、 JTextArea 和JTextField 等 。 ​ 7. 特殊对话框组件:可以直接产生特殊对话框的组件 , 如 JColorChooser 和 JFileChooser 等。

AWT组件的Swing实现

Swing 为除 Canvas 之外的所有 AWT 组件提供了相应的实现,Swing 组件比 AWT 组件的功能更加强大。相对于 AWT 组件, Swing 组件具有如下 4 个额外的功能 :

  1. 可以为 Swing 组件设置提示信息。使用 setToolTipText()方法,为组件设置对用户有帮助的提示信息 。

  2. 很多 Swing 组件如按钮、标签、菜单项等,除使用文字外,还可以使用图标修饰自己。为了允许在 Swing 组件中使用图标, Swing为Icon 接口提供了 一个实现类: Imagelcon ,该实现类代表一个图像图标。

  3. 支持插拔式的外观风格。每个 JComponent 对象都有一个相应的 ComponentUI 对象,为它完成所有的绘画、事件处理、决定尺寸大小等工作。 ComponentUI 对象依赖当前使用的 PLAF , 使用 UIManager.setLookAndFeel()方法可以改变图形界面的外观风格 。

  4. 支持设置边框。Swing 组件可以设置一个或多个边框。 Swing 中提供了各式各样的边框供用户边 用,也能建立组合边框或自己设计边框。 一种空白边框可以用于增大组件,同时协助布局管理器对容器中的组件进行合理的布局。

每个 Swing 组件都有一个对应的UI 类,例如 JButton组件就有一个对应的 ButtonUI 类来作为UI代理 。每个 Swing组件的UI代理的类名总是将该 Swing 组件类名的 J 去掉,然后在后面添加 UI 后缀 。 UI代理类通常是一个抽象基类 , 不同的 PLAF 会有不同的UI代理实现类 。 Swing 类库中包含了几套UI代理,分别放在不同的包下, 每套UI代理都几乎包含了所有 Swing组件的 ComponentUI实现,每套这样的实现都被称为一种PLAF 实现 。以 JButton 为例,其 UI 代理的继承层次下图:

简单了解swing(JFrame)

package 数字图像化处理Swing;
​
import javax.swing.*;
import java.awt.*;
​
public class Text01 {
​public static void main(String[] args) {new Jframe().init();}
}
​
class Jframe extends JFrame {public void init() {setBounds(100, 100, 500, 500);JLabel jl=new JLabel("awt和swing在大多数方法声明上面差不多,加了一个J");jl.setHorizontalAlignment(SwingConstants.CENTER);//居中显示add(jl);//获得一个容器,容器里面的颜色才是真正的颜色Container con=this.getContentPane();con.setBackground(Color.yellow);
​setVisible(true);setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);}
}
​
​

弹窗

JDialog,用来被弹出,默认就有关闭事件(原理就是单击事件之后出现另外一个窗口)

package 数字图像化处理Swing;
​
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
​
public class Text02 {public static void main(String[] args) {
new Mydailog();}
}
class Mydailog extends JFrame{public Mydailog(){setBounds(100,100,500,550);setVisible(true);setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);Container con=getContentPane();con.setBackground(Color.blue);//绝对布局con.setLayout(null);JButton jb=new JButton("点击开始游戏");jb.setBounds(150,150,200,80);con.add(jb);jb.addActionListener(new AbstractAction() {@Overridepublic void actionPerformed(ActionEvent e) {new Mytan();}});}
}
class Mytan extends JDialog{public Mytan(){this.setBounds(300,300,400,400);this.setVisible(true);Container con1=this.getContentPane();con1.setLayout(new FlowLayout());con1.add(new JLabel("恭喜你你通关了"));}
}

标签:

JLabel

JLabel jLabel = new JLabel("欢迎来到java-JFrame窗口",SwingConstants.CENTER);
//或者是jLabel.setHorizontalAlignment(SwingConstants.CENTER);//也是设置标签居中

图像标签ICON

import javax.swing.*;
import java.awt.*;
/*** Swing组件:标签(JLabel)设置图标标签*/
public class JLabelIcon extends JFrame implements Icon{private int width;private int height;//无参构造public JLabelIcon(){}public JLabelIcon(int width, int height) throws HeadlessException {this.width = width;this.height = height;}public static void main(String[] args) {new JLabelIcon(15,15).init();}public void init(){JLabelIcon jLabelIcon = new JLabelIcon(10, 10);JLabel label = new JLabel("标签图标", jLabelIcon, SwingConstants.CENTER);//第二个参数为Icon实现类Container container = this.getContentPane();container.add(label);this.setBounds(10,10,400,800);this.setVisible(true);this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);}@Overridepublic void paintIcon(Component c, Graphics g, int x, int y) {//画笔  画图标  创建对象后,默认自动画一次g.fillOval(x,y,width,height);}@Overridepublic int getIconWidth() {return this.width;}@Overridepublic int getIconHeight() {return this.height;}
}

将图片添加到标签内ImageIcon:

import javax.swing.*;
import java.awt.*;
import java.net.URL;
/*** 将图片添加到标签内* 添加一个图片到标签中,需要ImageIcon类*/
public class ImageIcon_ extends JFrame {public ImageIcon_(){//获取图片的地址JLabel label = new JLabel("ImageIcon",SwingConstants.CENTER);//设置标签的上下左右位置,所以是SwingConstantsURL url = ImageIcon_.class.getResource("Mid-AutumnFestival.jpg");//找到ImageIcon_类的同级目录下的1.jpg文件ImageIcon imageIcon = new ImageIcon(url);label.setIcon(imageIcon);setVisible(true);setBounds(100,100,400,400);setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);Container container = getContentPane();container.add(label);}public static void main(String[] args) {new ImageIcon_();}
}

面板

JPanel

import javax.swing.*;
import java.awt.*;
/*** JPanel面板*/
public class JPanel_ extends JFrame {public JPanel_() {Container container = this.getContentPane();container.setLayout(new GridLayout(2,1,10,10));JPanel panel1 = new JPanel(new GridLayout(1, 3));JPanel panel2 = new JPanel(new GridLayout(1, 2));JPanel panel3 = new JPanel(new GridLayout(2, 1));JPanel panel4 = new JPanel(new GridLayout(3,2));panel1.add(new JButton("1"));panel1.add(new JButton("1"));panel1.add(new JButton("1"));container.add(panel1);panel2.add(new JButton("2"));panel2.add(new JButton("2"));container.add(panel2);panel3.add(new JButton("3"));panel3.add(new JButton("3"));container.add(panel3);panel4.add(new JButton("4"));panel4.add(new JButton("4"));panel4.add(new JButton("4"));panel4.add(new JButton("4"));panel4.add(new JButton("4"));panel4.add(new JButton("4"));container.add(panel4);this.setVisible(true);this.setSize(800,800);this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);}public static void main(String[] args) {new JPanel_();}
}

滑动面板JScrollPane

import javax.swing.*;
import java.awt.*;
/*** JScrollPane:滑动面板 有滚动条*/
public class JScrollPane_ extends JFrame {public JScrollPane_() throws HeadlessException {Container container = this.getContentPane();//设置一个文本域  文本域可以换行,而文本框不行JTextArea textArea = new JTextArea(20,30);//设置起始行列数,行列可变化textArea.setText("滑动面板的文本域,有换行功能");//JScrollPane面板JScrollPane scrollPane = new JScrollPane(textArea);container.add(scrollPane);setVisible(true);setBounds(100,100,200,300);setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);}public static void main(String[] args) {new JScrollPane_();}
}

练习

实现如图效果,并且给每个图片添加单击事件,并且在单击按钮事件中加入滑条

package 数字图像化处理Swing;import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.net.URL;import static javax.swing.SwingConstants.*;public class Text03 {public static void main(String[] args) {new My03();}}
class My03 extends JFrame{public My03(){setVisible(true);Container con=getContentPane();JPanel panel1 = new JPanel(new GridLayout(1, 3));con.setLayout(new GridLayout(2,1,10,10));JButton jb1=new JButton("单击");JButton jb2=new JButton("不要点击");JButton jb3=new JButton("不要点击");JButton jb4=new JButton("不要点击");jb1.setBounds(200,200,100,100);con.add(jb1);con.setVisible(true);setBounds(1001,100,1000,1000);panel1.add(jb2);panel1.add(jb3);panel1.add(jb4);add(panel1);setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);jb2.addActionListener(new AbstractAction() {@Overridepublic void actionPerformed(ActionEvent e) {new My0302();}});jb3.addActionListener(new AbstractAction() {@Overridepublic void actionPerformed(ActionEvent e) {new My0302();}});jb4.addActionListener(new AbstractAction() {@Overridepublic void actionPerformed(ActionEvent e) {new My0302();}});jb1.addActionListener(new AbstractAction() {@Overridepublic void actionPerformed(ActionEvent e) {new My0301();}});}
}
class My0302 extends JFrame{public My0302(){setVisible(true);Container con=getContentPane();setBounds(100,100,500,500);JLabel jl=new JLabel("说了不要点击还点");jl.setHorizontalAlignment(CENTER);con.add(jl);con.setBackground(Color.yellow);}}
class My0301 extends JFrame{public My0301(){JLabel jl=new JLabel("ImageIcon", CENTER);Container con=getContentPane();URL ur=Text03.class.getResource("小球结束.png");ImageIcon im=new ImageIcon(ur);jl.setIcon(im);setVisible(true);setBounds(100,100,500,500);con.add(jl);JScrollPane scrollPane = new JScrollPane(jl);con.add(scrollPane);setDefaultCloseOperation(CENTER);}
}

按钮

图标按钮:把一个图标变为一个按钮图标

import javax.swing.*;
import java.awt.*;
import java.net.URL;
/*** 设置一个图标按钮  加了一个按钮提示方法* 将一个图片变为图标*/
public class JButtonIcon extends JFrame {public JButtonIcon() throws HeadlessException {Container container = getContentPane();//将一个图片变成图标URL url = JButtonIcon.class.getResource("Mid-AutumnFestival.jpg");ImageIcon imageIcon = new ImageIcon(url);//把这个图标放在按钮上JButton button = new JButton();button.setIcon(imageIcon);button.setToolTipText("图片按钮");//设置提示按钮,鼠标放到按钮上面会弹出一些提示container.add(button);setSize(500,300);setVisible(true);setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);}public static void main(String[] args) {new JButtonIcon();}
}
  • 单选按钮

    将按钮添加进来,不是将组添加进来!! 要设置按钮的位置,避免出现覆盖现象,没有设置组的话,就是多选

    import javax.swing.*;
    import java.awt.*;
    import java.net.URL;
    /*** 单选按钮  JRadioButton* 需要用到一个组,ButtonGroup*/
    public class JButton_1 extends JFrame {public void init(){Container container = getContentPane();//单选框JRadioButton radioButton1 = new JRadioButton("JRdioButton1");JRadioButton radioButton2 = new JRadioButton("JRdioButton2");JRadioButton radioButton3 = new JRadioButton("JRdioButton3");//由于是单选框,需要准备一个组,让三个按钮在这组内实现单选功能ButtonGroup group = new ButtonGroup();group.add(radioButton1);group.add(radioButton2);group.add(radioButton3);//将按钮添加进来,不是将组添加进来!! 要设置按钮的位置,避免出现覆盖现象container.add(radioButton1,BorderLayout.NORTH);container.add(radioButton2,BorderLayout.CENTER);container.add(radioButton3,BorderLayout.SOUTH);setSize(500,300);setVisible(true);setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);}public static void main(String[] args) {new JButton_1().init();}
    }
  • 复选按钮

    import javax.swing.*;
    import java.awt.*;
    /*** 多选框 JCheckBox*/
    public class JButton_2 extends JFrame {public void init(){Container container = getContentPane();//多选框JCheckBox checkBox1 = new JCheckBox("checkBox1");JCheckBox checkBox2 = new JCheckBox("checkBox2");JCheckBox checkBox3 = new JCheckBox("checkBox3");container.add(checkBox1,BorderLayout.NORTH);container.add(checkBox2,BorderLayout.CENTER);container.add(checkBox3,BorderLayout.SOUTH);setSize(500,300);setVisible(true);setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);}public static void main(String[] args) {new JButton_2().init();}
    }

3.6 列表

  • 下拉框

    import javax.swing.*;
    import java.awt.*;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    /*** 下拉框  JComboBox类* System.out.println(comboBox.getSelectedIndex());//返回当前项的位置* System.out.println(comboBox.getSelectedItem());//返回当前项的内容*/
    public class Combobox_1 extends JFrame {public Combobox_1() {Container container = this.getContentPane();JComboBox comboBox = new JComboBox();comboBox.addItem("正在热映");comboBox.addItem(null);comboBox.addItem("即将上映");comboBox.addItem("下架");container.add(comboBox,BorderLayout.NORTH);comboBox.addActionListener(new MyActionListener());this.setVisible(true);this.setBounds(100,100,400,400);this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);}public static void main(String[] args) {new Combobox_1();}
    }
    class MyActionListener implements ActionListener{@Overridepublic void actionPerformed(ActionEvent e) {JComboBox comboBox=(JComboBox)e.getSource();System.out.println(comboBox.getSelectedIndex());//返回当前项的位置System.out.println(comboBox.getSelectedItem());//返回当前项的内容}
    }
  • 列表框

    import javax.swing.*;
    import java.awt.*;
    import java.util.Vector;
    /*** 列表框  JList* 每一项都是可点击的*/
    public class Combobox_2 extends JFrame {public Combobox_2() {Container container = this.getContentPane();//生成列表的内容//String[] contents={"Item1","Item2","Item3"};//静态变量Vector vector = new Vector();//动态变量 动态集合JList list = new JList(vector);//列表中需要放入内容container.add(list);vector.add("正在热映");vector.add(null);//与下拉框不同,动态集合自动排除掉为空的内容,所以这里显示的就两个项vector.add("已下架");this.setVisible(true);this.setBounds(100,100,400,400);this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);}public static void main(String[] args) {new Combobox_2();}
    }
  • 应用场景

    • 选择地区,或者一些单个选项 (选项只有两个的话建议使用单选框,三个以上建议使用下拉框)

    • 列表框,展示项信息,一般都是动态扩容

3.7 文本框

  • 文本框:

import javax.swing.*;
import java.awt.*;
/*** 文本框 JTextField* 不能换行*/
public class JTextField_ extends JFrame {public JTextField_() throws HeadlessException {Container container = this.getContentPane();//设置文本框 不能换行JTextField textField1 = new JTextField("hello");//设置初始内容JTextField textField2 = new JTextField("world",20);//设置起始字符数,行列可变化container.add(textField1,BorderLayout.NORTH);container.add(textField2,BorderLayout.SOUTH);setVisible(true);setBounds(100,100,200,300);setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);}public static void main(String[] args) {new JTextField_();}
}
  • 密码框

    import javax.swing.*;
    import java.awt.*;
    /*** 密码框 JPasswordField 在文本框中用一个字符隐藏内容* 是JTextField的子类  默认是一个小黑点隐藏*/
    public class JPasswordField_ extends JFrame {public JPasswordField_() throws HeadlessException {Container container = this.getContentPane();//设置文本框 不能换行JPasswordField passwordField = new JPasswordField("hello");//设置初始内容passwordField.setEchoChar('*');//设置用一个字符代替输入字符,实现隐藏作用System.out.println(passwordField.getPassword());//得到文本框的内容container.add(passwordField,BorderLayout.NORTH);setVisible(true);setBounds(100,100,200,300);setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);}public static void main(String[] args) {new JPasswordField_();}
    }
  • 文本域

import javax.swing.*;
import java.awt.*;
/*** 文本域*/
public class JTextArea_ extends JFrame {public JTextArea_() throws HeadlessException {Container container = this.getContentPane();//设置一个文本域  文本域可以换行,而文本框不行JTextArea textArea = new JTextArea(20,30);//设置起始行列数,行列可变化textArea.setText("滑动面板的文本域,有换行功能");//JScrollPane面板JScrollPane scrollPane = new JScrollPane(textArea);container.add(scrollPane);setVisible(true);setBounds(100,100,200,300);setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);}public static void main(String[] args) {new JTextArea_();}
}

JTree、TreeModel实现树

树也是图形用户界面中使用非常广泛的 GUI 组件,例如使用 Windows 资源管理器时,将看到如下图所示的目录树:

如上图所示的树,代表计算机世界里的树,它从自然界实际的树抽象而来 。 计算机世界里的树是由一系列具有严格父子关系的节点组成的,每个节点既可以是其上一级节点的子节点,也可以是其下一级节点的父节点,因此同一个节点既可以是父节点,也可以是子节点(类似于一个人,他既是他儿子的父亲,又是他父亲的儿子)。

按照结点是否包含子结点,可以把结点分为下面两类:

普通结点:包含子结点的结点;

叶子结点:没有子结点的结点;

按照结点是否具有唯一的父结点,可以把结点分为下面两类:

根结点:没有父结点的结点,计算机中,一棵树只能有一个根结点

普通结点:具有唯一父结点的结点

使用 Swing 里的 Jtree 、 TreeModel 及其相关的辅助类可以很轻松地开发出计算机世界里的树。

创建树

Swing 使用 JTree 对 象来代表一棵树,JTree 树中结点可以使用 TreePath 来标识,该对象封装了当前结点及其所有的父结点。

当一个结点具有子结点时,该结点有两种状态:

展开状态:当父结点处于展开状态时,其子结点是可见的;

折叠状态: 当父结点处于折叠状态时,其子结点都是不可见的 。

如果某个结点是可见的,则该结点的父结点(包括直接的、间接的父结点)都必须处于展开状态,只要有任意一个父结点处于折叠状态,该结点就是不可见的 。

JTree常用构造方法:

JTree(TreeModel newModel):使用指定 的数据模型创建 JTree 对象,它默认显示根结点。
JTree(TreeNode root): 使用 root 作为根节 点创建 JTree 对象,它默认显示根结点 。
JTree(TreeNode root, boolean asksAllowsChildren): 使用root作为根结点创建JTree对象,它默认显示根结点。 asksAllowsChildren 参数控制怎样的结点才算叶子结点,如果该参数为 true ,则只有当程序使用 setAllowsChildren(false)显式设置某个结点不允许添加子结点时(以后也不会拥有子结点) ,该结点才会被 JTree 当成叶子结点:如果该参数为 false ,则只要某个结点当时没有子结点(不管以后是否拥有子结点) ,该结点都会被 JTree 当成叶子结点。

TreeNode继承体系及使用:

在构建目录树时,可以先创建很多DefaultMutableTreeNode对象,并调用他们的add方法构建好子父级结构,最后根据根结点构建一个JTree即可。

案例:

使用JTree和TreeNode完成下图效果:

演示代码:

import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;public class SimpleJTree {JFrame jf = new JFrame("简单树");JTree tree;DefaultMutableTreeNode root;DefaultMutableTreeNode guangdong;DefaultMutableTreeNode guangxi;DefaultMutableTreeNode foshan;DefaultMutableTreeNode shantou;DefaultMutableTreeNode guilin;DefaultMutableTreeNode nanning;public void init(){//依次创建所有结点root = new DefaultMutableTreeNode("中国");guangdong = new DefaultMutableTreeNode("广东");guangxi = new DefaultMutableTreeNode("广西");foshan = new DefaultMutableTreeNode("佛山");shantou = new DefaultMutableTreeNode("汕头");guilin = new DefaultMutableTreeNode("桂林");nanning = new DefaultMutableTreeNode("南宁");//通过add()方法建立父子层级关系guangdong.add(foshan);guangdong.add(shantou);guangxi.add(guilin);guangxi.add(nanning);root.add(guangdong);root.add(guangxi);//依据根结点,创建JTreetree = new JTree(root);jf.add(new JScrollPane(tree));jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);jf.pack();jf.setVisible(true);}public static void main(String[] args) {new SimpleJTree().init();}
}

JTree的其他外观设置方法:

tree.putClientProperty( "JTree.lineStyle", "None"):设置结点之间没有连接线
tree.putClientProperty("JTree.lineStyle" , "Horizontal"):设置结点之间只有水平分割线
tree.setShowsRootHandles(true):设置根结点有"展开、折叠"图标
tree.setRootVisible(false):隐藏根结点

DefaultMutableTreeNode其他成员方法:

Enumeration breadthFirstEnumerationO/preorderEnumeration(): 按广度优先的顺序遍历以此结点为根的子树,并返回所有结点组成的枚举对象 。
Enumeration depthFirstEnumerationO/postorderEnumeration(): 按深度优先的顺序遍历以此结点为根的子树,并返回所有结点组成的枚举对象 。
DefaultMutableTreeNode getNextSibling(): 返回此结点的下一个兄弟结点 。
TreeNode getParent(): 返回此结点的父结点 。 如果此结点没有父结点,则返回null 。
TreeNode[] getPath(): 返回从根结点到达此结点的所有结点组成的数组。
DefaultMutableTreeNode getPreviousSibling(): 返回此结点的上一个兄弟结点。
TreeNode getRoot(): 返回包含此结点的树的根结点 。
TreeNode getSharedAncestor(DefaultMutableTreeNode aNode): 返回此结点和aNode最近的共同祖先 。
int getSiblingCount(): 返回此结点的兄弟结点数 。
boolean isLeaf(): 返回该结点是否是叶子结点 。
boolean isNodeAncestor(TreeNode anotherNode): 判断anotherNode是否是当前结点的祖先结点(包括父结点) 。
boolean isNodeChild(TreeNode aNode): 如果aNode是此结点的子结点,则返回true。
boolean isNodeDescendant(DefaultMutableTreeNode anotherNode): 如果 anotherNode 是此结点的后代,包括是此结点本身、此结点的子结点或此结点的子结点的后代,都将返回true 。
boolean isNodeRelated(DefaultMutableTreeNode aNode) : 当aNode和当前结点位于同一棵树中时返回 true 。
boolean isNodeSibling(TreeNode anotherNode): 返回anotherNode是否是当前结点的兄弟结点 。
boolean isRoot(): 返回当前结点是否是根结点 。
Enumeration pathFromAncestorEnumeration(TreeNode ancestor): 返回从指定祖先结点到当前结点的所有结点组成的枚举对象 。

拖动、编辑树结点

JTree 生成的树默认是不可编辑的,不可以添加、删除结点,也不可以改变结点数据 :如果想让某个 JTree 对象变成可编辑状态,则可以调用 JTree 的setEditable(boolean b)方法,传入 true 即可把这棵树变成可编辑的树(可以添加、删除结点,也可以改变结点数据) 。

编辑树结点的步骤:

  1. 获取当前被选中的结点:

获取当前被选中的结点,会有两种方式:一:通过JTree对象的某些方法,例如 TreePath getSelectionPath()等,得到一个TreePath对象,包含了从根结点到当前结点路径上的所有结点;调用TreePath对象的 Object getLastPathComponent()方法,得到当前选中结点二:调用JTree对象的 Object getLastSelectedPathComponent() 方法获取当前被选中的结点
  1. 调用DefaultTreeModel数据模型有关增删改的一系列方法完成编辑,方法执行完后,会自动重绘JTree

案例:

使用JTree以及DefaultTreeModel、DefaultMutableTreeNode、TreePath完成下图效果:

演示代码:

import javax.swing.*;
import javax.swing.tree.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;public class EditTree {JFrame jf ;JTree tree;//JTree关联的数据模型对象DefaultTreeModel model;//定义几个初始结点DefaultMutableTreeNode root = new DefaultMutableTreeNode("中国");DefaultMutableTreeNode guangdong = new DefaultMutableTreeNode("广东");DefaultMutableTreeNode guangxi = new DefaultMutableTreeNode("广西");DefaultMutableTreeNode foshan = new DefaultMutableTreeNode("佛山");DefaultMutableTreeNode shantou = new DefaultMutableTreeNode("汕头");DefaultMutableTreeNode guilin = new DefaultMutableTreeNode("桂林");DefaultMutableTreeNode nanning = new DefaultMutableTreeNode("南宁");//定义需要被拖动的TreePathTreePath movePath;//定义按钮,完成操作JButton addSiblingBtn = new JButton("添加兄弟结点");JButton addChildBtn = new JButton("添加子结点");JButton deleteBtn = new JButton("删除结点");JButton editBtn = new JButton("编辑当前结点");public void init(){//通过add()方法建立父子层级关系guangdong.add(foshan);guangdong.add(shantou);guangxi.add(guilin);guangxi.add(nanning);root.add(guangdong);root.add(guangxi);jf = new JFrame("可编辑结点的树");tree = new JTree(root);//获取JTree关联的数据模型TreeModel对象model = (DefaultTreeModel) tree.getModel();//设置JTree可编辑tree.setEditable(true);//创建鼠标事件监听器MouseListener ml = new MouseAdapter() {//按下鼠标时,获得被拖动的结点@Overridepublic void mousePressed(MouseEvent e) {//如果需要唯一确定某个结点,则必须通过TreePath来获取TreePath tp = tree.getPathForLocation(e.getX(), e.getY());if (tp!=null){movePath = tp;}}//松开树表示,确定即将被拖入到的父结点@Overridepublic void mouseReleased(MouseEvent e) {TreePath tp = tree.getPathForLocation(e.getX(), e.getY());if (tp!=null && movePath!=null){//阻止向子结点拖动if (movePath.isDescendant(tp) && movePath!=tp){JOptionPane.showMessageDialog(jf,"目标结点是被移动结点的子结点,无法移动!","非法移动",JOptionPane.WARNING_MESSAGE);}//不是向子结点移动,并且鼠标按下和松开也不是同一个结点if (movePath!=tp){//add方法内部,先将该结点从原父结点删除,然后再把该结点添加到新结点中DefaultMutableTreeNode tartParentNode = (DefaultMutableTreeNode) tp.getLastPathComponent();DefaultMutableTreeNode moveNode = (DefaultMutableTreeNode) movePath.getLastPathComponent();tartParentNode.add(moveNode);movePath=null;tree.updateUI();}}}};//为JTree添加鼠标监听器tree.addMouseListener(ml);JPanel panel = new JPanel();addSiblingBtn.addActionListener(e -> {//获取选中结点DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();//如果结点为空,则直接返回if (selectedNode==null){return;}//获取该选中结点的父结点DefaultMutableTreeNode parent = (DefaultMutableTreeNode) selectedNode.getParent();//如果父结点为空,则直接返回if (parent==null){return;}//创建一个新结点DefaultMutableTreeNode newNode = new DefaultMutableTreeNode("新结点");//获取选中结点的索引int selectedIndex = parent.getIndex(selectedNode);//在选中位置插入新结点model.insertNodeInto(newNode,parent,selectedIndex);//----------显示新结点---------------//获取从根结点到新结点的所有结点TreeNode[] pathToRoot = model.getPathToRoot(newNode);//使用指定的结点数组创建TreePathTreePath treePath = new TreePath(pathToRoot);//显示指定的treePathtree.scrollPathToVisible(treePath);});panel.add(addSiblingBtn);addChildBtn.addActionListener(e -> {//获取选中结点DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();if (selectedNode==null){return ;}//创建新结点DefaultMutableTreeNode newNode = new DefaultMutableTreeNode("新结点");//model.insertNodeInto(newNode,selectedNode,selectedNode.getChildCount());使用TreeModel的方法添加,不需要手动刷新UIselectedNode.add(newNode);//使用TreeNode的方法添加,需要手动刷新UI//显示新结点TreeNode[] pathToRoot = model.getPathToRoot(newNode);TreePath treePath = new TreePath(pathToRoot);tree.scrollPathToVisible(treePath);//手动刷新UItree.updateUI();});panel.add(addChildBtn);deleteBtn.addActionListener(e -> {DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();if (selectedNode!=null && selectedNode.getParent()!=null){model.removeNodeFromParent(selectedNode);}});panel.add(deleteBtn);//实现编辑结点的监听器editBtn.addActionListener(e -> {TreePath selectionPath = tree.getSelectionPath();if (selectionPath!=null){//编辑选中结点tree.startEditingAtPath(selectionPath);}});panel.add(editBtn);jf.add(new JScrollPane(tree));jf.add(panel, BorderLayout.SOUTH);jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);jf.pack();jf.setVisible(true);}public static void main(String[] args) {new EditTree().init();}
}

监听结点事件

修改JTree的选择模式:

JTree 专门提供了 一个 TreeSelectionModel 对象来保存该 JTree 选中状态的信息 。 也就是说,JTree组件背后隐藏了两个 model 对象 , 其中TreeModel 用于保存该 JTree 的所有节点数据 , 而TreeSelectionModel 用于保存该 JTree的所有选中状态的信息 。

程序可以改变 JTree 的选择模式 , 但必须先获取该 JTree 对应的 TreeSelectionMode1 对象 , 再调用该对象的 setSelectionMode(int mode);方法来设置该JTree的选择模式 ,其中model可以有如下3种取值:

  1. TreeSelectionModel.CONTIGUOUS_TREE_SELECTION: 可 以连续选中多个 TreePath 。

  2. TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION : 该选项对于选择没有任何限制 。

  3. TreeSelectionModel.SINGLE_TREE_SELECTION: 每次只能选择一个 TreePath 。

为JTree添加监听器:

  1. addTreeExpansionListener(TreeExpansionListener tel) : 添加树节点展开/折叠事件的监听器。

  2. addTreeSelectionListener(TreeSelectionListener tsl) : 添加树节点选择事件的监听器。

案例:

实现下图效果:

演示代码:

import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;public class SelectJTree {JFrame jf = new JFrame("监听树的选择事件");JTree tree;DefaultMutableTreeNode root = new DefaultMutableTreeNode("中国");DefaultMutableTreeNode guangdong = new DefaultMutableTreeNode("广东");DefaultMutableTreeNode guangxi = new DefaultMutableTreeNode("广西");DefaultMutableTreeNode foshan = new DefaultMutableTreeNode("佛山");DefaultMutableTreeNode shantou = new DefaultMutableTreeNode("汕头");DefaultMutableTreeNode guilin = new DefaultMutableTreeNode("桂林");DefaultMutableTreeNode nanning = new DefaultMutableTreeNode("南宁");JTextArea eventTxt = new JTextArea(5, 20);public void init() {//通过add()方法建立父子层级关系guangdong.add(foshan);guangdong.add(shantou);guangxi.add(guilin);guangxi.add(nanning);root.add(guangdong);root.add(guangxi);tree = new JTree(root);//添加监听器tree.addTreeSelectionListener(e -> {if (e.getOldLeadSelectionPath()!=null){eventTxt.append("原选中结点的路径:"+e.getOldLeadSelectionPath().toString()+"\n");}eventTxt.append("新选中结点的路径:"+e.getNewLeadSelectionPath().toString()+"\n");});tree.setShowsRootHandles(true);tree.setRootVisible(true);Box box = Box.createHorizontalBox();box.add(new JScrollPane(tree));box.add(new JScrollPane(eventTxt));jf.add(box);jf.pack();jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);jf.setVisible(true);}public static void main(String[] args) {new SelectJTree().init();}
}

使用DefaultTreeCellRenderer改变结点外观

JTree默认的外观是比较单一的,它提供了如下几种改变结点外观的方式:

  1. 使用 DefaultTreeCellRenderer 直接改变节点的外观,这种方式可 以 改变整棵树所有节点 的字体、颜色和图标 。

  2. 为 JTree 指定 DefaultTreeCellRenderer 的扩展类对象作为 JTree 的节点绘制器,该绘制器负责为不同节点使用不同的字体、颜色和图标。通常使用这种方式来改变节点的外观 。

  3. 为 JTree 指定一个实现 TreeCellRenderer 接口的节点绘制器,该绘制器可以为不同的节点自由绘制任意内容,这是最复杂但最灵活的节点绘制器 。

第 一种方式最简单 , 但灵活性最差 ,因为它会改变整棵树所有节点的外观 。 在这种情况下 , Jtree的所有节点依然使用相同的图标 ,相当于整体替换了 Jtree 中 节点的所有默认图标 。 用户指定 的节点图标未必就比 JTree 默认的图标美观 。

DefaultTreeCellRenderer 提供了如下几个方法来修改节点的外观:

setBackgroundNonSelectionColor(Color newColor): 设置用于非选定节点的背景颜色 。
setBackgroundSelectionColor(Color newColor): 设置节点在选中状态下的背景颜色 。
setBorderSelectionColor(Color newColor): 设置选中状态下节点的边框颜色 。
setClosedIcon(Icon newIcon): 设置处于折叠状态下非叶子节点的图标 。
setFont(Font font) : 设置节点文本 的 字体。
setLeaflcon(Icon newIcon): 设置叶子节点的图标 。
setOpenlcon(Icon newlcon): 设置处于展开状态下非叶子节 点的图标。
setTextNonSelectionColor(Color newColor): 设置绘制非选中状态下节点文本的颜色 。
setTextSelectionColor(Color newColor): 设置绘制选中状态下节点文本的颜色 。

案例:

使用DefaultTreeCellRenderer完成下图效果:

演示代码:

import cn.itcast.swing.util.ImagePathUtil;import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import java.awt.*;public class ChangeAllCellRender {JFrame jf = new JFrame("改变所有结点外观");JTree tree;DefaultMutableTreeNode root = new DefaultMutableTreeNode("中国");DefaultMutableTreeNode guangdong = new DefaultMutableTreeNode("广东");DefaultMutableTreeNode guangxi = new DefaultMutableTreeNode("广西");DefaultMutableTreeNode foshan = new DefaultMutableTreeNode("佛山");DefaultMutableTreeNode shantou = new DefaultMutableTreeNode("汕头");DefaultMutableTreeNode guilin = new DefaultMutableTreeNode("桂林");DefaultMutableTreeNode nanning = new DefaultMutableTreeNode("南宁");public void init(){//通过add()方法建立父子层级关系guangdong.add(foshan);guangdong.add(shantou);guangxi.add(guilin);guangxi.add(nanning);root.add(guangdong);root.add(guangxi);tree = new JTree(root);//创建一个DefaultTreeCellRenderer对象DefaultTreeCellRenderer cellRenderer = new DefaultTreeCellRenderer();//设置非选定结点的背景颜色cellRenderer.setBackgroundNonSelectionColor(new Color(220,220,220));//设置选中结点的背景色cellRenderer.setBackgroundSelectionColor(new Color(140,140,140));//设置选中状态下结点的边框颜色cellRenderer.setBorderSelectionColor(Color.BLACK);//设置处于折叠状态下非叶子结点的图标cellRenderer.setClosedIcon(new ImageIcon(ImagePathUtil.getRealPath("10\\close.gif")));//设置结点文本的字体cellRenderer.setFont(new Font("SansSerif",Font.BOLD,16));//设置叶子结点图标cellRenderer.setLeafIcon(new ImageIcon(ImagePathUtil.getRealPath("10\\leaf.png")));//设置处于展开状态下非叶子结点图标跑cellRenderer.setOpenIcon(new ImageIcon(ImagePathUtil.getRealPath("10\\open.gif")));//设置绘制非选中状态下结点文本颜色cellRenderer.setTextNonSelectionColor(new Color(255,0,0));//设置选中状态下结点的文本颜色cellRenderer.setTextSelectionColor(new Color(0,0,255));tree.setCellRenderer(cellRenderer);tree.setShowsRootHandles(true);tree.setRootVisible(true);jf.add(new JScrollPane(tree));jf.pack();jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);jf.setVisible(true);}public static void main(String[] args) {new ChangeAllCellRender().init();}}

扩展DefaultTreeCellRenderer改变结点外观

DefaultTreeCellRenderer 实现类实现了TreeCellRenderer接口,该接口里只有 一个用于绘制节点内容的方法: getTreeCellRendererComponent() , 该方法负责绘制 JTree 节点 。学习JList的时候,如果要绘制JList的列表项外观的内容,需要实现ListCellRenderer 接口,通过重写getTreeCellRendererComponent()方法返回一个Component 对象 , 该对象就是 JTree 的节点组件 。两者之间非常类似

DefaultTreeCellRende rer 类继承了JLabel,实现 getTreeCellRendererComponent()方法时返回 this ,即返回一个特殊的 JLabel 对象 。 如果需要根据节点内容来改变节点的外观,则可以再次扩展DefaultTreeCellRenderer 类,并再次重写它提供的 getTreeCellRendererComponent()方法。

案例:

自定义类继承DefaultTreeCellRenderer,重写getTreeCellRendererComponent()方法,实现下图效果:

演示代码:

import cn.itcast.swing.util.ImagePathUtil;import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import java.awt.*;public class ExtendsDefaultCellTreeRenderer {JFrame jf = new JFrame("根据结点类型定义图标");JTree tree;//定义几个初始结点DefaultMutableTreeNode root = new DefaultMutableTreeNode(new NodeData(DBObjectType.ROOT,"数据库导航"));DefaultMutableTreeNode salaryDb = new DefaultMutableTreeNode(new NodeData(DBObjectType.DATABASE,"公司工资数据库"));DefaultMutableTreeNode customerDb = new DefaultMutableTreeNode(new NodeData(DBObjectType.DATABASE,"公司客户数据库"));DefaultMutableTreeNode employee = new DefaultMutableTreeNode(new NodeData(DBObjectType.TABLE,"员工表"));DefaultMutableTreeNode attend = new DefaultMutableTreeNode(new NodeData(DBObjectType.TABLE,"考勤表"));DefaultMutableTreeNode concat = new DefaultMutableTreeNode(new NodeData(DBObjectType.TABLE,"联系方式表"));DefaultMutableTreeNode id = new DefaultMutableTreeNode(new NodeData(DBObjectType.INDEX,"员工ID"));DefaultMutableTreeNode name = new DefaultMutableTreeNode(new NodeData(DBObjectType.COLUMN,"姓名"));DefaultMutableTreeNode gender = new DefaultMutableTreeNode(new NodeData(DBObjectType.COLUMN,"性别"));public void init(){//通过结点的add方法,建立结点的父子关系root.add(salaryDb);root.add(customerDb);salaryDb.add(employee);salaryDb.add(attend);customerDb.add(concat);concat.add(id);concat.add(name);concat.add(gender);tree = new JTree(root);tree.setCellRenderer(new MyRenderer());tree.setShowsRootHandles(true);tree.setRootVisible(true);//设置使用windows外观风格try {UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");} catch (Exception e) {e.printStackTrace();}//更新JTree的UI外观SwingUtilities.updateComponentTreeUI(tree);jf.add(new JScrollPane(tree));jf.pack();jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);jf.setVisible(true);}public static void main(String[] args) {new ExtendsDefaultCellTreeRenderer().init();}class MyRenderer extends DefaultTreeCellRenderer{//初始化5个图标ImageIcon rootIcon = new ImageIcon(ImagePathUtil.getRealPath("10\\root.gif"));ImageIcon databaseIcon = new ImageIcon(ImagePathUtil.getRealPath("10\\database.gif"));ImageIcon tableIcon = new ImageIcon(ImagePathUtil.getRealPath("10\\table.gif"));ImageIcon columnIcon = new ImageIcon(ImagePathUtil.getRealPath("10\\column.gif"));ImageIcon indexIcon = new ImageIcon(ImagePathUtil.getRealPath("10\\index.gif"));@Overridepublic Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) {//执行父类默认的绘制结点操作super.getTreeCellRendererComponent(tree,value,sel,expanded,leaf,row,hasFocus);DefaultMutableTreeNode  node = (DefaultMutableTreeNode) value;NodeData data = (NodeData) node.getUserObject();//根据结点数据中的nodeType决定结点的图标ImageIcon icon = null;switch (data.nodeType){case DBObjectType.ROOT:icon = rootIcon;break;case DBObjectType.DATABASE:icon = databaseIcon;break;case DBObjectType.TABLE:icon = tableIcon;break;case DBObjectType.COLUMN:icon = columnIcon;break;case DBObjectType.INDEX:icon = indexIcon;break;}//改变图标this.setIcon(icon);return this;}}//定义一个NodeData类,用于封装结点数据class NodeData{public int nodeType;public String nodeData;public NodeData(int nodeType, String nodeData) {this.nodeType = nodeType;this.nodeData = nodeData;}@Overridepublic String toString() {return this.nodeData;}}//定义一个接口,该接口里包含数据库对象类型的常量interface  DBObjectType{int ROOT=0;int DATABASE=1;int TABLE=2;int COLUMN=3;int INDEX=4;}}

实现TreeCellRenderer接口改变结点外观

这种改变结点外观的方式是最灵活的,程序实现TreeCellRenderer接口时同样需要实现getTreeCellRendererComponent()方法,该方法可以返回任意类型的组件,该组件将作为JTree的结点。通过这种方式可以最大程度的改变结点的外观。

案例:

自定义类,继承JPanel类,实现TreeCellRenderer接口,完成下图效果:

演示代码:

import cn.itcast.swing.util.ImagePathUtil;import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeCellRenderer;
import java.awt.*;public class CustomerTreeNode {JFrame jf = new JFrame("定制树的结点");JTree tree;//定义几个初始结点DefaultMutableTreeNode friends = new DefaultMutableTreeNode("我的好友");DefaultMutableTreeNode qingzhao = new DefaultMutableTreeNode("李清照");DefaultMutableTreeNode suge = new DefaultMutableTreeNode("苏格拉底");DefaultMutableTreeNode libai = new DefaultMutableTreeNode("李白");DefaultMutableTreeNode nongyu = new DefaultMutableTreeNode("弄玉");DefaultMutableTreeNode hutou = new DefaultMutableTreeNode("虎头");public void init() {friends.add(qingzhao);friends.add(suge);friends.add(libai);friends.add(nongyu);friends.add(hutou);tree = new JTree(friends);tree.setShowsRootHandles(true);tree.setRootVisible(true);tree.setCellRenderer(new ImageCellRenderer());jf.add(new JScrollPane(tree));jf.pack();jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);jf.setVisible(true);}public static void main(String[] args) {new CustomerTreeNode().init();}class ImageCellRenderer extends JPanel implements TreeCellRenderer {private ImageIcon icon;private String name;//定义绘制单元格时的背景色private Color background;//定义绘制单元格时的前景色private Color foreground;@Overridepublic Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {icon = new ImageIcon(ImagePathUtil.getRealPath("10\\" + value + ".gif"));name = value.toString();background = hasFocus ? new Color(140, 200, 235) : new Color(255, 255, 255);foreground = hasFocus ? new Color(255,255,3) : new Color(0,0,0);//返回当前JPanel作为结点return this;}//重写paintComponent改变JPanel的外观@Overrideprotected void paintComponent(Graphics g) {int imageWidth = icon.getImage().getWidth(null);int imageHeight = icon.getImage().getHeight(null);g.setColor(background);g.fillRect(0,0,getWidth(),getHeight());g.setColor(foreground);//绘制好友图标g.drawImage(icon.getImage(),getWidth()/2-imageWidth/2,10,null);//绘制好友姓名g.setFont(new Font("SansSerif",Font.BOLD,18));g.drawString(name,getWidth()/2-name.length()*10,imageHeight+30);}//设置当前组件结点最佳大小@Overridepublic Dimension getPreferredSize() {return new Dimension(80,80);}}
}

关于我写了三万字博客后悔了好久这件事之第二个三万字GUI(swing)相关推荐

  1. 关于队里面最菜的在博客打卡第六天这件事

    这是一道水题 题目链接:Problem - 1738B - Codeforces 代码: #include<iostream> #include<vector> using n ...

  2. SEO网络优化的三个博客优化技巧

    相信大家都听说过"博客",很多人也在使用博客记录自己的日常生活,但是对于新站长而言,刚开始写博客记录自己的学习经历,分享知识经验,很容易一腔热血在几个月以后就被打回原形,因为自身S ...

  3. 闽江学院2015-2016学年下学期《软件测试》课程-第三次博客作业

    闽江学院2015-2016学年下学期<软件测试>课程-第三次博客作业 作业提交班级:13软金2班全体同学 作业提交截止日期:2016年4月30日24:00前(超过截止时间提交的不给成绩) ...

  4. OO第三次博客总结作业

    OO第三次博客总结作业 1.规格化设计的大致发展历史和为什么得到了人们的重视  发展历史...上网搜索了一圈...什么都没搜索到,只能谈谈自己对规格化设计重要性的一些看法. 规格化设计,顾名思义,是有 ...

  5. OO第三次博客作业——规格

    OO第三次博客作业--规格 一.调研结果: 规格的历史: 引自博文链接:http://blog.sina.com.cn/s/blog_473d5bba010001x9.html 传统科学的特点是发现世 ...

  6. [BUAA OO]第三次博客作业

    OO第三次博客作业 1. 规格化设计的发展 我认为,规格化设计主要源自于软件设计的两次危机.第一次是由于大量存在的goto语句,让当时被广泛应用的面向过程式的编程语言臃肿不堪,在逻辑性上与工程规模上鱼 ...

  7. 博客小白如何快捷而又优雅的写好一篇博客

    人是注定要受自由之苦的. 有目录,不迷路 前言 Typora Markdown语法详解 标题 摘要 目录 文字 加粗 斜体 引用 删除线 文字标记 居中 颜色 组合 代码 多行代码 单行代码 列表 有 ...

  8. 我从大学开始写博客,如何写一篇技术博客,谈谈我的看法!

    前言 只有光头才能变强. 文本已收录至我的GitHub精选文章,欢迎Star:https://github.com/ZhongFuCheng3y/3y 我一直推崇学技术可以写技术博客去沉淀自己的知识, ...

  9. 注册博客,写的第一篇博客

    写的第一篇博客 一.谈谈以下内容 1.自我介绍. 2.编程的目标. 3.打算怎样学习编程? 4.打算每周花费多少时间? 5.我最想从事什么工作? 一.谈谈以下内容 1.自我介绍. 我目前是就读于辽宁工 ...

最新文章

  1. 黑马lavarel教程---9、缓存操作
  2. (三)nodejs循序渐进-值传递和引用传递,深拷贝和浅拷贝(基础篇)
  3. MySQL索引(1)
  4. 如何用 200 行 JavaScript 代码实现人脸检测?
  5. 与数据绑定相关的接口(转)
  6. K8s(二):130 道 K8s/Docker 配套练习题,学+练结合,一次吃透
  7. c语言开发kafka环境,c++(11)使用librdkafka库实现kafka的消费实例
  8. Flink状态专题:keyed state和Operator state
  9. 3D重建模的初步了解
  10. 室内三维地图编辑器,制作地图软件哪个最好
  11. (stream流)List转Map
  12. mysql中 经纬度用什么类型存储_MySQL数据库之***mysql中经度纬度字段用什么存储(关于mysql的float和decimal区别)...
  13. 网页设计html颜色大全,50个使用柔和色彩的网页设计作品欣赏
  14. 跨境支付成为第三方支付企业新战场
  15. 使用FeedDemon整理RSS Feed
  16. WinXP如何自动清理Temp文件夹
  17. React-滑条组件使用
  18. python中button对象的方法_Python cmds.shelfButton方法代码示例
  19. 大数据晋级之路(4)Hadoop生态系统体系架构及基本概念
  20. 互联网日报 | 1月19日 星期二 | 腾讯音乐全资收购懒人听书;字节跳动整合硬件业务专注教育硬件;PSA与FCA正式完成合并...

热门文章

  1. VuePress 博客之 SEO 优化(一) sitemap 与搜索引擎收录
  2. ios 表情符号 键盘_字体键盘表情符号
  3. php 图片生成视频,图片转化为视频的方法 如何将照片制作成为视频
  4. 23种设计模式模式笔记+易懂案例
  5. 《SQL Server 2008从入门到精通》--20180724
  6. win10恢复linux引导文件,easybcd误删Win10启动项,UEFI恢复引导
  7. 计算机上的游戏怎么不见了怎么办,电脑自带小游戏消失怎么找回?高手教你找回电脑自带小游戏...
  8. 9个设计师都在用的图片素材网站,风格齐全,高清免费
  9. Tracup|利用项目管理工具,为您的团队设立长期OR短期目标
  10. 如何下载西门子产品CAD、3D和EPLAN文件