python3 Tkinter实现线程控制程序暂停、恢复和终止

Python3 tkinter中使用event.wait()让多线程暂停、恢复和终止

最近使用tkinter完成一个小工具,期间在百度搜索到很多用多线程event.wait()使程序暂停的demo,控制while死循环的暂停。这里分享一个实例,使用event.wait()实现 在tkinter中用按钮让一个耗时程序暂停、恢复和终止。

实现步骤:
1.导入相关库

import threading
import time
from mttkinter import mtTkinter as tk
import tkinter.messagebox  # 引入弹窗库,防止解释器弹出报错。

这里使用mttkinter代替,因为在tkinter中使用多线程会报错:

main thread is not in main loop

这是tkinter的问题,使用mttkinter代替就好

2.创建线程类

class MyThread(threading.Thread):
    def __init__(self, func, *args):
        # 线程初始化
        super().__init__(target=func, args=args)
        self.func = func
        self.args = args

        self.__flag = threading.Event()  # 用于暂停线程的标识
        self.__flag.set()  # 设置为True
        self.__running = threading.Event()  # 用于停止线程的标识
        self.__running.set()  # 将running设置为True

        # 开始执行
        self.thread_run()

    # 打包进线程(耗时的操作)防止tkinter单线程阻塞
    def thread_run(self):
        self.__flag.wait()  # 为True时立即返回, 为False时阻塞直到内部的标识位为True后返回
        self.setDaemon(True)    # 守护--就算主界面关闭,线程也会留守后台运行
        self.start()  # 在这里开始

    def pause(self):
        self.__flag.clear()  # 设置为False,让线程阻塞
        print('阻塞线程')

    def resume(self):
        self.__flag.set()  # 设置为True,让线程停止阻塞
        print('已恢复线程')

    def stop(self):
        self.__flag.set()  # 将线程从暂停状态恢复, 如何已经暂停的话
        self.__running.clear()  # 设置为False

这里定义了线程类,原理很简单,传入一个函数,使用Threading为函数创建线程,然后定义暂停,恢复,终止的函数,通过threading.Event()来实现

3.tkinter窗口和业务函数

class TkinterWindow:
    def __init__(self):
    	self.isRun = False  # 是否有线程正在执行
        self.myThread = None   # 正在执行的线程(MyThread类的对象)
        
	# 信息窗口
    def messagebox(self):
		def main_active(pay_type, act_type):
			try:
				...
				# 这里的函数需要请求多个接口,返回数据需要一定的时间
				self.user_login()
				# 在每个耗时操作的函数后加上如下代码
				self.myThread._MyThread__flag.wait()  # 为True时立即返回, 为False时阻塞直到内部的标识位为True后返回
				self.zf_adjust_search(paytype=1)
				self.myThread._MyThread__flag.wait()  # 为True时立即返回, 为False时阻塞直到内部的标识位为True后返回
				self.zjzfAdjust()  # 耗时函数
			except AttributeError:
				print("任务已终止")	# 捕获异常,当点击终止任务时,清空self.myThread,这时可以用作跳出循环
			# 判断是否已被中断(正常结束就关闭线程)
            if self.myThread:
                self.myThread.stop()
                self.myThread = None  # 执行结束后,关闭线程
                self.isRun = False
                self.ternimal_print('任务已结束', 'info')
                
        def thread_it(func, *args):
            # 开始线程
            if self.myThread:
                tkinter.messagebox.showinfo(title='提示', message='当前已存在执行的任务,请结束任务后再试')
            else:
                self.myThread = MyThread(func, *args)	# 用传入的业务函数实例化一个线程
                
		# 暂停或恢复
		def pause_resume():
			if self.myThread:   # 如果存在执行的任务
				# 暂停和恢复
	            if self.isRun:  # True表示正在运行
					if self.myThread._MyThread__flag.is_set():  # 如果为True表示在执行(返回False表示暂停)
						mess = tkinter.messagebox.askquestion(title='提示', message='确认要暂停任务?')
	                    if mess == 'no':
	                        print('Choose no!')
						else:
							print('choose yes')
	                        self.myThread.pause()
	                        self.isRun = False
	                        self.ternimal_print('暂停程序', 'warning')
	                        # 在label显示任务已暂停
	                        var1.set("任务已暂停")
					else:
						tkinter.messagebox.showinfo(title='提示', message='没有需要暂停的任务')
				else:
					self.myThread.resume()
	                self.isRun = True
	                # 在label显示任务恢复,并显示正在执行的任务
	                var1.set("恢复任务程序运行")
	                self.ternimal_print('恢复程序运行', 'warning')
			else:
				tkinter.messagebox.showinfo(title='提示', message='当前没有正在执行的任务')
		
		# 终止函数
		def stop():
			if self.myThread:  # 如果存在执行的任务
				mess = tkinter.messagebox.askquestion(title='提示', message='确认结束任务?')
				if mess == 'no':
					print('Choose no!')
	            else:
	                print('choose yes')
	                self.myThread.stop()    # 结束任务
	                self.isRun = False
	                self.myThread = None
	                self.ternimal_print('已结束任务', 'warning')
	                # 在label中显示已结束任务
	                var1.set("任务已终止")
			else:
	            tkinter.messagebox.showinfo(title='提示', message='当前没有正在执行的任务')

	window = tk.Tk()   # 生成主窗口,命名 window
    window.title('信息查看窗口')  # 定义主窗口标题
    window.geometry('800x600')  # 定义主窗口的长宽
	fm_btn = tk.Frame(window)   # 按钮
    fm_btn.pack()
	# 结束按钮
    tk.Button(fm_btn, text='结束任务', command=stop).pack(side='right', fill='y', expand='yes')
    # 暂停/恢复按钮
    tk.Button(fm_btn, text='暂停/恢复', command=pause_resume).pack(side='right', fill='y', expand='yes')
    # 按钮选择一项更正  耗时操作,使用线程
    tk.Button(fm_btn, text='更正当前选项', command=lambda: thread_it(main_active, 'zjzf', 'get')).pack(side='right', fill='y', expand='yes') # 定义一个按钮,用来后续触发弹窗
    # 按钮遍历更正全部
    tk.Button(fm_btn, text='更正所有项', command=lambda: thread_it(main_active, 'zjzf', 'loop')).pack(side='right', fill='y', expand='yes')
    # 按钮选择一项更正
    tk.Button(fm_btn, text='更正当前选项SQ', command=lambda: thread_it(main_active, 'sqzf', 'get')).pack(side='right', fill='y', expand='yes')  # 定义一个按钮,用来后续触发弹窗
    # 按钮遍历更正全部
    tk.Button(fm_btn, text='更正所有项SQ', command=lambda: thread_it(main_active, 'sqzf', 'loop')).pack(side='right', fill='y', expand='yes')
	
	# 三个耗时函数
	def user_login(self):
		...
				
	def zf_adjust_search(self, paytype):
		...
				
	def zjzfAdjust(self)  # 耗时函数
		...

按钮绑定创建线程函数,业务函数作为该函数的参数,实例化一个线程
然后通过pause_resume和stop函数来控制线程的暂停和恢复

猜你喜欢

转载自blog.csdn.net/m0_53195006/article/details/128467835