简体   繁体   English

PySimpleGUI 冻结

[英]PySimpleGUI Freezes

I wrote a code for a hack in a game cold Boxing Simulator 2 in python 3.8.1 with PySimpleGui 4.15.1, and if I try to Click the start/stop button, the gui Freezes but the script connected with the Start/Stop button still runs.我在带有 PySimpleGui 4.15.1 的 python 3.8.1 中的游戏冷拳击模拟器 2 中编写了一个黑客代码,如果我尝试单击开始/停止按钮,gui 冻结但脚本与开始/停止按钮连接仍在运行。 But if i change the script connected to the Start/Stop button To something like Print('Chicken') then it works totally perfect‫‫‫‫‫‫‫‫‫‫‫但是,如果我将连接到“开始/停止”按钮的脚本更改为 Print('Chicken') 之类的东西,那么它完全可以完美运行

Here is the Code:这是代码:

import PySimpleGUI as sg
import ctypes
import time
import pynput

sg.theme('DarkBrown1')

layout = [  [sg.Text('BOXING SIMULATOR 2 HACK', size=(20, 2), justification='center')],
            [sg.Text('', size=(10, 2), font=('Helvetica', 20), justification='center', key='_OUTPUT_')],
            [sg.T(' ' * 5), sg.Button('Start/Stop', focus=True), sg.Quit()]]

window = sg.Window('BOXING SIMULATOR 2 HACK', layout)

SendInput = ctypes.windll.user32.SendInput

PUL = ctypes.POINTER(ctypes.c_ulong)
class KeyBdInput(ctypes.Structure):
    _fields_ = [("wVk", ctypes.c_ushort),
                ("wScan", ctypes.c_ushort),
                ("dwFlags", ctypes.c_ulong),
                ("time", ctypes.c_ulong),
                ("dwExtraInfo", PUL)]

class HardwareInput(ctypes.Structure):
    _fields_ = [("uMsg", ctypes.c_ulong),
                ("wParamL", ctypes.c_short),
                ("wParamH", ctypes.c_ushort)]

class MouseInput(ctypes.Structure):
    _fields_ = [("dx", ctypes.c_long),
                ("dy", ctypes.c_long),
                ("mouseData", ctypes.c_ulong),
                ("dwFlags", ctypes.c_ulong),
                ("time",ctypes.c_ulong),
                ("dwExtraInfo", PUL)]

class Input_I(ctypes.Union):
    _fields_ = [("ki", KeyBdInput),
                 ("mi", MouseInput),
                 ("hi", HardwareInput)]

class Input(ctypes.Structure):
    _fields_ = [("type", ctypes.c_ulong),
                ("ii", Input_I)]


def PressKeyPynput(hexKeyCode):
    extra = ctypes.c_ulong(0)
    ii_ = pynput._util.win32.INPUT_union()
    ii_.ki = pynput._util.win32.KEYBDINPUT(0, hexKeyCode, 0x0008, 0, ctypes.cast(ctypes.pointer(extra), ctypes.c_void_p))
    x = pynput._util.win32.INPUT(ctypes.c_ulong(1), ii_)
    SendInput(1, ctypes.pointer(x), ctypes.sizeof(x))

def ReleaseKeyPynput(hexKeyCode):
    extra = ctypes.c_ulong(0)
    ii_ = pynput._util.win32.INPUT_union()
    ii_.ki = pynput._util.win32.KEYBDINPUT(0, hexKeyCode, 0x0008 | 0x0002, 0, ctypes.cast(ctypes.pointer(extra), ctypes.c_void_p))
    x = pynput._util.win32.INPUT(ctypes.c_ulong(1), ii_)
    SendInput(1, ctypes.pointer(x), ctypes.sizeof(x))


HACK_running, counter = False, 0

while True:                                 
    event, values = window.read(timeout=10) 
    if event in (None, 'Quit'):            
        break
    elif event == 'Start/Stop':
        HACK_running = not HACK_running
    if HACK_running:
            PressKeyPynput(0x02)
            time.sleep(0.08)
            ReleaseKeyPynput(0x02)
            PressKeyPynput(0x11)
            time.sleep(0.5)
            ReleaseKeyPynput(0x11)
            PressKeyPynput(0x1F)
            time.sleep(0.6)
            ReleaseKeyPynput(0x1F)
            PressKeyPynput(0x02)
            time.sleep(0.08)
            ReleaseKeyPynput(0x02)
            time.sleep(300)

You can't do really long running tasks in a GUI without some kind of refresh or read operation.如果没有某种刷新或读取操作,您将无法在 GUI 中执行真正长时间运行的任务。

I answered the previous post that was identical to this one, pointing out the problem as being the inner while loop that never exits.我回答了与此相同的上一篇文章,指出问题在于永远不会退出的内部 while 循环。

If you must have the inner loop executing forever, then you'll at least need to refresh the GUI.如果您必须让内部循环永远执行,那么您至少需要刷新 GUI。 You can do this by calling window.refresh as shown below.您可以通过调用window.refresh来执行此操作,如下所示。

while True:                                 
    event, values = window.read(timeout=10) 
    if event in (None, 'Quit'):            
        break
    elif event == 'Start/Stop':
        HACK_running = not HACK_running
    if HACK_running:
            PressKeyPynput(0x02)
            time.sleep(0.08)
            ReleaseKeyPynput(0x02)
            PressKeyPynput(0x11)
            time.sleep(0.5)
            ReleaseKeyPynput(0x11)
            PressKeyPynput(0x1F)
            time.sleep(0.6)
            ReleaseKeyPynput(0x1F)
            PressKeyPynput(0x02)
            time.sleep(0.08)
            ReleaseKeyPynput(0x02)
            time.sleep(300)
            window.refresh()

You should never all sleep from within the PySimpleGUI event loop.您永远不应该在 PySimpleGUI 事件循环中全部休眠。

The better approach would be to call window.read(timeout=400) instead of time.sleep(0.4) .更好的方法是调用window.read(timeout=400)而不是time.sleep(0.4) This will keep the OS from thinking your program has hung.这将使操作系统不会认为您的程序已挂起。


[ EDIT July 2022 ] [编辑 2022 年 7 月]

A reminder for readers that PySimpleGUI, like many projects, is alive and continuously evolving.提醒读者,PySimpleGUI 与许多项目一样,是活跃的并且在不断发展。 Answers found here on StackOverflow are particularly dangerous as they never "die"... nor have "Closed" status... or a designation "No longer recommended"在 StackOverflow 上找到的答案特别危险,因为它们永远不会“死亡”......也没有“关闭”状态......或指定“不再推荐”

Some answers provided years ago about PySimpleGUI are not at all the recommended way of doing the same operation now.几年前提供的一些关于 PySimpleGUI 的答案现在根本不是推荐的执行相同操作的方法。 So much has changed... PySimpleGUI Windows can be much more dynamic, there's an entire set of APIs for handling subprocesses, another new set of APIs helps in managing JSON and INI files, and another is threading support.发生了很大的变化... PySimpleGUI Windows 可以更加动态化,有一整套 API 用于处理子进程,另一组新的 API 有助于管理 JSON 和 INI 文件,还有一个是线程支持。

For this problem, I would no longer recommend a "polling" solution like shown below.对于这个问题,我不再推荐如下所示的“轮询”解决方案。 Now I would start a thread and have the window.read() call no longer have a timeout.现在我将启动一个线程并让window.read()调用不再有超时。 Polling is a very very wasteful architecture.轮询是一种非常非常浪费的架构。 If possible, don't use a timeout... instead rely on an event happening when something happens.如果可能的话,不要使用超时......而是依靠发生某事时发生的事件。 In embedded-system-speak this is called being "interrupt-driven" and is a better solution over "polling" for numerous reasons.在嵌入式系统中,这被称为“中断驱动”,并且由于多种原因是比“轮询”更好的解决方案。

The methods you'll want to research are:|您要研究的方法是:|

  • Window.start_thread
  • Window.window.write_event_value

##imports you need to add ## ##imports 你需要添加##

import threading导入线程

create thread to the func is freeze为函数创建线程被冻结

thread1 = threading.Thread(target= your_func) thread1 = threading.Thread(target= your_func)

call the thread from your loop从循环中调用线程

thread1.start()线程1.start()

thet solve problem for me GL为我解决问题 GL

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM