1.使用python制作GUI界面
Python支持多種圖形界面的第三方庫(kù)户侥,包括:
a.Tk
b.wxWidgets
c.Qt
d.GTK
等等。
但是Python自帶的庫(kù)是支持Tk的Tkinter池凄,使用Tkinter,無需安裝任何包屿附,就可以直接使用斑芜。本章簡(jiǎn)單介紹如何使用Tkinter進(jìn)行GUI編程。
Tkinter
我們來梳理一下概念:
我們編寫的Python代碼會(huì)調(diào)用內(nèi)置的Tkinter精绎,Tkinter封裝了訪問Tk的接口速缨;Tk是一個(gè)圖形庫(kù),支持多個(gè)操作系統(tǒng)代乃,使用Tcl語(yǔ)言開發(fā)旬牲;Tk會(huì)調(diào)用操作系統(tǒng)提供的本地GUI接口,完成最終的GUI搁吓。所以原茅,我們的代碼只需要調(diào)用Tkinter提供的接口就可以了。
第一個(gè)GUI程序
使用Tkinter十分簡(jiǎn)單堕仔,我們來編寫一個(gè)GUI版本的“Hello, world!”擂橘。第一步是導(dǎo)入Tkinter包的所有內(nèi)容:
from tkinter import *
第二步是從Frame派生一個(gè)Application類,這是所有Widget的父容器:
class Application(Frame):
def __init__(self, master=None):
Frame.__init__(self, master)
self.pack()
self.createWidgets()
def createWidgets(self):
self.helloLabel = Label(self, text='Hello, world!')
self.helloLabel.pack()
self.quitButton = Button(self, text='Quit', command=self.quit)
self.quitButton.pack()
在GUI中贮预,每個(gè)Button贝室、Label契讲、輸入框等,都是一個(gè)Widget滑频。Frame則是可以容納其他Widget的Widget捡偏,所有的Widget組合起來就是一棵樹。
pack()方法把Widget加入到父容器中峡迷,并實(shí)現(xiàn)布局银伟。pack()是最簡(jiǎn)單的布局,grid()可以實(shí)現(xiàn)更復(fù)雜的布局绘搞。在createWidgets()
方法中彤避,我們創(chuàng)建一個(gè)Label和一個(gè)Button,當(dāng)Button被點(diǎn)擊時(shí)夯辖,觸發(fā)self.quit()使程序退出琉预。
第三步,實(shí)例化Application蒿褂,并啟動(dòng)消息循環(huán):
app = Application()
# 設(shè)置窗口標(biāo)題:
app.master.title('Hello World')
# 主消息循環(huán):
app.mainloop()
運(yùn)行結(jié)果如下:
輸入文本
我們?cè)賹?duì)這個(gè)GUI程序改進(jìn)一下圆米,加入一個(gè)文本框,讓用戶可以輸入文本啄栓,然后點(diǎn)按鈕后娄帖,彈出消息對(duì)話框。
from tkinter import *
import tkinter.messagebox as messagebox
class Application(Frame):
def __init__(self, master=None):
Frame.__init__(self, master)
self.pack()
self.createWidgets()
def createWidgets(self):
self.nameInput = Entry(self)
self.nameInput.pack()
self.alertButton = Button(self, text='Hello', command=self.hello)
self.alertButton.pack()
def hello(self):
name = self.nameInput.get() or 'world'
messagebox.showinfo('Message', 'Hello, %s' % name)
app = Application()
# 設(shè)置窗口標(biāo)題:
app.master.title('Hello World')
# 主消息循環(huán):
app.mainloop()
當(dāng)用戶點(diǎn)擊按鈕時(shí)昙楚,觸發(fā)hello()近速,通過self.nameInput.get()獲得用戶輸入的文本后,使用tkMessageBox.showinfo()可以彈出消息對(duì)話框堪旧。
程序運(yùn)行結(jié)果如下:
2.使用基于TCP協(xié)議的socket
要?jiǎng)?chuàng)建一個(gè)基于TCP連接的Socket削葱,可以這樣做:
# 導(dǎo)入socket庫(kù):
import socket
# 創(chuàng)建一個(gè)socket:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 建立連接:
s.connect(('www.sina.com.cn', 80))
創(chuàng)建Socket時(shí),AF_INET
指定使用IPv4協(xié)議崎场,如果要用更先進(jìn)的IPv6佩耳,就指定為AF_INET6。SOCK_STREAM指定使用面向流的TCP協(xié)議谭跨,這樣干厚,一個(gè)Socket
對(duì)象就創(chuàng)建成功,但是還沒有建立連接螃宙÷椋客戶端要主動(dòng)發(fā)起TCP連接,必須知道服務(wù)器的IP地址和端口號(hào)谆扎。新浪網(wǎng)站的IP地址可以用域名www.sina.com.cn自動(dòng)轉(zhuǎn)換到IP地址挂捅,但是怎么知道新浪服務(wù)器的端口號(hào)呢?答案是作為服務(wù)器堂湖,提供什么樣的服務(wù)闲先,端口號(hào)就必須固定下來状土。由于我們想要訪問網(wǎng)頁(yè),因此新浪提供網(wǎng)頁(yè)服務(wù)的服務(wù)器必須把端口號(hào)固定在80
端口伺糠,因?yàn)?0端口是Web服務(wù)的標(biāo)準(zhǔn)端口蒙谓。其他服務(wù)都有對(duì)應(yīng)的標(biāo)準(zhǔn)端口號(hào),例如SMTP服務(wù)是25端口训桶,F(xiàn)TP服務(wù)是21端口累驮,等等。端口號(hào)小于1024的是Internet標(biāo)準(zhǔn)服務(wù)的端口舵揭,端口號(hào)大于1024的谤专,可以任意使用。
因此午绳,我們連接新浪服務(wù)器的代碼如下:
s.connect(('www.sina.com.cn', 80))
注意參數(shù)是一個(gè)tuple置侍,包含地址和端口號(hào)。建立TCP連接后拦焚,我們就可以向新浪服務(wù)器發(fā)送請(qǐng)求墅垮,要求返回首頁(yè)的內(nèi)容:
# 發(fā)送數(shù)據(jù):
s.send(b'GET / HTTP/1.1\r\nHost: www.sina.com.cn\r\nConnection: close\r\n\r\n')
TCP連接創(chuàng)建的是雙向通道,雙方都可以同時(shí)給對(duì)方發(fā)數(shù)據(jù)耕漱。但是誰(shuí)先發(fā)誰(shuí)后發(fā),怎么協(xié)調(diào)抬伺,要根據(jù)具體的協(xié)議來決定螟够。例如,HTTP協(xié)議規(guī)定客戶端必須先發(fā)請(qǐng)求給服務(wù)器峡钓,服務(wù)器收到后才發(fā)數(shù)據(jù)給客戶端妓笙。
發(fā)送的文本格式必須符合HTTP標(biāo)準(zhǔn),如果格式?jīng)]問題能岩,接下來就可以接收新浪服務(wù)器返回的數(shù)據(jù)了:
# 接收數(shù)據(jù):
buffer = []
while True:
# 每次最多接收1k字節(jié):
d = s.recv(1024)
if d:
buffer.append(d)
else:
break
data = b''.join(buffer)
接收數(shù)據(jù)時(shí)寞宫,調(diào)用recv(max)方法,一次最多接收指定的字節(jié)數(shù)拉鹃,因此辈赋,在一個(gè)while循環(huán)中反復(fù)接收,直到recv()返回空數(shù)據(jù)膏燕,表示接收完畢钥屈,退出循環(huán)。當(dāng)我們接收完數(shù)據(jù)后坝辫,調(diào)用close()方法關(guān)閉Socket篷就,這樣,一次完整的網(wǎng)絡(luò)通信就結(jié)束了:
# 關(guān)閉連接:
s.close()
接收到的數(shù)據(jù)包括HTTP頭和網(wǎng)頁(yè)本身近忙,我們只需要把HTTP頭和網(wǎng)頁(yè)分離一下竭业,把HTTP頭打印出來智润,網(wǎng)頁(yè)內(nèi)容保存到文件:
header, html = data.split(b'\r\n\r\n', 1)
print(header.decode('utf-8'))
# 把接收的數(shù)據(jù)寫入文件:
with open('sina.html', 'wb') as f:
f.write(html)
現(xiàn)在,只需要在瀏覽器中打開這個(gè)sina.html文件未辆,就可以看到新浪的首頁(yè)了窟绷。
3.使用sqlite3
SQLite是一種嵌入式數(shù)據(jù)庫(kù),它的數(shù)據(jù)庫(kù)就是一個(gè)文件鼎姐。由于SQLite本身是C寫的钾麸,而且體積很小,所以炕桨,經(jīng)常被集成到各種應(yīng)用程序中饭尝,甚至在iOS和Android的App中都可以集成。
Python就內(nèi)置了SQLite3献宫,所以钥平,在Python中使用SQLite,不需要安裝任何東西姊途,直接使用涉瘾。
在使用SQLite前,我們先要搞清楚幾個(gè)概念:
表是數(shù)據(jù)庫(kù)中存放關(guān)系數(shù)據(jù)的集合捷兰,一個(gè)數(shù)據(jù)庫(kù)里面通常都包含多個(gè)表立叛,比如學(xué)生的表,班級(jí)的表贡茅,學(xué)校的表秘蛇,等等。表和表之間通過外鍵關(guān)聯(lián)顶考。
要操作關(guān)系數(shù)據(jù)庫(kù)赁还,首先需要連接到數(shù)據(jù)庫(kù),一個(gè)數(shù)據(jù)庫(kù)連接稱為Connection驹沿;
連接到數(shù)據(jù)庫(kù)后艘策,需要打開游標(biāo),稱之為Cursor渊季,通過Cursor執(zhí)行SQL語(yǔ)句朋蔫,然后,獲得執(zhí)行結(jié)果梭域。
Python定義了一套操作數(shù)據(jù)庫(kù)的API接口斑举,任何數(shù)據(jù)庫(kù)要連接到Python,只需要提供符合Python標(biāo)準(zhǔn)的數(shù)據(jù)庫(kù)驅(qū)動(dòng)即可病涨。
由于SQLite的驅(qū)動(dòng)內(nèi)置在Python標(biāo)準(zhǔn)庫(kù)中富玷,所以我們可以直接來操作SQLite數(shù)據(jù)庫(kù)。
我們?cè)赑ython交互式命令行實(shí)踐一下:
# 導(dǎo)入SQLite驅(qū)動(dòng):
>>> import sqlite3
# 連接到SQLite數(shù)據(jù)庫(kù)# 數(shù)據(jù)庫(kù)文件是test.db
# 如果文件不存在,會(huì)自動(dòng)在當(dāng)前目錄創(chuàng)建:
>>> conn = sqlite3.connect('test.db')
# 創(chuàng)建一個(gè)Cursor:
>>> cursor = conn.cursor()
# 執(zhí)行一條SQL語(yǔ)句赎懦,創(chuàng)建user表:
>>> cursor.execute('create table user (id varchar(20) primary key, name varchar(20))')
<sqlite3.Cursor object at 0x10f8aa260>
# 繼續(xù)執(zhí)行一條SQL語(yǔ)句雀鹃,插入一條記錄:
>>> cursor.execute('insert into user (id, name) values (\'1\', \'Michael\')')
<sqlite3.Cursor object at 0x10f8aa260>
# 通過rowcount獲得插入的行數(shù):
>>> cursor.rowcount
1
# 關(guān)閉Cursor:
>>> cursor.close()
# 提交事務(wù):
>>> conn.commit()
# 關(guān)閉Connection:
>>> conn.close()
我們?cè)僭囋嚥樵冇涗洠?/p>
>>> conn = sqlite3.connect('test.db')
>>> cursor = conn.cursor()
# 執(zhí)行查詢語(yǔ)句:
>>> cursor.execute('select * from user where id=?', ('1',))
<sqlite3.Cursor object at 0x10f8aa340>
# 獲得查詢結(jié)果集:
>>> values = cursor.fetchall()
>>> values[('1', 'Michael')]
>>> cursor.close()
>>> conn.close()
使用Python的DB-API時(shí),只要搞清楚Connection和Cursor對(duì)象励两,打開后一定記得關(guān)閉黎茎,就可以放心地使用。使用Cursor對(duì)象執(zhí)行insert当悔,update傅瞻,delete語(yǔ)句時(shí),執(zhí)行結(jié)果由rowcount返回影響的行數(shù)盲憎,就可以拿到執(zhí)行結(jié)果嗅骄。使用Cursor對(duì)象執(zhí)行select語(yǔ)句時(shí),通過featchall()可以拿到結(jié)果集饼疙。結(jié)果集是一個(gè)list溺森,每個(gè)元素都是一個(gè)tuple,對(duì)應(yīng)一行記錄窑眯。
如果SQL語(yǔ)句帶有參數(shù)屏积,那么需要把參數(shù)按照位置傳遞給execute()
方法,有幾個(gè)?占位符就必須對(duì)應(yīng)幾個(gè)參數(shù)磅甩,例如:
cursor.execute('select * from user where name=? and pwd=?', ('abc', 'password'))
SQLite支持常見的標(biāo)準(zhǔn)SQL語(yǔ)句以及幾種常見的數(shù)據(jù)類型炊林。具體文檔請(qǐng)參閱SQLite官方網(wǎng)站。