Python Forum
closing a "nested" window with a button in PySimpleGUI and repeating this process
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
closing a "nested" window with a button in PySimpleGUI and repeating this process
#1
Question 
Hello,

I'm currently experimenting with my first GUI in Python (or in any other programming language) using PySimpleGUI and I'm stumbling on some issues I cannot resolve.

This is the code I've written so far:

Import PySimpleGUI as sg

sg.theme('DarkAmber')

layout = [[sg.Text('Reverse complement:'), sg.Text(size=(15,1), key='-OUTPUT-')],
          [sg.Input(key='-IN-')],
          [sg.Button('Convert'), sg.Button('Exit'), sg.Button('Help')]]

layout_help = [[sg.Text("This program requires a DNA sequence as an input and returns the reverse complement")],[sg.Button("Cancel")]]

window = sg.Window('Reverse Complement Converter', layout)

window_help = sg.Window("Help", layout_help)

while True:
    event, values = window.read()
    if event == sg.WIN_CLOSED or event == 'Exit':
        break
    
    if event == 'Convert':
        seq=values['-IN-']
        rc= reverseComplement(seq)
        window['-OUTPUT-'].update(rc)
        
    if event == "Help":
        window_help.read()
        if event == "Cancel" or event == sg.WIN_CLOSED:
            window_help.close()
        
window.close()
If I run the script, the appropriate window opens:
[Image: ezgif-3-60b97a2c9c92.jpg]

The "Convert" button, linked to my custom reverseComplement() function actually functions. So the general functionality of my GUI works.

However, I experience following issues:
1) when I press the button "Help", I get the correct new windows pops up. However, I cannot close this help window by pressing the "Cancel" button. Pressing Cancel, does not do anything at the moment. I can, however, close it by pressing "X" in the top right corner. Why is this? Both the Cancel and X buttons should close the window right?

I also tried the following code without succes:

if event == "Help":
        window_help.read()
        if event == "Cancel" or event == sg.WIN_CLOSED:
            break
2) Also regarding the "Help" window: When I press "Help" and thereafter close the help window by pressing "X", nothing happens when I press te "Help" button again. Why is this? If the program stays in the event loop, it should be able to process "Help" more than once?



Any help would be much appreciated.
Reply
#2
I don't see how this could work.
if event == "Help":
        window_help.read()
        if event == "Cancel" or event == sg.WIN_CLOSED:
            break
To get to the "break" event has to equal "Help" and at the same time equal "Cancel" or sg.WIN_CLOSED. In you while loop you read one event at a time and process one event at a time.

You should also use elif to limit the code executed for each loop.
while True:
    event, values = window.read()
    if event == sg.WIN_CLOSED or event == 'Exit':
        break
     
    if event == 'Convert':  # Don't need elif here because of break
        seq=values['-IN-']
        rc= reverseComplement(seq)
        window['-OUTPUT-'].update(rc)
         
    elif event == "Help":
        window_help.read()

    elif event == "Cancel" or event == sg.WIN_CLOSED:
        window_help.close()
Reply
#3
(Dec-07-2020, 09:35 PM)deanhystad Wrote: I don't see how this could work.
if event == "Help":
        window_help.read()
        if event == "Cancel" or event == sg.WIN_CLOSED:
            break
To get to the "break" event has to equal "Help" and at the same time equal "Cancel" or sg.WIN_CLOSED. In you while loop you read one event at a time and process one event at a time.

You should also use elif to limit the code executed for each loop.
while True:
    event, values = window.read()
    if event == sg.WIN_CLOSED or event == 'Exit':
        break
     
    if event == 'Convert':  # Don't need elif here because of break
        seq=values['-IN-']
        rc= reverseComplement(seq)
        window['-OUTPUT-'].update(rc)
         
    elif event == "Help":
        window_help.read()

    elif event == "Cancel" or event == sg.WIN_CLOSED:
        window_help.close()

Thank you for your reply. I added the second if statement (below) with the reasoning that it would only apply to the "Help" window. So if "Help" is pressed, then a new window pop ups, with its own new event and if statement. That's how I used nested if statements before, so I thought it also worked like that in an event loop?

if event == "Help":
        window_help.read()
        if event == "Cancel" or event == sg.WIN_CLOSED:
            break
Thanks for rewriting the code. However, I still cannot close the Help window using the "Cancel" button. Also it is not possible to press Help twice. Any ideas how to solve this?
Reply
#4
As you use windows and not popups you have to catch signals from all windows.
Your code works with minor changes (I changed the "rc= reverseComplement(seq)" as I don't know what it does)

import PySimpleGUI as sg
 
sg.theme('DarkAmber')
 
layout = [[sg.Text('Reverse complement:', size=(15,1), key='-OUTPUT-')],
          [sg.Input(key='-IN-')],
          [sg.Button('Convert'), sg.Button('Exit'), sg.Button('Help')]]
 
window= sg.Window('Reverse Complement Converter', layout, finalize = True)
 
window_help = None
 
 
while True:
    win, event, values = sg.read_all_windows() # Read all signals from all windows
    if event in (sg.WIN_CLOSED, 'Exit', 'Cancel'):
        if win == window:
            break
        elif window_help and win == window_help:
            window_help.close()
            window_help = None
    elif event == 'Convert':
        seq=values['-IN-']
        rc= "YES!" #reverseComplement(seq)
        window['-OUTPUT-'].update(rc)   
    elif event == "Help":
        layout_help = [[sg.Text("This program requires a DNA sequence as an input and returns the reverse complement")],[sg.Button("Cancel")]]
        window_help = sg.Window("Help", layout_help, finalize = True)
         
window.close()
Robby_PY likes this post
Reply
#5
(Jan-09-2021, 10:27 PM)Serafim Wrote: As you use windows and not popups you have to catch signals from all windows.
Your code works with minor changes (I changed the "rc= reverseComplement(seq)" as I don't know what it does)

import PySimpleGUI as sg
 
sg.theme('DarkAmber')
 
layout = [[sg.Text('Reverse complement:', size=(15,1), key='-OUTPUT-')],
          [sg.Input(key='-IN-')],
          [sg.Button('Convert'), sg.Button('Exit'), sg.Button('Help')]]
 
window= sg.Window('Reverse Complement Converter', layout, finalize = True)
 
window_help = None
 
 
while True:
    win, event, values = sg.read_all_windows() # Read all signals from all windows
    if event in (sg.WIN_CLOSED, 'Exit', 'Cancel'):
        if win == window:
            break
        elif window_help and win == window_help:
            window_help.close()
            window_help = None
    elif event == 'Convert':
        seq=values['-IN-']
        rc= "YES!" #reverseComplement(seq)
        window['-OUTPUT-'].update(rc)   
    elif event == "Help":
        layout_help = [[sg.Text("This program requires a DNA sequence as an input and returns the reverse complement")],[sg.Button("Cancel")]]
        window_help = sg.Window("Help", layout_help, finalize = True)
         
window.close()

Thanks for your reply Serafim. Indeed, with your changes I can open and close the help window. Thank you! FYI: reverseComplement is a custom function which processes a string and outputs a string.

I have a few questions though:

1) In line 19 of your code, why did you write
elif window_help and win == window_help:
and not just
elif win == window_help
? I removed the "window_help" in this statement, and the GUI appears to work fine.

2)In the same elif statement as question 1. Why did you add
window_help=None
(line 21). Again, if I delete this line, it seems to work fine.

3)When I click the "Convert" button, the string processed by the reverseComplement function (i.e. "rc" value), should appear to the right of "Reverse complement:" as it is the "key" of this Text. This happend in my initial script. However, when I now press "Convert", the "rc" value replaces the "Reverse complement:" string. Any idea why this happens and how I could fix this? When I look at the code, I fail to understand why it replaces the whole string.

Thanks!
Reply
#6
In a GUI there are a lot of signals telling the application what is going on and some of these signals are a bit confusing, e.g. "sg.WIN_CLOSED" which only tells you that a window has given "None" as signal, not telling which window. Thus, I note that to start with there is no help window by declaring
window_help=None
and that means that
if window_help and win == window_help
ensures that the part
win == window_help
is tested only if window_help has a value (is referring to a window). If not you may have a crash when trying to close the window_help window (error: 'NoneType' object has no attribute 'close'). The python construct "if A and B" calculates B only if A is True (sort of a shortcut of the whole expression).

It might be that I am overly careful, but in my experience (50+ years of programming in a multitude of languages and in a large range of applications, the biggest counting millions of lines of code. I am 75 and still active as a programmer), if you are not careful with these matters, sooner or later there is a crash.
And, when that occurs, you want to be able to find the bug quickly. The more careful you are, the more precautions you take, the simpler to locate the error.

So far your application is small but it will grow. Being careful is a good basis for application development.
Robby_PY likes this post
Reply
#7
I didn't answer the last question.
When you update a Text element you replace the text in it. If you want to add text you will have to supply the original text + the addition:
    rc = reverseComplement(seq)
    window['-OUTPUT-'].update('Reverse complement: ' + rc)
but then you also need to expand it's size. Another option is of course to use the text as a label and add another text as output:
layout = [[sg.Text('Reverse complement:', size=(19,1)), sg.Text('',size=(15,1), key='-OUTPUT-')],
          [sg.Input(key='-IN-')],
          [sg.Button('Convert'), sg.Button('Exit'), sg.Button('Help')]]
I also want to add that I neither meant to be patronizing in my previous answer (it does look like it), nor did I mean to boast. In the mentioned multimillion line applications I contributed but did of course not write all of it. My latest project was with PySimpleGUI and just 1000 lines of code but had I used another GUI framework it would have been several times that. What I appreciate in PySimpleGui is the simplicity. You get a lot of GUI with very few lines of code.
Reply
#8
Thank you for your replies! Your clarification really helped in understanding the code.

Regarding the updating of a Text element: I understand what you mean. However, it is weird then that only the
-OUTPUT-
key was updated in my original code.

No worries, it didn't feel like patronizing or boasting to me!

(Jan-10-2021, 10:34 PM)Serafim Wrote: I didn't answer the last question.
When you update a Text element you replace the text in it. If you want to add text you will have to supply the original text + the addition:
    rc = reverseComplement(seq)
    window['-OUTPUT-'].update('Reverse complement: ' + rc)
but then you also need to expand it's size. Another option is of course to use the text as a label and add another text as output:
layout = [[sg.Text('Reverse complement:', size=(19,1)), sg.Text('',size=(15,1), key='-OUTPUT-')],
          [sg.Input(key='-IN-')],
          [sg.Button('Convert'), sg.Button('Exit'), sg.Button('Help')]]
I also want to add that I neither meant to be patronizing in my previous answer (it does look like it), nor did I mean to boast. In the mentioned multimillion line applications I contributed but did of course not write all of it. My latest project was with PySimpleGUI and just 1000 lines of code but had I used another GUI framework it would have been several times that. What I appreciate in PySimpleGui is the simplicity. You get a lot of GUI with very few lines of code.
Reply
#9
From every example I've seen I think the "Simple" in PySimpleGUI refers to the design of the package instead of it's use.
Reply
#10
(Jan-18-2021, 06:19 PM)deanhystad Wrote: From every example I've seen I think the "Simple" in PySimpleGUI refers to the design of the package instead of it's use.

If I compare my GUI programs over the years, PySimpleGUI is the one that gave me the most GUI-functionality by the smallest amount of code. It is not the most versatile but good enough for many cases. So it might refer both to the design and the ease of use. I used it in my two latest projects and it was actually pretty easy (after some reading before starting the first project) to get the GUIs up and running. For my next project I will have to find something else as I want to do things PySimpleGUI cannot deliver.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  PySimpleGUI Try Except jamesaarr 1 156 Nov-18-2021, 02:02 PM
Last Post: jamesaarr
  .get() invoke after a button nested press iddon5 5 1,054 Mar-29-2021, 03:55 AM
Last Post: deanhystad
  [PyQt] Received RunTimeError after script concludes, closing Dialog Window (clicking x-out) skipper0802 0 1,106 Oct-09-2020, 09:23 PM
Last Post: skipper0802
  how to add elements in the other window? (pysimplegui) syafiq14 0 1,072 Jul-20-2020, 10:35 PM
Last Post: syafiq14
  Closing window on button click not working kenwatts275 4 1,242 May-03-2020, 01:59 PM
Last Post: deanhystad
  tkinter window and turtle window error 1885 3 3,518 Nov-02-2019, 12:18 PM
Last Post: 1885
  [PySimpleGui] How to alter mouse click button of a standard submit button? skyerosebud 3 2,813 Jul-21-2019, 06:02 PM
Last Post: FullOfHelp
  [split] Closing a window but not the whole program scriptdrache 1 1,079 Jun-25-2019, 03:43 PM
Last Post: joe_momma
  [Tkinter] Tkinter window pop up again when i click button Orimura_Sandy 1 2,029 May-12-2019, 08:17 PM
Last Post: joe_momma
  [WxPython] Adding a Window to a Button wxPython ShashankDS 4 2,311 Apr-23-2019, 06:53 PM
Last Post: Yoriz

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020