Python Tkinter GUI在运行循环时冻结

Python Tkinter GUI在运行循环时冻结,python,Python,我是python编码新手,我一直在做一个项目,可以根据选定的颜色点击图像。我一直在使用一个程序,当我点击开始按钮时,它会循环搜索50次。然而,我一直在尝试实现一个停止按钮,但问题是当循环运行时,我的代码冻结了。有什么想法吗 我听说过尝试线程,但它似乎非常复杂,我无法正确地遵循任何与我的代码相关的教程。顺便说一下,搜索的图像一直在测试我使用的存储在程序文件中的图像 from imagesearch import * import pyautogui import tkinter as tk fro

我是python编码新手,我一直在做一个项目,可以根据选定的颜色点击图像。我一直在使用一个程序,当我点击开始按钮时,它会循环搜索50次。然而,我一直在尝试实现一个停止按钮,但问题是当循环运行时,我的代码冻结了。有什么想法吗

我听说过尝试线程,但它似乎非常复杂,我无法正确地遵循任何与我的代码相关的教程。顺便说一下,搜索的图像一直在测试我使用的存储在程序文件中的图像

from imagesearch import *
import pyautogui
import tkinter as tk
from tkinter import *
from tkinter.ttk import *
import time
import threading


# ---Defined Programs---
def run():
    global enterColor
    enterColor = str(enterColorField.get())
    program(enterColor)


def program(color):
    whitePos = imagesearch_numLoop(str(color) + ".PNG", 0, 50)
    pyautogui.moveTo(whitePos[0] + 20, whitePos[1] + 10)
    pyautogui.click()


def stop():
    print("Placeholder")


# ---Main Runner---
window = tk.Tk()
window.geometry("250x250")
window.configure(background="#181b54")

app = tk.Frame(window)
app.grid()

enterColorLabel = tk.Label(window, text="Enter Color:", bg="#181b54", fg="white")
enterColorLabel.place(x=10, y=50)

enterColorField = Combobox(window)
enterColorField['values'] = ("Black", "White")
enterColorField.current("0")  # set the selected item
enterColorField.place(x=10, y=70)

submitButton = tk.Button(window, text="Start", bg="#66ff00", command=run)
submitButton.place(x=10, y=130)

stopButton = tk.Button(window, text="Stop", bg="red", command=stop)
stopButton.place(x=50, y=130)

window.mainloop()


#---New Python Script---
import cv2
import numpy as np
import pyautogui
import random
import time

def imagesearch_numLoop(image, timesample, maxSamples, precision=0.8):
    pos = imagesearch(image, precision)
    count = 0
    while pos[0] == -1:
        print(image+" not found, waiting")
        count = count + 1
        if count>maxSamples:
            break
        pos = imagesearch(image, precision)
    return pos

每当单击开始,整个代码都会冻结。我甚至不能用x表示。

一个简单的答案是,在GUI设计中不能使用while循环

但是您可以使用方法。afterdelay,callback=None代替

以下是一个例子:

from tkinter import *

root = Tk()

def loop():
    print("Hi!")
    root.after(1000, loop) # 1000 is equal to 1 second.

root.after(1000, loop) # This line is to call loop() in 1 second.
root.mainloop()

这里有一个简单的多处理配方,希望对你有用。我们将有三个主要功能。第一个是一个示例循环,您可以将处理放在其中。我在函数中包含了参数,以向您展示在使用多处理时可以传递args和kwargs

def回路A、b、c、d: 我只睡3秒钟。。模拟您所做的任何处理。 时间3 回来 接下来是一个函数,我们将使用它对多处理过程进行排队

def队列_循环: p=多处理。Processtarget=循环, args=1,2, kwargs={c:3,d:4} 您可以像这样将args和kwargs传递给目标函数 请注意,该过程尚未启动。你呼叫p,开始激活它。 p、 开始 检查状态p这是我们将定义的下一个函数。 回来 然后,您可能有兴趣了解流程在整个执行过程中的状态。例如,有时需要在运行命令时禁用某些按钮

def检查状态P: p是多处理。进程对象 如果p.is_处于活动状态:则进程仍在运行 label.configtext=MP正在运行 mp_button.configstate=已禁用 未按下按钮。配置状态=已禁用 root.after200,lambda p=p:check_status 200毫秒后,它将再次检查状态。 其他: label.configtext=MP未运行 mp_button.configstate=正常 非按钮。配置状态=正常 回来 将所有这些放在一个片段中:

将tkinter作为tk导入 导入多处理 导入时间 def回路A、b、c、d: 我只睡3秒钟。。模拟您所做的任何处理。 时间3 回来 def队列_循环: p=多处理。Processtarget=循环, args=1,2, kwargs={c:3,d:4} 您可以像这样将args和kwargs传递给目标函数 请注意,该过程尚未启动。你呼叫p,开始激活它。 p、 开始 检查状态p这是我们将定义的下一个函数。 回来 def检查状态P: p是多处理。进程对象 如果p.is_处于活动状态:则进程仍在运行 label.configtext=MP正在运行 mp_button.configstate=已禁用 未按下按钮。配置状态=已禁用 root.after200,lambda p=p:check_status 200毫秒后,它将再次检查状态。 其他: label.configtext=MP未运行 mp_button.configstate=正常 非按钮。配置状态=正常 回来 如果uuuu name uuuuu==\uuuuuuuu main\uuuuuuuu: root=tk.tk mp\u button=tk.Buttonmaster=root,text=Using-mp,command=queue\u循环 mp_按钮包 label=tk.Labelmaster=root,text=MP未运行 label.pack not\mp\u button=tk.Buttonmaster=root,text=not-mp,command=lambda:loop1,2,3,4 不是按钮包 root.mainloop
结果是,当您单击Using MP按钮时,命令按钮将被禁用,进程将在不冻结UI的情况下启动。单击Not MP按钮将启动“正常”功能,并将冻结您的UI,正如您在自己的代码中所注意到的那样

mainloop冻结代码。看看这篇文章: