Java图形化界面编程超详细知识点(9)——Swing_树

本文详细介绍了如何使用Swing的JTree组件创建和编辑树结构,包括创建树、编辑节点、监听节点事件、自定义结点外观等。通过实例展示了如何构建和操作树形结构,如添加、删除和编辑节点,以及改变结点的显示样式。同时,还讨论了如何实现结点的选中事件监听和自定义结点渲染,以实现更丰富的交互效果。
摘要由CSDN通过智能技术生成

目录

6 JTree、TreeModel实现树

6.1 创建树

6.2 编辑树结点

6.3 监听结点事件

6.4 使用DefaultTreeCellRenderer改变结点外观

6.5 扩展DefaultTreeCellRenderer改变结点外观

6.6 实现TreeCellRenderer接口改变结点外观


6 JTree、TreeModel实现树

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

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

按照节点是否包含子节点,可把节点分为两类:

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

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

按照节点是否具有唯一的父节点,可把节点分为两类:

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

        普通节点:具有唯一父节点的节点;

6.1 创建树

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

JTree常用构造方法:

JTree(TreeModel newModel);使用指定的数据模型来创建JTree对象,它默认显示根节点

JTree(TreeNode root);使用root作为根节点创建JTree对象,它默认显示根节点

JTree(TreeNode root,boolean askAllowsChildren);使用root作为根节点创建JTree对象,它默认显示根节点。askAllowsChildren参数控制怎样的节点才算叶子节点,若参数为true,则只有当程序使用

setAllowsChildren(false);显式设置某个节点不允许添加子节点时(以后也不会有子节点),该节点才会被JTree当成叶子节点,如果该参数为false,则只要某个节点当时没有子节点(不管以后有没有子节点),该节点都会被JTree当成叶子节点

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

案例:

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

public class SimpleJTree {
    JFrame jf = new JFrame("简单树");
    public void init(){

        //创建DefaultMutableTreeNode对象代表结点
        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("南宁");

        //组装结点之间的关系
        root.add(guangDong);
        root.add(guangXi);

        guangDong.add(foShan);
        guangDong.add(shanTou);

        guangXi.add(guiLin);
        guangXi.add(nanNing);

        //创建JTree对象
        JTree tree = new JTree(root);

        //把JTree放入到窗口中进行展示
        jf.add(tree);

        jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        jf.pack();
        jf.setVisible(true);

    }

    public static void main(String[] args) {
        new SimpleJTree().init();
    }
}

6.2 编辑树结点

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

编辑树结点的步骤:

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

获取当前被选中的结点,会有两种方式;

        一:通过JTree对象的某些方法,例如TreePath getSelectionPath()等,得到一个TreePath对象,包含了从根结点到当前结点路径上的所有结点;

                调用TreePath对象的Object getLastPathComponent()方法,得到当前选中结点

        二:调用JTree对象的Object getLastSelectedPathComponent()方法获取当前被选中的结点

2.调用DefaultTreeModel数据模型有关增删改的一系列方法完成编辑,方法执行完后,重绘JTree

案例:

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

public class EditTree {

    JFrame jf = new JFrame("可编辑结点的树");
   
    //定义几个初始结点
    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("南宁");


    //定义按钮,完成操作
    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);

        JTree tree = new JTree(root);

        //完成树的结点编辑的代码
        tree.setEditable(true);
        DefaultTreeModel model = (DefaultTreeModel) tree.getModel();

        //处理添加
        addSiblingBtn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                //添加兄弟结点逻辑

                //1.获取当前选中的结点
                DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
                if (selectedNode == null) {
                    return;
                }

                //2.获取当前结点的父结点
                DefaultMutableTreeNode parentNode = (DefaultMutableTreeNode) selectedNode.getParent();
                if (parentNode == null) {
                    return;
                }

                //3.创建新结点
                DefaultMutableTreeNode newNode = new DefaultMutableTreeNode("新结点");

                //4.把新结点通过父结点进行添加
                int index = parentNode.getIndex(selectedNode);
                model.insertNodeInto(newNode, parentNode, index);

                //5.显示新结点
                TreeNode[] pathToRoot = model.getPathToRoot(newNode);
                TreePath treePath = new TreePath(pathToRoot);
                tree.scrollPathToVisible(treePath);

                //6.重绘tree
                tree.updateUI();

            }
        });

        addChildBtn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                //为选中结点添加子节点

                //1.获取选中结点
                DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
                if (selectedNode == null) {
                    return;
                }
                //2.创建新结点
                DefaultMutableTreeNode newNode = new DefaultMutableTreeNode("新结点");

                //3.把新结点添加到当前结点中
                selectedNode.add(newNode);

                //4.显示新结点
                TreeNode[] pathToRoot = model.getPathToRoot(newNode);
                TreePath treePath = new TreePath(pathToRoot);
                tree.scrollPathToVisible(treePath);

                //5.重绘UI
                tree.updateUI();
            }
        });

        //处理删除
        deleteBtn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {

                DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();

                if (selectedNode != null && selectedNode.getParent() != null) {
                    model.removeNodeFromParent(selectedNode);
                }

            }
        });

        //处理编辑
        editBtn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                //获取当前选中结点的路径
                TreePath selectionPath = tree.getSelectionPath();

                //判断如果路径不为空,则设置该路径的最后一个结点可编辑
                if (selectionPath != null) {
                    tree.startEditingAtPath(selectionPath);
                }
            }
        });
        jf.add(new JScrollPane(tree));

        JPanel panel = new JPanel();
        panel.add(addSiblingBtn);
        panel.add(addChildBtn);
        panel.add(deleteBtn);
        panel.add(editBtn);

        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();
    }
}

6.3 监听结点事件

为JTree添加监听器:

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

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

修改JTree的选择模式:

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

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

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

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

        3.TreeSelectionModel.SINGLE_TREE_SELECTION;每次只能选一个TreePath

案例:

        实现下图效果:

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);

        //TODO 设置选择模式
        TreeSelectionModel selectionModel = tree.getSelectionModel();
        selectionModel.setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);

        //TODO 设置监听器
        tree.addTreeSelectionListener(new TreeSelectionListener() {
            @Override
            public void valueChanged(TreeSelectionEvent e) {
                //把当前选中结点的路径显示到文本域中
                TreePath newLeadSelectionPath = e.getNewLeadSelectionPath();

                eventTxt.append(newLeadSelectionPath.toString()+"\n");
            }
        });

        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();
    }
}

6.4 使用DefaultTreeCellRenderer改变结点外观

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

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

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

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

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

setBackgroundNonSelectionColor(Color newColor);设置用于非选定结点的背景颜色

setBackgroundSelectionColor(Color newColor);设置结点再选中状态下的背景颜色

setBorderSelectionColor(Color newColor);设置选中状态下结点的边框颜色

setClosedIcon(Icon newIcon);设置处于折叠状态下非叶子结点的图标

setFont(Font font);设置结点文本的字体

setLeafIcon(Icon newIcon);设置叶子结点的图标

setOpenIcon(Icon newIcon);设置处于展开状态下非叶子结点的图标

setTextNonSelectionColor(Color newColor);设置绘制非选中状态下结点文本的颜色

setTextSelectionColor(Color newColor);设置绘制选中状态下结点文本的颜色

案例:

         使用DefaultTreeCellRenderer完成下图效果:

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 renderer = new DefaultTreeCellRenderer();
        //设置非选定结点的背景颜色
        renderer.setBackgroundNonSelectionColor(new Color(220,220,220));
        //设置选中结点的背景色
        renderer.setBackgroundSelectionColor(new Color(140,140,140));
        //设置选中状态下结点的边框颜色
        renderer.setBorderSelectionColor(Color.BLACK);
        //设置处于折叠状态下非叶子结点的图标
        renderer.setClosedIcon(new ImageIcon("E:\\GUISwing\\img\\tree\\close.gif"));
        //设置结点文本的字体
        renderer.setFont(new Font("StSong",Font.BOLD,16));
        //设置叶子结点图标
        renderer.setLeafIcon(new ImageIcon("E:\\GUISwing\\img\\tree\\leaf.png"));
        //设置处于展开状态下非叶子结点图标
        renderer.setOpenIcon(new ImageIcon("E:\\GUISwing\\img\\tree\\open.gif"));
        //设置绘制非选中状态下结点文本颜色
        renderer.setTextNonSelectionColor(new Color(255,0,0));
        //设置选中状态下结点的文本颜色
        renderer.setTextSelectionColor(new Color(0,0,255));

        //把结点绘制器设置给树对象
        tree.setCellRenderer(renderer);

        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();
    }

}

6.5 扩展DefaultTreeCellRenderer改变结点外观

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

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

案例:

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

public class ExtendsDefaultCellTreeRenderer {

    JFrame jf = new JFrame("根据结点类型定义图标");

    JTree tree;

    //初始化5个图标
    ImageIcon rootIcon = new ImageIcon("E:\\GUISwing\\img\\tree\\root.gif");
    ImageIcon databaseIcon = new ImageIcon("E:\\GUISwing\\img\\tree\\database.gif");
    ImageIcon tableIcon = new ImageIcon("E:\\GUISwing\\img\\tree\\table.gif");
    ImageIcon columnIcon = new ImageIcon("E:\\GUISwing\\img\\tree\\column.gif");
    ImageIcon indexIcon = new ImageIcon("E:\\GUISwing\\img\\tree\\index.gif");

    //定义一个NodeData类,用于封装结点数据
    class NodeData{
        public ImageIcon icon;
        public String name;

        public NodeData(ImageIcon icon, String name) {
            this.icon = icon;
            this.name = name;
        }


    }

    //定义几个初始结点
    DefaultMutableTreeNode root = new DefaultMutableTreeNode(new NodeData(rootIcon,"数据库导航"));
    DefaultMutableTreeNode salaryDb = new DefaultMutableTreeNode(new NodeData(databaseIcon,"公司工资数据库"));
    DefaultMutableTreeNode customerDb = new DefaultMutableTreeNode(new NodeData(databaseIcon,"公司客户数据库"));
    DefaultMutableTreeNode employee = new DefaultMutableTreeNode(new NodeData(tableIcon,"员工表"));
    DefaultMutableTreeNode attend = new DefaultMutableTreeNode(new NodeData(tableIcon,"考勤表"));
    DefaultMutableTreeNode concat = new DefaultMutableTreeNode(new NodeData(tableIcon,"联系方式表"));
    DefaultMutableTreeNode id = new DefaultMutableTreeNode(new NodeData(indexIcon,"员工ID"));
    DefaultMutableTreeNode name = new DefaultMutableTreeNode(new NodeData(columnIcon,"姓名"));
    DefaultMutableTreeNode gender = new DefaultMutableTreeNode(new NodeData(columnIcon,"性别"));

    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);

        //TODO 通过扩展DefaultTreeCellRenderer修改外观
        tree.setCellRenderer(new MyRenderer());


        jf.add(new JScrollPane(tree));
        jf.pack();
        jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        jf.setVisible(true);

    }


    //自定义类,继承DefaultTreeCellRenderer,完成结点的绘制
    private class MyRenderer extends DefaultTreeCellRenderer{

        //重写方法


        @Override
        public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) {
            //当前类间接的继承了JLabel这个组件类,展示一张图片和一些配套的文字
            //Object value这个参数,代表的就是即将要绘制的结点

            //获取当前结点
            DefaultMutableTreeNode node = (DefaultMutableTreeNode) value;

            //获取到当前即将绘制的结点的名称和图标
            NodeData nodeData = (NodeData) node.getUserObject();

            //通过setText方法和setIcon方法完成设置
            this.setText(nodeData.name);
            this.setIcon(nodeData.icon);
            return this;
        }
    }

    public static void main(String[] args) {
        new ExtendsDefaultCellTreeRenderer().init();
    }

}

6.6 实现TreeCellRenderer接口改变结点外观

        这种改变结点外观的方法最灵活,程序实现TreeCellRenderer接口时同样需要实现

getTreeCellRendererComponent()方法,该方法可以返回任意类型的组件,该组件将作为JTree的结点。通过这种方式可以最大程度的改变结点的外观。

案例:

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

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);

        //TODO 设置结点绘制器
        MyRenderer renderer = new MyRenderer();
        tree.setCellRenderer(renderer);

        jf.add(new JScrollPane(tree));
        jf.pack();
        jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        jf.setVisible(true);

    }

    //自定义类,实现TreeCellRenderer接口,绘制组件
    private class MyRenderer extends JPanel implements TreeCellRenderer{
        private ImageIcon icon;
        private String name;
        private Color background;
        private Color foreground;

        @Override
        public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
            //给成员变量设置值
            this.icon = new ImageIcon("E:\\GUISwing\\img\\tree\\"+value.toString()+".gif");
            this.name = value.toString();

            this.background = hasFocus? new Color(144,200,225) : new Color(255,255,255);
            this.foreground = hasFocus? new Color(255,255,3) : new Color(0,0,0);

            return this;
        }

        //通过重写getPreferenceSize方法,指定当前Jpanel组件的大小

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(80,80);
        }

        @Override
        public void paint(Graphics g) {
            //绘制组件内容

            int iconWidth = this.icon.getIconWidth();
            int iconHeight = this.icon.getIconHeight();

            //填充背景
            g.setColor(background);
            g.fillRect(0,0,getWidth(),getHeight());

            //绘制头像
            g.drawImage(this.icon.getImage(),getWidth()/2 - iconWidth/2,10,null);

            //绘制昵称
            g.setColor(foreground);

            g.setFont(new Font("StSong",Font.BOLD,18));
            g.drawString(this.name,getWidth()/2-this.name.length()*20/2,iconHeight+30);

        }
    }

    public static void main(String[] args) {
        new CustomerTreeNode().init();
    }
}

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小小西瓜呀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值