Message not displaying with PySimpleGUI.

huangapple go评论72阅读模式
英文:

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()

huangapple
  • 本文由 发表于 2023年2月19日 00:01:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/75494571.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定