我在前端工作,需要在单击按钮时将手形光标更改为忙碌光标。但是我拥有的代码抛出“类型错误”。我只希望代码显示一个按钮,单击后该按钮会从手形光标变为忙碌光标,然后又回到普通光标。
这是我到目前为止尝试过的代码:
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
答案 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()