英文:
Message not displaying with PySimpleGUI
问题
抱歉,我无法执行代码。我可以帮你解释代码的部分内容。以下是关于你的代码的解释:
你的代码中创建了一个使用PySimpleGUI构建的窗口应用程序,包括两个列,一个用于用户输入,另一个用于显示信息。用户可以输入信息并按下不同按钮执行相应的操作,比如显示信息、清除输入、打卡等功能。
在代码的一部分中,当用户按下 "In" 按钮时,根据条件分支中的判断,会尝试更新消息显示区域 msg_elem
中的内容,显示用户已打卡或已经打卡的消息。但是在你提到的情况下,这个更新似乎没有生效。
你描述了一个问题:当用户按下 "In" 按钮时,消息显示区域 msg_elem
中的内容没有更新。这可能是由于程序逻辑错误导致的。要确保消息更新的代码段被正确执行并且没有其他地方的代码影响了它的显示。
你提到使用Python调试器,消息是显示的,这表明代码本身可能没有问题。因此,这可能是因为程序正常运行时,消息更新被其他操作所影响,导致无法正确显示消息。可能需要仔细检查程序的流程,确保消息更新没有被其他操作覆盖或清除。
英文:
I have a project where I'm trying to build a simple time-clock using Python 3 on a Raspberry Pi. The Pi is running 64-bit Bullseye.
In my script, I create a window with two columns, one for entry and one for display. The entry side is working (as far as I have gone). The display side sorta works, and this is the issue.
The user will enter their code, press "Enter" to see their information, and then press "In" or "Out" for clocking in or out. When the user presses "In", I want to display a message that says either "Clocked In" or "Already Clocked in".
The issue is that the clocked-in message does not display. The statement that fails is the msg_elem.Update( ...
. If I run the Python debugger, the message is displayed, but not in "normal" running.
My question is What am I doing wrong?
This is a working example...
import sys, os, platform
import PySimpleGUI as sg
from PIL import Image, ImageTk
from time import sleep
import io
#
# Elements
# create the Elements we want to control outside the form
out_elem = sg.Text('', size=(55, 1), font=('Helvetica', 18), text_color='black',justification='center')
in_elem = sg.Input(size=(10,1), do_not_clear=True)
img_elem = sg.Image(size=(240,240),key="-IMAGE-")
msg_elem = sg.Text('', size=(65, 1), font=('Helvetica', 18), text_color='black',justification='center',key='-MSG-')
#
# Columns
button_column = [
[sg.Text("User Input"),in_elem],
[sg.ReadFormButton('1', size=(3,3)),
sg.ReadFormButton('2', size=(3,3)),
sg.ReadFormButton('3', size=(3,3)),
sg.ReadFormButton('Clear', size=(6,3))],
[sg.ReadFormButton('4', size=(3,3)),
sg.ReadFormButton('5', size=(3,3)),
sg.ReadFormButton('6', size=(3,3)),
sg.ReadFormButton('Enter', size=(6,3))],
[sg.ReadFormButton('7', size=(3,3)),
sg.ReadFormButton('8', size=(3,3)),
sg.ReadFormButton('9', size=(3,3)),
sg.ReadFormButton('Quit', size=(6,3))],
[sg.T(''), sg.T(' ' * 8),
sg.ReadFormButton('0', size=(3,3))],
[sg.T('')],
[sg.ReadFormButton('In', size=(13,3)),
sg.ReadFormButton('Out', size=(13,3)),]
]
display_column = [
[sg.Text("User Details")],
[out_elem],
[sg.T(' ' * 30), img_elem],
[msg_elem],
]
#
layout = [
[sg.Column(button_column),
sg.VSeperator(),
sg.Column(display_column,justification='center',vertical_alignment='top')]
]
form = sg.Window('Time Clock', layout, auto_size_buttons=False, size=(800,480))
keys_entered = ''
while True:
button, values = form.Read()
if button is None:
form["-IMAGE-"].update()
out_elem.Update( " " )
break
elif button == 'Clear':
keys_entered = ''
pcpid = ''
empid = ''
form["-IMAGE-"].update()
in_elem.Update(keys_entered)
out_elem.Update( " " )
msg_elem.Update( " " )
elif button in '1234567890':
keys_entered = in_elem.Get()
keys_entered += button
elif button == 'Enter':
keys_entered = '123'
first_name = 'Mike'
last_name = 'Retiredguy'
empid = 12345
im1 = Image.open( 'mike.png' )
im1.thumbnail((240,240))
bio = io.BytesIO()
im1.save( bio, format="PNG")
empimage = bio.getvalue()
form["-IMAGE-"].update( empimage )
dsplAns = f"{empid} - {last_name}, {first_name}"
out_elem.Update( dsplAns )
elif button == 'In':
# import pdb; pdb.set_trace()
sqlAns = 1 # User already clocked in
if sqlAns > 0:
msg_elem.Update( "...is already clocked in! (A)" ) # <=== THIS IS WHAT FAILS
else:
msg_elem.Update( "...is clocked in! (B)" ) # <=== THIS IS WHAT FAILS
sleep(10)
# Clear input
keys_entered = ''
pcpid = ''
empid = ''
form["-IMAGE-"].update()
in_elem.Update(keys_entered)
out_elem.Update( " " )
msg_elem.Update( " " )
elif button == 'Quit':
sys.exit(0)
in_elem.Update(keys_entered)
#
# ###EOF###
I have tried this on the RPi, and on a Virtual system with Debian (not Pi) linux. Both give me the same result. I've searched here on Stack Overflow, and Google in general, and I think I'm doing it correctly, but failing.
答案1
得分: 2
方法`msg_elem.Update`仅更新 PySimpleGUI 的架构,而不是 GUI。如果要立即更新 GUI,而不是等到返回 `window.read()`,在 `sleep(10)` 前需要调用 `window.refresh()`。`sleep(10)` 会让 GUI 等待很长时间,因此会显示 "Not Responding"。
演示代码
from time import sleep
import threading
import PySimpleGUI as sg
def func(window, value):
global running
message = f'你点击了按钮 "{value}",这条消息将在 3 秒后清除!'
window.write_event_value('Update', message)
sleep(3)
window.write_event_value('Update', '')
running = False
sg.set_options(font=('Courier New', 12))
layout = [
[sg.Button('你好'), sg.Button('世界')],
[sg.Text('', size=80, key='State')],
]
window = sg.Window('标题', layout)
running = False
while True:
event, values = window.read()
if event == sg.WIN_CLOSED:
break
elif event in ('你好', '世界') and not running:
running = True
threading.Thread(target=func, args=(window, event), daemon=True).start()
elif event == 'Update':
message = values[event]
window['State'].update(message)
window.close()
英文:
The method msg_elem.Update
just update the architecture of PySimpleGUI, not the GUI. Need to call window.refresh()
before sleep(10)
if you want the GUI updated immediately, not until back to window.read()
. sleep(10)
take long time for GUI to wait, so it will show "Not Responding".
Demo Code
from time import sleep
import threading
import PySimpleGUI as sg
def func(window, value):
global running
message = f'You clicked the button "{value}", this message will be cleared after 3s !'
window.write_event_value('Update', message)
sleep(3)
window.write_event_value('Update', '')
running = False
sg.set_options(font=('Courier New', 12))
layout = [
[sg.Button('Hello'), sg.Button('World')],
[sg.Text('', size=80, key='State')],
]
window = sg.Window('Title', layout)
running = False
while True:
event, values = window.read()
if event == sg.WIN_CLOSED:
break
elif event in ('Hello', 'World') and not running:
running = True
threading.Thread(target=func, args=(window, event), daemon=True).start()
elif event == 'Update':
message = values[event]
window['State'].update(message)
window.close()
答案2
得分: 1
以下是基于Jason方案的解决方案,利用PySimpleGUI的定时器功能简化代码,不需要使用线程。截至本帖发布日期,您需要获取 GitHub 上的 PySimpleGUI 版本来使用 Window.timer_start()
和 Window.timer_stop_all()
。如果需要,您也可以使用标志来防止多次按钮点击。
演示程序 Demo_Window_Timer.py 显示了如何更详细地使用这组 API 调用,并可以在 GitHub 的其他演示程序中找到。
这个概念与之前的回答相同。当按钮被点击时启动一个定时器。为了处理多次按钮点击,当新的按钮点击发生时,先前的定时器会被取消。
启动定时器的重要代码行是:
window.timer_start(3000, repeating=False) # 启动一个 3 秒的定时器
当定时器到期时,您会收到一个事件,您可以在启动定时器时指定,如果未指定,则将使用默认的键值。这就是此示例中所做的。检测定时器已经到期的代码行是:
elif event == sg.EVENT_TIMER:
完整的程序...
import PySimpleGUI as sg
sg.set_options(font=('Courier New', 12))
layout = [
[sg.Button('Hello'), sg.Button('World')],
[sg.Text('', size=80, key='State')],
]
window = sg.Window('Title', layout)
while True:
event, values = window.read()
if event == sg.WIN_CLOSED:
break
elif event in ('Hello', 'World'):
window.timer_stop_all() # 停止任何先前的定时器
window['State'].update(f'You clicked the button "{event}", this message will be cleared after 3s!')
window.timer_start(3000, repeating=False) # 启动一个 3 秒的定时器
elif event == sg.EVENT_TIMER:
window['State'].update('')
window.close()
英文:
Here is a solution based on Jason's solution that uses the PySimpleGUI timer capability to simplify the code so that threads are not required. As of the date of this post, you'll need to get the GitHub version of PySimpleGUI to use Window.timer_start()
and Window.timer_stop_all()
. You could also use a flag to protect against multiple button clicks if desired.
The Demo Program Demo_Window_Timer.py shows how to use this set of API calls in more detail and can be found with the other Demo Programs on GitHub.
The concept is the same as the previous answer. A timer is started when the button is clicked. To handle multiple button clicks, previous timers are canceled when a new button click happens.
The important line of code that starts the timer is:
window.timer_start(3000, repeating=False) # start a 3-second timer
When the timer expires, you'll get an event that you can specify when you start the timer, or if none is specified, the default key value will be used. That's what was done in this example. Detecting the timer has expired is this line:
elif event == sg.EVENT_TIMER:
The complete program...
import PySimpleGUI as sg
sg.set_options(font=('Courier New', 12))
layout = [
[sg.Button('Hello'), sg.Button('World')],
[sg.Text('', size=80, key='State')],
]
window = sg.Window('Title', layout)
while True:
event, values = window.read()
if event == sg.WIN_CLOSED:
break
elif event in ('Hello', 'World'):
window.timer_stop_all() # stop any previous timers
window['State'].update(f'You clicked the button "{event}", this message will be cleared after 3s !')
window.timer_start(3000, repeating=False) # start a 3-second timer
elif event == sg.EVENT_TIMER:
window['State'].update('')
window.close()
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论