前言
之前寫過一個關于Python 使用easyUI創建桌面小應用的博客,雖然easyUI很實用,但是安裝方面確實存在一些小小的問題。那么好吧,這次就嘗試著使用自帶的Tkinter好了。
另外不得不說的是,Windows環境下寫界面還是用C++或者C#的好,天生自帶優勢,界面也更加美觀。
基礎知識點
下面就一些基礎的空間簡要的描述一下,以及它們的簡單應用。
前導篇
要想寫界面,就得有個載體不是。這就好比說我們要蓋個房子,光有磚頭,瓦塊,木材是肯定不行的。我們還需要一個框架,一個承載這些組件的"平臺"。
在Tkinter中,同樣如此。而且創建這么一個“框架”也很簡單,如下代碼。
from tkinter import *
# 需要注意的是Python2.X中應該這么寫
# from Tkinter import *
platform = Tk()
platform.title('標題部分')
platform.mainloop()
運行一下,結果圖如下
Button篇
按鈕對于一個桌面應用來說是最最常見,也必不可少的一塊“磚頭”了。但是在寫界面的時候,我們沒有見過單獨一個按鈕就可以跑起來的吧。就好比磚頭需要蓋在房子里。所以button需要依附于一個框架,也就是剛才的platform。
源碼中是這樣解釋的。
"""Button widget."""
def __init__(self, master=None, cnf={}, **kw):
"""Construct a button widget with the parent MASTER.
STANDARD OPTIONS
activebackground, activeforeground, anchor,
background, bitmap, borderwidth, cursor,
disabledforeground, font, foreground
highlightbackground, highlightcolor,
highlightthickness, image, justify,
padx, pady, relief, repeatdelay,
repeatinterval, takefocus, text,
textvariable, underline, wraplength
WIDGET-SPECIFIC OPTIONS
command, compound, default, height,
overrelief, state, width
"""
也就是說button需要有一個parent控件。那么下面我們來看下代碼。
from tkinter import *
platform = Tk()
platform.title('標題部分')
Button(platform, text='我是一個按鈕').pack()
platform.mainloop()
如下
需要注意的是Button(platform, text='我是一個按鈕').pack()
這行代碼的pack方法,其作用是將按鈕“夯”進platform,讓它能顯示出來。不然的話,磚頭始終是磚頭,成不了房子的一部分。如果沒有這個方法的話,組件是不會顯示的。pack方法可以傳入slide參數來指定其靠齊方式。如side=LEFT啥的。
button組件除了
- text(按鈕上顯示的文本)
- width(寬度)
- height(按鈕的高度)
- compound(依附方位)
等之外。還有一個比較重要的屬性,那就是command。這就是響應按鈕被點擊的時候的回調函數。說白了就是 點擊按鈕之后會觸發什么響應事件。下面我們來看個小小的例子。
這樣就可以啦。也許你會想,為啥callback沒有參數啊,我想在點擊按鈕的時候傳一個參數來改變一些行為怎么辦呢?
關于這塊,我也查看了一下官方文檔,發現確實沒有相關的api可以被直接的調用。但是有下面這種間接的方式實現。
from tkinter import *
def callback():
global button
print('按鈕被點擊了!')
# 動態修改按鈕的屬性
button['text'] = '修改后的按鈕文本'
button['width']=28
button['height'] = 16
button['compound'] = 'center'
# 甚至還可以動態修改按鈕綁定的回調處理函數
button['command'] = callback2
def callback2():
print('動態修改按鈕的回調函數!')
platform = Tk()
platform.title('標題部分')
button = Button(platform, text='我是一個按鈕', command=callback)
button.pack()
platform.mainloop()
結果如下
Label篇
標簽,同樣是很簡單的一個控件。使用方法和button控件一致。
更多屬性設置可以參考官方文檔,或者直接點進去源碼查看。
Entry篇
沒有輸入控件的界面是不完整的界面,下面淺談一下entry控件的基本使用。
from tkinter import *
platform = Tk()
platform.title('標題部分')
Label(platform, text='Username:').pack(side=LEFT)
Entry(platform, bg='black', fg='white', width=12).pack(side=LEFT)
platform.mainloop()
結果如下:
關于這個輸入控件常用的方法有這么幾個:
- get() 獲取當前這個空間的字符內容。
- select_clear() 清空當前被選擇的輸入控件的內容,如果當前輸入控件沒有獲得鼠標焦點,則不會有什么影響。
- ... ...
其他控件
其他的控件的使用方式都是類似的,學會了前幾個,相信對于后面的也不是什么難事了。
有興趣的話可以參考官方的幫助文檔。
https://docs.python.org/2/library/tkinter.html
事件篇
下面介紹一下關于界面的事件處理篇。因為我在一開始使用的時候沒能成功,也是從各處搜索才找到答案。因此介紹一下,也為了讓更多的人少走彎路。
我自己的理解是Tkinter把關于界面的所有的事件都封裝成了一個對象,我們可以方便的從這個對象中獲取到已經發生的事件,然后只需要針對不同的事件作出相應的處理即可。
這里簡單的介紹一下對于鍵盤事件的處理吧。
一般來說只需要一個下面一個方法:
bind_all(哪個鍵, 對應的處理函數)
下面針對一個小例子進行講解。
from tkinter import *
root = Tk()
root.title("窗口測試")
def eventhandler(event):
if event.keysym == 'Left':
print('按下了方向鍵左鍵')
elif event.keysym == 'Right':
print('按下了方向鍵右鍵!')
btn = Button(root, text='button')
btn.bind_all('<KeyPress>', eventhandler)
btn.pack()
root.mainloop()
運行的時候我們按下鍵盤上的方向鍵左鍵,就會打印對應的處理內容。右鍵類似。
按下了方向鍵右鍵!
按下了方向鍵左鍵
按下了方向鍵左鍵
按下了方向鍵右鍵!
按下了方向鍵左鍵
按下了方向鍵右鍵!
按下了方向鍵右鍵!
按下了方向鍵右鍵!
按下了方向鍵右鍵!
按下了方向鍵左鍵
按下了方向鍵左鍵
按下了方向鍵左鍵
關于bind_all方法,第一個參數對應的內容很多。我在這里盡可能把常用的羅列一下,免得大家再去單獨搜索。
-
bind_all('<KeyPress-Up>', eventhandler)
鍵盤方向鍵上鍵 -
bind_all('<KeyPress-Down>', eventhandler)
鍵盤方向鍵下鍵 -
bind_all('<KeyPress-Left>', eventhandler)
鍵盤方向鍵左鍵 -
bind_all('<KeyPress-Right>', eventhandler)
鍵盤方向鍵右鍵 -
bind_all('<KeyPress>', eventhandler)
鍵盤鍵位通用處理 -
bind_all('<Enter>', eventhandler)
按下Enter鍵 -
bind_all('a', eventhandler)
鍵盤小寫字母a -
bind_all('A', eventhandler)
鍵盤大寫字母A -
bind_all('<Control-A>', eventhandler)
Control+shift+a -
bind_all('<Control-a>', eventhandler)
Control+a -
bind_all('<Control-Alt-b>', eventhandler)
Control+Alt+b
相似的,Tkinter支持下面這些按鍵。但是需要知道的是不支持
Control—Alt
Cancel/Break/BackSpace/Tab/Return/Sift_L/Shift_R/Control_L/Control_R/Alt_L/Alt_R/Pause
Caps_Loack/Escape/Prior(Page Up)/Next(Page Down)/End/Home/Left/Up/Right/Down/Print/Insert/Delete/
F1-12/Num_Lock/Scroll_Lock
小應用
學完了上面的這些控件及其需要注意的地方,寫一個簡單的桌面小應用就足夠了。
下面以一個小例子來收尾,功能是爬取糗事百科上的段子信息。
# coding: utf8
# @Author: 郭 璞
# @File: Main.py
# @Time: 2017/4/21
# @Contact: 1064319632@qq.com
# @blog: http://blog.csdn.net/marksinoberg
# @Description: 糗事百科 帶界面版本
# 網絡操作相關
import requests
from bs4 import BeautifulSoup
# 創建一個接口,返回json串
import json
# 創建GUI使用
from tkinter import *
def show(url):
headers = {
'host':'www.qiushibaike.com',
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36"
}
response = requests.get(url=url, headers=headers)
soup = BeautifulSoup(response.text, 'html.parser')
response = None
containers = soup.find_all('div', {'class': 'article block untagged mb15'})
result = []
for container in containers:
# 'div', {'class': 'author clearfix'}
try:
# 對于非匿名用戶可正常獲取
username = container.find('div', {'class': 'author clearfix'}).find_all('a')[1].find('h2').get_text()
except:
# 對于匿名用戶,HTML標簽特殊處理
username = container.find('div', {'class': 'author clearfix'}).find_all('span')[1].get_text()
# print(username)
content = container.find('a', {'class': 'contentHerf'}).find('div', {'class': 'content'}).find('span').get_text()
# print(content)
try:
hotcommentuser = container.find('a', {'class': 'indexGodCmt'}).find('div', {'class': 'cmtMain'}).find('span', {'class': 'cmt-name'}).get_text()
hotcommentcontent = container.find('a', {'class': 'indexGodCmt'}).find('div', {'class': 'cmtMain'}).find('div', {'class': 'main-text'}).get_text()
# 去除大塊大塊的空格,盡量去掉換行標記。
hotcomment = str(hotcommentuser).strip(' ').strip('\n').strip('\r') + str(hotcommentcontent).strip(' ').strip('\n').strip('\r')
except:
# 奇奇怪怪的問題。
hotcomment = "熱評人: 無, 熱評內容: 無"
# 封裝糗事及評論
item = {
'username': username,
'content': content,
'hotcomment': hotcomment
}
result.append(item)
# 以列表的形式返回數據,以備調用
return result
def main(page=3, outputpath='./qiubai.txt'):
"""
想要獲取幾頁的數據啊
:param page:
:return:
"""
total = []
for index in range(page):
url = 'http://www.qiushibaike.com/8hr/page/{}/'.format(index+1)
result = show(url=url)
total.extend(result)
# 待會可以刪除,轉為json格式罷了
total = json.dumps(total)
# 寫入一個文件待用
with open(outputpath, 'a', encoding='utf8') as f:
for item in total:
f.write(str(item)+"\n")
f.close()
print('糗事百科笑話全部入庫,詳情請查看{}文件'.format(outputpath))
def getdata(page=3):
"""
實時獲取糗事百科段子,默認頁數為3,可進行外部控制。但是范圍是1-35.
:param page:
:return:
"""
if page <1 or page > 35:
raise Exception('您輸入的頁碼超過了官網限制!請保持在1-35之間!')
else:
total = []
for index in range(page):
url = 'http://www.qiushibaike.com/8hr/page/{}/'.format(index + 1)
result = show(url=url)
total.extend(result)
# 返回獲取到的段子字典,以供外部調用!
return total
def ui(title="糗事百科段子--桌面版"):
global label
root = Tk()
root.title(title)
label = Label(root, text="系統正在努力為您拉取段子\n請稍后... ...", height=36, compound='center')
label['text'] = "軟件使用方法:\n- 按方向鍵←或者↑查看上一條段子\n- 按方向鍵↓或者→查看下一條段子。\n系統正在努力為您拉取段子\n請稍后... ..."
label.pack()
root.bind_all('<KeyPress>', eventhandler)
root.mainloop()
def eventhandler(event):
global index
total = getdata(page=3)
index = (index+len(total))%len(total)
if event.keysym == 'Up' or event.keysym == "Left":
index -= 1
print('前一個')
elif event.keysym == 'Down' or event.keysym == 'Right':
index += 1
print('下一個')
content = "發帖人:\t{}\n".format(total[index]['username'])+"\n\t{}\n".format(total[index]['content'])+"熱評:{}\n".format(total[index]['hotcomment'])
label['text'] = content
if __name__ == '__main__':
content = ""
index = 0
label = None
ui(title='我的糗事百科桌面版')
使用方式: 界面運行按下鍵盤的方向鍵即可操作。↑←代表查看上一個段子。↓→代表查看下一個段子。
運行效果如下面的GIF圖。 糗事百科簡易粗糙桌面版本。
總結
一般來說我們不會用Python來寫界面,但是為了以防萬一,了解一下還是不錯的。
這篇文章雖然算不上事無巨細,但是基本上看完之后就可以實戰自己的小桌面應用了。
那么今天就先到這吧。