最近無所事事,前天老師讓我寫一個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了。
哇,終於解決了我的疑問。我一直覺得是玄學問題。