Tkinter小結 界面+快捷鍵設置

前言

之前寫過一個關于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效果圖

需要注意的是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()

結果如下:


Entry控件顯示效果

關于這個輸入控件常用的方法有這么幾個:

  • 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來寫界面,但是為了以防萬一,了解一下還是不錯的。

這篇文章雖然算不上事無巨細,但是基本上看完之后就可以實戰自己的小桌面應用了。

那么今天就先到這吧。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,565評論 6 539
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,115評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,577評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,514評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,234評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,621評論 1 326
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,641評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,822評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,380評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,128評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,319評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,879評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,548評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,970評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,229評論 1 291
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,048評論 3 397
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,285評論 2 376

推薦閱讀更多精彩內容