PySimpleGUI - Quick Guide



PySimpleGUI - Introduction

Python GUIs for Humans

The PySimpleGui project started as a wrapper around TKinter package, which is bundled with Python’s standard library, with the objective to simplify the GUI building process.

PySimpleGui subsequently added the ability to design desktop GUIs based on PySide library (which itself ports Qt GUI toolkit, originally written in C++, to Python) and WxPython (which ports another popular GUI toolkit called WxWidgets). These libraries are called PySimpleGUIQt and PySimpleGUIWx respectively.

The latest addition to the PySimpleGui family is the PySimpleGUIWeb package which uses the Remi (REMote Interface Library) to construct GUI design that is rendered in a web page.

All the packages in the PySimpleGui group follow the similar API, which means the names of GUI elements, their properties and methods are same in all the four packages. As a result, just by replacing the import statement (and keeping the rest of the code unchanged), one can get the corresponding GUI design rendered. This is in fact the most important feature of PySimpleGui. That’s why, it is known as Python GUIs for Humans.

Comparison with other GUI Frameworks

A Python programmer has a variety of GUI frameworks to choose from, to develop a GUI application. TKinter is the one which is officially included in Python’s standard library. Others, most of them are open source, have to be explicitly installed.

Sr.No. Library & Description
1 TkInter

Included in Python standard library

2 PyQt

Python 3 bindings for the Qt application framework.

3 PySide

Qt for Python (formerly known as PySide) offers the official Python bindings for the Qt cross-platform application and UI framework.

4 PySimpleGUI

Wraps tkinter, Qt (pyside2), wxPython and Remi (for browser support) in a non-OOP API

5 wxPython

Supports Windows/Unix/Mac. Supports Python 2.7 and >=3.4. Wraps & extends the wxWidgets toolchain.

6 PyGObject

PyGObject is a Python package which provides bindings for GObject based libraries such as GTK Replacement for PyGtk.

7 PyForms

A Python framework to develop GUI application, which promotes modular software design and code reusability with minimal effort.

PySimpleGUI - Environment Setup

PySimpleGui supports both Python 3.x versions as well as Python 2.7 version. The main port, PySimpleGui doesn’t have any external dependencies, as Tkinter - on which it is based - is a part of Python’s standard library, and hence it needn’t be installed separately. Install it in the current Python3 environment by the PIP installer as follows

pip3 install PySimpleGUI

To verify if the library is correctly installed, enter the following statement −

>>> import PySimpleGUI
>>> PySimpleGUI.version
'4.60.1 Released 22-May-2022'

In case, the PIP installation doesn’t work, you can download "pysimplegui.py" from the Github repository (https://github.com/PySimpleGUI/PySimpleGUI) and place it in your folder along with the application that is importing it.

The pysimplegui.py file has the "main()" function. When called from Python prompt, it generates the following window to affirm that the package is correctly installed.

>>> import PySimpleGUI as psg
>>> psg.main()
Starting up PySimpleGUI Diagnostic & Help System
PySimpleGUI long version = 4.60.1 Released 22-May-2022
PySimpleGUI Version 4.60.1
tcl ver = 8.6 tkinter version = 8.6
Python Version 3.6.8 (tags/v3.6.8:3c6b436a57, Dec 24 2018,
00:16:47) [MSC v.1916 64 bit (AMD64)]
tcl detailed version = 8.6.6
PySimpleGUI.py location F:\python36\lib\sitepackages\PySimpleGUI\PySimpleGUI.py

The GUI window appears as below:

Environment Setup

If you are using Python3 version earlier than 3.4, you may need to install the "typing" module since it is not shipped in the corresponding standard library

pip3 install typing

For Python 2.7, change the name to PySimpleGUI27.

pip3 install PySimpleGUI27

You may need to also install "future" for version 2.7

pip3 install future

However, it is important to note that Python Software Foundation doesn’t officially support Python 2.x branches.

PySimpleGUI - Hello World

First Window using PySimpleGUI

To check whether PySimpleGUI along with its dependencies are properly installed, enter the following code and save it as "hello.py", using any Python-aware editor.

import PySimpleGUI as psg
layout = [[psg.Text(text='Hello World',
   font=('Arial Bold', 20),
   size=20,
   expand_x=True,
   justification='center')],
]
window = psg.Window('HelloWorld', layout, size=(715,250))
while True:
   event, values = window.read()
   print(event, values)
   if event in (None, 'Exit'):
      break
window.close()

The above code constructs a window with a Text element (equivalent of a Label in TKinter) and displays the "Hello World" message placed centrally across the width of the window.

Run this program from the command terminal as −

Python hello.py

The output generated by the program should be similar to the one displayed below −

First Window

Equivalent Tkinter Code

To obtain similar output using pure Tkinter code, we would require the following Python script −

from tkinter import *
window=Tk()
lbl=Label(window, text="Hello World",
   fg='white', bg='#64778D',
   font=("Arial Bold", 20))
lbl.place(x=300, y=15)
window.title('HelloWorld Tk')
window['bg']='#64778D'
window.geometry("715x250+10+10")
window.mainloop()

All other functionalities remain same, except we use the serve() function off waitress module to start the WSGI server. On visiting the '/' route in the browser after running the program, the Hello World message is displayed as before.

Instead of a function, a callable class can also be used as a View. A callable class is the one which overrides the __call__() method.

from pyramid.response import Response
class MyView(object):
   def __init__(self, request):
      self.request = request
   def __call__(self):
      return Response('hello world')

PySimpleGUIQt

The object model of PySimpleGUI API has been made compatible with the widgets as defined in PySide2 package (which is the Python port for Qt graphics toolkit). The Qt version of PySimpleGui is called PySimpleGUIQt. It can be similarly installed with following PIP command −

pip3 install PySimpleGUIQt

Since this package depends on PySide2, the same will also be installed.

>>> import PySide2
>>> PySide2.__version__
'5.15.2.1'
>>> import PySimpleGUIQt
>>> PySimpleGUIQt.version
'0.35.0 Released 6-Jun-2020'

As mentioned earlier, the most important feature of PySimpleGui projects is that the code written for one package is completely compatible with the other. Hence, the hello.py program used earlier can be used as it is for the Qt version. The only change needed is import PySimpleGUIQt instead of PySimpleGui.

import PySimpleGUIQt as psg
layout = [[psg.Text(text='Hello World',
   font=('Arial Bold', 20),
   justification='center')],
]
window = psg.Window('HelloWorldQt', layout, size=(715,250))
while True:
   event, values = window.read()
   print(event, values)
   if event in (None, 'Exit'):
      break
window.close()

The output is fairly similar.

GUIQT

Equivalent PySide2 Code

The pure PySide2 code to achieve the same result is as follows −

import sys
from PySide2.QtCore import *
from PySide2.QtGui import *
from PySide2.QtWidgets import *
def window():
   app = QApplication(sys.argv)
   w = QWidget()
   w.setStyleSheet("background-color: #64778D;")

   b = QLabel(w)
   b.setText("Hello World!")
   b.setFont(QFont('Arial Bold', 20))
   b.setAlignment(Qt.AlignCenter)
   b.setStyleSheet("color: white;")
   b.setGeometry(100, 100, 715, 250)
   b.move(50, 20)

   w.setWindowTitle("HelloWorldQt")
   w.show()
   sys.exit(app.exec_())
   if __name__ == '__main__':
      window()

It will produce the same output window.

PySimpleGUIWx

This module encapsulates the functionality of GUI widgets as defined in WxPython toolkit. WxPython is a Python port for the widely used WxWidgets library originally written in C++. Obviously, PySimpleGUIWx depends on WxPython package, and hence the latter will get automatically installed by the following PIP command −

pip3 install PySimpleGUIWx

To confirm that both PySimpleGUIWx and WxPython are properly installed, enter following statements in Python terminal.

>>> import PySimpleGUIWx
>>> PySimpleGUIWx.version
'0.17.1 Released 7-Jun-2020'
>>> import wx
>>> wx.__version__
'4.0.7'

Not much of change is required in the "hello.py" script. We need to just replace PySimpleGUI with PySimpleGUIWx module in the "import" statement.

import PySimpleGUIWx as psg
layout = [[psg.Text(text='Hello World',
   font=('Arial Bold', 20),
   size=(500, 5),
   justification='center')],
]
window = psg.Window('HelloWorldWx', layout, size=(715, 250))
while True:
   event, values = window.read()
   print(event, values)
   if event in (None, 'Exit'):
      break
window.close()

It will produce the following output:

GUIWx

Note that you’ll need a little more complex code to obtain the similar output with pure WxPython code as follows −

import wx
app = wx.App()
window = wx.Frame(None, title="WxPython", size=(715, 250))
panel = wx.Panel(window)
panel.SetBackgroundColour((100, 119, 141))
label = wx.StaticText(panel, -1, style=wx.ALIGN_CENTER)
label.SetLabel("Hello World")
label.SetForegroundColour((255, 255, 255))
font = wx.Font()
font.SetFaceName("Arial Bold")
font.SetPointSize(30)
label.SetFont(font)
window.Show(True)
app.MainLoop()

It will display a top level window with a text label having Hello World as the caption.

PySimpleGUIWeb

Remi (REMote Interface) is a GUI library for Python applications that are rendered in a web browser. PySimpleGUIWeb package ports the original PySimpleGui library to Remi so that its apps can be run in a browser. Following PIP command installs both PySimpleGUIWeb and Remi in the current Python environment −

pip3 install PySimpleGUIWeb

Check for their proper installation before writing an app.

>>> import PySimpleGUIWeb
>>> PySimpleGUIWeb.version
'0.39.0 Released 6-Jun-2020'

Following script is the PySimpleGUIWeb version of the original Hello World program.

import PySimpleGUIWeb as psg
layout = [[psg.Text(text='Hello World',
   font=('Arial Bold', 20),
   justification='center')]]
window = psg.Window('HelloWorldWeb', layout)
while True:
   event, values = window.read()
   print(event, values)
   if event in (None, 'Exit'):
      break
window.close()

To obtain similar output using pure Remi library’s functionality is a little complex, as the following code shows:

import remi.gui as gui
from remi import start, App
class HelloWeb(App):
   def __init__(self, *args):
      super(HelloWeb, self).__init__(*args)
   def main(self):
      wid = gui.VBox(style={"background-color": "#64778D"})
      self.lbl = gui.Label('Hello World', width='100%', height='100%',
      style={ "color":"white",
         "text-align": "center",
         "font-family": "Arial Bold",
         "font-size": "20px"}
      )
      wid.append(self.lbl)
      return wid
      if __name__ == "__main__":
         start(HelloWeb, debug=True, address='0.0.0.0', port=0)

When we run these programs, the Remi server starts, a browser window automatically opens and the Hello World message is displayed.

GUIWeb

Here we have seen the Hello World program written in the PySimpleGUI, PySimpleGUIQt, PySimpleGUIWx and PySimpleGUIWeb libraries. We can see that the widget library remains the same. Moreover, the same Hello world program, when written in pure Tkinter, PySide, WxPython and Remi respectively, becomes far more complex and tedious than the PySimpleGUI versions.

PySimpleGUI - Popup Windows

A function in PySimpleGUI module that start with the prefix popup* generates window of a predefined appearance. The name of the popup function indicates is purpose and configuration of buttons present on it. These popups are created with just one line of code. Each popup serves a certain purpose, and then closes immediately.

A most basic popup is created by the popup()function. It can be used like a print() function to display more than one parameters on the window, and an OK button. It acts like a message box, that disappears immediately on pressing the OK button

>>> import PySimpleGUI as psg
>>> psg.popup("Hello World")

It displays a popup window with Hello World text and OK button. Note that more than one strings can be displayed. Following popups with different button configurations are available −

  • popup_ok − Display Popup with OK button only

  • popup_ok_cancel − Display popup with OK and Cancel buttons

  • popup_cancel − Display Popup with "cancelled" button text

  • popup_yes_no − Display Popup with Yes and No buttons

  • popup_error − Popup with colored button and 'Error' as button text

These functions return the text of the button pressed by the user. For example, if the user presses OK button of the ok-cancel popup, it returns Ok which can be used in further programming logic.

Following popups accept input from the user in the form of text or let the user select file/folder/date from the selectors.

  • popup_get_text − Display Popup with text entry field. Returns the text entered or None if closed / cancelled

  • popup_get_file − Display popup window with text entry field and browse button so that a file can be chosen by user.

  • popup_get_folder − Display popup with text entry field and browse button so that a folder can be chosen.

  • popup_get_date − Display a calendar window, get the user's choice, return as a tuple (mon, day, year)

When user has made the selection and Ok button is pressed, the return value of the popup is the text, which can be used further in the program.

Following script shows the use of some of the above popups −

import PySimpleGUI as psg
text = psg.popup_get_text('Enter your name', title="Textbox")
print ("You entered: ", text)
file=psg.popup_get_file('Select a file',  title="File selector")
print ("File selected", file)
folder=psg.popup_get_folder('Get folder', title="Folder selector")
print ("Folder selected",folder)
ch = psg.popup_yes_no("Do you want to Continue?",  title="YesNo")
print ("You clicked", ch)
ch = psg.popup_ok_cancel("Press Ok to proceed", "Press cancel to stop",  title="OkCancel")
if ch=="OK":
   print ("You pressed OK")
if ch=="Cancel":
   print ("You pressed Cancel")
psg.popup_no_buttons('You pressed', ch, non_blocking=True)
psg.popup_auto_close('This window will Autoclose')

Output − The popups generated by the above code are shown below −

Popup Windows

The following output is displayed on the Python console

You entered: Tutorialspoint
File selected F:/python36/hello.png
Folder selected F:/python36/Scripts
You clicked Yes
You pressed Cancel

All types of popups are objects of respective classes inherited from popup class. All of them have a common set of properties. These properties have a certain default value, and can be used to customize the appearance and behaviour of the popup objects. Following table lists the common parameters −

Type Parameter Description
Any *args Values to be displayed on the popup
Str title Optional title for the window.
(str, str) or None button_color Color of the buttons shown (text color, button color)
Str background_color Window's background color
Str text_color text color
Bool auto_close If True the window will automatically close
Int auto_close_duration time in seconds to keep window open before closing it automatically
Bool non_blocking If True then will immediately return from the function without waiting for the user's input.
Tuple[font_name, size, modifiers] font specifies the font family, size, etc. Tuple or Single string format 'name size styles'.
Bool grab_anywhere If True can grab anywhere to move the window.
(int, int) Location Location on screen to display the top left corner of window. Defaults to window centered on screen
Bool keep_on_top If True the window will remain above all current windows
Bool modal If True, then makes the popup will behave like a Modal window. Default = True

Scrolled Popup

The popup_scrolled() function generates a popup with a scrollable text box in it. Use this to display a large amount of text, consisting of many lines with number of characters more than the width.

The size property is a tuple (w, h) with "w" being the number of characters in one line, and "h" being the lines displayed at a time. The horizontal/vertical scrollbar to the text box will become active if the number of characters/no of lines of text are more than "w" or "h".

In the following example, a big file zen.txt is displayed in a popup with scrollable text box. The file contains the design principles of Python called the "Zen of Python".

import PySimpleGUI as psg
file=open("zen.txt")
text=file.read()
psg.popup_scrolled(text, title="Scrolled Popup", font=("Arial Bold", 16), size=(50,10))

It will produce the following output

Scrolled Popup

Progress Meter

The "one_line_progress_meter" is a popup that displays the visual representation of an ongoing long process, such as a loop. It shows the instantaneous value of a certain parameter, estimated time to complete the process, and the elapsed time.

In the following example, a text file is read character by character. The Progress meter shows the progress of the process in the form of a progress bar, estimated time required for completion, and the instantaneous value of the count.

import PySimpleGUI as psg
import os
size = os.path.getsize('zen.txt')
file=open("zen.txt")
i=0
while True:
   text=file.read(1)
   i=i+1
   if text=="":
      file.close()
      break
   print (text,end='')
   psg.one_line_progress_meter(
      'Progress Meter', i, size,
      'Character Counter'
   )

It will produce the following output window −

Progress Meter

Debug Popup

During the execution of a program, it is usually required to keep track of intermediate values of certain variables, although not required in the following output. This can be achieved by the Print() function in PySimpleGUI library.

Note − Unlike Python’s built-in print() function, this function has "P" in uppercase).

As the program encounters this function for the first time, the debug window appears and all the subsequent Prints are echoed in it. Moreover, we can use EasyPrint or eprint that also have same effect.

The following program computes the factorial value of the number input by the user. Inside the for loop, we want to keep track of the values of f (for factorial) on each iteration. That is done by the Print function and displayed in the debug window.

import PySimpleGUI as psg
f=1
num=int(psg.popup_get_text("enter a number: "))
for x in range(1, num+1):
   f=f*x
   psg.Print (f,x)
print ("factorial of {} = {}".format(x,f))

Assuming that the user inputs 5, the debug window shows the following output

Debug Window

PySimpleGUI - Window Class

Popups have a predefined configuration of buttons, text labels and text input fields. The Window class allows you to design a GUI of more flexible design. In addition to these elements, other elements like listbox, checkbox, radio buttons, etc., are available. You can also provide a menu system to the GUI. Certain specialized widgets such as spinner, sliders, etc., can also be used to make the design more effective.

A window can be a non-persistent window, similar to the popups. It blocks the program flow till the user closes it by clicking a button on the client area or the close (X) button in the title bar.

A persistent window on the other hand continues to be visible till the event causing it to be closed occurs. The asynchronous window is the one whose contents are periodically updated.

Layout Structure

The placement of elements or widgets in the window’s client area is controlled by list of list objects. Each list element corresponds to one row on the window surface, and may contain one or more GUI elements available in PySimpleGUI library.

The first step is to visualize the placement of elements by making a drawing as follows −

Layout

The elements on the window are placed in four rows. First three rows have a Text element (displays a static text) and an InputText element (in which user can enter). Last row has two buttons, Ok and Cancel.

This is represented in the list of lists as below −

import PySimpleGUI as psg
layout = [
   [psg.Text('Name '),psg.Input()],
   [psg.Text('Address '), psg.Input()],
   [psg.Text('Email ID '), psg.Input()],
   [psg.OK(), psg.Cancel()]
]

This list object is used as the value of layout parameter for the constructor of the Window class.

window = psg.Window('Form', layout)

This will display the desired window. The user inputs are stored in a dictionary named as values. The read() method of Window class is called as the user presses the Ok button, and the window closes immediately.

The complete code to render the window is as follows −

import PySimpleGUI as psg
psg.set_options(font=('Arial Bold', 16))
layout = [
   [psg.Text('Name ', size=(15,1)),psg.Input(expand_x=True)],
   [psg.Text('Address ', size=(15,1)), psg.Input(expand_x=True)],
   [psg.Text('Email ID ', size=(15,1)), psg.Input(expand_x=True)],
   [psg.OK(), psg.Cancel()]
]
window = psg.Window('Form', layout, size=(715,207))
event, values = window.read()
print (event, values)
window.close()

Here is the output as displayed −

Layout Structure

Enter the data as shown and press the "OK" button. The values will be printed as below −

OK {0: 'Kiran Gupta', 1: 'Mumbai', 2: 'kiran@gmail.com'}

If, after filling the data, you press the "Cancel" button, the result printed will be −

Cancel {0: 'Kiran Gupta', 1: 'Mumbai', 2: 'kiran@gmail.com'}

Persistent Window

Note that this window gets closed as soon as any button (or the "X" button in the title bar) is clicked. To keep the window alive till a special type of button called Exit is pressed or if the window is closed by pressing "X", the read() method is placed in an infinite loop with provision to break when WIN_CLOSED event occurs (when Exit button is pressed) or Exit event occurs (when "X" button is pressed).

Let us change the Cancel button in the above code with Exit button.

import PySimpleGUI as psg
layout = [
   [psg.Text('Name '), psg.Input()],
   [psg.Text('Address '), psg.Input()],
   [psg.Text('Email ID '), psg.Input()],
   [psg.OK(), psg.Exit()]
]
window = psg.Window('Form', layout)
while True:
   event, values = window.read()
   if event == psg.WIN_CLOSED or event == 'Exit':
      break
   print (event, values)
window.close()

The appearance of the window will be similar as before, except that instead of Cancel, it has Exit button.

Persistent Window

The entered data will be printed in the form of a tuple. First element is the event, i.e., the caption of button, and second is a dictionary whose key is incrementing number and value is the text entered.

OK {0: 'kiran', 1: 'Mumbai', 2: 'kiran@gmail.com'}
OK {0: 'kirti', 1: 'Hyderabad', 2: 'kirti@gmail.com'}
OK {0: 'karim', 1: 'Chennai', 2: 'karim@gmail.com'}

Window Methods

The important method defined in the Window class is the read() method, to collect the values entered in all input elements. The Window class has other methods to customize the appearance and behaviour. They are listed below −

Sr.No. Method & Description
1 AddRow

Adds a single row of elements to a window's "self.Rows" variable

2 AddRows

Loops through a list of lists of elements and adds each row, list, to the layout.

3 close

Closes the window so that resources are properly freed up.

4 disable

Disables window from taking any input from the user

5 disappear

Causes a window to "disappear" from the screen, but remain on the taskbar.

6 enable

Re-enables window to take user input

7 fill

Fill in elements that are input fields with data provided as dictionary.

8 find_element

Find element object associated with the provided key. It is equivalent to "element = window[key]"

9 get_screen_dimensions

Get the screen dimensions.

10 hide

Hides the window from the screen and the task bar

11 load_from_disk

Restore values from a Pickle file created by the "SaveToDisk" function

12 layout

Populates the window with a list of widget lists.

13 read

Get all of your data from your Window. Pass in a timeout (in milliseconds) to wait.

14 reappear

Causes a disappeared window to display again.

15 save_to_disk

Saves the values contained in each of the input elements to a pickle file.

16 set_title

Change the title of the window in taskbar

Update Window with Key

The data entered by the user in different input elements on the window layout is stored in the dictionary format. The dictionary keys are numbered (starting from 0) corresponding to input elements from left to right and top to bottom. We can refer to the input data by dictionary operator. That means, the data in the first element is returned by "values[0]".

values = {0: 'kiran', 1: 'Mumbai', 2: 'kiran@gmail.com'}
data = [values[k] for k in values.keys()]
print (data)

It will print the following on the console −

['kiran', 'Mumbai', 'kiran@gmail.com']

However, if you want to manipulate the value of an element programmatically, the element must be initialized by assigning a unique string value to its key parameter. The key of an element is like the name of the variable or identifier, which makes it convenient to handle reading or assigning a value to it programmatically.

The key parameter should be a string. The convention is that it should be an uppercase string preceded and followed by a "-" character (Example: "- NAME-"). However, any string can be used.

Let us assign keys to the Input elements in the above example as shown below −

layout = [
   [psg.Text('Name '),psg.Input(key='-NM-')],
   [psg.Text('Address '), psg.Input(key='-AD-')],
   [psg.Text('Email ID '), psg.Input(key='-ID-')],
   [psg.OK(), psg.Exit()],
]

As a result, the values dictionary returned after the read() method will contain the key identifiers instead of integers previously.

OK {'-NM-': 'Kiran', '-AD-': 'Mumbai', '-ID-': 'kiran@gmail.com'}

Now, values[-NM-'] will fetch 'Kiran'. The key can be assigned to any element and not just the input element. You can use the same key to call Update on an element. We can use "find_element(key)" of the Window object, or use window['key'] to refer to the element.

Let us extend our previous example to add a row before the Ok and Cancel buttons and have an empty Text element with "-OUT-" key. On the OK event, this Text label shows the concatenation of data entered in three input elements having keys "-NM-", "-AD-" and "-ID-"

import PySimpleGUI as psg
psg.set_options(font=('Arial Bold', 16))
layout = [
   [psg.Text('Name ', size=(15, 1)),
   psg.Input(key='-NM-', expand_x=True)],
   [psg.Text('Address ', size=(15, 1)),
   psg.Input(key='-AD-', expand_x=True)],
   [psg.Text('Email ID ', size=(15, 1)),
   psg.Input(key='-ID-', expand_x=True)],
   [psg.Text('You Entered '), psg.Text(key='-OUT-')],
   [psg.OK(), psg.Exit()],
]
window = psg.Window('Form', layout, size=(715, 200))
while True:
   event, values = window.read()
   print(event, values)
   out = values['-NM-'] + ' ' + values['-AD-'] + ' ' + values['-ID-']
   window['-OUT-'].update(out)
   if event == psg.WIN_CLOSED or event == 'Exit':
      break
window.close()

Run the above code, enter text in three input elements and press OK. The -OUT- text label will be updated as shown here −

Update Window

Another example of use of key attribute is given below. To Input elements are assigned key parameters -FIRST- and -SECOND-. There are two buttons captioned Add and Sub. The Text element displays addition or subtraction of two numbers depending on the button pressed.

import PySimpleGUI as psg
import PySimpleGUI as psg
psg.set_options(font=('Arial Bold', 16))
layout = [
   [psg.Text('Enter a num: '), psg.Input(key='-FIRST-')],
   [psg.Text('Enter a num: '), psg.Input(key='-SECOND-')],
   [psg.Text('Result : '), psg.Text(key='-OUT-')],
   [psg.Button("Add"), psg.Button("Sub"), psg.Exit()],
]
window = psg.Window('Calculator', layout, size=(715, 180))
while True:
   event, values = window.read()
   print(event, values)
   if event == "Add":
      result = int(values['-FIRST-']) + int(values['-SECOND-'])
   if event == "Sub":
      result = int(values['-FIRST-']) - int(values['-SECOND-'])
   window['-OUT-'].update(result)
   if event == psg.WIN_CLOSED or event == 'Exit':
      break
window.close()

The following screenshot shows the result when the "Add" button is pressed.

Updated Window

Borderless Window

By default, the application window is created with a title bar above the client area wherein all other elements are placed in the layout. The titlebar consists of a window title on the left, and the control buttons (minimize, restore/maxmimize and close) on the right. However, particularly for a kiosk-like application, there is no need of a title bar. You can get rid of the title bar by setting the "no_titlebar" property of the Window object to "True".

Border Window

To terminate such an application, the event loop must be terminated on the occurrence of Exit button event.

Window with Disabled Close

If you wish to prevent the user to minimize the application window, the "disable_minimize" property of the Window object should be set to True. Similarly, the True value to "disable_close" property the Close button is displayed but it doesn’t create the WINDOW_CLOSED event.

Border Disabled

Transparent Window

The "alpha_channel" property of the Window object decides the transparency of the window. Its value is between 0 to 1. By default, it is 0, which means that the window appears as opaque. Set it to 1 to make it completely transparent. Any float value between 0 to 1 makes the transparency proportional.

Transparent Window

Multiple Windows

PySimpleGUI allows more than one windows to be displayed simultaneously. The static function in PySimpleGUI module reads all the active windows when called. To make the window active, it must be finalized. The function returns a tuple of (window, event, values) structure.

window, event, values = PySimpleGUI.read_all_windows()

If no window is open, its return value is (None, WIN_CLOSED, None)

In the following code, two functions "win1()" and "win2()" create a window each when called. Starting with the first window, the button captioned Window-2 opens another window, so that both are active. When CLOSED event on first window takes place, both are closed and the program ends. If the "X" button on second window is pressed, it is marked as closed, leaving the first open.

import PySimpleGUI as psg
def win1():
   layout = [
      [psg.Text('This is the FIRST WINDOW'), psg.Text('', key='-OUTPUT-')],
      [psg.Text('popup one')],
      [psg.Button('Window-2'), psg.Button('Popup'), psg.Button('Exit')]
   ]
   return psg.Window('Window Title', layout, finalize=True)
   def win2():
      layout = [
         [psg.Text('The second window')],
         [psg.Input(key='-IN-', enable_events=True)],
         [psg.Text(size=(25, 1), key='-OUTPUT-')],
         [psg.Button('Erase'), psg.popup('Popup two'), psg.Button('Exit')]]
         return psg.Window('Second Window', layout, finalize=True)
window1 = win1()
window2 = None
while True:
   window, event, values = psg.read_all_windows()
   print(window.Title, event, values)
   if event == psg.WIN_CLOSED or event == 'Exit':
      window.close()
   if window == window2:
      window2 = None
   elif window == window1:
      break
   elif event == 'Popup':
      psg.popup('Hello Popup')
   elif event == 'Window-2' and not window2:
      window2 = win2()
   elif event == '-IN-':
      window['-OUTPUT-'].update('You entered {}'.format(values["-IN-"]))
   elif event == 'Erase':
      window['-OUTPUT-'].update('')
      window['-IN-'].update('')
window.close()

It will produce the following output windows:

Multiple Windows

Asynchronous Window

The read() method of the Window class has the following additional parameters −

window.read(timeout = t, timeout_key=TIMEOUT_KEY, close=False)

The timeout parameter lets your GUIs to use in a non-blocking read situation. It is the miliseconds your device can wait before returning. It makes a window that runs on a periodic basis.

The longer you're able to add to the timeout value, the less CPU time you'll be taking. During the timeout time, you are "yielding" the processor to do other tasks. your GUI will be more responsive than if you used a nonblocking read.

The timeout_key parameter helps in deciding whether there has been any user action within the stipulated time. The default value of "timeout_key" is "__timeout__".

while True:
   event, value = window.read(timeout=10)
   if event == sg.WIN_CLOSED:
      break
   if event == sg.TIMEOUT_KEY:
      print("Nothing happened")

To make the window movable, set the "grab_anywhere" property of the Window object to true. If the "keep_on_top" property is set to True, the window will remain above the current windows.

PySimpleGUI - Element Class

The PySimpleGUI library consists of a number of GUI widgets that can be placed on top of the Window object. For instance, the buttons or the textboxes that we have used in the above examples. All these widgets are in fact objects of classes defined in this library, in which Element class acts as the base for all other widget classes.

An object of this Element class is never declared explicitly. It defines the common properties like size, color, etc. Here is the list of the available widgets (also called elements)

Sr.No. Widget & Description
1 Text Element

Display some text in the window. Usually this means a single line of text.

2 Input Element

Display a single text input field.

3 Multiline Element

Display and/or read multiple lines of text. This is both an input and output element.

4 Combo Element

A combination of a single-line input and a drop-down menu.

5 OptionMenu Element

Similar to Combo. Only on TKinter port

6 Checkbox Element

Displays a checkbox and text next to it.

7 Radio Element

Used in a group of other Radio Elements to provide user with ability to select only one choice in a list of choices.

8 Spin Element

A spinner with up/down buttons and a single line of text.

9 Button Element

Defines all possible buttons. The shortcuts such as Submit, FileBrowse, ... each create a Button

10 ButtonMenu element

Creates a button that when clicked will show a menu similar to right click menu.

11 Slider Element

Horizontal or vertical slider to increment/decrement a value.

12 Listbox Element

Provide a list of values for the user to choose one or more of. Returns a list of selected rows when a window.read() is executed.

13 Image Element

Show an image in the window. Should be a GIF or a PNG only.

14 Graph Element

Creates area to draw graph

15 Canvas Element

An area to draw shapes

16 ProgressBar Element

Displays a colored bar that is shaded as progress of some operation is made.

17 Table Element

Display data in rows and columns

18 Tree Element

Presents data in a tree-like manner, much like a file/folder browser.

19 Sizer Element

This element is used to add more space.

20 StatusBar Element

A StatusBar Element creates the sunken text-filled strip at the bottom.

21 Frame Element

The Frame element is a container object that holds on or more elements of other types.

22 Column Element

It is very useful if you want to design the GUI window elements represented in one or more vertical columns.

23 Tab Element

The use of Tab elements makes the design very convenient, effective and easy for the user to navigate. Tab element is also a container element such as Frame or Column.

Properties of Element Class

Following are the properties of the Element Class −

Sr.No. Property & Description
1 size

(w=characters-wide, h=rows-high)

2 font

specifies the font family, size

3 background_color

color of background

4 text_color

element's text color

5 key

Identifies an Element

6 visible

set visibility state of the element (Default = True)

Methods of Element Class

Following are the methods of the Element Class −

Sr.No. Method & Description
1 set_tooltip()

Called by application to change the tooltip text for an Element

2 set_focus()

Sets the current focus to be on this element

3 set_size()

Changes the size of an element to a specific size

4 get_size()

Return the size of an element in Pixels

5 expand()

Causes the Element to expand to fill available space in the X and Y directions

6 set_cursor()

Sets the cursor for the current Element

7 set_right_click_menu()

Sets right click menu to be invoked when clicked

PySimpleGUI - Events

Any GUI application is event driven, having the ability to respond to the various possible events occurring on the GUI elements. In PySimpleGUI, the event handling is done inside an infinite loop below the constitution of GUI design, continuously checking whether an event occurs and perform the actions based on the event.

There are two types of events −

  • Window events, and

  • Element events.

The window events are enabled by default, and include the button events (occur when any button is clicked) and the event of the "X" button on the titlebar clicked.

The element events are not enabled by default. Element-specific events can be detected only when the "enable_events" parameter is set to True when an element is created.

Window Closed Event

The infinite event loop that makes the PySimpleGUI window persistent, is terminated when the user presses the "X" button, or the close() method of Window class is executed. The standard way of terminating the loop is as follows −

import PySimpleGUI as psg
...
while True:
 ...

   if event == psg.WIN_CLOSED:
      break
 ...
window.close()

The Widow class also emits an "enable_close_attempted_event" if this parameter is set to True. It is a good practice to call yes-no popup when it is detected inside the loop.

window = psg.Window('Calculator', layout,  enable_close_attempted_event=True)
while True:
   event, values = window.read()
   print(event, values)
   if event == "Add":
      result = int(values['-FIRST-']) + int(values['-SECOND-'])
   if event == "Sub":
      result = int(values['-FIRST-']) - int(values['-SECOND-'])
   window['-OUT-'].update(result)
   if event == psg.WINDOW_CLOSE_ATTEMPTED_EVENT and psg.popup_yes_no('Do you really want to exit?') == 'Yes':
      break
   if event == psg.WIN_CLOSED or event == 'Exit':
      break

In this case, as the "X" button is pressed, the Popup with Yes/No button appears and the program exits when the "Yes" button is clicked.

It will produce the following output window −

Window Closed Event

The event value also returns the "-WINDOW CLOSE ATTEMPTED-" value.

-WINDOW CLOSE ATTEMPTED- {'-FIRST-': '200', '-SECOND-': '300'}

Button Events

The button click event is enabled by default. To disable, use "Button.update(disabled=True)". You can also set "enable_events=True" in Button’s constructor, it will enable the Button Modified event. This event is triggered when something 'writes' to a button.

When we read the contents of the window (using "window.read()"), the button value will be either its caption (if key is not set) or key if it is set.

In the above example, since the key parameter is not set on the Add and Sub buttons, their captions are returned when the window is read.

Add {'-FIRST-': '200', '-SECOND-': '300'}

Add key parameters to Add and Sub buttons in the program.

import PySimpleGUI as psg
layout = [
   [psg.Text('Enter a num: '), psg.Input(key='-FIRST-')],
   [psg.Text('Enter a num: '), psg.Input(key='-SECOND-')],
   [psg.Text('Result : '), psg.Text(key='-OUT-')],
   [psg.Button("Add", key='-ADD-'), psg.Button("Sub", key='- SUB-'), psg.Exit()],
]
window = psg.Window('Calculator', layout)
while True:
   event, values = window.read()
   print(event, values)

   if event == "-ADD-":
      result = int(values['-FIRST-']) + int(values['-SECOND-'])

   if event == "-SUB-":
      result = int(values['-FIRST-']) - int(values['-SECOND-'])

   window['-OUT-'].update(result)

   if event == psg.WIN_CLOSED or event == 'Exit':
      break
window.close()

The tuple returned by the read() method will now show the key of button pressed.

-ADD- {'-FIRST-': '200', '-SECOND-': '300'}

Events of Other Elements

Many of the elements emit events when some type of user interaction takes place. For example, when a slider is moved, or an item from the list is selected on or a radio button is clicked on.

Unlike Button or Window, these events are not enabled by default. To enable events for an Element, set the parameter "enable_events=True".

The following table shows the elements and the events generated by them.

Name Events
InputText any key pressed
Combo item selected
Listbox selection changed
Radio selection changed
Checkbox selection changed
Spinner new item selected
Multiline any key pressed
Text Clicked
Status Bar Clicked
Graph Clicked
Graph Dragged
Graph drag ended (mouse up)
TabGroup tab clicked
Slider slider moved
Table row selected
Tree node selected
ButtonMenu menu item chosen
Right click menu menu item chosen

PySimpleGUI - Menubar

Most of the desktop applications have a menu system to trigger different operations based on user’s choice of options in the menu. In a typical application window, the menu bar is placed just below the title bar and above the client area of the window.

A menubar is a horizontal bar consisting of clickable buttons. When any of these buttons is clicked it generates a pull down list of option buttons. Such an option button triggers a click event which can be processed inside an event loop.

The menu system is designed just as the window layout is specified. It is also a list of lists. Each list has one or more strings. The starting string of the list at the first level is the caption for the button appearing in the horizontal menu bar. It is followed by a list of caption strings for the option buttons in the drop down menu. These option captions are in a list inside the first level list.

You may have a sub-menu under an option button, in which case the captions are put in a third level list. Likewise, the captions can be nested up to any level.

The general format of a menu definition is as follows:

menu_def = [
   ['Memu1', ['btn1', 'btn2', 'btn3', 'btn4',]],
   ['menu2', ['btn5', 'btn6','btn7', 'btn8'],],
]

To attach the menu system to the main layout of PysimpleGUI window, place the Menu object in the first row of the layout.

The Menu constructor is given the menu_def list as the argument. Other rows of the main layout may be given after the row having Menu object.

layout= [[psg.Menu(menu_def),[..], [..]]

In the code given below, we have a menu bar with File, Edit and Help menus, each having a few menu buttons in respective menu bar.

import PySimpleGUI as psg
menu_def = [['File', ['New', 'Open', 'Save', 'Exit', ]], ['Edit', ['Cut', 'Copy', 'Paste', 'Undo'], ],  ['Help', 'About...'], ]
layout = [[psg.Menu(menu_def)],
   [psg.Multiline("", key='-IN-',
   expand_x=True, expand_y=True)],
   [psg.Multiline("", key='-OUT-',
   expand_x=True, expand_y=True)],
   [psg.Text("", key='-TXT-',
   expand_x=True, font=("Arial Bold", 14))]
]
window = psg.Window("Menu", layout, size=(715, 300))
while True:
   event, values = window.read()
   print(event, values)

   if event != psg.WIN_CLOSED:
      window['-TXT-'].update(values[0] + "Menu Button Clicked")
   if event == 'Copy':
      txt = window['-IN-'].get()
   if event == 'Paste':
      window['-OUT-'].update(value=txt)
   if event == psg.WIN_CLOSED:
      break
window.close()

Below the Menubar, two Multiline elements are placed. The last row has a Text element.

When any menu option button is clicked, the event so generated is the caption of the button. This caption is displayed on the Text label in the last row. Refer to the following figure −

Menu Bar Display

When the Copy event occurs, the text in the upper multiline box with -INkey is stored in a txt variable. Afterwards, when Paste button is pressed, the -OUT- box is updated with the value of txt.

Menu Bar Edit

Menu button with Hot Key

To map a menu button with a key on the keyboard, put an ampersand & character before the desired character. For example, put & before File so that the string is '&File'. By doing so, the File menu can be accessed by pressing "Alf+F" key. Here "F" key is said to be a hot key.

Add hot keys to the menu buttons in our menu definition.

menu_def = [
   ['&File', ['&New', '&Open', '&Save', 'E&xit',]],
   ['&Edit', ['C&ut', '&Copy','&Paste', '&Undo'],],
   ['&Help', '&About...'],
]

When the code is run, the hot keys in the menu are shown as underlined.

Menu Button Hot Key

Right-click Menu

This menu is detached from the menubar which is at the top of the application window. Whenever the user presses the right click button of the mouse, this menu pops up at the same position where the click takes place.

In the menubar defined above, each list is a definition of a single menu. Such single menu definition can be attached to any element by the right_click_menu parameter in the constructor. This parameter can also be passed while constructing the main Window object.

Let us use rightclick as a variable for the list corresponding to the Edit menu.

rightclick=['&Edit', ['C&ut', '&Copy','&Paste', '&Undo']]
menu_def = [
   ['&File', ['&New', '&Open', '&Save', 'E&xit',]], rightclick,
   ['&Help', '&About...'],
]

Use it as the value of right_click_menu parameter in the Window constructor. See the following snippet −

window=psg.Window("Menu", layout, size=(715, 300), right_click_menu=rightclick)

Make these changes and run the code. Click anywhere in the window. The menu pops up as shown −

Right Click Menu

ButtonMenu

This menu is similar to the right click menu, except that it is attached to a button and pops up when the button is clicked.

In the last row of the main layout, we add a ButtonMenu element and use the rightclick list as its layout.

layout= [
   [psg.Menu(menu_def)],
   [psg.Multiline("", key='-IN-', expand_x=True, expand_y=True)],
   [psg.Multiline("", key='-OUT-', expand_x=True, expand_y=True)],
   [psg.Text("", key='-TXT-', expand_x=True, font=("Arial Bold", 14)),
   psg.ButtonMenu('ButtonMenu', rightclick, key='-BMENU-')]
]

When the button at the lower right is clicked, the menu comes up as can be seen in the following figure −

ButtonMenu

PySimpleGUI - Matplotlib Integration

When Matplotlib is used from Python shell, the plots are displayed in a default window. The backend_tkagg module is useful for embedding plots in Tkinter.

The Canvas element in PySimpleGUI has TKCanvas method that returns original TKinter's Canvas object. It is given to the FigureCanvasTkAgg() function in the backend_tkagg module to draw the figure.

First, we need to create the figure object using the Figure() class and a plot to it. We shall draw a simple plot showing sine wave.

fig = matplotlib.figure.Figure(figsize=(5, 4), dpi=100)
t = np.arange(0, 3, .01)
fig.add_subplot(111).plot(t, 2 * np.sin(2 * np.pi * t))

Define a function to draw the matplotlib figure object on the canvas

def draw_figure(canvas, figure):
   figure_canvas_agg = FigureCanvasTkAgg(figure, canvas)
   figure_canvas_agg.draw()
   figure_canvas_agg.get_tk_widget().pack(side='top', fill='both', expand=1)
   return figure_canvas_agg

Obtain the Canvas from PySimpleGUI.Canvas object by calling its TkCanvas property.

layout = [
   [psg.Text('Plot test')],
   [psg.Canvas(key='-CANVAS-')],
   [psg.Button('Ok')]
]

Draw the figure by calling the above function. Pass the Canvas object and fifure object to it.

fig_canvas_agg = draw_figure(window['-CANVAS-'].TKCanvas, fig)

Example: Draw a Sinewave Line graph

The complete code is given below −

import matplotlib.pyplot as plt
import numpy as np
from matplotlib.backends.backend_tkagg import
FigureCanvasTkAgg
import PySimpleGUI as sg
import matplotlib
matplotlib.use('TkAgg')
fig = matplotlib.figure.Figure(figsize=(5, 4), dpi=100)
t = np.arange(0, 3, .01)
fig.add_subplot(111).plot(t, 2 * np.sin(2 * np.pi * t))
def draw_figure(canvas, figure):
   tkcanvas = FigureCanvasTkAgg(figure, canvas)
   tkcanvas.draw()
   tkcanvas.get_tk_widget().pack(side='top', fill='both', expand=1)
   return tkcanvas
layout = [[sg.Text('Plot test')],
   [sg.Canvas(key='-CANVAS-')],
   [sg.Button('Ok')]]
window = sg.Window('Matplotlib In PySimpleGUI', layout, size=(715, 500), finalize=True, element_justification='center', font='Helvetica 18')

# add the plot to the window
tkcanvas = draw_figure(window['-CANVAS-'].TKCanvas, fig)
event, values = window.read()
window.close()

The generated graph is as follows −

Sinewave Graph

PySimpleGUI - Working with PIL

Python Imaging Library is a free, cross-platform and open-source library for the Python programming language that has the functionality for opening, manipulating, and saving many different image file formats.

To install it, use the PIP command as follows −

pip3 install pillow

In the following example, we obtain the byte value of the PNG image with PIL function and display the same in Image element on a PySimpleGUI window.

import PySimpleGUI as sg
import PIL.Image
import io
import base64
def convert_to_bytes(file_or_bytes, resize=None):
   img = PIL.Image.open(file_or_bytes)
   with io.BytesIO() as bio:
      img.save(bio, format="PNG")
      del img
      return bio.getvalue()

imgdata = convert_to_bytes("PySimpleGUI_logo.png")
layout = [[sg.Image(key='-IMAGE-', data=imgdata)]]
window = sg.Window('PIL based Image Viewer', layout,resizable=True)
while True:
   event, values = window.read()
   if event == sg.WIN_CLOSED:
      break
window.close()

It will produce the following output window −

Working with PIL

PySimpleGUI - Debugger

In addition to the built-in debugger that most IDEs such as PyCharm or VS Code have, PySimpleGUI offers its own debugger. This debugger provides you the ability to "see" and interact with your code, while it is running.

To use the debugger service effectively, the window should be red asynchronously, i.e., you should provide a timeout to the read() function.

The debugger window is invoked by calling show_debugger_window() function anywhere inside the program as shown below −

import PySimpleGUI as sg
sg.show_debugger_window(location=(10,10))
window = sg.Window('Debugger Demo',
   [[sg.Text('Debugger'),
   sg.Input('Input here'),
   sg.Button('Push Me')]]
)
while True:
   event, values = window.read(timeout=500)
   if event == sg.TIMEOUT_KEY:
      continue
   if event == sg.WIN_CLOSED:
      break
   print(event, values)
window.close()

The PySimpleGUI debugger window appears at the specified screen location.

GUI Debugger

The window shows two tabs Variables and REPL. Click on the Variables tab. A list of variables to auto-watch is shown Check the ones that you want to watch during the execution of the program.

GUI Debugger All Locals

The second tab about REPL gives a Python interactive console to be executed around your program’s environment so that you can inspect the values of desired variables in the code.

PysimpleGUI Debugger

PySimpleGUI - Settings

Global Settings

Global settings are the application settings available application wide. These settings control the various properties of the Element class to be applied to all the Elements in the application.

These settings work in hierarchical manner. The global settings are overridden if those settings are given different value for a window. In turn the settings defined in Window object are given different value for a specific element.

For example, if the font size is set to 16 globally, the text of all elements is displayed accordingly. However, if a specific Text or Input element with Font property with size other than 16 is defined in the layout, it will change the appearance accordingly.

The function set_options is used to change settings that will apply globally. If it's a setting that applies to Windows, then that setting will apply not only to Windows that you create, but also to popup Windows.

import PySimpleGUI as sg
sg.set_options(font=('Arial Bold', 16))

User Settings

"User settings" is a dictionary that is automatically written to your hard drive. User settings are stored in a Python dictionary which is saved to and loaded from the disk. Individual settings are thus keys into a dictionary.

List of user setting functions −

Sr.No. Function & Description
1 user_settings

Returns settings as a dictionary

2 user_settings_delete_entry

Deletes a setting

3 user_settings_delete_filename

Deletes the settings file

4 user_settings_file_exists

Returns True if settings file specified exists

5 user_settings_filename

Returns full path and filename of settings file

6 user_settings_get_entry

Returns value for a setting. If no setting found, then specified default value is returned

7 user_settings_load

Loads dictionary from the settings file.

8 user_settings_save

Saves settings to current or newly specified file.

9 user_settings_set_entry

Sets an entry to a particular value

10 user_settings_write_new_dictionary

Writes a specified dictionary to settings file

Create the User Settings object.

settings = sg.UserSettings()

Use the dictionary-style [ ] syntax to read a setting. If the item's name is '- item-', then reading the value is achieved by writing

item_value = settings['-item-']

Following sttement is used to Write the setting.

settings['-item-'] = new_value

To delete an item, again the dictionary style syntax is used.

del settings['-item-']

You can also call the delete_entry method to delete the entry.

settings.delete_entry('-item-')

The following simple program demonstrates load/saving of user settings

import PySimpleGUI as sg
import json
sg.set_options(font=('Arial Bold', 16))
layout = [
   [sg.Text('Settings', justification='left')],
   [sg.Text('User name', size=(10, 1), expand_x=True),
   sg.Input(key='-USER-')],
   [sg.Text('email ID', size=(10, 1), expand_x=True),
   sg.Input(key='-ID-')],
   [sg.Text('Role', size=(10, 1), expand_x=True),
   sg.Input(key='-ROLE-')],
   [sg.Button("LOAD"), sg.Button('SAVE'), sg.Button('Exit')]
]
window = sg.Window('User Settings Demo', layout, size=(715, 200))
# Event Loop
while True:
   event, values = window.read()
   if event in (sg.WIN_CLOSED, 'Exit'):
      break
   if event == 'LOAD':
      f = open("settings.txt", 'r')
      settings = json.load(f)
      window['-USER-'].update(value=settings['-USER-'])
      window['-ID-'].update(value=settings['-ID-'])
      window['-ROLE-'].update(value=settings['-ROLE-'])
   if event == 'SAVE':
      settings = {'-USER-': values['-USER-'],
      '-ID-': values['-ID-'],
      '-ROLE-': values['-ROLE-']}
      f = open("settings.txt", 'w')
      json.dump(settings, f)
      f.close()
window.close()

Enter the data in the input boxes and click the "Save" button.

PysimpleGUI Settings

A JSON file will be saved. To load the previously saved settings, click the "Load" button.

Advertisements