Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/319.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/6/multithreading/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中使用线程和tkinter模块?_Python_Multithreading_Tkinter_Python Multithreading_Software Design - Fatal编程技术网

停止线程并避免';运行时错误';在python中使用线程和tkinter模块?

停止线程并避免';运行时错误';在python中使用线程和tkinter模块?,python,multithreading,tkinter,python-multithreading,software-design,Python,Multithreading,Tkinter,Python Multithreading,Software Design,我已经在网上讨论了多种解决方案,但它们需要大量的代码,一旦扩展,这些代码可能会让人困惑。有没有一种简单的方法可以停止线程并避免运行时错误:线程只能启动一次,以便无限次地调用线程。以下是我的代码的简单版本: import tkinter import time import threading def func(): entry.config(state='disabled') label.configure(text="Standby for seconds") t

我已经在网上讨论了多种解决方案,但它们需要大量的代码,一旦扩展,这些代码可能会让人困惑。有没有一种简单的方法可以停止线程并避免
运行时错误:线程只能启动一次
,以便无限次地调用线程。以下是我的代码的简单版本:

import tkinter
import time
import threading

def func():

    entry.config(state='disabled')
    label.configure(text="Standby for  seconds")
    time.sleep(3)
    sum = 0
    for i in range(int(entry.get())):
        time.sleep(0.5)
        sum = sum+i
        label.configure(text=str(sum))
    entry.config(state='normal')

mainwindow = tkinter.Tk()
mainwindow.title('Sum up to any number')

entry = tkinter.Entry(mainwindow)
entry.pack()
label = tkinter.Label(mainwindow, text = "Enter an integer",font=("Arial",33))
label.pack()

print(entry.get())

button = tkinter.Button(mainwindow, text="Press me", command=threading.Thread(target=func).start)
button.pack()

可以从其他线程调用tkinter小部件上的修改,这些修改将在主线程可用时立即发生。如果调用修改的后台线程休眠,而主线程仅在
mainloop
中,我们可以模拟应用程序中的暂停,而不会像问题所针对的那样阻塞主线程

然后,我们可以对
线程
进行子类化,以生成一个线程,该线程运行自己的循环,并且即使在其目标完成后仍保持
已启动
,以便我们可以调用其目标任意多次。我们甚至可以通过使用
守护进程
模式和
尝试
-
块外,将后台线程中发生的错误传递给用户,并在不挂起应用程序的情况下优雅地退出线程

thread.do
充当一个开关,我们可以在
lambda
中设置该开关,以便在按下
按钮时在
线程上运行
func
。这在主线程和后台线程之间实现了一个廉价的消息传递系统,我们可以通过少量额外代码来扩展该系统,以允许使用参数调用
func
,并从中返回值

import threading, time, tkinter, sys

class ImmortalThread(threading.Thread):
  def __init__(self, func):
    super().__init__(daemon=True)
    self.func = func
    self.do = tkinter.BooleanVar()
  def run(self):
    while True:
      if self.do.get():
        try:
          self.func()
          self.do.set(False)
        except:
          print("Exception on", self, ":", sys.exc_info())
          raise SystemExit()
      else:
        # keeps the thread running no-ops so it doesn't strip
        time.sleep(0.01)

def func():
  entry.config(state='disabled')
  label.configure(text="Standby for  seconds")
  time.sleep(3)
  sum = 0
  for i in range(int(entry.get())):
    time.sleep(0.5)
    sum = sum+i
    label.configure(text=str(sum))
  entry.config(state='normal')

mainwindow = tkinter.Tk()
mainwindow.title("Sum up to any number")

entry = tkinter.Entry(mainwindow)
entry.pack()
label = tkinter.Label(mainwindow, text="Enter an integer", font=("Arial", 33))
label.pack()

thread = ImmortalThread(func)
thread.start()
button = tkinter.Button(mainwindow, text="Press me", command=lambda: thread.do.set(True))
button.pack()

mainwindow.mainloop()

虽然这是一种简单的方法,可以用更少的代码行完成任务。我无法使用
.join()
方法。但是,该应用程序似乎没有创建任何新线程。这一点通过
threading.active_counts()
方法显而易见。代码如下:

import tkinter, threading, time

def calc():
    entry.config(state='disabled')
    label.configure(text="Standby for 3 seconds")
    time.sleep(3)
    sum = 0
    for i in range(int(entry.get())):
        time.sleep(0.5)
        sum = sum+i
        labelnum.configure(text=str(sum))
    button.config(state='normal')
    label.configure(text="Sum up to any number")
    entry.config(state='normal')

def func():
    t = threading.Thread(target=calc)
    t.start()
    #del t
    print('Active threads:',threading.active_count())


mainwindow = tkinter.Tk()
mainwindow.title('Sum up to any number')
entry = tkinter.Entry(mainwindow)
entry.pack()
label = tkinter.Label(mainwindow, text = "Enter an integer",font=("Arial",33))
label.pack()
labelnum = tkinter.Label(mainwindow, text="",font=('Arial',33))
labelnum.pack()
button = tkinter.Button(mainwindow, text="Press me", command=func)
button.pack()
mainwindow.mainloop()

您根本不能使用这种方法:Tkinter对象只能从事件分派(例如,
mainloop
)线程中使用。这是否回答了您的问题?代码避免了“运行时错误”,但仍然不允许重复求和。我在下面贴了一个答案,我想你应该看看。代码可以按照我的要求完成任务,但它只是一次又一次地创建线程,我真的不知道每次求和时创建线程是否是一种好的做法。也许你会有一个杀死线程的主意?谢谢