New Recipes Toolbars, Explanation of the "Event Loop"

This commit is contained in:
MikeTheWatchGuy 2018-09-12 18:31:39 -04:00
parent 57396f3dc1
commit bb990fca05
4 changed files with 171 additions and 9 deletions

View File

@ -5,11 +5,11 @@ import PySimpleGUI as sg
"""
sg.SetOptions(element_padding=(0,0))
sg.ChangeLookAndFeel('Dark')
# sg.ChangeLookAndFeel('Dark')
# --- Define our "Big-Button-Spinner" compound element. Has 2 buttons and an input field --- #
NewSpinner = [sg.ReadFormButton('-', size=(4,1), font='Any 12'),
sg.In('0', size=(5,1), font='Any 14', justification='r', key='spin'),
sg.ReadFormButton('+', size=(4,1), font='Any 12')]
NewSpinner = [sg.ReadFormButton('-', size=(2,1), font='Any 12'),
sg.In('0', size=(2,1), font='Any 14', justification='r', key='spin'),
sg.ReadFormButton('+', size=(2,1), font='Any 12')]
# --- Define Window --- #
layout = [
[sg.Text('Spinner simulation')],

View File

@ -1004,11 +1004,23 @@ Use the upper half to generate your hash code. Then paste it into the code in t
## Desktop Floating Toolbar
#### Hiding your windows commmand window
For this and the Time & CPU Widgets you may wish to consider using a tool or technique that will hide your Windows Command Prompt window. I recommend the techniques found on this site:
[http://www.robvanderwoude.com/battech_hideconsole.php](http://www.robvanderwoude.com/battech_hideconsole.php)
At the moment I'm using the technique that involves wscript and a script named RunNHide.vbs. They are working beautifully. I'm using a hotkey program and launch by using this script with the command "python.exe insert_program_here.py". I guess the next widget should be one that shows all the programs launched this way so you can kill any bad ones. If you don't properly catch the exit button on your form then your while loop is going to keep on working while your window is no longer there so be careful in your code to always have exit explicitly handled.
### Floating toolbar
This is a cool one! (Sorry about the code pastes... I'm working in it)
Impress your friends at what a tool-wizard you are by popping a custom toolbar that you keep in the corner of your screen. It stays on top of all your other windows.
![toolbar gray](https://user-images.githubusercontent.com/13696193/45324308-bfb73700-b51b-11e8-90e7-ab24f3d6e61d.jpg)
You can easily change colors to match your background by changing a couple of parameters in the code.
@ -1091,12 +1103,13 @@ You can easily change colors to match your background by changing a couple of pa
## Desktop Floating Widget
## Desktop Floating Widget - Timer
This is a little widget you can leave running on your desktop. Will hopefully see more of these for things like checking email, checking server pings, displaying system information, dashboards, etc
.
Much of the code is handling the button states in a fancy way. It could be much simpler if you don't change the button text based on state.
![timer](https://user-images.githubusercontent.com/13696193/45336349-26a31300-b551-11e8-8b06-d1232ff8ca10.jpg)
import PySimpleGUI as sg
import time
@ -1159,6 +1172,49 @@ Much of the code is handling the button states in a fancy way. It could be much
form.CloseNonBlockingForm()
## Desktop Floating Widget - CPU Utilization
Like the Timer widget above, this script can be kept running. You will need the package psutil installed in order to run this Recipe.
The spinner changes the number of seconds between reads.
![cpu widget 2](https://user-images.githubusercontent.com/13696193/45456096-77348080-b6b7-11e8-8906-6663c31ad0eb.jpg)
import PySimpleGUI as sg
import psutil
# ---------------- Create Form ----------------
sg.ChangeLookAndFeel('Black')
form_rows = [[sg.Text('')],
[sg.Text('', size=(8, 2), font=('Helvetica', 20), justification='center', key='text')],
[sg.Exit(button_color=('white', 'firebrick4'), pad=((15,0), 0)), sg.Spin([x+1 for x in range(10)], 1, key='spin')]]
# Layout the rows of the form and perform a read. Indicate the form is non-blocking!
form = sg.FlexForm('Running Timer', no_titlebar=True, auto_size_buttons=False, keep_on_top=True, grab_anywhere=True)
form.Layout(form_rows)
# ---------------- main loop ----------------
while (True):
# --------- Read and update window --------
button, values = form.ReadNonBlocking()
# --------- Do Button Operations --------
if values is None or button == 'Exit':
break
try:
interval = int(values['spin'])
except:
interval = 1
cpu_percent = psutil.cpu_percent(interval=interval)
# --------- Display timer in window --------
form.FindElement('text').Update(f'CPU {cpu_percent:02.0f}%')
# Broke out of main loop. Close the window.
form.CloseNonBlockingForm()
## Menus

View File

@ -137,8 +137,9 @@ The `PySimpleGUI` package is focused on the ***developer***. Create a custom GU
Bulk form-fill operation
Save / Load form to/from disk
Borderless (no titlebar) windows
Always on top
Always on top windows
Menus
No async programming required (no callbacks to worry about)
An example of many widgets used on a single form. A little further down you'll find the TWENTY lines of code required to create this complex form. Try it if you don't believe it. Start Python, copy and paste the code below into the >>> prompt and hit enter. This will pop up...
@ -181,6 +182,7 @@ You will see a number of different styles of buttons, data entry fields, etc, in
---
### Design Goals
> Copy, Paste, Run.
`PySimpleGUI's` goal with the API is to be easy on the programmer, and to function in a Python-like way. Since GUIs are visual, it was desirable for the code to visually match what's on the screen.
@ -188,12 +190,16 @@ You will see a number of different styles of buttons, data entry fields, etc, in
> Be Pythonic
Be Pythonic... Attempted to use language constructs in a natural way and to exploit some of Python's interesting features. Python's lists and optional parameters make PySimpleGUI work.
- Forms are represented as Python lists.
- A form is a list of rows
- A row is a list of elements
- Return values are a list of button presses and input values.
- Return values can also be represented as a dictionary
- The SDK calls collapse down into a single line of Python code that presents a custom GUI and returns values
- Linear programming instead of callbacks
-----
@ -593,7 +599,7 @@ The third is the 'compact form'. It compacts down into 2 lines of code. One li
You will use these design patterns or code templates for all of your "normal" (blocking) types of input forms. Copy it and modify it to suit your needs. This is the quickest way to get your code up and running with PySimpleGUI. This is the most basic / normal of the design patterns.
### How GUI Programming in Python Should Look?
### How GUI Programming in Python Should Look? At least for beginners
Why is Python such a great teaching language and yet no GUI framework exists that lends itself to the basic building blocks of Python, the list or dictionary? PySimpleGUI set out to be a Pythonic solution to the GUI problem. Whether it achieved this goal is debatable, but it was an attempt just the same.
@ -747,6 +753,53 @@ This sample program demonstrates these 2 steps as well as how to address the ret
sg.Popup(button, values, values[0], values['address'], values['phone'])
## The Event Loop / Callback Functions
All GUIs have a few things in common, one of them being an "event loop" of some sort. If your program shows a single form, collects the data and then executes the primary code of the program then you likely don't need an event loop. This simple scenarios are front-end GUIs where you call sg.GetFile for example and then call your program that does something with the file.
Event Loops are used in programs where the window stays open after button presses. The program processes button clicks a loop. You often hear the term event loop when discussing embedded systems or on a Raspberry Pi. Let's take a Pi demo program as an example. This program shows a GUI window, gets button presses, and uses them to control some LEDs. It loops, reading user input and doing something with it.
This little program has a typical Event Loop
![pi leds](https://user-images.githubusercontent.com/13696193/45448517-8cea7b80-b6a0-11e8-8dbe-eeefea2e93c1.jpg)
import PySimpleGUI as sg
layout = [[sg.T('Raspberry Pi LEDs')],
[sg.ReadFormButton('Turn LED On')],
[sg.ReadFormButton('Turn LED Off')],
[sg.Exit()]]
form = sg.FlexForm('Raspberry Pi GUI', grab_anywhere=False)
form.Layout(layout)
# ---- Event Loop ---- #
while True:
button, values = form.Read()
# ---- Process Button Clicks ---- #
if button is None or button == 'Exit':
break
if button == 'Turn LED Off':
turn_LED_off()
elif button == 'Turn LED On':
turn_LED_on()
# ---- After Event Loop ---- #
sg.Popup('Done... exiting')
In the Event Loop we are reading the form and then doing a series of button compares to determine what to do based on the button that was clicks (value of `button` variable)
The way buttons are presented to the caller in PySimpleGUI is ***not*** how *most* GUI frameworks handle button clicks. Most GUI frameworks, including tkinter, use ***callback*** functions. A function you define would be called when a button is clicked. This requires you to write code where data is shared between these callback functions. There is a lot more communications that have to happen between parts of your program.
One of the larger hurdles for beginners to GUI programming are these callback functions. PySimpleGUI was specifically designed in a way that callbacks would not be required. There is no coordination between one function and another required. You simple read your button click and take appropriate action.
Whether or not this is a "proper" design for GUI programs can be debated. It's not a terrible tradeoff to run your own event loop and having a functioning GUI application versus one that maybe never gets written because callback functions were too much to grasp.
---
## All Widgets / Elements

View File

@ -137,8 +137,9 @@ The `PySimpleGUI` package is focused on the ***developer***. Create a custom GU
Bulk form-fill operation
Save / Load form to/from disk
Borderless (no titlebar) windows
Always on top
Always on top windows
Menus
No async programming required (no callbacks to worry about)
An example of many widgets used on a single form. A little further down you'll find the TWENTY lines of code required to create this complex form. Try it if you don't believe it. Start Python, copy and paste the code below into the >>> prompt and hit enter. This will pop up...
@ -181,6 +182,7 @@ You will see a number of different styles of buttons, data entry fields, etc, in
---
### Design Goals
> Copy, Paste, Run.
`PySimpleGUI's` goal with the API is to be easy on the programmer, and to function in a Python-like way. Since GUIs are visual, it was desirable for the code to visually match what's on the screen.
@ -188,12 +190,16 @@ You will see a number of different styles of buttons, data entry fields, etc, in
> Be Pythonic
Be Pythonic... Attempted to use language constructs in a natural way and to exploit some of Python's interesting features. Python's lists and optional parameters make PySimpleGUI work.
- Forms are represented as Python lists.
- A form is a list of rows
- A row is a list of elements
- Return values are a list of button presses and input values.
- Return values can also be represented as a dictionary
- The SDK calls collapse down into a single line of Python code that presents a custom GUI and returns values
- Linear programming instead of callbacks
-----
@ -593,7 +599,7 @@ The third is the 'compact form'. It compacts down into 2 lines of code. One li
You will use these design patterns or code templates for all of your "normal" (blocking) types of input forms. Copy it and modify it to suit your needs. This is the quickest way to get your code up and running with PySimpleGUI. This is the most basic / normal of the design patterns.
### How GUI Programming in Python Should Look?
### How GUI Programming in Python Should Look? At least for beginners
Why is Python such a great teaching language and yet no GUI framework exists that lends itself to the basic building blocks of Python, the list or dictionary? PySimpleGUI set out to be a Pythonic solution to the GUI problem. Whether it achieved this goal is debatable, but it was an attempt just the same.
@ -747,6 +753,53 @@ This sample program demonstrates these 2 steps as well as how to address the ret
sg.Popup(button, values, values[0], values['address'], values['phone'])
## The Event Loop / Callback Functions
All GUIs have a few things in common, one of them being an "event loop" of some sort. If your program shows a single form, collects the data and then executes the primary code of the program then you likely don't need an event loop. This simple scenarios are front-end GUIs where you call sg.GetFile for example and then call your program that does something with the file.
Event Loops are used in programs where the window stays open after button presses. The program processes button clicks a loop. You often hear the term event loop when discussing embedded systems or on a Raspberry Pi. Let's take a Pi demo program as an example. This program shows a GUI window, gets button presses, and uses them to control some LEDs. It loops, reading user input and doing something with it.
This little program has a typical Event Loop
![pi leds](https://user-images.githubusercontent.com/13696193/45448517-8cea7b80-b6a0-11e8-8dbe-eeefea2e93c1.jpg)
import PySimpleGUI as sg
layout = [[sg.T('Raspberry Pi LEDs')],
[sg.ReadFormButton('Turn LED On')],
[sg.ReadFormButton('Turn LED Off')],
[sg.Exit()]]
form = sg.FlexForm('Raspberry Pi GUI', grab_anywhere=False)
form.Layout(layout)
# ---- Event Loop ---- #
while True:
button, values = form.Read()
# ---- Process Button Clicks ---- #
if button is None or button == 'Exit':
break
if button == 'Turn LED Off':
turn_LED_off()
elif button == 'Turn LED On':
turn_LED_on()
# ---- After Event Loop ---- #
sg.Popup('Done... exiting')
In the Event Loop we are reading the form and then doing a series of button compares to determine what to do based on the button that was clicks (value of `button` variable)
The way buttons are presented to the caller in PySimpleGUI is ***not*** how *most* GUI frameworks handle button clicks. Most GUI frameworks, including tkinter, use ***callback*** functions. A function you define would be called when a button is clicked. This requires you to write code where data is shared between these callback functions. There is a lot more communications that have to happen between parts of your program.
One of the larger hurdles for beginners to GUI programming are these callback functions. PySimpleGUI was specifically designed in a way that callbacks would not be required. There is no coordination between one function and another required. You simple read your button click and take appropriate action.
Whether or not this is a "proper" design for GUI programs can be debated. It's not a terrible tradeoff to run your own event loop and having a functioning GUI application versus one that maybe never gets written because callback functions were too much to grasp.
---
## All Widgets / Elements