【问题标题】:tkinter window stops respondingtkinter 窗口停止响应
【发布时间】:2018-07-11 23:23:53
【问题描述】:

我有这个代码:

#python 2.7.15

import pyautogui
import time
import msvcrt
from threading import Thread
import win32api
import battle
import Tkinter
from Tkinter import *

#launcher pos x:868 y:975
#rocket pos x:829 y:936

def click():
        left = win32api.GetKeyState(0x01)
        while True:
                click = win32api.GetKeyState(0x01)
                if click != left:
                        left = click
                        #print(a)
                        if click < 0:
                                pyautogui.hotkey("ctrlleft")
                                time.sleep(1)

def rocket():
        rocket = True
        while rocket:
            pyautogui.hotkey("2")
            time.sleep(0.5)
            pyautogui.hotkey("7")
            time.sleep(20)

root = Tk()
root.geometry("300x200")
root.title("Bot options")
root = Tkinter.Button(root, text = "Click me", command = rocket)
root.pack()
root.mainloop()


"""key = msvcrt.getche()
if key == 'z':
        click()
elif key == 'x':
    if __name__ == '__main__':
            Thread(target = click).start()
            Thread(target = battle.battle).start()
            Thread(target = rocket).start()"""

问题是,当我在运行时单击所创建窗口内的“单击我”按钮时,窗口停止响应。我尝试将command = rocket 更改为command = rocket() 但没有弹出窗口并且功能开始工作

【问题讨论】:

    标签: python python-2.7 tkinter


    【解决方案1】:

    您不能在事件处理程序中执行一个永远运行的while True: 循环,或者任何长时间运行的循环。

    如果你这样做了,你永远不会将控制权返回给 tkinter 事件循环。但是事件循环是您的程序如何处理诸如鼠标移动和按键以及来自操作系统的重要消息之类的事情。所以,如果你不让它运行,你的 GUI 就会挂起,最终你会得到一个沙滩球、沙漏、怀表或任何 Windows 用来表示“无响应”的东西。


    所以,你需要做这样的事情:

    def rocket():
        pyautogui.hotkey("2")
        root.after(500, rocket2)
    
    def rocket2():
        pyautogui.hotkey("7")
        root.after(20000, rocket)
    

    现在,不是永远循环,而是在等待半秒时阻塞整个程序,然后在等待 20 秒时再次阻塞,它只是快速执行一些操作,要求 tkinter 在 0.5 秒内运行其余代码,然后返回.

    当然,你需要在click 中做类似的事情。


    另一种选择是使用线程,它不需要像这样将循环从里到外翻转。 (你已经导入了threading,但你没有用它做任何事情。)

    线程并不总是一个好的解决方案。例如,您不允许从后台线程访问任何 tkinter 小部件,并且在大多数程序中,您需要执行诸如从 Entry 获取值并更新 Label 中的文本等操作。但在这里,你没有这样做。 pyautogui 似乎是那种也可能无法从后台线程使用的库,但我没有检查过;如果它是线程安全的,那么您的函数可以轻松更改。

    您想调用一个在后台线程中启动rocket 的函数,而不是直接调用rocket

    def rocket():
        rocket = True
        while rocket:
            pyautogui.hotkey("2")
            time.sleep(0.5)
            pyautogui.hotkey("7")
            time.sleep(20)
    
    def start_rocket():
        th = threading.Thread(target=rocket)
        th.start()
    
    # …
    
    root = Tkinter.Button(root, text = "Click me", command = start_rocket)
    

    【讨论】:

    • 我一直在尝试修复点击功能的代码,但没有任何效果。我尝试在 pyautogui.hotkey("ctrlleft") 之后放置一个 root.after(100, click),我没有收到任何错误,但代码通常不会执行。还有什么建议吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-19
    • 2013-06-22
    • 2020-01-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多