Draw2D备忘

<!--[if !supportLists]-->1           <!--[endif]-->模型:

<!--[if !supportLists]-->1.1          <!--[endif]-->图:

<!--[if !vml]--><!--[endif]-->

<!--[if !supportLists]-->1.2          <!--[endif]-->说明:Draw2D建构于SWT之上。Draw2D通过LightweightSystem沟通了SWTDraw2DLightweigthSystem主要负责两部分的工作:一是负责把SWT事件,转变为Draw2D内部的事件,这需要通过两步来实现,首先是把LightweigthSystem注册为Canvas的事件监听器,其次LightweightSystem需要记录系统内所有Figure的位置和尺寸信息,这样,当他收到事件通知以后才能把事件重新转发到对应的Figure上;二是负责管理Figure的更新和绘制,由于Draw2D并不是直接使用SWT提供的组件拼装Figure,而是自己定义了一套组件,当组件需要进行显示前,他会传入一个Draw2D自己定义的Graphics实现SWTGraphics,各Figure在这SWTGraphics上进行内容绘制,因此,与SWT中的组件不同,我们可以对Draw2DFigure的绘制进行完全的定制。

Draw2D当中,所有的图形,组件都通过Figure来表示,而Figure是设计成可以添加子Figure的,所以,在Draw2D当中,原则上所有的东西包括图形,控件等都能互相嵌套。

从上面的分析可得,虽然Draw2D建构于SWT之上,但是他使用的也仅是SWT提供的事件通知机制和绘图机制,所以,如果我们能够让Swing平台向Draw2D平台提供相同的服务的话,那么我们就能够在Swing之上实现Draw2D

另外,Draw2D他自己重新实现了一套边框,布局,组件和图形的库,如果从重用的角度来说,这样显然是不合适的,因为这样就相当于他和SWT具有一个平行的类结构,而不是希望中的垂直结构;但是如果从耦合的角度来说。这样做显然是能最大限度的降低Draw2DSWT之间的耦合程度。

 

 

<!--[if !supportLists]-->2           <!--[endif]-->Figure

<!--[if !supportLists]-->2.1          <!--[endif]-->Border

<!--[if !supportLists]-->2.1.1    <!--[endif]-->说明:每个Figure都可以具有边框,在Draw2D当中提供了以下的边框实现:GroupBoxBorderTitleBarBorderLineBorderCompoundBorder等。由于CompoundBorder区分了innerBorderoutterBorder,所以,相同的两个Border的不同组合顺序将影响最后合成的Border的外观。

<!--[if !supportLists]-->2.1.2    <!--[endif]-->类图:

<!--[if !vml]--><!--[endif]-->

<!--[if !supportLists]-->2.1.3    <!--[endif]-->代码:

private void init() {

IFigure panel = new Figure();

   ToolbarLayout layout = new ToolbarLayout();

   layout.setSpacing(10);

   panel.setLayoutManager(layout);

   Panel[] panels = new Panel[8];

   Border border = null;

   Color red = new Color(null, 255, 0, 0);

   for (int i = 0; i < panels.length; i++) {

        panels[i] = new Panel();

        panels[i].setLayoutManager(new BorderLayout());

        panels[i].add(new Label("Label " + i), BorderLayout.BOTTOM);

        panel.add(panels[i]);

        switch (i) {

        case 0:

            border = new GroupBoxBorder("Group");

            break;

        case 1:

            border = new TitleBarBorder("Title");

            break;

        case 2:

            border = new FrameBorder("Frame");

            break;

        case 3:

            border = new LineBorder(red);

            break;

        case 4:

            border = new SchemeBorder(SchemeBorder.SCHEMES.RAISED);

            break;

        case 5:

            border = new SimpleLoweredBorder(5);

            break;

        case 6:

            border = new CompoundBorder(new LineBorder(red),

                      new TitleBarBorder("Title"));

            break;

        case 7:

            border = new CompoundBorder(new TitleBarBorder("Title"),

                      new LineBorder(red));

            break;

        }

        panels[i].setBorder(border);

   }

   lws.setContents(panel);

}

 

<!--[if !supportLists]-->2.1.4    <!--[endif]-->运行图:

<!--[if !vml]--><!--[endif]-->

 

<!--[if !supportLists]-->2.2          <!--[endif]-->Layout

<!--[if !supportLists]-->2.2.1    <!--[endif]-->说明:Layout用于对Figure内部的子Figure进行布局。

<!--[if !supportLists]-->2.2.2    <!--[endif]-->类图:

<!--[if !vml]--><!--[endif]-->

<!--[if !supportLists]-->2.2.3    <!--[endif]-->代码:

private void init() {

   …

   Color black = display.getSystemColor(SWT.COLOR_BLACK);

   Color red = display.getSystemColor(SWT.COLOR_RED);

   Color green = display.getSystemColor(SWT.COLOR_GREEN);

   Panel[] panels = new Panel[3];

   LayoutManager layout = null;

   ToolbarLayout layouts = new ToolbarLayout();

   layouts.setSpacing(10);

   panel.setLayoutManager(layouts);

   for (int i = 0; i < panels.length; i++) {

        panels[i] = new Panel();

        Label l1 = new Label("Label              1");

        l1.setForegroundColor(red);

        Label l2 = new Label("Label 2");

        l2.setForegroundColor(green);

        panels[i].add(l1);

        panels[i].add(l2);

        panels[i].setBorder(new LineBorder(black));

        switch (i) {

        case 0:

            layout = new StackLayout();

            break;

        case 1:

            layout = new XYLayout();

            layout.setConstraint(l1, new Rectangle(10, 10, -1, -1));

            layout.setConstraint(l2, new Rectangle(80, 40, -1, -1));

            break;

        case 2:

            layout = new FlowLayout();

            break;

        }

        panels[i].setLayoutManager(layout);

        panel.add(panels[i]);

   }

}

 

<!--[if !supportLists]-->2.2.4    <!--[endif]-->运行图:

<!--[if !vml]--><!--[endif]-->

 

<!--[if !supportLists]-->2.2.5    <!--[endif]-->补充:StackLayout会把组件在Z轴上堆叠起来。XYLayout需要对每个子组件添加对应的Constraint,用于设定其在界面上显示的位置和尺寸。

 

<!--[if !supportLists]-->3           <!--[endif]-->Shape

<!--[if !supportLists]-->3.1          <!--[endif]-->说明:Draw2D提供了代表主要几何图形的Figure,例如椭圆,矩形等。Draw2D中的几何图形与一般的SWTJava 2D中的几何图形的一个非常主要的区别是,Draw2D中的几何图形是由Figure继承而来的,因此,我们可以为这些图形设定布局管理器,边框等,而且,当我们需要在图形内部添加图形时,我们是以一种父子关系树的方式添加的,而在其他的图形编程当中,当我们需要完成同样的功能时,我们使用的是图形覆盖的方式。还有另外的一点就是,由于Draw2D中的几何图形都是Figure,所以,我们需要使用处理一般控件的方式,即通过setSize()方法来设定他们的尺寸。而不是像在SWTJava 2D当中那样,在构造函数中指明他的左上角坐标和尺寸。

 

<!--[if !supportLists]-->3.2          <!--[endif]-->Polyline

<!--[if !supportLists]-->3.2.1    <!--[endif]-->说明:折线的Figure实现。

<!--[if !supportLists]-->3.2.2    <!--[endif]-->代码:

private void init() {

Polyline l1 = new Polyline();

for (int i = 0; i < 20; i++)

l1.addPoint(new Point(i * 20, i % 2 * 20));

panel.add(l1);

}

注:不能在Polyline上调用add()添加子Figure

<!--[if !supportLists]-->3.2.3    <!--[endif]-->运行图:

<!--[if !vml]--><!--[endif]-->

 

<!--[if !supportLists]-->3.3          <!--[endif]-->Polygone

<!--[if !supportLists]-->3.3.1    <!--[endif]-->说明:封闭多边形的Figure实现。

<!--[if !supportLists]-->3.3.2    <!--[endif]-->代码:

private void init() {

   …

Polygon p1 = new Polygon();

PointList list = new PointList();

list.addPoint(0, 0);

list.addPoint(80, 80);

list.addPoint(240, 80);

list.addPoint(160, 0);

p1.setPoints(list);

 

Polygon p2 = new Polygon();

p2.addPoint(new Point(0, 0));

p2.addPoint(new Point(40, 40));

p2.addPoint(new Point(120, 40));

p2.addPoint(new Point(80, 0));

p2.setBackgroundColor(display.getSystemColor(SWT.COLOR_BLUE));

 

   panel.add(p1);

p1.setLayoutManager(new FlowLayout());

p1.add(p2);

   …

}

<!--[if !supportLists]-->3.3.3    <!--[endif]-->运行图:

<!--[if !vml]--><!--[endif]-->

 

<!--[if !supportLists]-->3.4          <!--[endif]-->RectangleFigureRoundRectangleTriangleEllipse

<!--[if !supportLists]-->3.4.1    <!--[endif]-->说明:矩形,圆角矩形,三角形,椭圆的Figure实现。

<!--[if !supportLists]-->3.4.2    <!--[endif]-->代码:

private void init() {

   …

   Shape[] shapes = new Shape[4];

   Color[] colors = new Color[] { ColorConstants.red,

            ColorConstants.green, ColorConstants.blue,

            ColorConstants.yellow };

   for (int i = 0; i < shapes.length; i++) {

        switch (i) {

        case 0:

            shapes[i] = new RectangleFigure();

            break;

        case 1:

            shapes[i] = new RoundedRectangle();

            break;

        case 2:

            shapes[i] = new Triangle();

            break;

        case 3:

            shapes[i] = new Ellipse();

            break;

        }

        shapes[i].setSize(100, 50);

        shapes[i].setBackgroundColor(colors[i]);

        panel.add(shapes[i]);

   }

   lws.setContents(panel);

   …

}

<!--[if !supportLists]-->3.4.3    <!--[endif]-->运行图:

<!--[if !vml]--><!--[endif]-->

 

<!--[if !supportLists]-->4           <!--[endif]-->Widge

<!--[if !supportLists]-->4.1          <!--[endif]-->说明:Draw2D提供了部分控件的Figure实现,包括标签,按钮,复选框等。由于这些控件都是从Figure中继承而来,因此他们都能在内部添加子Figure

<!--[if !supportLists]-->4.2          <!--[endif]-->Label

<!--[if !supportLists]-->4.2.1    <!--[endif]-->说明:标签的Figure实现。

<!--[if !supportLists]-->4.2.2    <!--[endif]-->代码:

private void init() {

   …

   Label[] labels = new Label[50];

   BorderLayout layout = null;

   Random r = new Random();

   Color color = null;

   for (int i = 0; i < labels.length; i++) {

        labels[i] = new Label();

        color = new Color(null, r.nextInt(255), r.nextInt(255), r

                 .nextInt(255));

        labels[i].setBorder(new LineBorder(color));

        if (i > 0) {

            layout = new BorderLayout();

            labels[i - 1].setLayoutManager(layout);

            labels[i - 1].add(labels[i], BorderLayout.CENTER);

        }

   }

   lws.setContents(labels[0]);

}

<!--[if !supportLists]-->4.2.3    <!--[endif]-->运行图:

<!--[if !vml]--><!--[endif]-->

 

<!--[if !supportLists]-->4.3          <!--[endif]-->ButtonToggleButtonCheckBox

<!--[if !supportLists]-->4.3.1    <!--[endif]-->说明:按钮,图钉,复选框的Figure实现。

<!--[if !supportLists]-->4.3.2    <!--[endif]-->代码:

private void init() {

   …

Panel panel = new Panel();

   ToolbarLayout tbl = new ToolbarLayout();

   tbl.setSpacing(10);

   panel.setLayoutManager(tbl);

   Panel[] panels = new Panel[3];

   FlowLayout layout = null;

   IFigure figure = null;

   for (int i = 0; i < panels.length; i++) {

        panels[i] = new Panel();

        layout = new FlowLayout();

        panels[i].setLayoutManager(layout);

        for (int j = 0; j < 4; j++) {

            switch (i) {

            case 0:

                 figure = new Button("Button " + j);

                 break;

            case 1:

                 figure = new ToggleButton("ToggleButton " + j);

                 break;

            case 2:

                 figure = new CheckBox("CheckBox " + j);

                 break;

            }

            panels[i].add(figure);

        }

        panel.add(panels[i]);

   }

lws.setContents(panel);

}

<!--[if !supportLists]-->4.3.3    <!--[endif]-->运行图:

<!--[if !vml]--><!--[endif]-->

 

<!--[if !supportLists]-->4.4          <!--[endif]-->ScrollBar

<!--[if !supportLists]-->4.4.1    <!--[endif]-->说明:滚动条的Figure实现。

<!--[if !supportLists]-->4.4.2    <!--[endif]-->代码:

private void init() {

   ScrollBar t1 = new ScrollBar();

   t1.setMinimum(0);

   t1.setMaximum(100);

   t1.setStepIncrement(1);

   t1.setHorizontal(true);

   t1.setForegroundColor(display.getSystemColor(SWT.COLOR_RED));

   Image image = new Image(display, "icons/thumb.gif");

   ImageFigure imagef = new ImageFigure(image);

   imagef.setBorder(new LineBorder(1));

   Button up = new Button();

   up.setBackgroundColor(display.getSystemColor(SWT.COLOR_BLUE));

   Button down = new Button();

   down.setBackgroundColor(display.getSystemColor(SWT.COLOR_GREEN));

   t1.setThumb(imagef);

   t1.setPageUp(up);

   t1.setPageDown(down); 

   …

}

<!--[if !supportLists]-->4.4.3    <!--[endif]-->运行图:

<!--[if !vml]--><!--[endif]-->

<!--[if !supportLists]-->5           <!--[endif]-->Layer and Panes

<!--[if !supportLists]-->5.1          <!--[endif]-->ScrollPane

<!--[if !supportLists]-->5.1.1    <!--[endif]-->说明:滚动面板的Figure实现,他负责管理他内部的Figure的滚动。

<!--[if !supportLists]-->5.1.2    <!--[endif]-->代码:

private void init() {

   …

ScrollPane sp = new ScrollPane();

   sp.setSize(200, 50);

   sp.setScrollBarVisibility(ScrollPane.ALWAYS);

   Panel p = new Panel();

   p.setLayoutManager(new ToolbarLayout());

   Random r = new Random();

   Label label = null;

   for (int i = 0; i < 10; i++) {

        label = new Label("Label " + i);

        label.setForegroundColor(new Color(null, r.nextInt(255), r

                 .nextInt(255), r.nextInt(255)));

        p.add(label);

   }

   panel.add(sp);

   sp.setContents(p);

}

 

<!--[if !supportLists]-->5.1.3    <!--[endif]-->运行图:

<!--[if !vml]--><!--[endif]-->

 

<!--[if !supportLists]-->5.2          <!--[endif]-->ScalePane

<!--[if !supportLists]-->5.2.1    <!--[endif]-->说明:能对面板内的内容进行拉伸。

<!--[if !supportLists]-->5.2.2    <!--[endif]-->代码:

private void init() {

   …

   ScrollBar bar = new ScrollBar();

   bar.setHorizontal(true);

   bar.setMinimum(0);

   bar.setMaximum(10);

   bar.setExtent(1);

   bar.setStepIncrement(1);

   bar.addPropertyChangeListener(new PropertyChangeListener() {

        public void propertyChange(PropertyChangeEvent evt) {

            try {

                 int value = Integer.parseInt(evt.getNewValue().toString());

                 slp.setScale(value);

            } catch (Exception e) {}

        }

   });

   slp = new ScalableLayeredPane();

   RectangleFigure rect = new RectangleFigure();

   rect.setBackgroundColor(display.getSystemColor(SWT.COLOR_BLUE));

   slp.add(rect);

   panel.setLayoutManager(new BorderLayout());

   panel.add(bar, BorderLayout.TOP);

   panel.add(slp, BorderLayout.CENTER);

}

<!--[if !supportLists]-->5.2.3    <!--[endif]-->运行图:

<!--[if !vml]--><!--[endif]-->

 

<!--[if !vml]--><!--[endif]-->

 

<!--[if !supportLists]-->6           <!--[endif]-->Graphics

<!--[if !supportLists]-->6.1          <!--[endif]-->说明:在Figure被显示以前,他将调用paintFigure()paintClientArea()paintBorder()等方法,对他的内容以及子Figure进行绘画,通过重写这些方法,我们可以对Figure所显示的内容进行定制。

<!--[if !supportLists]-->6.2          <!--[endif]-->代码:

private void init() {

   Panel panel = new Panel();

   Label label = new Label("right") {

        public void paintFigure(Graphics g) {

            super.paintFigure(g);

            String text = super.getText();

            Image image = new Image(null, "icons/" + text + ".gif");

            org.eclipse.swt.graphics.Rectangle rect = image.getBounds();

            Color old = g.getForegroundColor();

            Color red = new Color(null, 255, 0, 0);

            g.setForegroundColor(red);

            g.drawRectangle(new Rectangle(0, 0, rect.width, rect.height));

            g.drawImage(image, 0, 0);

            g.setForegroundColor(old);

        }

   };

   panel.add(label);

   lws.setContents(panel);

}

<!--[if !supportLists]-->6.3          <!--[endif]-->运行图:

<!--[if !vml]--><!--[endif]-->

 

<!--[if !supportLists]-->7           <!--[endif]-->Connection

<!--[if !supportLists]-->7.1          <!--[endif]-->说明:Connection提供了用于表示在两个Figure之间的连线。Draw2D提供了PolylineConnection实现类。

<!--[if !supportLists]-->7.2          <!--[endif]-->Anchor

<!--[if !supportLists]-->7.2.1    <!--[endif]-->说明:当两个图形需要建立连线时,需要先添加用于连接的Anchor,然后在Connection上设定源和目标的AnchorDraw2D提供了ChopboxAnchor(指向Figure中心),LabelAnchor(指向提供的Label),EllipseAnchor(指向提供的Ellipse),XYAnchor(指向提供的坐标)。

<!--[if !supportLists]-->7.2.2    <!--[endif]-->代码:

private void init() {

   …

   Panel panel = new Panel();

   Button b1 = new Button("Button 1");

   b1.setBackgroundColor(ColorConstants.green);

   Button b2 = new Button("Button 2");

   b2.setBackgroundColor(ColorConstants.yellow);

   PolylineConnection con = new PolylineConnection();

   ChopboxAnchor sor = new ChopboxAnchor(b1);

   ChopboxAnchor tar = new ChopboxAnchor(b2);

   con.setSourceAnchor(sor);

   con.setTargetAnchor(tar);

   XYLayout layout = new XYLayout();

   layout.setConstraint(b1, new Rectangle(10, 10, -1, -1));

   layout.setConstraint(b2, new Rectangle(80, 80, -1, -1));

   panel.setLayoutManager(layout);

   panel.add(b1);

   panel.add(b2);

   panel.add(con);

   lws.setContents(panel);

}

 

<!--[if !supportLists]-->7.2.3    <!--[endif]-->运行图:

<!--[if !vml]--><!--[endif]-->

 

<!--[if !supportLists]-->7.3          <!--[endif]-->Decoration

<!--[if !supportLists]-->7.3.1    <!--[endif]-->说明:当我们需要在连接上添加类似UML图中的聚合标签时,我们可以使用Decoration类。Draw2D提供了PolylineDecoration(折线)和PolygonDecoration(多边形)两个实现类。

<!--[if !supportLists]-->7.3.2    <!--[endif]-->代码:

private void init() {

   PolygonDecoration dec = new PolygonDecoration();

   PointList list = new PointList();

   list.addPoint(0, 0);

   list.addPoint(-1, 1);

   list.addPoint(-2, 0);

   list.addPoint(-1, -1);

   dec.setTemplate(list);

   con.setSourceDecoration(dec);   

}

<!--[if !supportLists]-->7.3.3    <!--[endif]-->运行图:

<!--[if !vml]--><!--[endif]-->

 

<!--[if !supportLists]-->7.4          <!--[endif]-->Locator

<!--[if !supportLists]-->7.4.1    <!--[endif]-->说明:由于Connection使用的是DelegatingLayout,所以,当我们需要为Connection添加子标签或者图形时,我们都需要指定一个用于布局的LocatorDraw2D提供了ArrowLocatorBendpointLocatorMidpointLocatorConnectionEndPointLocatorRelativeLocator(相对于提供的某一Figure)实现。

<!--[if !supportLists]-->7.4.2    <!--[endif]-->代码:

private void init() {

   …

   ConnectionEndpointLocator tarL = new ConnectionEndpointLocator(con,

            true);

   tarL.setUDistance(5);

   tarL.setVDistance(5);

   Label sll = new Label("1..*");

   con.add(sll, tarL);

}

<!--[if !supportLists]-->7.4.3    <!--[endif]-->运行图:

<!--[if !vml]--><!--[endif]-->

 

<!--[if !supportLists]-->7.5          <!--[endif]-->Routers

<!--[if !supportLists]-->7.5.1    <!--[endif]-->说明:用于指定Connection的连接路线。Draw2D提供了FanRouter,(最短路径) ,BendpointConnectionRouter(随意插入节点),ManhattanConnecionRouter(曼哈顿式),ShortestPathConnectionRouter

<!--[if !supportLists]-->7.5.2    <!--[endif]-->代码:

private void init() {

   …

BendpointConnectionRouter rou = new BendpointConnectionRouter();

   ArrayList<AbsoluteBendpoint> plist = new ArrayList<AbsoluteBendpoint>();

   plist.add(new AbsoluteBendpoint(80, 50));

   plist.add(new AbsoluteBendpoint(10, 70));

   rou.setConstraint(con, plist);

   con.setConnectionRouter(rou);

   …

}

<!--[if !supportLists]-->7.5.3    <!--[endif]-->运行图:

<!--[if !vml]--><!--[endif]-->

 

<!--[if !supportLists]-->8           <!--[endif]-->DirectedGraph

<!--[if !supportLists]-->8.1          <!--[endif]-->说明:Draw2D通过DirectedGraph提供了一个图的抽象,我们通过指定DirectedGraph的节点和边列表,就可以完整的描述一个图,当我们需要把图在Figure上显示时,我们首先需要使用DirectedGraphLayout来对DirectedGraph进行布局,他会根据边的关系,来对各节点进行布局,并设定他们的坐标,因此当真正在Figure上进行布局时,我们只需获取这些点上的坐标即可。

<!--[if !supportLists]-->8.2          <!--[endif]-->代码:

public class DirectGraphDemo {

   public DirectGraphDemo() {

        Panel panel = new Panel();

panel.setLayoutManager(new XYLayout());

DirectedGraph graph = createGraph():

        buildGraph(panel, graph);

        lws.setContents(panel);

   }

 

   private DirectedGraph createGraph(){

        NodeList nodelist = new NodeList();

        Node node1 = new Node("node 1");

        Node node2 = new Node("node 2");

        Node node3 = new Node("node 3");

        Node node4 = new Node("node 4");

        nodelist.add(node1);

        nodelist.add(node2);

        nodelist.add(node3);

        nodelist.add(node4);

 

        EdgeList edgelist = new EdgeList();

        edgelist.add(new Edge(node1, node2));

        edgelist.add(new Edge(node2, node3));

        edgelist.add(new Edge(node1, node4));

        DirectedGraph graph = new DirectedGraph();

        graph.nodes = nodelist;

        graph.edges = edgelist;

                  new DirectedGraphLayout().visit(graph);

                   return graph;

}

   private void buildGraph(IFigure contents, DirectedGraph graph) {

        for (int i = 0; i < graph.nodes.size(); i++) {

            Node node = graph.nodes.getNode(i);

            buildNodeFigure(contents, node);

        }

        for (int i = 0; i < graph.edges.size(); i++) {

            Edge edge = graph.edges.getEdge(i);

            buildEdgeFigure(contents, edge);

        }

   }

   private void buildNodeFigure(IFigure contents, Node node) {

        Label label = new Label();

        label.setBackgroundColor(ColorConstants.orange);

        label.setOpaque(true);

        label.setBorder(new LineBorder());

        label.setText(node.data.toString());

        contents.add(label);

        contents.setConstraint(label, new Rectangle(node.x, node.y, node.width,

                 node.height));

   }

   private void buildEdgeFigure(IFigure contents, Edge edge) {

        PolylineConnection connx = new PolylineConnection();

        XYAnchor sourceAnchor = new XYAnchor(edge.start);

        XYAnchor targetAnchor = new XYAnchor(edge.end);

        connx.setSourceAnchor(sourceAnchor);

        connx.setTargetAnchor(targetAnchor);

        contents.add(connx);

   }

   public static void main(String[] args) {

        DirectGraphDemo demo = new DirectGraphDemo();

   }

}

<!--[if !supportLists]-->8.3          <!--[endif]-->运行图:

<!--[if !vml]--><!--[endif]-->

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值