You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python Tkinter开发自动化bot运行卡死、启停失效崩溃问题求助

问题根因

你的程序卡死、崩溃、报属性错误一共是4个核心问题:

  1. GUI阻塞问题:你把bot的死循环逻辑直接绑在了按钮的command上,Tkinter的主循环是单线程的,点启动后bot的while循环直接占住了主线程,GUI连刷新、响应按钮点击的资源都没有,自然点停止没反应、切回来就崩。
  2. P键显隐报错问题:你写的main_window.win根本不存在,main_window本身就是Tk生成的窗口对象,直接调用它的withdraw/deiconify方法就行,多写个.win当然找不到属性。
  3. 线程写法错误:设置守护线程的方法是给线程对象的daemon属性赋值True,不是调用.Daemon(True)方法,你原来的写法线程根本没被正确设为守护进程,关窗口的时候线程还在后台跑容易抛异常。另外Tkinter的控件操作只能在主线程做,你原来的add()函数每次循环都新建Label往窗口堆,既不销毁旧标签,跨线程改GUI还会偶发崩溃。
  4. 逻辑bug:你把全局的start函数、starter函数和按钮变量重名了,按钮赋值之后原来的函数名被覆盖,点启动的时候实际调用的是Button对象不是你写的函数。还有stopp标志位初始值设的True,窗口一加载没点启动bot就可能跑起来。
修复方案
  • 把bot的运行逻辑单独放到子线程里,启动按钮只负责创建子线程启动循环,绝对不能占Tk主循环的线程
  • 删掉main_window.win的多余写法,直接对main_window调用窗口显隐方法
  • 修正守护线程的写法,所有GUI控件的更新都通过after()方法调度回主线程执行,不要在子线程里直接创建/修改Label
  • 把函数名和按钮变量名分开,不要重名;修正计数标签的逻辑,固定两个标签用来显示书本、青金石数量,不要每次循环新建Label堆在窗口上
  • 给图像识别加容错,找不到图片的时候直接跳过本轮循环,不要因为找不到坐标直接抛异常崩溃
修复后的完整代码
from pynput.keyboard import Key, Controller
import pyautogui
keyboards = Controller()
import keyboard as kb
from threading import Thread
from tkinter import *
import time

# 全局变量
bookss = 0
lapiss = 0
main_window = Tk()
stopp = False  # 初始状态设为停止,避免窗口加载就自动跑
bot_thread = None  # 存bot线程对象,避免重复点启动开多个线程

# 启停控制
def stopper():
    global stopp
    stopp = False

def start_bot():
    global stopp, bot_thread
    if stopp:  # 已经在运行就不重复开线程
        return
    stopp = True
    bot_thread = Thread(target=bot_loop, daemon=True)
    bot_thread.start()

# 计数更新,固定用两个标签,不要每次新建
book_label = Label(main_window, text=f"已使用书本: 0")
lapis_label = Label(main_window, text=f"已使用青金石: 0")
def update_count():
    global bookss, lapiss
    bookss += 1
    lapiss += 3
    book_label.config(text=f"已使用书本: {bookss}")
    lapis_label.config(text=f"已使用青金石: {lapiss}")

# bot功能函数,加找不到图片的容错
def book():
    try:
        cord = pyautogui.locateCenterOnScreen('book1.png', region=(630, 530, 1290, 840), confidence=0.8)
        if not cord:
            return
        pyautogui.moveTo(cord, duration=.25)
        keyboards.press(Key.shift)
        pyautogui.leftClick(cord)
    except Exception as e:
        print(f"找书本出错: {e}")

def lapis():
    try:
        coord = pyautogui.locateCenterOnScreen('lapis_lazuli1.png', region=(630, 530, 1290, 840), confidence=0.8)
        if not coord:
            return
        pyautogui.moveTo(coord, duration=.25)
        keyboards.press(Key.shift)
        pyautogui.leftClick(coord, duration = .25)
    except Exception as e:
        print(f"找青金石出错: {e}")

# bot主循环,跑在子线程
def bot_loop():
    global stopp
    while stopp:
        time.sleep(4)
        if not stopp:
            break
        book()
        pyautogui.moveTo(1, 1, duration=0)
        time.sleep(.05)
        if not stopp:
            break
        lapis()
        pyautogui.moveTo(1, 1, duration=0)
        time.sleep(.05)
        keyboards.release(Key.shift)
        pyautogui.moveTo(1060, 465, duration= 0)
        pyautogui.leftClick(1060, 465, duration= 0)
        pyautogui.moveTo(702, 447, duration= 0)
        time.sleep(.05)
        keyboards.press('q')
        keyboards.release('q')
        # 用after把GUI更新调度回主线程,避免跨线程操作控件崩溃
        main_window.after(0, update_count)

# P键显隐窗口逻辑,修正win属性错误
def keybinds():
    isopen = True
    while True:
        if kb.is_pressed("p"):
            if isopen:
                # 直接操作main_window,不要写不存在的.win属性
                main_window.after(0, main_window.withdraw)
                isopen = False
            else:
                main_window.after(0, main_window.deiconify)
                main_window.after(0, main_window.focus_force)
                isopen = True
            time.sleep(0.5)
        time.sleep(0.01)  # 加小休眠避免占满CPU

# GUI布局
Label(main_window, text= "Enchant-a-bot 4.0").pack()
Button(main_window, text= "quit", command= main_window.quit).pack()
Button(main_window, text = "stop", command = stopper).pack()
# 注意函数名和按钮变量不要重名
Button(main_window,text="start", command = start_bot).pack()
book_label.pack()
lapis_label.pack()

# 启动快捷键线程,修正daemon设置方式
keybinds_thread = Thread(target=keybinds, daemon=True)
keybinds_thread.start()

# GUI主循环
if __name__ == "__main__":
    main_window.mainloop()
额外注意点
  • 用pyautogui.locateCenterOnScreen的时候建议装opencv-python,加confidence参数提升识别准确率,不然稍微有点色差就找不到图直接抛错
  • 循环里每个耗时操作前都加一下stopp标志位判断,不然点停止之后要等当前整轮循环跑完才会停,响应会很慢
  • 所有涉及Tk控件的操作,不管是改文字还是显隐窗口,都用main_window.after(0, 要执行的函数)扔回主线程跑,不然跨线程改Tk控件在Windows上大概率会直接无响应崩溃

内容的提问来源于stack exchange,提问作者Victor Voznyuk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 19:12:29