wxPython - Go语言中文社区

wxPython


知识内容:

1.wxPython介绍

2.wxPython组件

3.wxPython布局

4.wxPython事件处理

5.wxPython实战

 

参考:https://www.yiibai.com/wxpython

 

 

 

一、wxPython介绍

1.wxPython是什么

官方解释:wxPython, the cross-platform GUI toolkit for the Python language. With wxPython software developers can create truly native user interfaces for their Python applications, that run with little or no modifications on Windows, Macs and Linux or other unix-like systems

翻译过来就是:wxPython是python中的跨平台的GUI工具,可以使用它给python程序快速搭建用户界面,可以运行到各种操作系统中

 

 

2.wxPython安装及基本使用

(1)安装

使用pip安装或在pycharm中的设置中直接安装

 

(2)基本使用

使用wxPython创建GUI程序的三个主要步骤如下:

  • 导入wxPython包
  • 建立框架类
  • 建立主程序

下面是以上三步骤的实例:

 1 # __author__ = "wyb"
 2 # date: 2018/4/29
 3 
 4 import wx           # 1.导入wxPython
 5 
 6 
 7 # 2.建立框架类
 8 class MyFrame(wx.Frame):
 9     def __init__(self, superior):
10         wx.Frame.__init__(self, parent=superior, title=u'first', size=(500, 500))
11         self.Bind(wx.EVT_SIZE, self.OnSize)
12         self.Bind(wx.EVT_MOVE, self.OnFrameMove)
13 
14         panel = wx.Panel(self, -1)
15         label1 = wx.StaticText(panel, -1, "FrameSize:")
16         label2 = wx.StaticText(panel, -1, "FramePos:")
17         label3 = wx.StaticText(parent=panel, label="MouseSize:")
18         self.sizeFrame = wx.TextCtrl(panel, -1, "", style=wx.TE_READONLY)
19         self.posFrame = wx.TextCtrl(panel, -1, "", style=wx.TE_READONLY)
20         self.posMouse = wx.TextCtrl(panel, -1, "", style=wx.TE_READONLY)
21         panel.Bind(wx.EVT_MOTION, self.OnMouseMove)
22         self.panel = panel
23 
24         sizer = wx.FlexGridSizer(3, 2, 5, 5)
25         sizer.Add(label1)
26         sizer.Add(self.sizeFrame)
27         sizer.Add(label2)
28         sizer.Add(self.posFrame)
29         sizer.Add(label3)
30         sizer.Add(self.posMouse)
31 
32         border = wx.BoxSizer()
33         border.Add(sizer, 0, wx.ALL, 15)
34         panel.SetSizerAndFit(border)
35         self.Fit()
36 
37     def OnSize(self, event):
38         size = event.GetSize()
39         self.sizeFrame.SetValue("%s, %s" % (size.width, size.height))
40         event.Skip()
41 
42     def OnFrameMove(self, event):
43         pos = event.GetPosition()
44         self.posFrame.SetValue("%s, %s" % (pos.x, pos.y))
45 
46     def OnMouseMove(self, event):
47         pos = event.GetPosition()
48         self.posMouse.SetValue("%s, %s" % (pos.x, pos.y))
49 
50 
51 # 3.建立主程序
52 if __name__ == '__main__':
53     app = wx.App()              # 创建应用程序对象
54     frame = MyFrame(None)       # 创建框架类对象
55     frame.Show(True)            # 展示框架
56     app.MainLoop()              # 开始事件循环

注: 上述具体内容看下面的详细介绍

 

(3)hello world程序

1 import wx 
2  
3 app = wx.App() 
4 window = wx.Frame(None, title = "hello world", size = (400,300)) 
5 panel = wx.Panel(window) 
6 label = wx.StaticText(panel, label = "Hello World", pos = (100,100)) 
7 window.Show(True) 
8 app.MainLoop() 

 

 

 

二、wxPython组件

1.Frame组件

(1)Frame简介

Frame也称为框架或窗体,是所有框架的父类,也是包含标题栏、菜单、按钮等其他控件的容器,运行之后可移动、缩放

 

(2)Frame构造函数

创建GUI程序时,需要继承wx.Frame派生出子类,在子类中调用基类构造函数进行必要的初始化工作,Frame的构造函数格式如下:

1 __init__(self, Window parent, int id=-1, String title=EmptyString, Point pos=DefaultPosition, Size size=DefaultSize, long Style=DEFAULT_FRAME_STYLE, String name=FrameStr)

各参数具体含义如下:

  • parent:框架的父窗体,为None表示创建顶级窗体
  • id:ID值,为-1时将自动生成一个新id,由系统保证其唯一性
  • title:窗体的标题
  • pos:指定窗体左上角在屏幕中的位置
  • size:指定窗体的大小
  • style:指定窗体的类型
  • name:指定框架的名字,指定后可以使用这个名字来寻找窗体

注:上述参数中只有parent没有默认值,so最简单的调用方式是wx.Frame.__init__(self, parent=None),这将生成一个默认位置、默认大小、默认标题的顶层窗体

 

(3)关于id

在wxPython的函数中很多时候要设置id,如果无法确定如何设置id,可以使用wx.NewId()函数来生成id号,这样讲就可以避免ID号唯一的麻烦

例如:

1 frame = wx.Frame__init__(None, wx.NewId())
2 
3 # 设置配置菜单
4 configmenu = wx.Menu()
5 configmenu.Append(wx.NewId(), "自动换行", "选择是否自动换行")
6 configmenu.Append(wx.NewId(), "状态栏", "选择是否显示状态栏")

当然也可以使用全局常量wx.ID_ANY(值为-1)来让wxPython自动生成新的唯一ID号,需要时也可以使用GetId()方法得到它

1 frame = wx.Frame.__init__(None, -1)
2 id = frame.GetId()

 

(4)wx.Frame类成员函数

S.N.函数 & 描述
1

CreateStatusBar()

创建窗口底部状态栏
2

CreateToolBar()

创建工具栏在窗口的顶部或左侧
3

GetMenuBar()

获取引用菜单栏
4

GetStatusBar()

获取引用状态栏
5

SetMenuBar()

在帧(frame)显示菜单栏对象
6

setStatusBar()

关联状态栏对象到框架(frame)
7

SetToolBar()

关联工具栏对象到框架(frame)

8

SetStatusText()

在状态栏上显示的文字
9

Create()

创建有提供参数的框架
10

Centre()

放置该帧(frame)显示在中心
11

SetPosition()

放置帧(frame)在给定的屏幕坐标
12

SetSize()

由给定尺寸调整框架(frame)大小
13

SetTitle()

插入给定文本到标题栏

(5)wx.Frame 事件绑定器

S.N.事件 & 描述
1

EVT_CLOSE

当帧被用户关闭/或以编程方式点击关闭按钮
2

EVT_MENU_OPEN

当一个菜单即将打开
3

EVT_MENU_CLOSE

当一个菜单刚刚关闭
4

EVT_MENU_HIGHLIGHT

当指定id菜单项突显

 

 

2.按钮、静态文本框、文本框

(1)Button按钮

在任何GUI界面按钮组件的应用最为广泛。它捕获用户生成的点击事件。其最明显的用途是触发绑定到一个处理函数

wx.Button类对象带有一些文本作为其标题,是一个简单易用的按钮

构建Button:Wx.Button(parent=None, label=None, pos=None, size=None)

在上述参数中label是按钮上的文本,pos与size分别是设置位置和大小,parent表示父窗体

wx.Button类的常用方法:

  • SetLabel() 编程设置按钮的标题
  • GetLabel() 返回按钮的标题
  • SetDefault() 按钮设置为默认顶层窗口。模拟click事件按下回车键

 

(2)StaticText静态文本框

wx.StaticText类对象提供了一个控件持有只读文本,被动控制,不产生任何事件,只是单纯的文本

构建StaticText:Wx.StaticText(parent=None, label=None, pos=None, size=None, style=None)

在上述参数中label是文本,pos与size分别是设置位置和大小,parent表示父窗体。style表示文本的样式

 

(3)TextCtrl文本框

wx.TextCtrl类的一个对象用于显示文一个多行文本框,TextCtrl小部件可以是单行,多行或密码字段

构建TextCtrl:Wx.TextCtrl(parent=None, value=None, pos=None, size=None, style=None)

在上述参数中value是默认文本,pos与size分别是设置位置和大小,parent表示父窗体。style表示文本框的样式

1 tc_stu_id = wx.TextCtrl(panel)        # 普通文本框
2 tc_pwd = wx.TextCtrl(panel,style = wx.TE_PASSWORD)     # 密码框
3 tc_lines = wx.TextCtrl(panel,size = (200,100),style = wx.TE_MULTILINE)   # 多行文本框
4 
5 # 不可编辑文本框:
6 wx.TextCtrl ( panel, value = "ReadOnly Text",    style = wx.TE_READONLY | wx.TE_CENTER )

TextCtrl类常用方法:

  • GetValue()获取值
  • SetValue()设置值
  • AppendText()添加值

 

 

3.菜单系列(MenuItem  Menu  MenuBar) 

(1)Menu

Menu类用来创建菜单,使用如下:

 1      # 设置文件菜单:
 2         filemenu = wx.Menu()
 3         # 向菜单中添加对象
 4         menuNew = filemenu.Append(wx.ID_NEW, "新建", "新建文件")
 5         menuOpenFile = filemenu.Append(wx.ID_OPEN, "打开", "打开文件")
 6         filemenu.AppendSeparator()          # 在菜单中的选项之间加分隔符
 7         menuSaveFile = filemenu.Append(wx.ID_SAVE, "保存", "保存文件")
 8         filemenu.AppendSeparator()
 9         menuExit = filemenu.Append(wx.ID_EXIT, "退出", "退出notebook")
10 
11         # 设置编辑菜单
12         editmenu = wx.Menu()
13         # 向菜单中添加对象
14         editmenu.Append(wx.ID_CANCEL, "撤销", "撤销操作")
15         editmenu.Append(wx.ID_PASTE, "粘贴", "粘贴信息")
16 
17         # 设置配置菜单
18         configmenu = wx.Menu()
19         # 向菜单中添加对象
20         configmenu.Append(wx.NewId(), "自动换行", "选择是否自动换行")
21         configmenu.Append(wx.NewId(), "状态栏", "选择是否显示状态栏")
22 
23         # 设置帮助菜单
24         helpmenu = wx.Menu()
25         # 向菜单中添加对象
26         helpmenu.Append(wx.ID_ABOUT, "关于", "关于notebook")
27         helpmenu.Append(wx.ID_HELP, "帮助", "查看帮助信息")

 

 

(2)MenuBar

MenuBar用来创建菜单栏,使用如下:

1      # 创建菜单栏
2         menuBar = wx.MenuBar()
3         menuBar.Append(filemenu, "文件(F)")
4         menuBar.Append(editmenu, "编辑(E)")
5         menuBar.Append(configmenu, "配置(C)")
6         menuBar.Append(helpmenu, "帮助(H)")
7         self.SetMenuBar(menuBar)

 

(3)MenuItem

一个菜单中的对象可以使用Append方法直接添加,也可以先生成一个MenuItem对象再添加这个对象

1 Item = Wx.MenuItem(parentmenu, id, text, kind)
2 
3 wx.Menu.Append(Item)
1 item = wx.MenuItem(filemenu, wx.NewId(), "test", "test")
2 filemenu.Append(item)

 

 

4.工具栏及状态栏

(1)ToolBar工具栏

工具栏包括文本文字说明或图标按钮的一个或多个水平条,通常被放置在MenuBar顶层帧的正下方

ToolBar类的构造函数不带任何参数则使用工具栏默认参数。附加参数可以传递给wx.ToolBar类构造如下

Wx.ToolBar(parent, id, pos, size, style)

 

(2)StatusBar状态栏

创建状态栏及设置状态栏:

1 self.StatusBar = self.frame.CreateStatusBar()
2 self.statusBar.SetStatusText('You clicked the Open menu')

 

 

5.对话框

对话框有:

  • 简单消息框MessageBox
  • 接受用户输入的文本GetTextFromUser
  • 接受用户输入的密码GetPasswordFromUser
  • 接受用户输入的数字GetNumberFromUser
  • 文件对话框FileDialog
  • 字体对话框FontDialog
  • 颜色对话框ColourDialog

(1)MessageBox

1 finalStr = "OK"
2 wx.MessageBox(finalStr)

 

(2)FileDialog

wx.FileDialog 允许用户从系统的文件中选择一个或者多个文件。支持通配符,可以让用户选择关心的文件。例如:"BMP files (*.bmp)|*.bmp|GIF files (*.gif)|*.gif"只会显示和选择图片后缀类型是bmp gif

 

 

6.单选框、复选框、组合框、列表框

(1)RadioButton单选框与CheckBox复选框

常用操作:

1 GetValue() 判断单选或复选是否被选中
2 SetValue() 设置单选或复选的选中状态(参数为True表示选中,否则表示未选中)

在某些应用中可能需要响应单选框、复选框的鼠标点击事件,可以使用wx.EVT_RADIOBOX(),wx.CHECKBOX()分别为单选框和复选框来绑定事件处理函数

单选框与复选框应用:

 1 # __author__ = "wyb"
 2 # date: 2018/5/7
 3 import wx
 4 
 5 
 6 class wxGUI(wx.App):
 7     def OnInit(self):
 8         self.frame = wx.Frame(parent=None, title='wxGUI', size=(300, 300))
 9         self.panel = wx.Panel(self.frame, -1)
10 
11         # 单选框 所有的选项中只能选一种
12         self.radioButtonSexM = wx.RadioButton(self.panel, -1, 'Male', pos=(80, 60))
13         self.radioButtonSexF = wx.RadioButton(self.panel, -1, 'FeMale', pos=(80, 80))
14         # 复选框 可以不选或选一种或多选
15         self.checkBoxAdmin = wx.CheckBox(self.panel, -1, 'Administrator', pos=(150, 60))
16         self.checkBoxRoot = wx.CheckBox(self.panel, -1, 'Root', pos=(150, 80))
17 
18         self.label1 = wx.StaticText(self.panel, -1, 'username: ', pos=(0, 110), style=wx.ALIGN_RIGHT)
19         self.label2 = wx.StaticText(self.panel, -1, 'password: ', pos=(0, 130), style=wx.ALIGN_RIGHT)
20 
21         self.textName = wx.TextCtrl(self.panel, -1, pos=(70, 110), size=(160, 20))
22         self.textPwd = wx.TextCtrl(self.panel, -1, pos=(70, 130), size=(160, 20), style=wx.TE_PASSWORD)
23 
24         # 建立OK按钮并绑定事件
25         self.buttonOK = wx.Button(self.panel, -1, 'OK', pos=(30, 160))
26         self.Bind(wx.EVT_BUTTON, self.OnButtonOK, self.buttonOK)
27         # 建立Cancel按钮并绑定事件
28         self.buttonCancel = wx.Button(self.panel, -1, 'Cancel', pos=(120, 160))
29         self.Bind(wx.EVT_BUTTON, self.OnButtonCancel, self.buttonCancel)
30         self.buttonOK.SetDefault()          # 设置默认选择OK按钮
31 
32         self.frame.Show()
33         return True
34 
35     # OK按钮的响应事件
36     def OnButtonOK(self, event):
37         finalStr = ''
38         if self.radioButtonSexM.GetValue() == True:
39             finalStr += 'Sex: Malen'
40         elif self.radioButtonSexF.GetValue() == True:
41             finalStr += 'Sex: FeMalen'
42         if self.checkBoxAdmin.GetValue() == True:
43             finalStr += 'Administratorn'
44         if self.textName.GetValue() == 'wyb' and self.textPwd.GetValue() == 'wyb':
45             finalStr += 'login'
46         else:
47             finalStr += 'wrong username or wrong password!'
48         wx.MessageBox(finalStr)
49 
50     # Cancel按钮的响应事件
51     def OnButtonCancel(self, event):
52         self.radioButtonSexM.SetValue(True)
53         self.radioButtonSexF.SetValue(False)
54         self.checkBoxAdmin.SetValue(True)
55         self.textName.SetValue('')
56         self.textPwd.SetValue('')
57 
58 
59 if __name__ == '__main__':
60     app = wxGUI()
61     app.MainLoop()

 

(2)ComboBox组合框

组合框用来实现从固定的多个选项中选择其中一个的操作,外观与文本框类似,但是单击下拉箭头时弹出所有可选项,极大地方便了用户的操作,并且在窗体上不占用太多空间

如果需要响应和处理组合框的鼠标单击事件,可以使用wx.EVT_COMBOBOX()为组合框绑定事件处理函数,组合框实例如下:

 1 # __author__ = "wyb"
 2 # date: 2018/5/8
 3 import wx
 4 
 5 class wxGUI(wx.App):
 6     def OnInit(self):
 7         self.frame = wx.Frame(parent=None, title='wxGUI', size=(300, 200))
 8         self.panel = wx.Panel(self.frame, -1)
 9         self.names = {'北京': ['东城', '海淀', '朝阳'], '武汉': ['武昌', '汉口', '汉阳']}
10 
11         # ComBox1
12         # print(self.names.keys())
13         print(list(self.names.keys()))
14         self.comboBox1 = wx.ComboBox(self.panel, value='请选择', choices=list(self.names.keys()), pos=(0, 50), size=(100, 30))
15         self.Bind(wx.EVT_COMBOBOX, self.OnCombo1, self.comboBox1)
16 
17         # ComBox2
18         self.comboBox2 = wx.ComboBox(self.panel, value='请选择', choices=[], pos=(0, 100), size=(100, 30))
19         self.Bind(wx.EVT_COMBOBOX, self.OnCombo2, self.comboBox2)
20 
21         self.frame.Show()
22         return True
23 
24     def OnCombo1(self, event):
25         k = self.comboBox1.GetValue()
26         self.comboBox2.Set(self.names[k])           # 动态修改第二个组合框中的值
27 
28     def OnCombo2(self, event):
29         wx.MessageBox(self.comboBox2.GetValue())    # 弹出选择的第二个组合框中的值
30 
31 app = wxGUI()
32 app.MainLoop()

 

(3)ListBox列表框

列表框用来放置多个元素提供给用户进行选择,其中每个元素都是字符串,支持用户单选和多选,组合框实例如下:

 1 # __author__ = "wyb"
 2 # date: 2018/5/10
 3 import wx
 4 
 5 
 6 class ListBoxDemo(wx.Frame):
 7     def __init__(self, superion):
 8         wx.Frame.__init__(self, parent=superion, title='ListBox demo', size=(200, 200))
 9         panel = wx.Panel(self)
10         self.buttonQuit = wx.Button(parent=panel, label='Quit', pos=(60, 120))
11         self.Bind(wx.EVT_BUTTON, self.OnButtonQuit, self.buttonQuit)
12         li = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']
13         self.listBox = wx.ListBox(panel, choices=li)            # 创建列表框
14         self.Bind(wx.EVT_BUTTON, self.OnClick, self.listBox)    # 绑定事件处理器
15 
16     def OnClick(self, event):
17         t = self.listBox.GetSelection()
18         s = self.listBox.GetString(t)
19         print(s)
20         s = self.listBox.GetStringSelection()
21         wx.MessageBox(s)
22 
23     def OnButtonQuit(self, event):
24         dlg = wx.MessageDialog(self, 'Really Quit?', 'Caution', wx.CANCEL|wx.OK|wx.ICON_QUESTION)
25         if dlg.ShowModal() == wx.ID_OK:
26             self.Destroy()
27 
28 
29 if __name__ == '__main__':
30     app = wx.App()
31     frame = ListBoxDemo(None)
32     frame.Show()
33     app.MainLoop()

 

 

 

三、wxPython布局

1.wxPython布局简介

布局方法:绝对定位和相对定位,绝对定位是指一个GUI部件可通过指定以像素为单位的绝对坐标放置在容器窗口中。 坐标是相对于它的构造尺寸参数定义的窗口的尺寸大小。窗口中的窗口小部件的位置由它的构造函数的pos参数定义的

绝对定位实例:

1 import wx  
2 
3 app = wx.App() 
4 window = wx.Frame(None, title = "wxPython Frame", size = (300,200)) 
5 panel = wx.Panel(window) 
6 label = wx.StaticText(panel, label = "Hello World", pos = (100,50)) 
7 window.Show(True) 
8 app.MainLoop() 

而在wxPython中的相对定位是指使用布局类容器来定位,wxPython的API提供了布局类的容器内的小部件的定位更优雅的管理:

  • 在窗口中的窗口小部件会自动调整大小
  • 确保均匀的外观上不同分辨率的显示设备
  • 添加或去除部件动态地是可能的,而不需要重新设计

布局管理器在wxPython中被称为Sizer。Wx.Sizer是所有sizer 的基类。一些重要的sizer有wx.BoxSizer,wx.StaticBoxSizer,wx.GridSizer,wx.FlexGridSizer

我的博客中主要介绍BoxSizer布局和GridSizer布局这两种方法

 

 

2.BoxSizer布局

BoxSizer布局是由它的定位参数(wxVERTICAL或wxHORIZONTAL)确定

  • Box = wx.BoxSizer(wxHORIZONTAL)   -> 水平布局(从左到右添加组件)
  • Box = wx.BoxSizer(wxVERTICAL)   -> 垂直布局(从上到下添加组件)  
Add() 方法(从wxSizer继承)它附加到sizer的下一行/列
Box.Add(control, proportion, flag, border)

 

 

3.GridSizer布局

一个GridSizer对象展示二维网格。控件被添加在网格插槽从左到右和由上到下方顺序。GridSizer对象有四个参数

Box = wx.GridSizer(rows, columns, vgap, hgap)    ->   vgap和hgap指定参数控制相邻控件之间的纵向和横向间距,rows和columns分别指定行数和列数

Add() 方法(从wxSizer继承)它附加到sizer的下一个格子中
Box.Add(control, proportion, flag, border)

 

GridSizer布局实例:

 1 import wx
 2 class Example(wx.Frame): 
 3    def __init__(self, parent, title): 
 4       super(Example, self).__init__(parent, title = title,size = (300,200))       
 5       self.InitUI() 
 6       self.Centre() 
 7       self.Show()      
 8          
 9    def InitUI(self): 
10       p = wx.Panel(self) 
11       r = wx.GridSizer(4, 4, 5, 5) 
12         
13       for i in range(1,17): 
14          btn = "Btn"+str(i) 
15          r.Add(wx.Button(p,label = btn),0,wx.EXPAND) 
16 
17          p.SetSizer(r)  
18    
19 app = wx.App() 
20 Example(None, title = 'Grid Demo’) 
21 app.MainLoop()

 

 

 

四、wxPython事件处理

不像控制台模式应用程序,一个基于GUI的应用程序是事件驱动的,这是在一个顺序的方式执行的。  函数或方法响应于像点击按钮,从集合或鼠标点击等,调用事件选择项目处理函数,用户的操作被执行

点击一个按钮发出 wx.CommandEvent 事件。该事件数据被分派到程序事件处理的方法。wxPython中有许多预定义的事件绑定器。一个事件绑定封装了具体的小部件(控件),其关联的事件类型和事件处理方法之间的关系

例如,要调用一个按钮的点击事件的程序上的 OnClick()方法,下面的语句是必需的:
self.Control.Bind(EVT_BUTTON, OnClick)   -> control为控件(大部分情况下为按钮)

 

 

 

五、wxPython实战

1.判断素数

 1 # __author__ = "wyb"
 2 # date: 2018/5/7
 3 
 4 import wx
 5 from math import sqrt
 6 
 7 
 8 class IsPrimeFrame(wx.Frame):
 9     def __init__(self, superion):
10         wx.Frame.__init__(self, parent=superion, title="Check Prime", size=(400, 200))
11         panel = wx.Panel(self)
12         panel.SetBackgroundColour('White')
13         wx.StaticText(parent=panel, label='Input a integer:', pos=(10, 10))
14         self.inputN = wx.TextCtrl(parent=panel, pos=(120, 10))
15         self.result = wx.StaticText(parent=panel, label='', pos=(10, 50))
16         self.buttonCheck = wx.Button(parent=panel, label='Check', pos=(70, 90))
17 
18         self.Bind(wx.EVT_BUTTON, self.OnButtonCheck, self.buttonCheck)
19         self.buttonQuit = wx.Button(parent=panel, label='Quit', pos=(150, 90))
20         self.Bind(wx.EVT_BUTTON, self.OnB
                        
版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/weixin_34268579/article/details/94568523
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2021-05-23 21:55:16
  • 阅读 ( 542 )
  • 分类:

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢