让人又爱又恨的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了。
哇,终于解决了我的疑问。我一直觉得是玄学问题。

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