使用中途中断线程-Python

问题描述 投票:-1回答:1

我正在尝试为我玩的旧游戏创建助手。这将显示您使用进度条施放的咒语所剩余的时间长度(与宏绑定。即,我拥有的D宏的咒语长度为3.7秒,如下所示)。我对编程有点陌生,所以我分阶段进行了此操作。我已经完成了该程序,以便它搜索我的宏并将有关Key事件的正确计时器发送给该函数。但是问题是咒语只是简单地排队而不是在再次按下新的宏时打断。

我试图在较短的实验脚本中解决此问题,因为我发现在学习时更容易做点位,然后再将它们组合起来。如您所见,我试图在单独的线程上运行计时器,以便可以在中途取消计时器(在完整程序中,这是在宏完成之前按下宏的时间)。

[从我在该站点上找到的示例中,我以为线程中的该全局变量可以工作,但是在取消func(x)并打印它已暂停之前,它仍然只是完成了func(x)的运行。对不起,如果我说的不够好-或说的太多。我第一次在这里发帖

下面的代码-预先感谢!

import time 
import sys
from tkinter import *
from tkinter.ttk import *
root = Tk() 
progress = Progressbar(root, orient = HORIZONTAL, length = 500, mode = 'determinate')
progress.pack()
# on key press check spells
global casting
def func(x):
    global casting  
    while casting == True and progress['value']<100:
        increments = 100/x
        progress['value'] += increments
        root.update_idletasks() 
        time.sleep(0.01) 
    else:
        progress['value'] = 0
        root.update_idletasks()
        return

#def cancel():
#   time.sleep(2)
##  global casting
#   casting = False
#   print("Halted casting")

casting = True
t1 = threading.Thread(target=func(370))
t1.start()
time.sleep(0.9)
casting = False
print("Halted")
t1.join

###### New code updated 


from tkinter import *
from tkinter.ttk import *
global casting
myMacros = {
    "my_keys": {
        "d": ["Flamestrike", 370],
        "x": ["Poison", 150],
        "q": ["Cure", 100],
        "a": ["Lightning", 250],
        "w": ["Greater Heal", 300],
        "z": ["Magic Arrow", 100],
        "e": ["Magic Reflection", 350]
    }
}

def update_progressbar(x):
    if casting is True and progress['value'] < 100:
        increments = 100/x
        progress['value'] += increments
        # schedule this function to run again in 10ms
        root.after(10, update_progressbar, x)
    else:
        progress['value'] = 0

def cancel():
    global casting
    casting = False

def cast(x):
    global casting
    casting = True
    update_progressbar(x)

def key(event):
# Adding dynamic spellcasts grabbed from dictionary
    if(event.char in myMacros["my_keys"]):
        cancel()
#       print(myMacros["my_keys"][event.char][0])
#       print(myMacros["my_keys"][event.char][1])
        cast(myMacros["my_keys"][event.char][1])

root = Tk()
progress = Progressbar(root, orient = HORIZONTAL, length = 500, mode = 'determinate')
#start_button = Button(root, text="Cast", command=cast)
#cancel_button = Button(root, text="Cancel", command=cancel)

progress.pack(side="top", fill="x")
#start_button.pack(side="left")
#cancel_button.pack(side="left")
root.bind("<Key>",key)
root.mainloop()
python multithreading tkinter global-variables
1个回答
0
投票

对于这种类型的问题,您不需要线程,也不应使用循环。 Tkinter已经运行了一个循环:mainloop。 Tkinter不是线程安全的,线程是具有许多陷阱的高级主题。在这种情况下,线程添加的问题多于解决的问题。

相反,编写一个可以定期调用以更新进度条并使用after安排该功能的功能。当您想在循环中运行一小段代码时,这是正确的技术,尽管它仅在要运行的代码花费的时间少于一秒钟的情况下才有效。就是这种情况-更新进度条只需要几毫秒。

该函数看起来像这样。请注意,它是如何进行一些工作的,然后计划自己在将来再次运行。 casting变量设置为false或进度达到100时,循环将停止。

def update_progressbar(x):
    global after_id
    if casting and progress['value'] < 100:
        increments = 100/x
        progress['value'] += increments

        # schedule this function to run again in 10ms
        after_id = root.after(10, update_progressbar, x)
    else:
        progress['value'] = 0

然后您需要通过调用update_progressbar来开始此操作:

update_progressbar(370)

这里是一个基于原始代码的完整工作示例。我添加了两个按钮来启动和取消进度条。

screenshot

from tkinter import *s
from tkinter.ttk import *
global casting
global after_id
after_id = None

def update_progressbar(x):
    global after_id
    if casting and progress['value'] < 100:
        increments = 100/x
        progress['value'] += increments

        # schedule this function to run again in 10ms
        after_id = root.after(10, update_progressbar, x)
    else:
        progress['value'] = 0


def cancel():
    global casting
    casting = False
    if after_id is not None:
        root.after_cancel(after_id)

def cast():
    global casting
    casting = True
    update_progressbar(370)

root = Tk()
progress = Progressbar(root, orient = HORIZONTAL, length = 500, mode = 'determinate')
start_button = Button(root, text="Cast", command=cast)
cancel_button = Button(root, text="Cancel", command=cancel)

progress.pack(side="top", fill="x")
start_button.pack(side="left")
cancel_button.pack(side="left")

root.mainloop()
© www.soinside.com 2019 - 2024. All rights reserved.