构建一个最简单的wxPython 程序至少需要一个wx.App 对象和一个wx.Frame 对象。
模板:
import wx # 加载模块
# 继承窗体类
class MyFrame(wx.Frame):
def __init__(self):
# 初始化父类
super().__init__(parent=None,title="第一个窗体程序!",size=(500,200))
self.Center() # 设置窗口居中
# 这里可以添加自己的设计代码
# ·······
# 这里可以添加自己的设计代码
# wx.App 对象代表当前应用程序
class App(wx.App):
def OnInit(self):
myFrame=MyFrame() # 创建窗体实例
myFrame.Show() # 显示窗口
return True
def OnExit(self):
print(' 应用程序退出')
return 0
if __name__ =="__main__":
app=App() # 创建应用程序对象
app.MainLoop() # 进入主事件循环
一、wx.Frame类介绍:
wx.Frame(parent, id=-1, title= "", pos=wx.DefaultPosition, size=wx.DefaultSize,style=wx.DEFAULT_FRAME_STYLE,name="frame")
parent : 框架的父窗口。对于顶级窗口,这个值是None 。
id : 关于新窗口的wxPython ID 号。可以明确地传递一个 值。如果 传递-1 ,wxPython 自动生成一个新的ID 。
title : 窗口的标题。
pos : 一个wx.Point 对象,它指定这个新窗口的左上角在屏幕中的位置。
size : 一个wx.Size 对象,它指定这个窗口的初始尺寸。(-1,-1) 将让系统决定窗口的初始尺寸。
style: 指定窗口的类型的常量。可以使用或运算来组合它们。
name : 框架的内在的名字。以后可以使用它来寻找这个窗口。
二、窗体布局
wxPython 提供了8 个布局管理器类,包括wx.Sizer 、wx.BoxSizer 、wx.StaticBoxSizer 、wx.WrapSizer 、wx.StdDialogButtonSizer 、wx.GridSizer 、wx.FlexGridSizer 、wx.GridBagSizer。
其中wx.Sizer 是布局管理器的根类, 一般不会直接使用wx.Sizer ,而是使用它的子类 ,最常用的有:wx.BoxSizer 、wx.StaticBoxSizer 、wx.GridSizer 和wx.FlexGridSizer 。
1. Box 布局
Box 布局类是wx.BoxSizer ,Box 布局是所有布局中最常用的,它可以让其中的子窗口(或控件)沿垂直或水平方向布局,创建wx.BoxSizer 对象时可以指定布局方向。
当需要添加子窗口(或控件)到父窗口时,需要调用wx.BoxSizer 对象Add() 方法,Add() 方法是从父类wx.Sizer 继承而来的,Add() 方法的语法说明如下:
Add(window, proportion=0, flag=0, border=0, userData=None)
Add(sizer, proportion=0, flag=0, border=0,userData=None)
Add(size, proportion=0, flag=0, border=0, userData=None)
其中proportion 参数仅被wx.BoxSizer 使用,用来设置当前子窗口(或控件)在父窗口所占空间比例 ,proportion=0 表示保持本身大小;flag 是参数标志,用来控制对齐、边框和调整尺寸;border 参数用来设置边框的宽度;userData参数可被用来传递额外的数据。
flag标志:
对齐
边框
尺寸
2. StaticBox 布局
StaticBox 布局类是wx.StaticBoxSizer ,继承于wx.BoxSizer 。StaticBox 布局等同于Box ,只是在Box 周围多了一个附加的带静态文本的边框。
3. Grid 布局
Grid 布局类是wx.GridSizer ,Grid 布局以网格形式对子窗口(或控件)进行摆放,容器被分成大小相等的矩形,一个矩形中放置一个子窗口(或控件)。
四种构造方法:
wx.GridSizer(rows, cols, vgap, hgap) :
创建指定行数和列数的wx.GridSizer 对象,并指定水平和垂直间隙,参数hgap 是水平间隙,参数vgap 是垂直间隙。添加的子窗口(或控件)个数超过rows 与cols之积,则引发异常。
wx.GridSizer(rows, cols, gap) :
同wx.GridSizer(rows, cols,vgap, hgap) ,gap 参数指定垂直间隙和水平间隙,gap 参数是wx.Size 类型,例如wx.Size(2, 3) 是设置水平间隙为2 像素,垂直间隙为3 像素。
wx.GridSizer(cols, vgap, hgap) :
创建指定列数的wx.GridSizer 对象,并指定水平和垂直间隙。由于没有限定行数,所以添加的子窗口(或控件)个数没有限制。
wx.GridSizer(cols, gap=wx.Size(0, 0)) :
wx.GridSizer(cols,vgap, hgap) ,gap 参数指定垂直间隙和水平间隙,gap 参数是wx.Size类型。
import wx
class MyFrame(wx.Frame):
def __init__(self):
super().__init__(parent=None,title="Grid布局",size=(300,300))
self.Center()
panel=wx.Panel(self)
grid= wx.GridSizer(3,3,1,1)
for i in range(9):
item=wx.Button(parent=panel,id=-1,label=str(i+1))
grid.Add(item,1,flag=wx.EXPAND)
panel.SetSizer(grid) # 设置布局
class App(wx.App):
def OnInit(self):
frame=MyFrame()
frame.Show()
return True
if __name__=="__main__":
app=App()
app.MainLoop()
4. FlexGrid 布局
Grid 布局时网格大小是固定的,如果想网格大小不同可以使用FlexGrid。
FlexGrid 布局类是wx.FlexGridSizer ,它的父类是wx.GridSizer 。
wx.FlexGridSizer 的构造方法与wx.GridSizer 相同,这里不再赘述。wx.FlexGridSizer 有两个特殊方法如下:
1 )AddGrowableRow(idx, proportion=0) :
指定行是可扩展的,参数idx 是行索引,从零开始,参数proportion 设置该行所占空间比例。
2 )AddGrowableCol(idx, proportion=0) :
指定列是可扩展的,参数idx 是列索引,从零开始,参数proportion 设置该列所占空间比例。上述方法中的proportion 参数 默认是0 ,表示各个列占用空间是均等的。
import wx
class MyFrame(wx.Frame):
def __init__(self):
super().__init__(parent=None,title="FlexGrid布局",size=(400,200))
self.Center()
panel=wx.Panel(self)
flexgrid=wx.FlexGridSizer(3,2,10,10)
text1=wx.StaticText(parent=panel,id=-1,label="标题")
boxctrl1=wx.TextCtrl(parent=panel,id=1)
text2 = wx.StaticText(parent=panel, id=-1, label="作者")
boxctrl2 = wx.TextCtrl(parent=panel, id=2)
text3 = wx.StaticText(parent=panel, id=-1, label="内容")
boxctrl3 = wx.TextCtrl(parent=panel, id=3,style=wx.TE_MULTILINE)
flexgrid.Add(text1)
flexgrid.Add(boxctrl1,1,flag=wx.EXPAND)
flexgrid.Add(text2)
flexgrid.Add(boxctrl2,1,flag=wx.EXPAND)
flexgrid.Add(text3)
flexgrid.Add(boxctrl3,1,flag=wx.EXPAND)
flexgrid.AddGrowableCol(1,2)
flexgrid.AddGrowableRow(2, 3)
box=wx.BoxSizer()
box.Add(flexgrid,1,flag=wx.ALL|wx.EXPAND,border=10)
panel.SetSizer(box)
class App(wx.App):
def OnInit(self):
frame=MyFrame()
frame.Show()
return True
if __name__=="__main__":
app=App()
app.MainLoop()
三、wxPython控件
wxPython 的所有控件都继承自wx.Control 类。主要有文本输入控件、按钮、静态文本、列表、单选按钮 、复选框等控件。
1. 静态文本
wxPython 中静态文本类是 wx.StaticText
,可以显示文本。
构造函数:
wx.StataicText(parent, id, label, pos=wx.DefaultPosition,size=wx.DefaultSize, style=0, name="staticText")
2. 按钮
wxPython 中的按钮主要有wx.Button 、wx.BitmapButton和wx.ToggleButton 三个。wx.Button 是普通按钮,wx.BitmapButton 是带有图标的按钮,wx.ToggleButton 是能进行两种状态切换的按钮。
构造函数:
wx.Button(parent, id, label, pos, size=wxDefaultSize,style=0, validator, name='button')
参数label 是显示在按钮上的文本。它可以在程序运行期间使用SetLabel() 来改变,并且使GetLabel() 来获取。另外两个有用的方法是GetDefaultSize() 和SetDefault() 。GetDefaultSize() 返回系统默认按钮的尺寸(对于框架间的一致性是有用的);SetDefault() 设置按钮为对话框或框架的默认按钮。默认按钮的绘制不同于其它按钮,它在对话框获得焦点时,通常按下回车键被激活。
3. 文本输入控件
文本 输入控件类是wx.TextCtrl 。
4. 复选框
构造函数:
wx.CheckBox(parent, id, label,pos=wx.DefaultPosition, size=wx.DefaultSize,style=0, name='checkBox')
命令事件:EVT_CHECKBOX
wx.CheckBox 的开关状态可以使用GetValue()和getValue(state) 方法来访问,并且其值是一个布尔值。IsChecked() 方法等同于GetValue()方法。
5. 单选按钮
构造函数:
wx.RadioButton(parent, id, label,pos=wx.DefaultPosition, size=wx.DefaultSize,style=0, validator=wx.DefaultValidator, name='radioButton')
创建wx.RadioButton 对象时设置style=wx.RB_GROUP ,这说明是一个组的开始,直到遇到另外设置style=wx.RB_GROUP 的wx.RadioButton对象为止都是同一个组。
import wx
class MyFrame(wx.Frame):
def __init__(self):
super().__init__(parent=None,title="复选框与单选框",size=(500,200))
self.Center()
panel=wx.Panel(self)
hbox1=wx.BoxSizer()
text1=wx.StaticText(parent=panel,id=0,label="选择你喜欢的编程语言:")
check1=wx.CheckBox(parent=panel,id=1,label="Python")
check2 = wx.CheckBox(parent=panel, id=2, label="Java")
check3 = wx.CheckBox(parent=panel, id=3, label="C++")
check2.SetValue(True)
hbox1.Add(text1,flag=wx.LEFT|wx.RIGHT,border=10)
hbox1.Add(check1, flag=wx.LEFT | wx.RIGHT, border=10)
hbox1.Add(check2, flag=wx.LEFT | wx.RIGHT, border=10)
hbox1.Add(check3, flag=wx.LEFT | wx.RIGHT, border=10)
self.Bind(wx.EVT_CHECKBOX,self.on_check,id=1,id2=3)
hbox2=wx.BoxSizer()
text2=wx.StaticText(parent=panel,id=4,label="选择性别:")
radio1=wx.RadioButton(parent=panel,id=5,label="男",style=wx.RB_GROUP)
radio2 = wx.RadioButton(parent=panel, id=6, label="女")
hbox2.Add(text2,flag=wx.LEFT|wx.RIGHT,border=10)
hbox2.Add(radio1, flag=wx.LEFT | wx.RIGHT, border=10)
hbox2.Add(radio2, flag=wx.LEFT | wx.RIGHT, border=10)
self.Bind(wx.EVT_RADIOBUTTON, self.on_radio1, id=5, id2=6)
hbox3 = wx.BoxSizer()
text3 = wx.StaticText(parent=panel, id=10, label="选择你喜欢吃的水果:")
radio3 = wx.RadioButton(parent=panel, id=7, label="苹果",style=wx.RB_GROUP)
radio4 = wx.RadioButton(parent=panel, id=8, label="橘子")
radio5 = wx.RadioButton(parent=panel, id=9, label="香蕉")
hbox3.Add(text3, flag=wx.LEFT | wx.RIGHT, border=10)
hbox3.Add(radio3, flag=wx.LEFT | wx.RIGHT, border=10)
hbox3.Add(radio4, flag=wx.LEFT | wx.RIGHT, border=10)
hbox3.Add(radio5, flag=wx.LEFT | wx.RIGHT, border=10)
self.Bind(wx.EVT_RADIOBUTTON, self.on_radio2, id=7, id2=9)
vbox=wx.BoxSizer(wx.VERTICAL)
vbox.Add(hbox1,flag=wx.ALL|wx.EXPAND,border=10)
vbox.Add(hbox2, flag=wx.ALL | wx.EXPAND, border=10)
vbox.Add(hbox3, flag=wx.ALL | wx.EXPAND, border=10)
panel.SetSizer(vbox)
ico=wx.Icon("C:\\Users\\自由自在\\Desktop\\Python应用开发\\Python(1)\\素材\wxPython\\icon\\0.png",wx.BITMAP_TYPE_ANY)
self.SetIcon(ico)
self.CreateStatusBar()
self.SetStatusText("准备就绪")
def on_check(self,event):
ch=event.GetEventObject()
self.SetStatusText("选择: "+ch.GetLabel()+" 状态:"+str(event.IsChecked()))
def on_radio1(self,event):
ch=event.GetEventObject()
self.SetStatusText("第一组 "+ch.GetLabel()+" 被选中")
def on_radio2(self,event):
ch=event.GetEventObject()
self.SetStatusText("第二组 "+ch.GetLabel()+" 被选中")
class App(wx.App):
def OnInit(self):
myFrame=MyFrame()
myFrame.Show()
return True
if __name__ =="__main__":
app=App()
app.MainLoop()
6. 下拉列表
wxPython 提供了两种下拉列表控件类wx.ComboBox 和wx.Choice 。wx.ComboBox 默认它的文本框是可以修改的,wx.Choice 是只读不可以修改的,除此之外它们没有区别。
构造函数:
wx.ComboBox(parent, id, value="",pos=wx.DefaultPosition, size=wx.DefaultSize, choices,style=0, validator=wx.DefaultValidator,name="comboBox")
value 用来设置默认值,即下拉列表的文本框中初始显示的内容;
choices 参数用来设置列表选择项,它是列表类型;
style 参数用来设置wx.ComboBox 风格样式,主要有4 种风格:
wx.CB_SIMPLE :列表部分一直显示不收起来。wx.CB_DROPDOWN :默认风格,单击向下按钮列表部分展开,选择完成收起来。wx.CB_READONLY :文本框不可修改。
wx.CB_SORT :对列表选择项进行排序。
8wx.Choice 的构造方法与列表框的基本相同:*
wx.Choice(parent, id, pos=wx.DefaultPosition,size=wx.DefaultSize, choices=None, style=0,validator=wx.DefaultValidator, name="choice")
import wx
class MyFrame(wx.Frame):
def __init__(self):
super().__init__(parent=None,title="下拉列表",size=(400,200))
self.Center()
panel=wx.Panel(self)
text1=wx.StaticText(parent=panel,id=-1,label="选择喜欢的编程语言:")
list1=["Python","Java","C++"]
combobox=wx.ComboBox(parent=panel,id=-1,value="C++",choices=list1,
style=wx.CB_SORT|wx.TE_PROCESS_ENTER)
self.Bind(wx.EVT_COMBOBOX,self.on_combobox,combobox)
hbox1=wx.BoxSizer()
hbox1.Add(text1,1,flag=wx.LEFT|wx.RIGHT|wx.FIXED_MINSIZE,border=5)
hbox1.Add(combobox, 1, flag=wx.FIXED_MINSIZE|wx.ALL)
list2=["男","女"]
text2 = wx.StaticText(parent=panel, id=-1, label="选择性别:")
choice=wx.Choice(parent=panel,id=-1,choices=list2)
choice.SetSelection(0)
self.Bind(wx.EVT_CHOICE,self.on_choice,choice)
hbox2 = wx.BoxSizer()
hbox2.Add(text2, 1, flag=wx.LEFT|wx.RIGHT |wx.FIXED_MINSIZE,border=5)
hbox2.Add(choice, 1, flag=wx.ALL |wx.FIXED_MINSIZE)
vbox=wx.BoxSizer(wx.VERTICAL)
vbox.Add(hbox1,1,flag=wx.ALL |wx.EXPAND,border=5)
vbox.Add(hbox2, 1,flag=wx.ALL |wx.EXPAND,border=5)
panel.SetSizer(vbox)
self.CreateStatusBar()
self.SetStatusText("准备就绪")
def on_combobox(self,event):
str=event.GetString()
self.SetStatusText("选择:"+str)
def on_choice(self,event):
str = event.GetString()
self.SetStatusText("选择:" + str)
class App(wx.App):
def OnInit(self):
frame=MyFrame()
frame.Show()
return True
if __name__=="__main__":
app=App()
app.MainLoop()
7. 列表
列表控件类似于下拉列表控件,只是没有文本框,只有一个列表选项。列表控件可以单选或多选。列表控件类是wx.ListBox.
构造方法
wx.ListBox(parent, id, pos=wx.DefaultPosition,size=wx.DefaultSize, choices=None, style=0,validator=wx.DefaultValidator,name="listBox")
wx.ListBox 没有label 属性。显示在列表中的元素放置在参数choices 中,它是一个字符串的序列。列表框有三种互斥的样式,它决定用户如何从列表框中选择元素。
(1 )wx.LB_EXTENDED :用户可以通过使用shift 并敲击鼠标来选择一定范围内的连续的 选项,或使用等同功能的按键。
(2 )wx.LB_MULTIPLE :用户可以一次选择多个选项(选项可以是不连续的)。实际上,在这种情况下,列表框的行为就像是一组复选框。
(3 )wx.LB_SINGLE :用户一次只能选一个选项。实际上,在这种情况下,列表框的行为 就像是一组单选按钮。
8. 静态图片控件
静态图片控件类是wx.StaticBitmap ,静态图片控件用来显示一张图片,图片可以是wx.Python 所支持的任何图片格式。
图片替换后,需要重新绘制窗口,否则布局会发生混乱。self.panel.Layout() 是重新设置panel 面板布局,因为静态图片控件是添加在panel面板上的。
import wx
class MyFrame(wx.Frame):
def __init__(self):
super().__init__(parent=None,title="静态图片控件",size=(300,300))
self.Center()
self.panel=wx.Panel(self)
button1=wx.Button(parent=self.panel,id=1,label="Button1")
button2= wx.Button(parent=self.panel, id=2, label="Button2")
self.Bind(wx.EVT_BUTTON,self.on_button,id=1,id2=2)
self.bmaps=[wx.Bitmap("C:\\Users\\自由自在\\Desktop\\Python应用开发\\Python(1)\\素材\wxPython\\images\\bird3.gif",wx.BITMAP_TYPE_ANY),
wx.Bitmap("C:\\Users\\自由自在\\Desktop\\Python应用开发\\Python(1)\\素材\wxPython\\images\\bird4.gif",wx.BITMAP_TYPE_ANY),
wx.Bitmap("C:\\Users\\自由自在\\Desktop\\Python应用开发\\Python(1)\\素材\wxPython\\images\\bird5.gif",wx.BITMAP_TYPE_ANY)]
self.image=wx.StaticBitmap(self.panel,-1,self.bmaps[0])
vbox=wx.BoxSizer(wx.VERTICAL)
vbox.Add(button1,1,flag=wx.CENTER|wx.EXPAND)
vbox.Add(button2, 1, flag=wx.CENTER | wx.EXPAND)
vbox.Add(self.image, 3, flag=wx.CENTER | wx.EXPAND)
self.panel.SetSizer(vbox)
def on_button(self,event):
id=event.GetId()
if id==1:
self.image.SetBitmap(self.bmaps[1])
else:
self.image.SetBitmap(self.bmaps[2])
self.panel.Layout()
class App(wx.App):
def OnInit(self):
frame=MyFrame()
frame.Show()
return True
if __name__=="__main__":
app=App()
app.MainLoop()
9. 使用网格
当有大量数据需要展示时,可以使用网格。
wxPython 的网格类似于Excel 电子表格,wxPython 网格类是wx.grid.Grid.
但是wx.grid.Grid 添加单元格数据比较麻烦,而且对于网格的控制也很少,为此可以使用wx.grid.GridTableBase 类,该类是一个抽象类,开发人员需要实现该类一些方法。
wx.grid.GridTableBase 中需要被覆盖的方法:
GetNumberCols() :
返回显示在网格中的列的数目
GetNumberRows() :
返回显示在网格中的行的数目
GetValue(row, col) :
返回单元格(row, col) 处的值
IsEmptyCell(row, col) :
如果坐标(row, col) 处的单元格为空的话,返回True 。否则返回False 。SetValue(row, col, value) :
该方法在当用户编辑一个单元格时自动被调用。要得到一行或一列的标签,使用GetColLabelValue(col) GetRowLabelValue(row) 方法。
import wx
import wx.grid
tableText = ["书籍编号", "书籍名称", "作者", "出版社", "出版日期", "库存数量"]
data = [["0036", "高等数学", "李放", "人民邮电出版社", "20000212", "1"],
["0004", "FLASH精选", "刘杨", "中国纺织出版社", "19990312", "2"],
["0025", "软件工程", "牛田", "经济科学出版社", "20000328", "4"],
["0015", "人工智能", "周末", "机械工业出版社", "19991223", "3"]]
class MyGridTable(wx.grid.GridTableBase):
def __init__(self):
super().__init__()
self.colLabels=tableText
def GetNumberRows(self):
return len(data)
def GetNumberCols(self):
return len(tableText)
def GetValue(self, row, col):
return data[row][col]
def GetColLabelValue(self, col):
return tableText[col]
class MyFrame(wx.Frame):
def __init__(self):
super().__init__(parent=None,title="网格控件",size=(500,200))
self.Center()
panel=wx.Panel(self)
grid=wx.grid.Grid(parent=panel)
table=MyGridTable()
grid.SetTable(table,True)
grid.AutoSize()
box=wx.BoxSizer()
box.Add(grid,flag=wx.ALL,border=10)
panel.SetSizer(box)
class App(wx.App):
def OnInit(self):
frame=MyFrame()
frame.Show()
return True
if __name__ =="__main__":
app=App()
app.MainLoop()
10. 分隔窗口
分隔窗口(wx.SplitterWindow) 就是将窗口分成两部分,即分成左右或上下两部分。如下图所示窗口,整体上分为左右两个窗口,右窗口又分为上下两窗口,两个窗口之间的分隔线是可以拖曳的,称为“窗框”(sash )。
在wxPython 中,分割窗是wx.SplitterWindow 的实例。
构造方法:
wx.SplitterWindow(parent, id=-1,pos=wx.DefaultPosition, size=wx.DefaultSize,style=wx.SP_3D, name="splitterWindow")
常用的方法:
(1 )SplitVertically(window1, window2, sashPosition=0):设置左右布局的分隔窗口,window1 为左窗口,window2 为右窗口,sashPosition 是窗框的位置。
(2 )SplitHorizontally(window1, window2,sashPosition=0) :设置上下布局的分隔窗口,window1 为上窗口,window2 为下窗口,sashPosition 是窗框的位置。
(3 )SetMinimumPaneSize(paneSize) :设置最小窗口尺寸。如果左右布局,是指左窗口的最小尺寸;如果上下布局,是指上窗口的最小尺寸。如果没有设置则默认为0.
import wx
class MyFrame(wx.Frame):
def __init__(self):
super().__init__(parent=None,title="分隔窗口控件",size=(350,180))
self.Center()
splitterr=wx.SplitterWindow(self,id=-1)
left=wx.Panel(splitterr)
right= wx.Panel(splitterr)
splitterr.SplitVertically(left, right, 100)
splitterr.SetMinimumPaneSize(80)
list=["苹果","橘子","香蕉"]
listbox=wx.ListBox(parent=left,id=-1,choices=list,style=wx.LB_SINGLE)
vbox1=wx.BoxSizer(wx.VERTICAL)
vbox1.Add(listbox,1,flag=wx.ALL|wx.EXPAND,border=5)
left.SetSizer(vbox1)
text=wx.StaticText(parent=right,id=-1,label="右侧面板")
vbox2=wx.BoxSizer(wx.VERTICAL)
vbox2.Add(text,1,flag=wx.ALL|wx.EXPAND,border=5)
right.SetSizer(vbox2)
class App(wx.App):
def OnInit(self):
frame=MyFrame()
frame.Show()
return True
if __name__=="__main__":
app=App()
app.MainLoop()
11. 消息对话框MessageDialog
构造函数:
wx.MessageDialog(parent, message, caption="Message box",style=wx.OK | wx.CANCEL, pos=wx.DefaultPosition)
按钮样式:
图标样式:
对话框通过使用ShowModal() 被调用。
四、事件处理
绑定是通过事件处理类的Bind() 方法实现的。
语法:
Bind(self, event, handler, source=None,id=wx.ID_ANY, id2=wx.ID_ANY)
event 是事件类型;
handler 是事件处理者(方法);
source 是事件源;
id 是事件源的标识;
id2 设置要绑定事件源的id 范围;
如果不再需要事件处理时,最好调用事件处理类的Unbind() 方法解除绑定。
self.Bind(wx.EVT_BUTTON, self.on_click, id=10,id2=20)
最快的脚步不是跨越,而是继续;最慢的步伐不是小步,而是徘徊。