Same Code for Python GUI and Web Apps

The Python PySimpleGUI project has two main goals:

  • A simpler method for creating graphical interfaces, and
  • Common code for Tkinter, QT, xW and Web graphics

I feel comfortable doing my own Tkinter and Web interfaces, but common code for both is very cool and it could be very useful for Rasp Pi applications. However things didn’t work “out of the box”, so this blog will look at some workarounds and issues.

A Simple Example

If you are used to coding in QT or xW PySimple is absolutely easier to use.

PySimpleGUI has some defined graphic objects (like Text or Button) and the screen placement is defined by how they are grouped with [ ] brackets. For example two objects in a [ ] bracket puts the two objects on the same line. 

If you’re a Tkinter user PySimpleGUI may seem a little more cumbersome in it’s layout design. (I find Tkinter’s grid methods to be a superior layout approach).

For my first example I used the published example and I added an option for the graphic method (tkinter, Qt, Wx and Web):

 import sys, random, time  
   
 mode = "tkinter"  
 # Check for command line arguments   
 if len(sys.argv) > 1: # if there is use the Web Interface  
   if sys.argv[1] == 'web':  
     import PySimpleGUIWeb as sg  
     mode = "Web"  
   elif sys.argv[1] == 'wx':  
     import PySimpleGUIWx as sg  
     mode = "Wx"  
   elif sys.argv[1] == 'qt':  
     import PySimpleGUIQt as sg  
     mode = "Qt"  
   else:  
     import PySimpleGUI as sg  
   
 else: # if no arguments use the standard GUI  
   import PySimpleGUI as sg  
   
 # Basic example from PySimpleGUI
   
 sg.change_look_and_feel('DarkAmber')  # Add a touch of color  
 # All the stuff inside your window.  
 layout = [ [sg.Text('Some text on Row 1')],  
       [sg.Text('Enter something on Row 2'), sg.InputText()],  
       [sg.Button('Ok'), sg.Button('Cancel')] ]  
   
 # Create the Window  
 window = sg.Window('PySimpleGUI ' + mode , layout)  
 # Event Loop to process "events" and get the "values" of the inputs  
 while True:  
   event, values = window.read()  
   if event in (None, 'Cancel'):  # if user closes window or clicks cancel  
     break  
   print('You entered ', values[0])  
   
 window.close()  
 print('Program terminating normally')  
   

The output for the different graphic methods looks incredibly similar for this example:

GUI_wxGUI_webGUI_tkGUI_qt

It’s important to note that PySimpleGUI is still under development so many of the features will be in transition. If you stick to basic functions like: buttons, images and text you should be good.

I found that the default Tkinter version to be very solid, and the other versions would complain on some of the added features such as: frames, sliders, and progressbars.

A Realtime Update Example

For my next example I wanted to do a Rasp Pi type example with some simulated values from a temperature sensor.

To write back to a graphic object:

  • define a key name when the object is defined (key = “myojbname”)
  • use:  window[‘myojbname’]( new_value) to update the object
 import sys, random, time  
   
 mode = "tkinter"  
 # Check for command line arguments   
 if len(sys.argv) > 1: # if there is use the Web Interface  
   if sys.argv[1] == 'web':  
     import PySimpleGUIWeb as sg  
     mode = "Web"  
   elif sys.argv[1] == 'wx':  
     import PySimpleGUIWx as sg  
     mode = "Wx"  
   elif sys.argv[1] == 'qt':  
     import PySimpleGUIQt as sg  
     mode = "Qt"  
   else:  
     import PySimpleGUI as sg  
   
 else: # if no arguments use the standard GUI  
   import PySimpleGUI as sg  
   
 # Basic example of PSGWeb  
   
 def main():  
   sg.change_look_and_feel('LightGrey')  
   dataframe = [  
     [sg.Text('Temperature (C):',size=(12,2)),  
     sg.Text(' ', font='Courier 48', text_color='red', key='degC')],  
     [sg.Text('Humidity (%)  :',size=(12,2)),  
     sg.Text(' ', font='Courier 48', text_color='red', key='humid')],  
       
   ]  
   layout = [  
     [sg.Image(filename = "dht11.png"),sg.Frame("DHT11 Sensor", dataframe,font='Any 12', title_color='blue')]  
     ]  
     
   if mode == "web":  # Note: customization on the Web interface
     window = sg.Window('Pi Weather Data ' + mode, layout,web_ip='192.168.0.107', web_port = 8888, web_start_browser=False, disable_close=True)  
   else:  
     window = sg.Window('Pi Weather Data ' + mode, layout)  
     
   while True:  
     event, values = window.read(timeout=10)  
     temp_degC = random.randint(20,30)  
     humidity = random.randint(0,100)  
     window['degC']( temp_degC)  
     window['humid'](humidity)  
     time.sleep(1)  
       
   window.close()  
   
 main()  
 print('Program terminating normally')  
   

The Wx code would not run, and the development team has commented on compatibility issues that they are having with Wx so future support may be dropped.

The Tkinter and Qt, but for this example the Web presentation dropped the frame outline.

GUI2_qtGUI2_tkGUI2_web

PySimpleGUIWeb

The PySimpleGUIWeb project is based on the Remi Project which defines graphics objects in an HTML/Web environment.

One big difference that I found between the Remi project and PySimpleGUIWeb is that Remi supports callbacks. I found that callbacks are extremely useful if you are trying to mix reads and writes in the same application. PySimpleGUI uses a read to get user input but this gets confusing if you are using a timer for writing new data to the GUI.

The PySimpleGUIWeb library by default was missing some key documentation. I found that “out of the box” it wasn’t usable for my applications . However everything that I needed was in the Window class it just wasn’t clearly documented.

The following web features can be controlled:

  • web_ip=’xx.xx.xx.xx’ , default is localhost (127.0.0.1), not good for remote connections.
  • web_port= xxxx , default is a random port id. Again not useful for remote connections.
  • web_start_browser=False, default a web browser is launched (not useful for SSH).
  • disable_close=True , default closes the app when the web browser closes.

An example to open a Web connection (not local) that doesn’t auto-open a browser and stays open would be:

window = sg.Window('Pi Weather Data ',  layout,web_ip='192.168.0.107', web_port = 8888, web_start_browser=False, disable_close=True)

Final Thoughts

I like the concept of the same code being used on both a Tkinter and a Web  app. I believe that this has a lot of potential. However at this point only the simplest features are available in the Web, so I’d rather use a Python Web framework like Bottle.

I really like some of the concepts of PySimpleGUI but I think that understanding and using the standard Tkinter allows you more flexibility and it lets you include add-in modules like Tk_tools.