赞
踩
一直想用python的 tkinter模块实现类似QT中信号和槽的功能,但是在网上没有找到合适的方法(也可能是自己没有找到)。尝试着将界面代码中的 self 作为参数传入功能代码中,最终实现了。本人使用python3.7.4, 32位版本。
为了展示tkinter进度条的实现,写了两个python文件,一个是UICode.py,该文件是UI界面代码。一个是WorkCode.py,该文件是功能代码。
代码中起主要作用的代码:
def run(self):
self.progressbarOne['value'] = 0
WorkCode.progressbar_func(self.num, self) # 需要将self作为参数传入,才可以实时更改UI实例中进度条的值
整体代码如下:
# -*- coding:utf-8 -*- import tkinter as tk import tkinter.ttk import WorkCode class GuiSample(object): def __init__(self): self.root = tk.Tk() # 设置GUI界面属性 self.root.title('tkinter 进度条测试') # 设置GUI标题 self.root.wm_attributes("-alpha", 1.0) # 设置GUI透明度(0.0~1.0) self.root.wm_attributes("-topmost", True) # 设置GUI置顶 # self.root.wm_attributes("-toolwindow", True) # 设置为工具窗口(没有放大和缩小按钮) # self.root.overrideredirect(-1) # 去除GUI边框(GUI标题、放大缩小和关闭按钮都会消失) # self.bind_window_move_events() # 如果去除GUI边框了,就要绑定窗口移动事件,否则GUI无法移动 self.width = 350 self.height = 150 ws = self.root.winfo_screenwidth() hs = self.root.winfo_screenheight() x = (ws / 2) - (self.width / 2) y = (hs / 2) - (self.height / 2) self.root.geometry('%dx%d+%d+%d' % (self.width, self.height, x, y)) # 设置类中的全局变量 self.num = 30 # 设置所有窗口部件 self.build_label() self.build_button() self.build_progressbarOne() # 执行所有窗口部件 self.label1.place(x=115, y=30, anchor=tk.W) self.progressbarOne.place(x=55, y=60, anchor=tk.W) self.test_button.place(x=155, y=100, anchor=tk.W) def run(self): self.progressbarOne['value'] = 0 WorkCode.progressbar_func(self.num, self) # 需要将self作为参数传入,才可以实时更改UI实例中进度条的值 def build_progressbarOne(self): self.progressbarOne = tk.ttk.Progressbar(self.root, length=240) # 进度值最大值 self.progressbarOne['maximum'] = 100 # 进度值初始值 self.progressbarOne['value'] = 0 def build_label(self): self.label1 = tk.Label(self.root, text="这是一个测试进度条") def build_button(self): self.test_button = tk.Button(self.root, text='开 始', command=self.run) if __name__ == '__main__': progressbarSample = GuiSample() progressbarSample.root.mainloop()
起到实时传递任务进度的代码:
def get_progress(num, leng, self): # 该函数起到实时更新进度条的作用,可以看做是一个信号函数
progressNum = 0
if leng != 0:
progressNum = num/leng
self.progressbarOne['value'] = progressNum * 100 # 在这里设置进度条的值
self.root.update()
整体代码如下:
import time
def progressbar_func(num, self): # 该函数是实际的功能函数,在该函数中调用get_progress(),实时显示任务进度
for i in range(0, num):
time.sleep(0.1)
get_progress(i, num-1, self)
def get_progress(num, leng, self): # 该函数起到实时更新进度条的作用,可以看做是一个信号函数
progressNum = 0
if leng != 0:
progressNum = num/leng
self.progressbarOne['value'] = progressNum * 100 # 在这里设置进度条的值
self.root.update() # 在这里更新进度条的值
要实现两个进度条相互不受影响,需要采用线程,每一个进度条是一个线程。还是两个python文件,一个是UICode.py,该文件是UI界面代码。一个是WorkCode.py,该文件是功能代码。
“self”参数传递过程:使用GuiSample类run函数开启线程,将“self”传入线程,在线程中调用功能代码时,“self”参数通过线程中的run函数传入功能代码。
GuiSample类run函数:
def run(self, barNum):
t = MyThread(self.num, self, barNum)
t.start()
线程中的run函数:
def run(self):
while self.__running.isSet():
self.__flag.wait() # 为True时立即返回, 为False时阻塞直到内部的标识位为True后返回
WorkCode.progressbar_func(self.num, self.handle, self.barNum)
self.stop()
def build_button(self):代码不能按照如下形式来写,因为“command=self.run(1)”会在没有点击按钮时直接调用调用run函数,需要通过lambda表达式调用run函数。
def build_button(self):
self.test_button = tk.Button(self.root, text='开 始', command=self.run(1))
self.test_button2 = tk.Button(self.root, text='开 始', command=self.run(2))
整体代码:
# -*- coding:utf-8 -*- import tkinter as tk import tkinter.ttk import WorkCode import threading class MyThread(threading.Thread): def __init__(self, num, handle, barNum): super().__init__() self.__flag = threading.Event() # 用于暂停线程的标识 self.__flag.set() # 设置为True self.__running = threading.Event() # 用于停止线程的标识 self.__running.set() # 将running设置为True self.num = num self.handle = handle self.barNum = barNum def run(self): while self.__running.isSet(): self.__flag.wait() # 为True时立即返回, 为False时阻塞直到内部的标识位为True后返回 WorkCode.progressbar_func(self.num, self.handle, self.barNum) self.stop() def pause(self): self.__flag.clear() # 设置为False, 让线程阻塞 def resume(self): self.__flag.set() # 设置为True, 让线程停止阻塞 def stop(self): self.__flag.set() # 将线程从暂停状态恢复, 如何已经暂停的话 self.__running.clear() # 设置为False class GuiSample(object): def __init__(self): super().__init__() self.root = tk.Tk() # 设置GUI界面属性 self.root.title('tkinter 进度条测试') # 设置GUI标题 self.root.wm_attributes("-alpha", 1.0) # 设置GUI透明度(0.0~1.0) self.root.wm_attributes("-topmost", True) # 设置GUI置顶 # self.root.wm_attributes("-toolwindow", True) # 设置为工具窗口(没有放大和缩小按钮) # self.root.overrideredirect(-1) # 去除GUI边框(GUI标题、放大缩小和关闭按钮都会消失) # self.bind_window_move_events() # 如果去除GUI边框了,就要绑定窗口移动事件,否则GUI无法移动 self.width = 350 self.height = 280 ws = self.root.winfo_screenwidth() hs = self.root.winfo_screenheight() x = (ws / 2) - (self.width / 2) y = (hs / 2) - (self.height / 2) self.root.geometry('%dx%d+%d+%d' % (self.width, self.height, x, y)) # 设置类中的全局变量 self.num = 30 self.barNum = 0 # 设置所有窗口部件 self.build_label() self.build_button() self.build_progressbarOne() # 执行所有窗口部件 self.label1.place(x=115, y=30, anchor=tk.W) self.progressbarOne.place(x=55, y=60, anchor=tk.W) self.test_button.place(x=155, y=100, anchor=tk.W) self.label2.place(x=115, y=160, anchor=tk.W) self.progressbarTwo.place(x=55, y=190, anchor=tk.W) self.test_button2.place(x=155, y=230, anchor=tk.W) def run(self, barNum): t = MyThread(self.num, self, barNum) t.start() def build_progressbarOne(self): self.progressbarOne = tk.ttk.Progressbar(self.root, length=240) # 进度值最大值 self.progressbarOne['maximum'] = 100 # 进度值初始值 self.progressbarOne['value'] = 0 self.progressbarTwo = tk.ttk.Progressbar(self.root, length=240) # 进度值最大值 self.progressbarTwo['maximum'] = 100 # 进度值初始值 self.progressbarTwo['value'] = 0 def build_label(self): self.label1 = tk.Label(self.root, text="这是第一个测试进度条") self.label2 = tk.Label(self.root, text="这是第二个测试进度条") def build_button(self): self.test_button = tk.Button(self.root, text='开 始', command=lambda :self.run(1)) self.test_button2 = tk.Button(self.root, text='开 始', command=lambda :self.run(2)) if __name__ == '__main__': progressbarSample = GuiSample() progressbarSample.root.mainloop()
import time def progressbar_func(num, handle,barNum): # 该函数是实际的功能函数,在该函数中调用get_progress(),实时显示任务进度 for i in range(0, num): time.sleep(0.1) get_progress(i, num-1, self, barNum) def get_progress(num, leng, self, barNum): # 该函数起到实时更新进度条的作用,可以看做是一个信号函数 progressNum = 0 if leng != 0: progressNum = num/leng if barNum == 1: self.progressbarOne['value'] = progressNum * 100 # 在这里设置进度条的值 if barNum == 2: self.progressbarTwo['value'] = progressNum * 100 # 在这里设置进度条的值 self.root.update() # 在这里更新进度条的值
在进度条没有完成进度之前,再次点击“开始”按钮,会出现显示不顺畅问题(如下动画所示),其实是两个进度重叠显示造成的。因为点击一次“开始”按钮,就会进行一次进度条的显示。代码没有能实现线程的暂停功能。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。