我有此代码:
#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()
,但是没有弹出窗口并且功能开始起作用
答案 0 :(得分:0)
您不能在事件处理程序中执行一个永远运行的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)