当前位置:   article > 正文

python tkinter 解决button事件卡死问题(开启线程 | 关闭线程 )_tkinter按钮按下不弹起

tkinter按钮按下不弹起

问题描述

Python使用tk编写GUI界面中Button调用方法如果执行时间过长(比如绑定的函数中有while循环)会导致

  1. tk 界面卡死
  2. 一拖动就会卡死

开启线程

实测完美解决方法:

import threading
import time

def thread_it(fc):
    t = threading.Thread(target=fc)
    t.setDaemon(True)
    t.start()
    
def target_fc():
    time.sleep(10)

# 下面这句并不能直接使用,因为例子中我并没有引入import tkinter,仅表示示例
# Button绑定事件,如果有传递参数要通过lamda:+函数 
button1 = ttk.Button(root, text='Button', command=lambda: thread_it(target_fc))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

关闭线程

使用ctypes强行杀掉线程,下述例子仅表示如何关闭,开启的例子参考上面,代码并非直接升版,就比如下面例子中t 是假设已经开启的情况下

import inspect
import ctypes

 
def _async_raise(tid, exctype):
    """raises the exception, performs cleanup if needed"""
    tid = ctypes.c_long(tid)
    if not inspect.isclass(exctype):
        exctype = type(exctype)
    res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(exctype))
    if res == 0:
        raise ValueError("invalid thread id")
    elif res != 1:
        # """if it returns a number greater than one, you're in trouble,
        # and you should call it again with exc=NULL to revert the effect"""
        ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, None)
        raise SystemError("PyThreadState_SetAsyncExc failed")
def stop_thread(thread):
    _async_raise(thread.ident, SystemExit)
 
# 假设开启了一个t线程,用下述方法可以直接关掉
stop_thread(t)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

评论区问题解决方案

1.0 @顾道

线程部分的代码在类中实现, 以下是部分代码,仅供参考

class App:
	# 开启线程
    def thread_it(self, fc):
        self.t = threading.Thread(target=fc)
        self.t.setDaemon(True)
        self.t.start()
        
    # 终止线程
    def _async_raise(self, tid, exctype):
        """raises the exception, performs cleanup if needed"""
        tid = ctypes.c_long(tid)
        if not inspect.isclass(exctype):
            exctype = type(exctype)
        res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(exctype))
        if res == 0:
            raise ValueError("invalid thread id")
        elif res != 1:
            # """if it returns a number greater than one, you're in trouble,
            # and you should call it again with exc=NULL to revert the effect"""
            ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, None)
            raise SystemError("PyThreadState_SetAsyncExc failed")

    def stop_thread(self, thread):
        self._async_raise(thread.ident, SystemExit)

    # 动态改变按钮状态,新增该函数是为避免绑定事件后,无法关闭线程而设立。
    def change_button_runorstop(self):
        # self.button.configure(text='取消执行') #动态更改button的文本显示
        if self.button4["text"] == "执行":
            self.thread_it(self.move_mouse_to)
        elif self.button4["text"] == "取消执行":
            self.button4["text"] = "执行"
            self.stop_thread(self.t)
            self.text_1.insert('1.0', '取消任务成功\n')
	# 移动鼠标到指定位置
    def move_mouse_to(self):
    	# 此处方法省略


	def setup_widgets(self):
		# 按钮绑事件
		self.button4 = ttk.Button(self.tab_1, text="执行",command=self.change_button_runorstop)  # command= lambda :self.thread_it(self.move_mouse_to))
	    self.button4.grid(row=1, column=4, padx=5, pady=10, sticky="nsew", rowspan=2)  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/124975
推荐阅读
相关标签
  

闽ICP备14008679号