TypeError:*之后的<lambda>()参数必须是可迭代的,而不是Queue

时间:2019-04-24 05:14:52

标签: python multithreading tkinter

我在前端工作,需要在单击按钮时将手形光标更改为忙碌光标。但是我拥有的代码抛出“类型错误”。我只希望代码显示一个按钮,单击后该按钮会从手形光标变为忙碌光标,然后又回到普通光标。

这是我到目前为止尝试过的代码:

import threading
from threading import Thread
from threading import Event
import queue

sem=threading.Semaphore()

def setup_for_long_running_task(self):
    print("start")
    self.f1.config(cursor="wait")  # Set the cursor to busy
    sem.acquire()

    return_que = queue.Queue(1)
    workThread = Thread(target=lambda q, w_self: \
                        q.put(self.long_running_task()),
                        args=return_que)
    workThread.start()

    self.f1.after(5000,use_results_of_long_running_task(self,workThread,return_que))  # 500ms is half a second
    sem.release()
    print("stop")

def long_running_task(self):

    Event().wait(3.0)  # Simulate long running task

def use_results_of_long_running_task(self, workThread,return_que):
    ThreadRunning = 1
    while ThreadRunning:
        Event().wait(0.1)  # this is set to .1 seconds. Adjust for your process
        ThreadRunning = workThread.is_alive()

    while not return_que.empty():
        return_list = return_que.get()

    self.f1.config(cursor="")  

错误消息:

    TypeError: <lambda>() argument after * must be an iterable, not Queue. 

    Exception in thread Thread-7:
    Traceback (most recent call last):
    File "C:\ProgramData\Anaconda3\lib\threading.py", line 917, in 
    _bootstrap_inner
    self.run()
    File "C:\ProgramData\Anaconda3\lib\threading.py", line 865, in run
    self._target(*self._args, **self._kwargs)
    TypeError: <lambda>() argument after * must be an iterable, not Queue

2 个答案:

答案 0 :(得分:0)

即使您只有一个参数,线程也需要args作为元组或列表(可迭代对象)

 args=(return_que,)

您的lambda需要两个参数lambda q, w_self:,但是args中只有一个元素

 args=(return_que, ???)

但我不知道您想用作w_self的什么。

答案 1 :(得分:0)

在启动线程时以及线程结束后使用威胁并更改游标类型的脚本下面。它以1秒的时间间隔模拟倒计时。

我已经设置了父光标,但是如果您保留对另一个小部件(例如按钮)的引用,则可以完成相同的工作。

调用MyThread类强制将光标类型设置为

  

self.parent.config(cursor =“ watch”)

当线程结束时,self.check = False,我们重置游标类型

  

self.parent.config(cursor =“”)

#!/usr/bin/python3
import tkinter as tk
from tkinter import ttk
from tkinter import messagebox
import threading
import queue
import time

class MyThread(threading.Thread):

    def __init__(self,parent, queue, count):
        threading.Thread.__init__(self)

        self.parent = parent
        self.parent.config(cursor="watch")
        self.queue = queue
        self.check = True
        self.count = count


    def stop(self):
        self.check = False

    def run(self):

        while self.check:

            if self.count <1:
                self.parent.config(cursor="")
                self.check = False
            else:                
                self.count -= 1
                time.sleep(1)
                self.queue.put(self.count)

class Main(ttk.Frame):
    def __init__(self, parent):
        super().__init__()

        self.parent = parent
        self.parent.config(cursor="")

        self.queue = queue.Queue()
        self.my_thread = None

        self.spins = tk.IntVar()
        self.count = tk.IntVar()

        self.spins.set(5)

        self.init_ui()

    def init_ui(self):

        f = ttk.Frame()

        ttk.Label(f, text = "Set count").pack()
        tk.Spinbox(f, from_=2, to=20, textvariable= self.spins).pack()

        ttk.Label(f, text = "Get count").pack()
        ttk.Label(f, textvariable = self.count).pack()

        w = ttk.Frame()

        self.start = ttk.Button(w, text="Start", command=self.start_count).pack()
        ttk.Button(w, text="Stop", command=self.stop_count).pack()
        ttk.Button(w, text="Close", command=self.on_close).pack()

        f.pack(side=tk.LEFT, fill=tk.BOTH, expand=1)
        w.pack(side=tk.RIGHT, fill=tk.BOTH, expand=1)


    def start_count(self):

        if (threading.active_count()!=0):

            self.my_thread = MyThread(self.parent, self.queue,self.spins.get())
            self.my_thread.start()
            self.on_periodic_call()

    def stop_count(self):
        if self.my_thread is not None:
            if(threading.active_count()!=1):
                self.my_thread.stop()


    def on_periodic_call(self):

        self.on_check_queue()
        if self.my_thread.is_alive():
            self.after(1, self.on_periodic_call)
        else:
            pass

    def on_check_queue(self):
        while self.queue.qsize():
            try:
                self.count.set(self.queue.get(0))
            except queue.Empty:
                pass                    

    def on_close(self):
        if self.my_thread is not None:
            if(threading.active_count()!=1):
                self.my_thread.stop()

        self.parent.on_exit()

class App(tk.Tk):
    """Start here"""

    def __init__(self):
        super().__init__()

        self.protocol("WM_DELETE_WINDOW", self.on_exit)

        self.set_style()
        self.set_title()

        Main(self)

    def set_style(self):
        self.style = ttk.Style()
        #('winnative', 'clam', 'alt', 'default', 'classic', 'vista', 'xpnative')
        self.style.theme_use("clam")


    def set_title(self):
        s = "{0}".format('Simple App')
        self.title(s)

    def on_exit(self):
        """Close all"""
        if messagebox.askokcancel("Simple App", "Do you want to quit?", parent=self):
            self.destroy()               

if __name__ == '__main__':
    app = App()
    app.mainloop()