




版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
第11
章
使用Python進行GUI開發
2錄目CONTENTS11.1
GUI編程概述11.2Tkinter的主要組件11.3實例:三連棋游戲11.4總結與習題11.1GUI編程概述411.1GUI編程概述
11.1.1窗口與組件11.1.2事件驅動與回調機制511.1GUI編程概述
1.讓沒有太多計算機專業背景的用戶難以接受2.極大地限制了程序使用效率基于控制臺交互使用Python語言,可以通過多種GUI開發庫進行GUI開發,包括內置在Python中的Tkinter,以及優秀的跨平臺GUI開發庫
PyQt和wxPython等。611.1GUI編程概述
11.1.1窗口與組件在GUI開發過程中,首先要創建一個頂層窗口,該窗口是一個容器,可以存放程序所需的各種按鈕、下拉框、單選框等組件。每種GUI開發庫都擁有大量的組件,可以說一個GUI程序就是由各種不同功能的組件組成的。頂層窗口作為一個容器,包含了所有的組件;而組件本身亦可充當一個容器,包含其他組件。這些包含其他組件的組件被稱為父組件,被包含的組件被稱為子組件。這是一種相對的概念,組件的所屬關系通常可以用樹來表示。頂層窗口各個組件11.1.2事件驅動與回調機制711.1GUI編程概述
當每個GUI組件都構建并布局完畢之后,程序的界面設計階段就算完成了。但是此時的用戶界面只能看而不能用,還需要為每個組件添加相應的功能。用戶在使用GUI程序時,會進行各種操作,如鼠標移動、鼠標點擊、按下鍵盤上的按鍵等,這些操作均稱為事件。同時,每個組件也對應著一些特有的事件,如在文本框中輸入文本、拖動滾動條等。可以說,整個GUI程序都是在事件驅動下完成各項功能的。GUI程序從啟動時就會一直監聽這些事件,當某個事件發生時程序會調用對應的事件處理函數并做出相應的響應,這種機制被稱為回調,而事件對應的處理函數被稱為回調函數。因此,為了使一個GUI具有預期功能,用戶需要為每個事件編寫合理的回調函數。11.2Tkinter的主要組件911.2Tkinter組件
11.2.1標簽Label11.2.2框架Frame11.2.3按鈕Button11.2.4輸入框Entry11.2.5單選按鈕Radiobutton 復選按鈕Checkbutton11.2.6列表框Listbox
滾動條Scrollbar11.2.7畫布11.2.8標準對話框1011.2Tkinter的主要組件
Tkinter是標準的PythonGUI庫,它可以幫助用戶快速而容易地完成一個GUI應用程序的開發。使用Tkinter庫創建一個GUI程序只需要以下幾個步驟。(1)導入Tkinter模塊。(2)創建GUI應用程序的主窗口(頂層窗口)。(3)添加完成程序功能所需要的組件。(4)編寫回調函數。(5)進入主事件循環,對用戶觸發的事件做出響應。1
#coding:utf-823
import
tkinter
#導入tkinker模塊45
top=tkinter.Tk()
#創建應用程序主窗口6
top.title("主窗口")7
top.mainloop()
#進入事件主循環1111.2Tkinter的主要組件
11.2.1標簽Label1
#coding:utf-823
from
tkinter
import*45
top=Tk()6
top.title("主窗口")7
label=Label(top,text="HelloWorld,\nfromTkinter")
#創建標簽組件8
label.pack()
#將組件顯示出來9
top.mainloop()
#進入事件主循環text只是Label的一個屬性,如同其他組件一樣,Label還提供了很多設置,可以改變其外觀或行為,具體細節可以參考Python開發者文檔。1211.2Tkinter的主要組件
11.2.1標簽Label1
#coding:utf-821
from
tkinter
import*23
top=Tk()4
top.title("主窗口")5
for
relief_setting
in["raised","flat","groove","ridge","solid","sunken"]:6
frame=Frame(top,borderwidth=2,relief=relief_setting)#定義框架7
Label(frame,text=relief_setting,width=10).pack()8
#顯示框架,并設定向左排列,左右、上下間隔距離均為5像素9
frame.pack(side=LEFT,padx=5,pady=5)10
top.mainloop()
#進入事件主循環框架(Frame)是其他組件的一個容器,通常是用來包含一組控件的主體。用戶可以定制框架的外觀,我們可以通過這一列并排的框架看到不同樣式的區別。其中,為了顯示浮雕模式的效果,必須將寬度borderwidth設置為大于2的值。11.2.3按鈕Button1311.2Tkinter的主要組件
1
#coding:utf-823
from
tkinter
import*45
top=Tk()6
top.title("主窗口")7
bt1=Button(top,text="禁用",state=DISABLED)
#將按鈕設置為禁用狀態8
bt2=Button(top,text="退出",command=top.quit)
#設置回調函數9
bt1.pack(side=LEFT)10
bt2.pack(side=LEFT)11
top.mainloop()
#進入事件主循環
其中,可以明顯地看出“禁用”按鈕是灰色的,并且單擊該按鈕不會有任何反應;“退出”按鈕被綁定了回調函數top.quit,當單擊該按鈕后,主窗口會從主事件循環mainloop中退出按鈕(Button)是接收用戶鼠標點擊事件的組件。用戶可以使用按鈕的command屬性為每個按鈕綁定一個回調程序,用于處理按鈕點擊時的事件響應。同時,用戶也可以通過其state屬性禁用一個按鈕的點擊行為。11.2.4輸入框Entry1411.2Tkinter的主要組件
輸入框(Entry)是用來接收用戶文本輸入的組件。1
#coding:utf-823
from
tkinter
import*45
top=Tk()6
top.title("登錄")7
#第一行框架8
f1=Frame(top)9
Label(f1,text="用戶名").pack(side=LEFT)10
E1=Entry(f1,width=30)11
E1.pack(side=LEFT)12
f1.pack()13
#第二行框架14
f2=Frame(top)15
Label(f2,text="密
碼").pack(side=LEFT)16
E2=Entry(f2,width=30)17
E2.pack(side=LEFT)18
f2.pack()19
#第三行框架20
f3=Frame(top)21
Button(f3,text="登錄").pack()22
f3.pack()23
top.mainloop()
在前兩個框架組件中,分別加入了標簽和輸入框組件,提示并接收用戶輸入。在最后一個框架組件中,加入了登錄按鈕。
與按鈕相同,用戶可以通過使用將state屬性設置為DISABLED的方式禁用輸入框,以禁止用戶輸入或修改輸入框中的內容,11.2.5單選按鈕Radiobutton復選按鈕Checkbutton1511.2Tkinter的主要組件
單選按鈕(Radiobutton)提供給用戶進行選擇輸入的組件。是排他性選擇,即用戶只能選取一組選項中的一個選項;當創建一組單選按鈕時,必須將這一組單選按鈕與一個相同的變量關聯起來,以設定或獲得單選按鈕組當前的選中狀態;同樣,這種按鈕也可以通過其state屬性被設置為禁用。1
#coding:utf-823
from
tkinter
import*45
top=Tk()6
top.title("單選")7
f1=Frame(top)8
choice=IntVar(f1)
#定義動態綁定變量9
for
txt,val
in[('1',1),('2',2),('3',3)]:10
#將所有的選項與變量choice綁定起來11
r=Radiobutton(f1,text=txt,value=val,variable=choice)12
r.pack()1314
choice.set(1)
#設定默認選項15
Label(f1,text="您選擇了:").pack()16
Label(f1,textvariable=choice).pack()
#將標簽與變量動態綁定起來17
f1.pack()18
top.mainloop()
11.2.5單選按鈕Radiobutton復選按鈕Checkbutton1611.2Tkinter的主要組件
復選按鈕(Checkbutton)是提供給用戶進行選擇輸入的組件??梢灾С钟脩暨x擇多個選項。當創建一個復選按鈕時,需要將每一個選項與一個不同的變量關聯起來,以表示每個選項的選中狀態。同樣,這種按鈕也可以通過其state屬性被設置為禁用。1
#coding:utf-823
from
tkinter
import*45
top=Tk()6
top.title("多選")7
f1=Frame(top)8
choice={}
#存放綁定變量的字典9
cstr=StringVar(f1)10
cstr.set("")1112
def
update_cstr():13
#被選中選項的列表14
selected=[str(i)for
i
in[1,2,3]if
choice[i].get()==1]15
#設置動態字符串cstr,用逗號連接選中的選項16
cstr.set(",".join(selected))1718
for
txt,val
in[('1',1),('2',2),('3',3)]:19
ch=IntVar(f1)
#建立與每個選項綁定的變量20
choice[val]=ch
#將綁定的變量加入字典choice21
r=Checkbutton(f1,text=txt,variable=ch,command=update_cstr)22
r.pack()2324
Label(f1,text="您選擇了:").pack()25
Label(f1,textvariable=cstr).pack()
#將標簽與變量字符串cstr綁定起來26
f1.pack()27
top.mainloop()
1711.2Tkinter的主要組件
11.2.6列表框Listbox
滾動條Scrollbar
列表框(Listbox)會用列表的形式展示多個選項以供用戶選擇。同時,在某些情況下這個列表會比較長,所以可以為列表框添加一個滾動條(Scrollbar)以處理界面上無法顯示的情況。1
#coding:utf-823
from
tkinter
import*45
top=Tk()6
top.title("列表框")7
scrollbar=Scrollbar(top)
#創建滾動條8
scrollbar.pack(side=RIGHT,fill=Y)
#設置滾動條布局9
#將列表與滾動條綁定,并加入主窗體10
mylist=Listbox(top,yscrollcommand=scrollbar.set)11
for
line
in
range(20):12
mylist.insert(END,str(line))
#向列表尾部插入元素1314
mylist.pack(side=LEFT,fill=BOTH)
#設置列表布局15
scrollbar.config(command=mylist.yview)
#將滾動條行為與列表綁定1617
mainloop()
1811.2Tkinter的主要組件
11.2.7畫布我們可以使用create_rectangle、create_oval、create_arc、create_plolygon和create_line函數分別在畫布上繪制出矩形、橢圓、圓弧、多邊形或者線段。1
from
tkinter
import*2
3
4
class
CanvasDemo:5
def
__init__(self):6
window=Tk()7
window.title('CanvasDemo')
#設置標題8
9
#放置畫布10
self.canvas=Canvas(window,width=200,height=100,bg='white')11
self.canvas.pack()12
13
#放置按鈕14
frame=Frame(window)15
frame.pack()16
btRectangle=Button(frame,text='Rectangle',17
command=self.displayRect)18
btOval=Button(frame,text='Oval',19
command=self.displayOval)20
btArc=Button(frame,text='Arc',1911.2Tkinter的主要組件
11.2.7畫布21
command=self.displayArc)22
btPolygon=Button(frame,text='Polygon',23
command=self.displayPolygon)24
btLine=Button(frame,text='Line',25
command=self.displayLine)26
btString=Button(frame,text='String',27
command=self.displayString)28
btClear=Button(frame,text='Clear',29
command=self.clearCanvas)30
btRectangle.grid(row=1,column=1)31
btOval.grid(row=1,column=2)32
btArc.grid(row=1,column=3)33
btPolygon.grid(row=1,column=4)34
btLine.grid(row=1,column=5)35
btString.grid(row=1,column=6)36
btClear.grid(row=1,column=7)37
38
window.mainloop()
#進入主循環39
2011.2Tkinter的主要組件
11.2.7畫布40
#顯示矩形41
def
displayRect(self):42
self.canvas.create_rectangle(10,10,190,90,43
tags='rect')44
45
#顯示橢圓46
def
displayOval(self):47
self.canvas.create_oval(10,10,190,90,48
fill='red',tags='oval')49
50
#顯示圓弧51
def
displayArc(self):52
self.canvas.create_arc(10,10,190,90,53
start=0,extent=90,width=8,fill='red',tags='arc')54
55
#顯示多邊形56
def
displayPolygon(self):57
self.canvas.create_polygon(10,10,190,90,30,50,58
tags='polygon')59
2111.2Tkinter的主要組件
11.2.7畫布60
#顯示線段61
def
displayLine(self):62
self.canvas.create_line(10,10,190,90,63
fill='red',tags='line')64
self.canvas.create_line(10,90,190,10,width=9,65
arrow='last',activefill='red',tags='line')66
67
#顯示字符串68
def
displayString(self):69
self.canvas.create_text(60,40,text='Hi,Canvas',70
font="Times10boldunderline",tags='string')、7172
#清空畫布73
def
clearCanvas(self):74
self.canvas.delete('rect','oval','arc','polygon','line',
'string')75
76
CanvasDemo()11.2.8標準對話框2211.2Tkinter的主要組件
1
from
tkinter
import
messagebox
2
from
tkinter
import
simpledialog3
4
#普通信息對話框5
messagebox.showinfo("showinfo","Thisisaninfomessage.")6
#警告對話框7
messagebox.showwarning("showwarning","Thisisawarning.")8
#錯誤對話框9
messagebox.showerror("showerror","Thisisanerror.")10
#是否對話框11
isYes=messagebox.askyesno("askyesno"<"Continue?")12
print(isYes)13
#OK/取消對話框14
isOK=messagebox.askokcancel("askokcancle","OK?")15
print(isOK)16
#Yes/No/取消對話框17
isYesNoCancle=messagebox.askyesnocancel("askyesnocancel",18
"Yes,No,Cancle?")19
print(isYesNoCancle)20
#填寫信息對話框21
name=simpledialog.askstring("asksttring","Enteryouname")22
print(name)
11.2.8標準對話框2311.2Tkinter的主要組件
程序調用showinfo、showwarning和showerror函數來顯示一條消息(第5行)、一個警告(第7行)和一個錯誤(第9行)。這些函數都被定義在messagebox模塊中。askyesno函數在對話框中顯示“是”和“否”按鈕(第11行)。如果單擊“是”則函數返回True;如果單擊“否”則函數將返回False。askokcancle函數在對話框中顯示“確定”和“取消”按鈕,(第14行)。如果單擊“確定”按鈕,則函數返回True;如果單擊“取消”按鈕,則函數返回False。askyesnocancle函數(第17-18行)在對話框中顯示“是”、“否”和“取消”按鈕。如果單擊“是”按鈕,則函數返回True;如果單擊“否”按鈕,則函數返回False;而如果單擊“取消”按鈕,則函數返回None。askstring函數(第21行)會在單擊對話框中的“確定”按鈕時返回對話框中輸入的字符串。而單擊“取消”按鈕時返回None。更多的組件及細節可以參考Python的官方文檔。11.2Tkinter實例:三連棋游戲2511.3實例:三連棋游戲
11.3.1用戶界面設計11.3.2創建菜單11.3.3創建游戲面板11.3.4用戶界面與游戲的鏈接11.3.1用戶界面設計2611.3Tkinter實例:三連棋游戲
創建一個GUI之前,首先要給出一個設計草圖,指明在界面中應該添加哪些組件以及如何排列這些組件。在三連棋游戲中,應該有一個菜單欄和一個游戲面板。菜單欄中包括“文件”和“幫助”兩個下拉菜單,前者包含“新游戲”、“恢復”、“保存”和“退出”菜單項,而后者包含“幫助”和“關于”菜單項。游戲面板主要包含由9個按鈕構成的3×3棋盤和一個置于窗口底端的狀態欄。其布局方式如圖11-11所示。2711.3Tkinter實例:三連棋游戲
11.3.2創建菜單為了創建一個菜單,需要做以下操作。(1)創建一個頂層菜單對象。(2)創建下拉菜單對象。(3)利用子菜單的add_command方法添
加菜單項,并綁定回調函數。(4)利用頂層菜單的add_cascade方法將
下拉菜單添加到頂層菜單中。
(5)將頂層菜單對象與主窗口綁定。1
#coding:utf-823
import
tkinter
as
tk4
importmessageboxas
mb
#導入消息框56
top=tk.Tk()789
def
buildMenu(parent):10
menus=(11
("文件",(("新游戲",evNew),12
("恢復",evResume),13
("保存",evSave),14
("退出",evExit))),15
("幫助",(("幫助",evHelp),16
("關于",evAbout)))17
)18
#建立頂層菜單對象19
menubar=tk.Menu(parent)20
for
menu
in
menus:21
#建立子菜單對象22
m=tk.Menu(parent)23
for
item
in
menu[1]:24
#向子菜單中添加菜單項2811.3Tkinter實例:三連棋游戲
11.3.2創建菜單24
#向子菜單中添加菜單項25
m.add_command(label=item[0],command=item[1])26
#向頂層菜單中添加子菜單(“文件”和“幫助”)27
menubar.add_cascade(label=menu[0],menu=m)28
returnmenubar2930
def
dummy():31
mb.showinfo("Dummy","Eventtobedone")3233
evNew=dummy34
evResume=dummy35
evSave=dummy36
evExit=top.quit37
evHelp=dummy38
evAbout=dummy39
#創建菜單40
mbar=buildMenu(top)41
#將菜單與主窗口綁定42
top["menu"]=mbar43
tk.mainloop()
在上面的代碼中,首先將菜單結構定義在一個嵌套元組menus中,然后使用循環的方式將菜單項加入子菜單,以及將子菜單加入頂層菜單,這種方式可以為用戶避免大量重復代碼的輸入。需要說明的是,在本小節中并沒有實現菜單項的具體功能,除“退出”以外的菜單項都只與一個測試函數dummy綁定,11.3.3創建游戲面板2911.3Tkinter實例:三連棋游戲
首先應創建一個框架來作為游戲面板的容器,隨后在該框架中依次構建由九個按鈕組成的棋盤和一個標簽充當的狀態欄。同樣,在本節中,只創建游戲面板的界面,而界面中按鈕的功能并沒有被實現,它們的點擊事件與一個測試函數evClick綁定。8
def
evClick(row,col):9
mb.showinfo("單元格","被點擊的單元格:行:{},列:{}".format(row,col))11
def
buildBoard(parent):12
outer=tk.Frame(parent,border=2,relief="sunken")13
inner=tk.Frame(outer)14
inner.pack()15
#創建棋盤上的按鈕(棋子)16
for
row
in
range(3):17
for
col
in
range(3):18
cell=tk.Button(inner,text="",width="5",height="2",19
command=lambda
r=row,c=col:evClick(r,c))20
cell.grid(row=row,column=col)21
return
outer2223
#創建棋盤24
board=buildBoard(top)25
board.pack()26
#創建狀態欄27
status=tk.Label(top,text="測試",border=0,28
background="lightgrey",foreground="red")29
status.pack(anchor="s",fill="x",expand=True)30
tk.mainloop()
11.3.3創建游戲面板3011.3Tkinter實例:三連棋游戲
11.3.4用戶界面與游戲的鏈接3111.3Tkinter實例:三連棋游戲
由于采取了MVC的設計模式,可以將邏輯層(游戲功能)和表示層(用戶界面)的開發過程分開,因此在前面的兩個小節中,只構建了用戶界面,而沒有實現任何功能。在本小節中,將先給出游戲功能的實現,隨后重點介紹如何將游戲功能與用戶界面連接起來,構成一個完整的GUI程序。11.3.4用戶界面與游戲的鏈接數據交互部分3211.3Tkinter實例:三連棋游戲
1
#coding:utf-823
import
os.path45
game_file="oxogame.dat"67
#獲取文件路徑以保存和讀取游戲8
def
_getPath():9
try:10
game_path=os.environ['HOMEPATH']or
os.environ['HOME']11
if
not
os.path.exists(game_path):12
game_path=os.getcwd()13
except(KeyError,TypeError):14
game_path=os.getcwd()15
return
game_path1617
#將游戲保存到文件中18
def
saveGame(game):19
path=os.path.join(_getPath(),game_file)20
try:21
with
open(path,'w')asgf:22
gamestr=''.join(game)23
gf.write(gamestr)24
except
FileNotFoundError:25
print("Failedtosavefile")2627
#從文件中恢復游戲對象28
def
restoreGame():29
path=os.path.join(_getPath(),game_file)30
with
open(path)asgf:31
gamestr=gf.read()32
return
list(gamestr)11.3.4用戶界面與游戲的鏈接游戲邏輯部分3311.3Tkinter實例:三連棋游戲
1
#coding:utf-823
import
random4
importoxo_data567
#返回一個新游戲8
def
newGame():9
return
list(""*9)1011
#存儲游戲12
def
saveGame(game):13
'savegametodisk'14
oxo_data.saveGame(game)1516
#恢復存檔游戲,若沒有存檔則返回新游戲17
def
restoreGame():18
try:19
game=oxo_data.restoreGame()20
if
len(game)==9:21
returngame22
else:23
returnnewGame()24
except
IOError:25
returnnewGame()27
#隨機返回一個空的可用棋盤位置,若棋盤已滿則返回-128
def
_generateMove(game):29
options=[i
for
i
in
range(len(game))ifgame[i]==""]30
if
options:31
returnrandom.choice(options)32
else:33
return-13435
#判斷玩家是否勝利36
def
_isWinningMove(game):37
wins=((0,1,2),(3,4,5),(6,7,8),38
(0,3,6),(1,4,7),(2,5,8),39
(0,4,8),(2,4,6))40
fora,b,cinwins:41
chars=game[a]+game[b]+game[c]42
ifchars=='XXX'
orchars=='OOO':43
return
True44
return
False11.3.4用戶界面與游戲的鏈接游戲邏輯部分3411.3Tkinter實例:三連棋游戲
46
def
userMove(game,cell):47
ifgame[cell]!='':48
raise
ValueError('Invalidcell')49
else:50
game[cell]='X'51
if_isWinningMove(game):52
return
'X'53
else:54
return
""5556
def
computerMove(game):57
cell=_generateMove(game)58
ifcell==-1:59
return
'D'60
game[cell]='O'61
if_isWinningMove(game):62
return
'O'63
else:64
return
""11.3.4用戶界面與游戲的鏈接游戲邏輯與實際功能鏈接3511.3Tkinter實例:三連棋游戲
在游戲功能部分開發完成之后,需要將用戶界面與實際功能連接起來。在此游戲中,主要是通過編寫綁定在棋盤按鈕上的evClick函數實現的。此外,還有一些瑣碎的工作沒有做,如菜單事件處理程序的填充、狀態欄內容的更新等。11.3.4用戶界面與游戲的鏈接游戲邏輯與實際功能鏈接3611.3Tkinter實例:三連棋游戲
新游戲事件27
#新游戲事件28
def
evNew():29
status['text']="游戲中"30
game2cells(oxo_logic.newGame())恢復游戲事件32
#恢復游戲事件33
def
evResume():34
status['text']="游戲中"35
game=oxo_logic.restoreGame()36
game2cells(game)存儲游戲事件38
#存儲游戲事件39
def
evSave():40
game=cells2game()41
oxo_logic.saveGame(game)退出游戲事件43
#退出游戲事件44
def
evExit():45
ifstatus['text']=="游戲中":46
ifmb.askyesno("退出","是否想在退出前保存?"):47
evSave()48
top.quit()
幫助事件51
def
evHelp():52
mb.showinfo("幫助",'''53
文件->新游戲:
開始一局新游戲54
文件->恢復:恢復上次保存的游戲55
文件->保存:保存現在的游戲56
文件->退出:退出游戲57
幫助->幫助:幫助58
幫助->關于:展示作者信息''')11.3.4用戶界面與游戲的鏈接游戲邏輯與實際功能鏈接3711.3Tkinter實例:三連棋游戲
關于事件60
#關于事件61
def
evAbout():62
mb.showinfo("關于","由ztypl開發的GUI演示程序")點擊事件64
#點擊事件65
def
evClick(row,col):66
ifstatus['text']=="游戲結束":67
mb.showerror("游戲結束","游戲結束!")68
return69
game=cells2game()70
index=(3*row)+col71
result=oxo_logic.userMove(game,index)72
game2cells(game)7374
if
notresult:75
result=oxo_puterMove(game)76
game2cells(game)77
ifresult=="D":78
mb.showinfo("結果","平局!")79
status['text']="游戲結束!"80
else
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
評論
0/150
提交評論