Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/python-3.x/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/sharepoint/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 纺车功能并不总是退出_Python_Python 3.x_Text_Tkinter - Fatal编程技术网

Python 纺车功能并不总是退出

Python 纺车功能并不总是退出,python,python-3.x,text,tkinter,Python,Python 3.x,Text,Tkinter,我有一个函数,它循环一个旋转的gif来显示一个正在运行的进程。当进程完成时,将使用不同的值(开/关)再次调用该函数,标签变为✓. 如果我只有来自threadspawner()kick off的两个线程,那么它们会很好地完成,并将标签更改为✓. 如果我同时开始大量的线程(比如12个),那么线程就可以很好地结束了,但是一个或两个标签的旋转轮有时不会更改为一个✓. 请注意,在下面的示例中,我无法让加载程序停止并更改为✓. 也许这是我搞砸的一部分,但在我的代码中,它切换得很好 我应该以不同的方式表示装载

我有一个函数,它循环一个旋转的gif来显示一个正在运行的进程。当进程完成时,将使用不同的值(开/关)再次调用该函数,
标签变为✓. 如果我只有来自
threadspawner()
kick off的两个线程,那么它们会很好地完成,并将
标签更改为✓. 如果我同时开始大量的线程(比如12个),那么线程就可以很好地结束了,但是一个或两个标签的旋转轮有时不会更改为一个✓.

请注意,在下面的示例中,我无法让加载程序停止并更改为✓. 也许这是我搞砸的一部分,但在我的代码中,它切换得很好

我应该以不同的方式表示装载轮还是以不同的方式调用装载机(“关闭”)

我尝试为每个线程使用一个全局变量,并在线程开始时将其设置为True,然后在线程结束时将其设置为off。这只有在我更新loader循环中的变量以获得新值时才起作用,这意味着我必须为每个线程创建一个不同的loader函数,这是大量额外的代码。我尝试使用
while
循环而不是
if
循环,但没有任何改变

我想对每个线程运行的纺车使用相同的加载器功能。如果这不是最好的方法,请告诉我正确的方向

from tkinter import *
import time
import threading
main = Tk()


def threadspawner():
    global var1
    global var2
    print(var1)
    if var1.get() == 2:

        thread1 = threading.Thread(target=lambda: loader(lbl1, 'on')) #<-- starts the spinning wheel to show that something is happening
        thread1.start()
        time.sleep(1)  #start doing stuff here
        loader(lbl1, 'off') #<-- Turns off the spinning wheel
        thread1.join()
    if var2.get() == 2:
        thread2 = threading.Thread(target=lambda: loader(lbl1, 'on')) #<-- starts the spinning wheel to show that something is happening
        thread2.start()
        time.sleep(2)
        loader(lbl2, 'off')#<-- Turns off the spinning wheel
        thread2.join()

var1 = IntVar()
chk1 = Checkbutton(main, text='process1', onvalue=2, offvalue=0, variable=var1)
chk1.grid(row=1)
lbl1 = Label(main, text='')
lbl1.grid(row=1, column=1)

var2 = IntVar()
chk2 = Checkbutton(main, text='process2', variable=var2)
chk2.grid(row=2)
lbl2 = Label(main, text='')
lbl2.grid(row=2, column=1)

strt = Button(main, text='Start', command=lambda: threading.Thread(target=lambda: threadspawner()).start())
strt.grid(columnspan=2)

def loader(label, switch):
    global lbl1
    global lbl2

    #im using images for my program but you do not have them so I use keyboard entries below to represent

    #img = PhotoImage(file='icons\\wheel.gif', format="gif -index 0")
    #img1 = PhotoImage(file='icons\\wheel.gif', format="gif -index 1")
    #img2 = PhotoImage(file='icons\\wheel.gif', format="gif -index 2")
    if switch == 'off':
        label['text'] = '✓'
        return
    if switch == 'on':
        print('starting loop')
        if switch == 'on':
            label['text'] = '/'
        time.sleep(.1)
        if switch == 'on':
            label['text'] = '-'
        time.sleep(.1)
        if switch == 'on':
            label['text'] = '\\'
        time.sleep(.1)
        if switch == 'on':
            loader(label, 'on')
main.mainloop()
从tkinter导入*
导入时间
导入线程
main=Tk()
def threadspawner():
全球var1
全球var2
打印(var1)
如果var1.get()==2:

thread1=threading.Thread(target=lambda:loader(lbl1,'on'))#您所做的操作的问题是
switch
是一个局部变量,因此当
loader
函数启动时,微调器启动,但当它停止时,传递给无限加载函数链的
开关
参数仍然是
'on'
,因此即使标签设置为
'✓',立即重置文本以继续加载动画;当使用参数
'off'
调用加载器函数时,
开关
变量仅在该函数调用的本地范围内具有值
'off'

一个快速而肮脏的修复方法是创建一个新的全局变量,该变量可用于永远停止加载程序函数自身调用。这有很多问题,例如一次只允许一个微调器

global_switch = 'off'

def loader(label, switch):
    global lbl1, lbl2, global_switch

    if not switch==None:
        global_switch = switch

    if global_switch == 'off':
        ....
    if global_switch == 'on':
        ....
            loader(label, None)
main.mainloop()
然而,我推荐使用类的更整洁的方法。(关于将其转换为使用图像而不是文本,有一些未经测试的评论建议)。另外,您不能在主线程之外安全地进行tkinter调用,因此,尽管这不是您所问的最初问题,但我使用了
after
方法来代替线程和
time.sleep()
s

以下是我建议的解决方案:

from tkinter import *
import time
import threading
main = Tk()


def threadspawner():
    global var1
    global var2
    print(var1.get(),var2.get())
    if var1.get() != 0:
        lbl1.start() #<-- starts the spinning wheel to show that something is happening
        time.sleep(1)  #start doing stuff here
        lbl1.stop() #<-- Turns off the spinning wheel
    if var2.get() != 0:
        lbl2.start() #<-- starts the spinning wheel to show that something is happening
        time.sleep(2)
        lbl2.stop() #<-- Turns off the spinning wheel

class Loader(Label):
    positions_text = '/-\\'
    #positions_imgs = [PhotoImage(file='icons\\wheel.gif', format="gif -index "+str(i)) for i in range(3)]
    def __init__(self, parent, *args, **kwargs):
        kwargs['text']=''
        Label.__init__(self, parent, *args, **kwargs)
        self.parent = parent
        self.runnng = False
        self.pos = 0
    def start(self):
        self.running = True
        self.parent.after(0,self.update)

    def update(self):
        self.config(text = self.positions_text[self.pos])
        #self.config(image = self.positions_imgs[self.pos])
        self.pos = (self.pos+1)%len(self.positions_text)
        #self.pos = (self.pos+1)%len(self.positions_imgs)
        if self.running:
            self.parent.after(100,self.update)
        else:
            self.config(text = '✓')
    def stop(self):
        self.running = False



var1 = IntVar()
chk1 = Checkbutton(main, text='process1', onvalue=2, offvalue=0, variable=var1)
chk1.grid(row=1)
lbl1 = Loader(main) # create an instance of the Loader class
lbl1.grid(row=1, column=1)

var2 = IntVar()
chk2 = Checkbutton(main, text='process2', variable=var2)
chk2.grid(row=2)
lbl2 = Loader(main) # create an instance of the Loader class
lbl2.grid(row=2, column=1)

strt = Button(main, text='Start', command=lambda: threading.Thread(target=threadspawner).start())
strt.grid(columnspan=2)

main.mainloop()
从tkinter导入*
导入时间
导入线程
main=Tk()
def threadspawner():
全球var1
全球var2
打印(var1.get(),var2.get())
如果var1.get()!=0:

lbl1.start()#这里似乎没有任何东西可以保证您在打开微调器后将其关闭。唯一可靠的方法是在线程启动时使用变量“开”,在线程结束时使用变量“关”,然后在加载程序循环中更新变量吗?为什么要从单独的线程关闭和打开它?为什么要在等待另一个线程完成之前关闭微调器?不能从多个线程安全地访问Tkinter函数。使用线程执行冗长的任务是一个合理的解决方案,但您必须以某种方式安排代表它们的任何GUI更新发送到主线程(可能通过队列),并在那里执行。@user2357112我想在用于启动该线程的选中按钮旁边表示正在运行的线程。有一个纺车是我找到的最好的方法。为了简单起见,我尝试用loader函数控制每个线程的旋转轮。您建议我如何向GUI中的用户显示线程正在运行/完成?