设置未在 GUI 中输入的变量和"Not Responding"问题



我想写一个程序,移动鼠标光标并按下shift键,这样计算机就不会被锁定。问题是,如果用户不设置两个变量,它们应该自动为0和1,但我似乎缺少了一些东西。另一件我不能理解的事情是,当我启动程序时,如果我不点击它,一切都很好,但如果我点击程序的窗口,它会说";不响应";但是程序正在运行。我不明白我在这里做错了什么。以下是我的代码:

#!/usr/bin/python
import pyautogui
import time
import sys
import os
import PySimpleGUI as sg
from datetime import datetime
def main():
sg.theme('DarkAmber')
layout = [  [sg.Text('Please enter the time intervall between the movements:', size = (45,1)), sg.Input(key='-IT-', enable_events=True)],
[sg.Text('Please enter how long should the script run:', size = (45,1)), sg.Input(key='-DURATION-', enable_events=True)],
[sg.Button('Start'), sg.Button('Stop')],
[sg.Output(size=(60,15))]   ]
window = sg.Window('Press to start to move!', layout, size=(450,250), element_justification='right')
while True:
event, values = window.read()
if event in (sg.WIN_CLOSED, 'Stop'):         
break

if event == '-IT-' and values['-IT-'] and values['-IT-'][-1] not in ('0123456789'):
window['-IT-'].update(values['-IT-'][:-1])
if event == '-DURATION-' and values['-DURATION-'] and values['-DURATION-'][-1] not in ('0123456789'):
window['-DURATION-'].update(values['-DURATION-'][:-1])

elif event == 'Start':
if values['-IT-'] == "" and values['-DURATION-'] == "":
window['-IT-'].update(1)
window['-DURATION-'].update(0)
elif values['-IT-'] != "" and values['-DURATION-'] == "":
window['-DURATION-'].update(0)
elif values['-IT-'] == "" and values['-DURATION-'] != "":
window['-IT-'].update(1)    
move(numMin=int('0'+values['-IT-']), numDuration=int('0'+values['-DURATION-']))
window.close()
main()

编辑:我刚刚删掉了代码中不必要的部分。所以,如果我没有误解的话,我需要使用一个线程,第二个问题对我来说不清楚,我可以在不添加零(0(的情况下键入一个空字符串吗?因为当我尝试只进行类型转换时,它不起作用,如果我添加一个零,代码的行为就会改变。

采取"长时间">

如果你是Windows用户,你已经看到窗口显示在他们的标题栏中;不响应";紧接着是一个Windows弹出窗口,声明";您的程序已停止响应";。好吧,如果你愿意的话,你也可以让这个消息和弹出窗口出现!你所需要做的就是执行一个操作;"太长";(即几秒钟(。

你有几个选择来处理这个问题。如果您的操作可以分成更小的部分,那么您可以偶尔调用Window.Refresh((来避免出现此消息。例如,如果你正在运行一个循环,请将该调用与你的其他工作联系起来。这将使GUI保持愉快,Window不会抱怨。

另一方面,如果您的操作不在您的控制之下,或者您无法添加Refresh调用,那么下一个可用选项是将长操作移动到线程中。

";"老办法">

有几个演示程序可供您查看如何做到这一点。你基本上把你的工作放在一个线程中。当线程完成时,它通过队列发送消息来告诉GUI。事件循环将在定时器设置为表示如何"控制"的值的情况下运行;响应的";您希望您的GUI能够完成工作。

";新方式"-Window.write_event_value

截至2020年7月,这个目前仅在tkinter端口中可用的新功能令人兴奋,它代表了未来在PySimpleGUI中处理多线程的方式(希望如此(。

以前,使用一个队列,事件循环将在其中轮询来自线程的传入消息。

现在,线程可以直接将事件注入到Window中,这样它就会显示在window.read()调用中。这允许您的事件循环";pend";,等待正常窗口事件以及线程生成的事件。

你可以在这个演示中看到这个新功能的作用:demo_Multithreadd_Write_Event_Value.py

这是供你检查和教育的程序。不再轮询线程事件真是太好了。

import threading
import time
import PySimpleGUI as sg
"""
Threaded Demo - Uses Window.write_event_value communications
Requires PySimpleGUI.py version 4.25.0 and later
This is a really important demo  to understand if you're going to be using multithreading in PySimpleGUI.
Older mechanisms for multi-threading in PySimpleGUI relied on polling of a queue. The management of a communications
queue is now performed internally to PySimpleGUI.
The importance of using the new window.write_event_value call cannot be emphasized enough.  It will hav a HUGE impact, in
a positive way, on your code to move to this mechanism as your code will simply "pend" waiting for an event rather than polling.
Copyright 2020 PySimpleGUI.org
"""
THREAD_EVENT = '-THREAD-'
cp = sg.cprint
def the_thread(window):
"""
The thread that communicates with the application through the window's events.
Once a second wakes and sends a new event and associated value to the window
"""
i = 0
while True:
time.sleep(1)
window.write_event_value('-THREAD-', (threading.current_thread().name, i))      # Data sent is a tuple of thread name and counter
cp('This is cheating from the thread', c='white on green')
i += 1
def main():
"""
The demo will display in the multiline info about the event and values dictionary as it is being
returned from window.read()
Every time "Start" is clicked a new thread is started
Try clicking "Dummy" to see that the window is active while the thread stuff is happening in the background
"""
layout = [  [sg.Text('Output Area - cprint's route to here', font='Any 15')],
[sg.Multiline(size=(65,20), key='-ML-', autoscroll=True, reroute_stdout=True, write_only=True, reroute_cprint=True)],
[sg.T('Input so you can see data in your dictionary')],
[sg.Input(key='-IN-', size=(30,1))],
[sg.B('Start A Thread'), sg.B('Dummy'), sg.Button('Exit')]  ]
window = sg.Window('Window Title', layout, finalize=True)
while True:             # Event Loop
event, values = window.read()
cp(event, values)
if event == sg.WIN_CLOSED or event == 'Exit':
break
if event.startswith('Start'):
threading.Thread(target=the_thread, args=(window,), daemon=True).start()
if event == THREAD_EVENT:
cp(f'Data from the thread ', colors='white on purple', end='')
cp(f'{values[THREAD_EVENT]}', colors='white on red')
window.close()
if __name__ == '__main__':
main()

多线程程序

关于多线程的主题,我们准备了另一个演示,展示了如何在程序中运行多个线程,这些线程都与事件循环通信,以便在GUI窗口中显示一些内容。回想一下,对于PySimpleGUI(至少是tkinter端口(,您不能在主程序线程之外的线程中进行PySimpleGUI调用。

这些线程程序的关键是从线程到事件循环的通信。为这些演示选择的机制使用Python内置的队列模块。事件循环轮询这些队列,以查看是否已从要显示的某个线程发送了内容。

你会发现这个演示显示多个线程与一个GUI通信,它被称为:

Demo_Multithreaded_Queued.py

对于普通的PySimpleGUI(基于tkinter(,再次发出警告-您的GUI绝不能作为主程序线程以外的任何东西运行,并且任何线程都不能直接调用PySimpleGUI调用。

最新更新