返回顶部
首页 > 资讯 > 精选 >Java Swing编程的特殊容器是什么
  • 866
分享到

Java Swing编程的特殊容器是什么

2023-06-17 11:06:59 866人浏览 泡泡鱼
摘要

今天就跟大家聊聊有关Java Swing编程的特殊容器是什么,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。Swing还提供我们许多特殊容器方便我们编程,jsplitPane(分割面板

今天就跟大家聊聊有关Java Swing编程的特殊容器是什么,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。

Swing还提供我们许多特殊容器方便我们编程,jsplitPane(分割面板),JTabbedPane(多选项卡),JLayeredPane(层容器,允许组件互相重叠),讲两个复杂的容器JDesktopPane和JInternalFrame这些多是为了实现MDI(多文档界面),这些容器不是三言两语能说清楚的,所以我将以举例的方式(其中多是书中的例子,举的都不错,自己一个一个写可吃不消),如还有不懂的,请多查阅api文档。

eg:JSplitPane(分割面板)

public class TestSplitPane  {      Book[] books = new Book[]{          new Book("Struts2权威指南" , new ImageIcon("ico/struts2.jpg") ,               "全面介绍Struts2的各方/n面知识"),          new Book("轻量级J2EE企业应用实战" , new ImageIcon("ico/j2ee.jpg") ,              "介绍Struts、spring和/nHibernate整合开发的知识"),          new Book("基于J2EE的ajax宝典" , new ImageIcon("ico/ajax.jpg") ,               "全面介绍J2EE平台上Ajax/n开发的各方面知识")      };      JFrame jf = new JFrame("测试JSplitPane");      JList bookList = new JList(books);      JLabel bookCover = new JLabel();      JTextArea bookDesc = new JTextArea();       public void init()      {          //为三个组件设置***大小          bookList.setPreferredSize(new Dimension(150, 300));          bookCover.setPreferredSize(new Dimension(300, 150));          bookDesc.setPreferredSize(new Dimension(300, 150));          //为下拉列表添加事件监听器          bookList.addListSelectionListener(new ListSelectionListener()          {              public void valueChanged(ListSelectionEvent event)              {                    Book book = (Book)bookList.getSelectedValue();                  bookCover.setIcon(book.getIco());                  bookDesc.setText(book.getDesc());              }           });          //创建一个垂直的分割面板,          //将bookCover放在上面,将bookDesc放在下面 , 支持连续布局          JSplitPane left = new JSplitPane(JSplitPane.VERTICAL_SPLIT, true ,               bookCover, new JScrollPane(bookDesc));          //打开“一触即展”的特性          left.setOneTouchExpandable(true);          //下面代码设置分割条的大小。          //left.setDividerSize(50);           //设置该分割面板根据所包含组件的***大小来调整布局           left.resetToPreferredSizes();          //创建一个水平的分割面板          //将left组件放在左边,将bookList组件放在右边          JSplitPane content = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,              left, bookList);          jf.add(content);          jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);          jf.pack();          jf.setVisible(true);      }      public static void main(String[] args)      {            new TestSplitPane().init();      }  }  class Book  {       private String name;      private Icon ico;      private String desc;       public Book(){}       public Book(String name , Icon ico , String desc)      {          this.name = name;          this.ico = ico;          this.desc = desc;      }       public void setName(String name)      {          this.name = name;      }      public String getName()      {           return this.name;      }       public void setIco(Icon ico)      {          this.ico = ico;      }      public Icon getIco()      {           return this.ico;      }       public void setDesc(String desc)      {          this.desc = desc;      }      public String getDesc()      {           return this.desc;      }      public String toString()      {          return name;      }  }

eg:JTabbedPane(多选项卡)

public class TestJTabbedPane  {      JFrame jf = new JFrame("测试Tab页面");      //创建一个Tab页面的标签放在左边,采用换行布局策略的JTabbedPane      JTabbedPane tabbedPane = new JTabbedPane(JTabbedPane.LEFT , JTabbedPane.WRAP_TAB_LAYOUT);         ImageIcon icon = new ImageIcon("ico/close.gif");      String[] layouts = {"换行布局" , "滚动条布局"};      String[] positions = {"左边" , "顶部" , "右边" , "底部"};      Map<String , String> books = new LinkedHashMap<String , String>();       public void init()      {          books.put("ROR敏捷开发***实践" , "ror.jpg");          books.put("Struts2权威指南" , "struts2.jpg");          books.put("基于J2EE的Ajax宝典" , "ajax.jpg");          books.put("轻量级J2EE企业应用实战" , "j2ee.jpg");          books.put("Spring2.0宝典" , "spring.jpg");          String tip = "可看到本书的封面照片";          //向JTabbedPane中添加5个Tab页面,指定了标题、图标和提示,但该Tab页面的组件为null          for (String bookName : books.keySet())          {              tabbedPane.addTab(bookName, icon, null , tip);          }          jf.add(tabbedPane, BorderLayout.CENTER);          //为JTabbedPane添加事件监听器          tabbedPane.addChangeListener(new ChangeListener()          {              public void stateChanged(ChangeEvent event)              {                         //如果被选择的组件依然是空                  if (tabbedPane.getSelectedComponent() == null)                  {                      //获取所选Tab页                      int n = tabbedPane.getSelectedIndex();                      //为指定标前页加载内容                      loadTab(n);                  }              }          });          //系统默认选择***页,加载***页内容          loadTab(0);          tabbedPane.setPreferredSize(new Dimension(500 , 300));          //增加控制标签布局、标签位置的单选按钮          JPanel buttonPanel = new JPanel();          ChangeAction action = new ChangeAction();          buttonPanel.add(new ButtonPanel(action , "选择标签布局策略" ,layouts));          buttonPanel.add (new ButtonPanel(action , "选择标签位置" ,positions));          jf.add(buttonPanel, BorderLayout.SOUTH);          jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);          jf.pack();          jf.setVisible(true);       }      //为指定标签页加载内容      private void loadTab(int n)      {          String title = tabbedPane.getTitleAt(n);          //根据标签页的标题获取对应图书封面          ImageIcon bookImage = new ImageIcon("ico/" + books.get(title));          tabbedPane.setComponentAt(n, new JLabel(bookImage));          //改变标签页的图标          tabbedPane.setIconAt(n, new ImageIcon("ico/open.gif"));      }      //定义改变标签页的布局策略,放置位置的监听器      class ChangeAction implements ActionListener      {          public void actionPerfORMed(ActionEvent event)          {              JRadioButton source = (JRadioButton)event.getSource();              String selection = source.getActionCommand();              if (selection.equals(layouts[0]))              {                  tabbedPane.setTabLayoutPolicy(JTabbedPane.WRAP_TAB_LAYOUT);              }              else if (selection.equals(layouts[1]))              {                  tabbedPane.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);              }              else if (selection.equals(positions[0]))              {                  tabbedPane.setTabplacement(JTabbedPane.LEFT);              }              else if (selection.equals(positions[1]))              {                  tabbedPane.setTabPlacement(JTabbedPane.TOP);              }              else if (selection.equals(positions[2]))              {                  tabbedPane.setTabPlacement(JTabbedPane.RIGHT);              }              else if (selection.equals(positions[3]))              {                  tabbedPane.setTabPlacement(JTabbedPane.BOTTOM);              }          }      }       public static void main(String[] args)      {            new TestJTabbedPane().init();      }  }   //定义一个JPanel类扩展类,该类的对象包含多个纵向排列的JRadioButton控件  //且Panel扩展类可以指定一个字符串作为TitledBorder  class ButtonPanel extends JPanel  {        private ButtonGroup group;      public ButtonPanel(TestJTabbedPane.ChangeAction action , String title, String[] labels)      {            setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), title));          setLayout(new BoxLayout(this, BoxLayout.X_AXIS));          group = new ButtonGroup();          for (int i = 0; labels!= null && i < labels.length; i++)          {                JRadioButton b = new JRadioButton(labels[i]);              b.setActionCommand(labels[i]);              add(b);              //添加事件监听器              b.addActionListener(action);              group.add(b);              b.setSelected(i == 0);          }      }  }

eg:JLayeredPane(层容器,允许组件互相重叠)

public class TestJLayeredPane  {      JFrame jf = new JFrame("测试JLayeredPane");      JLayeredPane layeredPane = new JLayeredPane();      public void init()      {          //向layeredPane中添加3个组件          layeredPane.add(new ContentPanel(10 , 20 , "Struts2权威指南" ,               "ico/struts2.jpg"), JLayeredPane.MODAL_LAYER);          layeredPane.add(new ContentPanel(100 , 60 , "RoR敏捷开发***实践",               "ico/ror.jpg"), JLayeredPane.DEFAULT_LAYER);          layeredPane.add(new ContentPanel(190 , 100 , "轻量级J2EE企业应用实战",               "ico/j2ee.jpg"), 4);          layeredPane.setPreferredSize(new Dimension(400, 300));          layeredPane.setVisible(true);          jf.add(layeredPane);          jf.pack();          jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);          jf.setVisible(true);      }      public static void main(String[] args)       {          new TestJLayeredPane().init();      }  }  //扩展了JPanel类,可以直接创建一个放在指定位置,  //且有指定标题、放置指定图标的JPanel对象  class ContentPanel extends JPanel  {      public ContentPanel(int xPos , int yPos , String title , String ico)      {          setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), title));          JLabel label = new JLabel(new ImageIcon(ico));          add(label);          setBounds(xPos , yPos , 160, 200);      }  }

以上3例子由于都是广告,我就不贴给大家了,没图片不影响程序的效果。

***是JDesktopPane和JInternalFrame来实现MDI

public class TestInternalFrame  {      final int DESKTOP_WIDTH = 480;      final int DESKTOP_HEIGHT = 360;      final int FRAME_DISTANCE = 30;       JFrame jf = new JFrame("MDI界面");      //定义一个虚拟桌面      private MyJDesktopPane desktop = new MyJDesktopPane();      //保存下一个内部窗口的座标点      private int nextFrameX;      private int nextFrameY;      //定义内部窗口为虚拟桌面的1/2大小      private int width = DESKTOP_WIDTH / 2;      private int height = DESKTOP_HEIGHT / 2;      //为主窗口定义2个菜单      JMenu fileMenu = new JMenu("文件");      JMenu windowMenu = new JMenu("窗口");      //定义newAction用于创建菜单和工具按钮      Action newAction = new AbstractAction("新建", new ImageIcon("ico/new.png"))      {          public void actionPerformed(ActionEvent event)          {              //创建内部窗口              final JInternalFrame iframe = new JInternalFrame("新文档",                  true, // 可改变大小                  true, // 可关闭                  true, // 可***化                  true); // 可最小化              iframe.add(new JScrollPane(new JTextArea(8, 40)));              //将内部窗口添加到虚拟桌面中              desktop.add(iframe);              //设置内部窗口的原始位置(内部窗口默认大小是0X0,放在0,0位置)              iframe.reshape(nextFrameX, nextFrameY, width, height);              //使该窗口可见,并尝试选中它              iframe.show();              //计算下一个内部窗口的位置              nextFrameX += FRAME_DISTANCE;              nextFrameY += FRAME_DISTANCE;              if (nextFrameX + width > desktop.getWidth()) nextFrameX = 0;              if (nextFrameY + height > desktop.getHeight()) nextFrameY = 0;          }      };      //定义exitAction用于创建菜单和工具按钮      Action exitAction = new AbstractAction("退出", new ImageIcon("ico/exit.png"))      {          public void actionPerformed(ActionEvent event)          {              System.exit(0);          }      };       public void init()      {          //为窗口安装菜单条和工具条          JMenuBar menuBar = new JMenuBar();          JToolBar toolBar = new JToolBar();          jf.setJMenuBar(menuBar);          menuBar.add(fileMenu);          fileMenu.add(newAction);          fileMenu.add(exitAction);          toolBar.add(newAction);          toolBar.add(exitAction);          menuBar.add(windowMenu);          JMenuItem nextItem = new JMenuItem("下一个");          nextItem.addActionListener(new ActionListener()          {              public void actionPerformed(ActionEvent event)              {                  desktop.selectNextWindow();              }          });          windowMenu.add(nextItem);          JMenuItem cascadeItem = new JMenuItem("级联");          cascadeItem.addActionListener(new ActionListener()          {              public void actionPerformed(ActionEvent event)              {                  //级联显示窗口,内部窗口的大小是外部窗口的0.75                  desktop.cascadewindows(FRAME_DISTANCE , 0.75);              }          });          windowMenu.add(cascadeItem);          JMenuItem tileItem = new JMenuItem("平铺");          tileItem.addActionListener(new ActionListener()          {              public void actionPerformed(ActionEvent event)              {                  //平铺显示所有内部窗口                  desktop.tileWindows();              }          });          windowMenu.add(tileItem);          final JCheckBoxMenuItem draGoutlineItem = new JCheckBoxMenuItem("仅显示拖动窗口的轮廓");          dragOutlineItem.addActionListener(new ActionListener()          {              public void actionPerformed(ActionEvent event)              {                  //根据该菜单项是否选择来决定采用哪种拖动模式                  desktop.setDragMode(dragOutlineItem.isSelected()                       ? JDesktopPane.OUTLINE_DRAG_MODE                      : JDesktopPane.LIVE_DRAG_MODE);              }          });          windowMenu.add(dragOutlineItem);          desktop.setPreferredSize(new Dimension(480, 360));          //将虚拟桌面添加到***JFrame容器中          jf.add(desktop);          jf.add(toolBar , BorderLayout.NORTH);          jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);          jf.pack();          jf.setVisible(true);      }       public static void main(String[] args)      {            new TestInternalFrame().init();      }  }  class MyJDesktopPane extends JDesktopPane  {      //将所有窗口以级联方式显示,      //其中offset是两个窗口的位移距离,scale是内部窗口与JDesktopPane的大小比例      public void cascadeWindows(int offset , double scale)      {          //定义级联显示窗口时内部窗口的大小          int width = (int)(getWidth() * scale);          int height = (int)(getHeight() * scale);          //用于保存级联窗口时每个窗口的位置          int x = 0;          int y = 0;          for (JInternalFrame frame : getAllFrames())          {                try             {                    //取消内部窗口的***化,最小化                  frame.setMaximum(false);                  frame.setIcon(false);                  //把窗口重新放置在指定位置                  frame.reshape(x, y, width, height);                  x += offset;                  y += offset;                  //如果到了虚拟桌面边界                  if (x + width > getWidth()) x = 0;                  if (y + height > getHeight()) y = 0;              }              catch (PropertyVetoException e)              {}          }      }      //将所有窗口以平铺方式显示      public void tileWindows()      {            //统计所有窗口          int frameCount = 0;          for (JInternalFrame frame : getAllFrames())          {              frameCount++;          }          //计算需要多少行、多少列才可以平铺所有窗口          int rows = (int) Math.sqrt(frameCount);          int cols = frameCount / rows;          //需要额外增加到其他列中的窗口          int extra = frameCount % rows;          //计算平铺时内部窗口的大小          int width = getWidth() / cols;          int height = getHeight() / rows;          //用于保存平铺窗口时每个窗口在横向、纵向上的索引          int x = 0;          int y = 0;          for (JInternalFrame frame : getAllFrames())          {                try             {                  //取消内部窗口的***化,最小化                  frame.setMaximum(false);                  frame.setIcon(false);                  //将窗口放在指定位置                  frame.reshape(x * width, y * height, width, height);                  y++;                  //每排完一列窗口                  if (y == rows)                  {                      //开始排放下一列窗口                      y = 0;                      x++;                      //如果额外多出的窗口与剩下的列数相等,则后面所有列都需要多排列一个窗口                      if (extra == cols - x)                      {                          rows++;                          height = getHeight() / rows;                      }                  }              }              catch (PropertyVetoException e)              {}          }      }      //选中下一个非图标窗口      public void selectNextWindow()      {            JInternalFrame[] frames = getAllFrames();          for (int i = 0; i < frames.length; i++)          {                if (frames[i].isSelected())              {                    // 找出下一个非最小化的窗口,尝试选中它,                  //如果选中失败,则继续尝试选中下一个窗口                  int next = (i + 1) % frames.length;                  while (next != i)                  {                      //如果该窗口不是处于最小化状态                      if (!frames[next].isIcon())                      {                          try                         {                                frames[next].setSelected(true);                              frames[next].toFront();                              frames[i].toBack();                              return;                          }                          catch (PropertyVetoException e)                          {}                      }                      next = (next + 1) % frames.length;                  }              }          }      }  }

大家注意看继承JDesktopPane的类MyJDesktopPane

其中的3个方法非常有用,这是对窗口控制的基本方法(级联,平铺,选下个窗口),大家可以保留下来,以备后用。

看完上述内容,你们对Java Swing编程的特殊容器是什么有进一步的了解吗?如果还想了解更多知识或者相关内容,请关注编程网精选频道,感谢大家的支持。

--结束END--

本文标题: Java Swing编程的特殊容器是什么

本文链接: https://lsjlt.com/news/288611.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Java Swing编程的特殊容器是什么
    今天就跟大家聊聊有关Java Swing编程的特殊容器是什么,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。Swing还提供我们许多特殊容器方便我们编程,JSplitPane(分割面板...
    99+
    2023-06-17
  • Java Swing编程中的JTable表格是什么
    今天就跟大家聊聊有关Java Swing编程中的JTable表格是什么 ,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。表格是GUI编程中使用较多,但也是最麻烦的一个控件之一。表格是用...
    99+
    2023-06-17
  • Java编程语言的特点是什么
    Java编程语言的特点包括:1. 简单易学:Java语法简洁清晰,与C++等语言相比更容易学习和理解。2. 面向对象:Java是一种...
    99+
    2023-08-31
    Java
  • Java mysql特殊形式的查询语句是什么
    这篇文章给大家分享的是有关Java mysql特殊形式的查询语句是什么的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。创建新表:-- 创建学员表CREATE TABLE IF...
    99+
    2023-06-29
  • java特殊字符转义处理的方法是什么
    在Java中,可以使用反斜杠(\)来转义特殊字符。以下是一些常见的特殊字符转义序列:- \n:换行- \t:制表符- \r:回车- ...
    99+
    2023-08-11
    java
  • Java编程语言特性和优势是什么
    本篇内容主要讲解“Java编程语言特性和优势是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java编程语言特性和优势是什么”吧!1 前言Java是近 10 年来计算机软件发展过程中的传奇,...
    99+
    2023-06-26
  • 日志记录在Java容器中的编程算法是什么?
    日志记录是软件开发中非常重要的一环,它可以帮助开发者快速找出软件中的问题,提高软件的可维护性和可靠性。在Java容器中,我们可以使用log4j、logback等日志框架来记录日志。那么,如何在Java容器中编写一个高效的日志记录算法呢?本...
    99+
    2023-07-29
    容器 日志 编程算法
  • 容器编程算法在Java中的实现方法是什么?
    随着计算机技术的发展,容器编程算法在软件开发中得到了广泛的应用。作为一种高效而灵活的数据结构,容器可以帮助开发者更加高效地管理程序中的数据,提高程序的运行效率。在Java中,容器编程算法的实现方法有很多,下面我们将介绍其中的几种常用方法。...
    99+
    2023-11-08
    打包 编程算法 容器
  • Java Swing编程中的拖放功能怎么用
    这篇文章给大家介绍Java Swing编程中的拖放功能怎么用,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。拖放功能其实就像我们使用windows 的时候按住CTRL然后拖动某个图标,会复制该对象。这给用户提供了很棒的用...
    99+
    2023-06-17
  • java swing控件扩展的方法是什么
    Java Swing控件的扩展方法有以下几种:1. 继承基本控件:可以通过继承JButton、JLabel、JTextField等基...
    99+
    2023-08-26
    JAVA swing
  • Java中的容器是什么
    这篇文章主要介绍“Java中的容器是什么”,在日常操作中,相信很多人在Java中的容器是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java中的容器是什么”的疑惑有所帮助!接下来,请跟着小编一起来学习吧...
    99+
    2023-06-02
  • Java编程中容器算法打包的最佳实践是什么?
    在Java编程中,容器算法是必不可少的一部分,它们用于存储和处理数据,使得Java程序更加高效和灵活。然而,在使用Java容器算法时,如何打包它们才能发挥最佳效果呢?本文将介绍一些最佳实践,以帮助Java开发人员更好地使用容器算法。 选...
    99+
    2023-11-08
    打包 编程算法 容器
  • CSS的继承、层叠和特殊性是什么
    这篇文章主要讲解了“CSS的继承、层叠和特殊性是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“CSS的继承、层叠和特殊性是什么”吧!CSS 的某些样式是...
    99+
    2024-04-02
  • linux中的特殊字符及含义是什么
    这篇文章主要讲解了“linux中的特殊字符及含义是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“linux中的特殊字符及含义是什么”吧! ...
    99+
    2023-04-20
    linux
  • linux特殊字符转义的方法是什么
    在Linux中,特殊字符可以通过反斜杠(\)进行转义,以使其作为普通字符处理。例如,如果想要在一个字符串中包含一个双引号字符,可以使...
    99+
    2024-04-02
  • JAVA中swing实现托盘的方法是什么
    在JAVA中,可以使用以下步骤来实现托盘功能:1. 导入相关的类和包:```javaimport java.awt.*;import...
    99+
    2023-09-25
    JAVA swing
  • Java开发技术:掌握容器编程算法的关键是什么?
    在Java开发中,容器是一个非常重要的概念。Java中的容器可以理解为一种数据结构,用于存储和管理一组对象。在Java中,常见的容器有List、Set、Map等。掌握容器编程算法是Java开发的必备技能之一,因为它能够帮助我们更好地管理和...
    99+
    2023-08-08
    容器 编程算法 开发技术
  • Java中什么是容器
    这篇文章给大家分享的是有关Java中什么是容器的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。什么是容器?在Java的GUI界面设计中,关于容器的理解,从字面意思我们就可以认为它是存放控件的地方,而这个地方依托在窗...
    99+
    2023-06-20
  • Laravel容器在PHP编程中的作用是什么?
    Laravel是一个流行的PHP框架,它提供了很多有用的功能,其中之一就是容器。容器是一个依赖注入的实现,它在Laravel应用程序中扮演着非常重要的角色。在本文中,我们将探讨Laravel容器在PHP编程中的作用,并演示如何在应用程序中使...
    99+
    2023-09-16
    load laravel 容器
  • shell脚本中特殊字符的作用是什么
    shell脚本中特殊字符的作用是什么,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。1. #注释作用, #! 除外此外, 在参数替换 echo ${PATH#*:...
    99+
    2023-06-09
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作