讓人又愛又恨的tkinter之坑

最近無所事事,前天老師讓我寫一個python爬蟲軟件,可以自定義調一些參數,用來下載一些視頻。本來想着,爬蟲啊,多麼簡單的事情… 然後就爽快的答應了… 然後就發生了一些匪夷所思的事情。特此說明一下。

如果有同學對視頻爬蟲感興趣可以去B站看看本項目的研發心得:B站傳送門:如何自制一款視頻爬蟲下載器

一.tkinter簡介

tkinter作爲python自帶的UI庫,不得不說,寫一些(醜陋)的界面還是挺簡單的,當然不是說人家就寫不出好看的界面,大名鼎鼎的pyqt5還是可以的,相對而言,python寫一款小工具還是蠻不錯的,如果你試着用過java的swing編寫,那將是多麼令人乏味的一件事情呢?

二、tkinter的簡答使用

如果你想使用tkinter創建一個窗口,非常簡單,不羅嗦,看代碼:

import tkinter
window  = tkinter.Tk()
# 使主程序進入一個循環,用於監聽其他事件(鍵盤、鼠標)
window.mainloop()

對的就是這麼假單。有些同學說,不就一個窗口嗎,沒看出來有啥特點啊,你可能沒用用過java的swing寫過程序,雖然已經很過時了,但是其繁瑣的佈局設計,自定義佈局每次都要setLayout(null),你就會明白原來把一件事情實現的過程越來越簡單的感覺真好。
另外要注意的是,我們初始化控件的時候,一定要寫在mainloop()前面,因爲mainloop會使主線程陷入一個內部循環,無法執行後面的語句。

label控件的使用

import tkinter
window = tkinter.Tk()
select = tkinter.StringVar()
select.set("hello python")
label1 = tkinter.Label(window, text='hello world', font=('Arial', 12), bg='green', fg="white")
label1.place(x=40, y=100)
label2 = tkinter.Label(window, textvariable=select, font=('Arial', 12), bg='green', fg="white")
label2.place(x=40, y=200)
window.mainloop()

使用如上代碼,我們就可以看到如下內容啦。
這些參數都很簡單,就不一 一解釋了。這裏大家可能看到一個新的東西,也是帶我走向鑽牛角尖的地方。對了,就是textvariable。這個東西其實也沒什麼,用起來也很簡單,就相當於綁定一個變量到一個控件上,然後對這個變量set可以改變這個控件的值,如上面的代碼,select.set("hello python")設置的值同步更新到窗口。
在這裏插入圖片描述

三、下拉框的簡單使用

def gradesFunc():
    print(gradesSelect.get())
if __name__ == '__main__':
    window = tkinter.Tk()
    grades = tkinter.Label(window, text='年級:', font=('Arial', 12))
    grades.place(x=10, y=2)
    gradesSelect = ttk.Combobox(window)
    gradesSelect.pack()
    gradesSelect['value'] = ['一年級', '二年級', '三年級']
    gradesSelect.bind("<<ComboboxSelected>>", lambda event: gradesFunc())
	window.mainloop()

ps:效果圖
在這裏插入圖片描述
這個代碼中,我們製作了一個簡單的下拉框,同時爲下拉框綁定了一個事件,當我們選中任意一條數據時,該事件將被觸發。

四、列表框(listBox)

def listBoxMouseClick(event):
	# 輸出所有選中的下標值,類型爲元祖
    print(listBox.curselection())
if __name__ == '__main__':
 
    # 設置窗口大小
    width = 600
    height = 600
    window = tkinter.Tk()
    # 獲取屏幕尺寸以計算佈局參數,使窗口居屏幕中央
    screenwidth = window.winfo_screenwidth()
    screenheight = window.winfo_screenheight()
    alignstr = '%dx%d+%d+%d' % (width, height, (screenwidth - width ) /2, (screenheight - height ) /2)
    window.geometry(alignstr)
    listBox = tkinter.Listbox(window, selectmode=tkinter.MULTIPLE, width=80)
    listBox.place(x=20, y=20)
    listBox.insert(tkinter.END,'喜歡你沒道理')
    listBox.insert(tkinter.END, '不喜歡你更沒道理')
    listBox.bind('<<ListboxSelect>>', listBoxMouseClick)

    window.mainloop()

效果如下圖:

在這裏插入圖片描述
其中,我們給該列表框添加了點擊事件,也就是說,每次點擊數據條目時,都會觸發一個事件,達到我們想要的目的,比如說:我們想做一個功能,用來獲取 選中了幾條數據呢?這樣,添加個點擊事件恰到好處。直接使用len(listBox.curselection())即可。
這裏,再簡單說明下,其他可能用到的鼠標事件:

     <Button-1>  鼠標左鍵
     <Button-2>   鼠標中間鍵(滾輪)
     <Button-3>  鼠標右鍵
     <Double-Button-1>   雙擊鼠標左鍵
     <Double-Button-3>   雙擊鼠標右鍵
     <Triple-Button-1>   三擊鼠標左鍵
     <Triple-Button-3>   三擊鼠標右鍵

要用到哪個直接綁定就好了.
以下介紹一些比較常用的api:

#用來選中所有行數 
listBox.select_set(0, .size())
#取消選中所有行數
listBox.select_clear(0, size())
#獲取第1行數據
listBox.get(0)
#將數據插入第二行
listBox.insert(1'(●''●)'#數據從尾部插入
listBox.insert(Tkinter.END,'(●''●)')

好了,本次就介紹這麼幾個控件。看看我被坑的地方在哪呢

面臨的坑:

StringVar 何種情況會 失效?

import tkinter
def click():
    select = tkinter.StringVar()
    select.set("dd")
    label = tkinter.Label(l, textvariable=select, font=('Arial', 12), bg='green', fg="white")
    label.place(x=100, y=100)

    window = tkinter.Tk()
    window.title('new window')
    # 爲什麼 label取不到數據
    label2 = tkinter.Label(window, textvariable=select, font=('Arial', 12), bg='green', fg="white")
    label2.place(x=100, y=100)
    window.mainloop()
if __name__ == '__main__':
    l = tkinter.Tk()
    bt = tkinter.Button(l, text ="下載視頻", font=('Arial', 15),command = click)
    bt.place(x=50,y=50)
    l.mainloop()

我編寫項目的時候,遇到的問題,最後我抽象出來就是上面的形式,先創建一個窗口,按鈕點擊會再創建一個窗口,但是第二個窗口無法獲取select = tkinter.StringVar()變量設置的值,令我百思不得其解,我就是想知道爲什麼?但是我找遍了搜索引擎,沒有找到,抱着對學習有着一種認真研究的精神,我鑽牛角尖花費了一天多時間。
到最終,我終於 找到答案了,stackoverflow不愧是一個專業的地方。直接上圖吧:
在這裏插入圖片描述
大致意思就是說,StringVar不能同時使用兩個Tk(),只能同時可見於一個TK域中。獻上鍊接:StringVar失效問題
另外: 提供一種他們所說的解決方案,也就是 不要創建兩個TK窗口,創建一個即可,然後,再創建的窗口 通過Toplevel傳入主窗口即可.如:newWindow = tk.Toplevel(window)。注意:使用這種方案,生成的新窗口不必再使用mainloop了。
哇,終於解決了我的疑問。我一直覺得是玄學問題。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章