PySimpleGUI / PySimpleGUI

Python GUIs for Humans! PySimpleGUI is the top-rated Python application development environment. Launched in 2018 and actively developed, maintained, and supported in 2024. Transforms tkinter, Qt, WxPython, and Remi into a simple, intuitive, and fun experience for both hobbyists and expert users.

Home Page:https://www.PySimpleGUI.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Announcements

MikeTheWatchGuy opened this issue · comments

Announcements - New Features, Design Patterns, and Methods

I'm unsure how GitHub sends out updates. I don't think people are informed about Wiki changes for example. I've been announcing new features and more importantly, new ways of doing things, on the Wiki. I'm going to put announcements here so they are more visible. If there are objections about the traffic, well, what can I say, it's a busy/active project.

New use pattern - Element lookup using Keys

keys can be used to lookup Elements. As a result, all Elements are capable of having a key, including non-output elements such as a Text Element.

To get an element object from a form, you call
form.FindElement(key)

This is the new, preferred method for doing Updates on elements.

Previously if you wanted to output something to a Text Element, you needed to create the text element outside of the form layout and keep that text element variable around so you can call text_element. Update('new text')

The new design pattern is thus:
In your form layout, include a key on your Element:

layout = [[sg.Text('My text', key='text')]]

Later in your code you can update this Text Element by making this call, assuming the variable form is your FlexForm object:

form.FindElement('text').Update('new text')

The Demo programs have all been updated to use this new technique. This capability and its impact on the length of programs led to pushing version 2.30 out the door quickly.

Borderless Windows are Here

Try them on your next form.
Add this to your FlexForm call:
no_titlebar = True

You can expect to see some of these in the Demo programs.

borderless grayed buttons

You can click anywhere on the window and drag to move it. Don't forget to put an exit key on these windows.

Be sure and make an "exit" button or you'll be running task manager to close your windows. The reason is the when you turn on this option, you will not see an icon on your taskbar for the window. This happens on both Windows and Linux. Thus, if you do not supply an exit button, the user will have no means to close the window.

Grab Anywhere

Tonight's change is perhaps going to be a really cool thing or one that is going to piss people off.

But, hey, I like it this way. If you don't, setgrab_anywhere = Falsein your call to FlexForm.

As the name implies, you can grab and drag your window using any point on the window, not just the title bar. I was only enabling this when the title bar was turned off. I think it's a much superior way to interact with a window.

FlexForm is becoming quite the call!
def __init__(self, title, default_element_size=DEFAULT_ELEMENT_SIZE, default_button_element_size = (None, None), auto_size_text=None, auto_size_buttons=None, scale=(None, None), location=(None, None), button_color=None, font=None, progress_bar_color=(None, None), background_color=None, is_tabbed_form=False, border_depth=None, auto_close=False, auto_close_duration=DEFAULT_AUTOCLOSE_TIME, icon=DEFAULT_WINDOW_ICON, return_keyboard_events=False, use_default_focus=True, text_justification=None, no_titlebar=False, grab_anywhere=True):

So, enjoy a lazy way of interacting with windows on me.

You will want to turn if off for forms with a SLIDER. you need the slider to move, not the window. I'll update the Demos that use sliders to turn off the grab_anywhere.

Tables

This one has been requested a number of times. Rather than make a Table Element, decided to see if the current PySimpleGUI is capable of making nice tables using standard Elements. The answer seems to be yes, it's possible with existing Elements. The key was to enable text justification in the InputText element. By right justifying the text in those Elements, it's possible to create a nice looking table.

Here's an example using a ComboBox and Input Elements.

light table

You'll find the code that generated the table in the file Demo_Table_Simulation.py. It requires the latest PySimpleGUI from GitHub in order to use the justification setting.

This is a "live keyboard" demo. It updates the table values as you are typing.

There are 3 fields at the top of the table. If you enter a value into the 3rd field, the cell that the other 2 cells represents will be changed to that value. Enter 1, 2, 1234 and cell (1,2) will be changed to 1234.

There is a new trick demonstrated in this demo that shows off the power of Python. Rather than pass in a string as the key to the Input Elements, I passed a tuple. Nothing about the key requires it to be a string. The only requirement is that you use the same type to look up the element when you call FindElement or use the key to read the return values.

This is the code that makes the Input Elements:

    for i in range(20):
        inputs = [sg.In('{}{}'.format(i,j), size=(8, 1), pad=(1, 1), justification='right', key=(i,j), do_not_clear=True) for j in range(10)]

See how the key is set to (i,j). This allow me to easily find the Element that is represented by (i,j) later. What to access the cell at (0,0)? This you would make this call:
form.FindElement((0,0))

Hopefully this is enough capability for the folks that need tables in their forms/window.

Three Point Oh!

So maybe I kinda screwed up the numbering when the last one became 2.30. I didn't think about it looking like 2.3 also. Doh!

There have been a lot of changes lately so perhaps it's time for a major bump.

It's a clean slate

keep_on_top = True

What might this setting do in a call to FlexForm? If you guessed create a window that's ways on top you're right.

This one little flag enables cool floating toolbars that stay on top of all of your other windows. I'll admit a large portion of this project is for selfish purposes, that I have a platform to develop tools on top of.

Now I've got this nifty toolbar on the top part of my screen, always ready to launch or do something.

floating launcher

3.0.2 release today to turn off the grab_anywhere feature for non-blocking forms. tkinter is printing out a warning/error message when the form is closed using a button. Doesn't appear to have any effect on the overall functioning, but it's distressing to see. Better to disable this feature for now.

Plan is to add back an override mechanism should a user want it.

RELEASED 3.0.2

Floating Toolbar - New demo program

This is an always-on-top, compact floating toolbar. They are super-handy to leave running. Something satisfying about writing code that then gets used often, especially if they make you much more efficient.

Async Forms

Updated the Readme / primary doc to discuss the use of non-block forms.

As explained in the documentation there are a number of techniques to move away from async forms including using the change_submits = True parameter for elements and return_keyboard_events = True

Floating Desktop Widgets

I've discovered that in about 30 lines of code you can create a floating desktop widget.

snap0276

If you click the pause button, it switches to Run.

snap0275

This "Widget" is always on top of the other windows.

Looking for a way of launching these in a way that have no taskbar icons. If launched from PyCharm it behaves this way. If launched from a Toolbar, the toolbar's window is attached to the timer. Close it and the timer closes.

This demo is the first time I've ever combined a ReadNonBlocking with a Read in the same form. The reason for using it in this program is that while the timer is paused, there' s nothing happening so why have the program running the loop when it can wait for the user to do something like click a button. When the button is clicked we return from the Read call.

Thank you to jfong for sending an interesting version of this program. His ideas have rolled into a into the project code many times.

Menus are done

The last of the big features, Menus, was just released to GitHub. With it comes the ability to get the look and feel of a windows program. I don't know if the architecture will lend itself to being used this way or not, but it did seem like a useful feature to add..

snap0204

3.7 Support

Thanks to @mrstephenneal we can now say that PySimpleGUI works on Python 3.7. There was a button issue causing trouble. Looks like it's fixed now so I think 3.7 is now safe to with PSG.

Release 3.01.00

Menus! (and a Listbox.Update bug) are the big features.

Since the Menu code is somewhat isolated, and I want to get some users on it, decided to go ahead and push it all out there in 3.01.00

I didn't mention this in the readme section on menus, but by default (you can't currently turn it off) menus are detachable. If you double-click the dashed line then you get a floating version of that menu. Should make for some pretty interesting user interfaces?

tear off

3.1.1

There have been enough bug fixes to trigger another PyPI release. People have been doing more and more with the Update method. These fixes were mostly in those methods.

Update methods updated

Added the ability to enable / disable all input elements.
Set parameter disable=True to disable, disable=False to enable, disable=None to leave it alone

A number of Demo programs also refreshed.

Expect a PyPI release soon.

Note that some Update method changes also changed parameter names from new_value to value, new_values to values. Some were different than others. Removed new_ so they all match now. Sorry to those living on the bleeding edge!

Here's a before/after. Elements towards the bottom of the window were disabled.

Yes, even buttons can be disabled now. No more needing to gray out your own buttons!

enabled
disabled

3.1.2

Big change this time around is the ability to disable widgets. All input widgets have an Update method that has the parameter disabled that you set to True if you want to disable it.

A few critical bugs in there too which pushed up the release to today.

Resizable Windows, Font settings for input text elements, beginnings of Treeview Element

You can stretch windows bigger now and some of the elements will resize with the window. **

The Input Text Elements did not have a functioning Font setting. Doh! Don't know how that got missed.

The very beginnings of the Treeview element are in there.

Hopefully nothing was broke. Any time I make changes to the core widget packing I get nervous!

** Had to turn off some of the Resizable windows features....Buttons and other elements were moving / expanding in forms that I didn't want the to expand. The change fucked up too many elements to leave on for now.

Two new Demo programs - CPU Desktop Widget, Spinner Compound Element

Added another Desktop Widget to the demos. This one shows the CPU utilization.

cpu widget

The spinner allows you to change how often it's refreshed

The Spinner Compound Element was done in response from a user wanting to see a different kind of spinner. This one has larger buttons and is laid out horizontally.

spinner compound

The point of this demo is that it's possible to put together multiple Elements into a higher level element. There aren't many of these I can think of at the moment, but given how many user questions are asked, something else is bound to be asked for.

Table Element, Complete rework of Popups, Death of MsgBox

You can blame the Popup changes on this issue:
#204

All of the Popups were rewritten to use a long list of customization parameters. The base Popup function remained more or less the same.

Decided while I was going all the Popup work that it's time to completely remove MsgBox. Sorry all you early adopters. You'll need to do a bulk rename and then you'll be fine.

Table Elements

Finally have something to show in the form of tables. The element name is Table. While the tkinter Treeview widget was used, many of the parameters were not exposed. If they were, the caller could really mess things up. Better to present a nice "Table-friendly'" interface than something specific to tkinter. After all, the plan is to expand PySimpleGUI to use other GUI frameworks.

A Demo program is in the works.

It's possible to add scrollbars to the Table element by simply placing it into a Column element.

There's still work to do and a good number of bugs, but I encourage you to give it a try.

scrolled table

If you do not put the Table Element inside of a Column, then you can still view and scroll the table, it just will not have scrollbars.

There is a problem currently with keyboard input when placed into a Column. The keyboard keys work fine when NOT inside of the Column but stop working when placed inside a Column Element.

This program will read a CSV file and display it in a window.

import csv
import PySimpleGUI as sg

filename = sg.PopupGetFile('filename to open', no_window=True, file_types=(("CSV Files","*.csv"),))
# --- populate table with file contents --- #
data = []
if filename is not None:
    with open(filename, "r") as infile:
        reader = csv.reader(infile)
        try:
            data = list(reader)  # read everything else into a list of rows
        except:
            sg.PopupError('Error reading file')
            exit(69)

sg.SetOptions(element_padding=(0, 0))

col_layout = [[sg.Table(values=data, headings=[x for x in range(len(data[0]))], max_col_width=8,
                        auto_size_columns=False, justification='right', size=(8, len(data)))]]

layout = [[sg.Column(col_layout, size=(1200,600), scrollable=True)],]

form = sg.FlexForm('Table', grab_anywhere=False)
b, v = form.LayoutAndRead(layout)

It's another bit of PySimpleGUI "challenge code"..... The challenge is to do the same operation in another GUI framework in less lines of code. I would enjoy seeing the tkinter code required to create the window that this 20 line PySimpleGUI program creates. Most of the code deals with reading the CSV file 👍

Linux Virtual Environment

I finally installed VirtualBox and am running Ubuntu Linux. I tried to install the Mint distro, but the display was scrambled when it booted.

I was surprised how close the Linux screen shots look to the Windows.

ping graph linux
toolbar linux
all linux
ping linux

Even Pong worked the first time.

I don't believe that Python has been labelled the "go to language" for doing cross-platform GUI work. I guess I never stopped to think about it. I don't recall seeing this kind of thinking in posts or books I've read on Python. Perhaps it's time for that to change?

3.2.0

Released a new release to PyPI. Sorry about all these releases, but features continue to pour into the code. I'm finding even the folks that are actively using PySimpleGUI only run the pip installed version rather than the GitHub version. That means if I want runtime on the code, I'm only going to get any is to do a full release.

There were a number of changes that could f-up, so be on the lookout. The biggest addition to 3.2.0 was the Table Element (beta quality at the moment).

If you are running older programs then you may crash due to missing functions, MsgBox and several others. This is because I've moved 100% to Popup calls. It's not like I haven't been warning people so I don't expect complaints.

Some people are calling ReadNonBlocking prior to your Event Loop so that the form gets fully made. This call is needed if you want to perform actions on elements prior to calling Read. For example, if you want your form to be shown with some Elements set in the disabled state (using calls to Update), you will need to make an additional call after your Layout call.

Instead of calling ReadNonBlocking in these situations, you can call Finalize/PreRead/PrepareForUpdate. I have not been able to standardize on a name, so I'm providing multiple. I'm sure a winner will emerge. I've been using Finalize.

The call sequence becomes this:

form.Layout(layout)
form.Finalize()
element.Update(.....)
while True:
     b, v = form.Read()

You'll also find the Finalize call used in the scripts that use the Canvas Element.

See the Readme for more info on what's in the release. Note that the readme has not yet been updated with the Table Element and several other changes. There's only so much I can do.

One Line Progress Meters

PySimpleGUI has always had a one-line progress meter called EasyProgressMeter. However, that function has a limitation of only 1 meter being active at a time.

The new way to do Progress Meters is the function OneLineProgesssMeter.

All of the documentation and examples will reflect this new function.

Have to say it's nice to be able to run as many meters as desired without having to worry about more than 1 being on the screen at a time.

I intend to remove EasyProgressMeter within the next 5 or 6 releases to PyPI. I tried to insert a warning in the code, but too much code was shared to fit the message in.

I'm sorry about the change, but really would like to both add this function and rename the capability to something very descriptive. If there is enough revolt over removing EasyProgressMeter, I'll leave it in and simply drop it from all the documentation.

onelineprogressmeters

3.3.0

Yea, yea, it seems like only yesterday that version 3.2.0 was released. That's because it WAS only yesterday. I've been busy.

There are 2 changes I wanted out quickly....

  1. The ability to turn off displaying row numbers
  2. The new OneLineProgressMeter function

The Progress Meter feature alone is a great use of PySimpleGUI. A number of users are using it only for this purpose in their programs.

Graphing

New demo program - graph ping using canvas.
I'm thinking about creating a Graph Element, something that makes it super easy to users tog create graphs, both line and x,y plot. The demo should how to take a canvas element and graph ping times.

There is another ping-graph demo using Matplotlib. This graph only uses tkinter.

Finally, because the pings take a long time, I moved the ping calls outside of the GUI event loop. Calling ping inside event loop was causing the GUI to respond sluggishly. This is because the ping was taking 1 second which means the gui wasn't being refreshed / wasn't responsive during the second. Now the GUI sleeps for 200 ms while the ping is done by a thread.

This is yet another toe in the water with threading. The problems I saw in the past are no longer there, it would appear.

I also checked in the ping.py file that you need for this demo. It's a pure python implementation of ping and works pretty well, even if slow.

ping graph

Progress Meters

Thanks to @JorjMcKie I've learned more about the performance of the EasyProgressMeter and thus probably the OneLineProgressMeter. The more arguments to display the longer it takes.

Was going to document in the Cookbook / Readme that if you have performance concerns, you can call the progress meter less frequently. You don't have to update it 1 count at a time. It could be like this:

for i in range(10000):
    if i % 5 == 0: sg.OneLineProgressMeter('My 1-line progress meter', i+1, 10000, 'single')

This meter is only called every 5 times through the loop. It finished quite a bit quicker than the test updating the meter every single time.

PySimpleGUI programs as an EXE file!

The biggest thing to hit PySimpleGUI since Colors.... the ability to run programs written for PySimpleGUI as an exe file. ALL credit goes to @JorjMcKie for this.

There is no need to distribute Python with your programs. It's all included in the exe and folder of supporting files.

From what I understand of nuitka, this code is compiled C++ code, not python code. The performance is thus potentially better! It's the best of both worlds.

Working to get the process documented. It's tricky and required a special script. Stay tuned....

Graph Element

This one is pretty exciting as it does something new on the screen. The Graph Element allows you to easily create a canvas and draw on it using your own coordinate system. You don't need to do conversions from your graph coordinates to the tkinter canvas graph coordinates.

The Demo program for it is a good example. It displays a pint graph. The graph we're creating is a line graph what we would like to to from 0,0 in the bottom left to 100, 500 in the upper right. This will give us 100 data points along the x axis and up to 500 ms on the y axis.

After creating the Graph Element, we can do 3 operations on it:

  1. Draw Line
  2. Draw Point
    3 Erase

The draw line draws a line from 1 point to another. The points are specified using your graph coordinates, not the tkinter canvas coordinates.

snap0282

I know I have a LOT of documentation to do.

In the meantime, try using Control+P if you're using PyCharm. Press Control+P while you are typing in the parameters and you'll see a popup showing you what the legal parameters are. This feature is almost necessary when using PySimpleGUI because functions have SO many optional parameters.

snap0283

I hope to see some cool creations using the capability. I'm starting to see more and more projects pop up on GitHub that use PySimpleGUI! Keep those examples coming! And keep the requests for new features coming too. They have made this such a better package because of your help.

Sample code:

This is your layout:

    layout = [  [sg.T('Ping times to Google.com', font='Any 18')],
               [sg.Graph((300,300), (0,0), (100,500),background_color='white', key='graph')],
               [sg.Quit()]]

    form = sg.FlexForm('Canvas test', grab_anywhere=True)
    form.Layout(layout)

To draw a line, call DrawLine:

form.FindElement('graph').DrawLine(from_point, to_point)

Movable Graph Element

Made the Graph Element "movable". This means the graph can be shifted when it reaches the "End".

Here's a 1,000 data-point ping graph or 16 minutes woth of pining

scrollingping

Button return values as keys rather than button text

Just dropped in a sizable change in how buttons work. For buttons that have a key value, the key is returned rather than the button text. This is needed for forms that have multiple buttons with the same text.

The 'best' way to rework existing code is to get your key == button_text.

Expect a number of Demos and Recipes to change. Lots to do to explain this one.

It's another excellent suggestion provides by @mrstephenneal.

Keep those ideas coming people! They're turning PSG into an event better package! Don't be shy if you need a change.

Nuitka launches only from command window

Not sure what happened, but I can't seem to load the Nuitka .EXE file by double clicking. It doesn't do anything but flash a command window like it has crashed.

However, when I type the exe filename on a command prompt, it works GREAT. Perhaps if I added to a batch file then double-click would work. Will try soon.

Clickable 'text'

I noticed on some GUIs it's possible to determine when someone clicks on text. I experimented and found a way to duplicate this behavior

disappearingButton

The 'Clear' text is actually a button with the border_width = 0 and color = black like the background. Poof... instant clickable text

Cross that feature off the list

Frame Element

Just when you think I'm out of new elements to spring on you, I cough up another.
For those people with an eye for design and want their forms to look as good ad possible, give you the Frame Element

frame

The frame element allows you to group your Elements into a nice box with a text label.

It takes 2 required parameters - title & layout.

You can customize the text font, size, color, relief style. I do not yet have a setting where you can specify the location of the label.

You can think of these as Column Elements with a label and an outline because that is exactly what they are, except you cannot scroll a Frame Element.

The implementation uses the tkinter labelframe widget. I decided to name this Element Frame since that's exactly what it is. I do not have a labelled and unlabeled Frame. If you want a frame without a label, specify None for the title

This is one of those features that have zero impact on your form's capabilities, but has a big impact on the appearance of a form.

3.4.0

Released 3.4.0 today. I'm sure most of you head straight to the readme file, scroll to the bottom and read the release notes. I'll go ahead and post them here just to humor myself.

There is significant amounts of work to be done on the docs to get the new Frame and Graph elements documented in the readme, Cookbook and tutorial. Soon I hope. In the meantime, all you advanced users can quickly figure them out using PyCharms Control+P feature.

3.4.0

  • New Element Frame (a labelled frame for grouping elements. Similar to Column),
  • New Element Graph (like a Canvas element except uses the caller's coordinate system rather than tkinter's).
  • Set an initial_folder for browsing type buttons (browse for file/folder).
  • Buttons return key value rather than button text if a key is specified,
  • OneLineProgressMeter! Replaced EasyProgressMeter (sorry folks that's the way progress works sometimes),
  • Changed ALL of the Popup calls to provide many more customization settings - changed PopupGetFolder, PopupGetFile, PopupGetText, Popup, PopupNoButtons, PopupNonBlocking, PopupNoTitlebar, PopupAutoClose, PopupCancel, PopupOK, PopupOKCancel, PopupYesNo

Stack Overflow, Reddit

I've been watching both StackOverflow and Reddit for opportunities to help people out using PySimpleGUI.

I answered on StackOverflow question about adding a GUI onto a command line program that I'm particularly proud of. A sample GUI was provided that was made in Visual Studio. It took 15 lines of code in PySimpleGUI to duplicate the design.

Check it out if you get the chance:
StackOverflow Post

Fun with Graph Element

I'm 1/2 way through my 6,000 ping graph :-) The top is 500 ms.

3000 pings

3.4.0 is no more

Deleted release 3.4.0. Everyone will have to wait on the new release. You can always get and test against the Master Branch to see if you're going to have trouble in the upcoming releases. It would be great if someone people could be running from Master rather than PyPI.

This backed out the button change as well as the laundry list of new features and bug fixes. It'll all have to wait until I can make sure all Demos work with new code and there is more documentation updated.

6,000 Point Canvas (6,000 Point Ping Graph)

My ping graph has finally finished and is scrolling nicely. It's spanning 3 monitors

6000 point pings

Is there a class using PySimpleGUI??

I see three different repositories popped up, at the same time, with the same structure. They all implement a calculator using PyGame and PySimpleGUI.
It sure looks like some class is teaching PSG!

That's crazy!

I dunno if PySimpleGUI is ready to be used in a class just yet. Heck, I'm still breaking features.

https://github.com/ozone94/Calculator_PySimpleGUI/tree/2d2d8898ce51f2ca223434acd2af6c8682ddf5c3

https://github.com/ATBLightning/PySimpleGUI_AsTheCalculator/tree/db837888c47763a990c5c7e15d66a21b99924c16

https://github.com/poschananT/CalculatorPySimpleGUI_6001012620033

https://github.com/Thanaban/SimpleGUI_calculator

3.4.1

OK, the release is back to being a release, now that there's the required Button.GetText call which allows you to figure out the current text value on a button.

This release shouldn't break anyone's code.... unless you're one of those super-advanced users that are changing the text on their buttons (smarty pants's). Those folks have a the special Button.GetText method just for them so that the button text can be retrieved.

For those of your that are writing a lot of code that uses ReadFormButton, I have created a shortcut, ReadButton, so that you save a few characters in your layout.

Overall this is a pretty strong release with two new elements, Graph and Frame. The Frame element enables PSG windows to look even better, more professional.

I can't WAIT to see what people do with these things. I see something new that you guys create every day and it's quite motivating. Keep the ideas and inspiration coming!

There IS a class using PySimpleGUI

Holy crap.... I saw this in a readme today:
My reference :: Introduction to Computer Science Using Python and Pygame by Paul Vincent Craven
Can't wait to see if more text is added to this:
https://manachanok94.blogspot.com/2018/09/calculator-using-pygame-vs-pysimplegui.html

Sure looks like there's a computer science class using it!
Part of the exercise also appears to be the students

  • Create a GitHub repository
  • Make a readme, structure the GitHub nicely
  • Create a blog and in the blog write the difference between writing a calculator program in PyGame versus PySimpleGUI... really looking forward to getting this feedback from students!

This is one of the goals I originally had for the package, make something usable by students, people just starting so that they get exposed to doing good user interfaces from the beginning of their career. It seems like a good thing to learn how to lay out a screen in a pleasing and functional way.

"Be careful what you ask for" is definitely fitting for this situation.

https://github.com/Manachanok/Calculator

Some students already commenting on how much more compact PySimpleGUI is at their calculator assignment than their PyGame implementations.
One student wrote this:

It's a total of 34 lines compared to Pygame written in a hundred lines. Simple by name

I try to remain neutral when speaking of other packages. Everyone working on these packages has fantastic intentions, works hard, is altruistic, and we all have a slightly different outlook on how to create a simple GUI. It's not my place to knock any, any, of the GUI packages.

Text Element Relief Setting

Oh what a relief it is.

Continuing on polishing the look and feel of PySimpleGUI. Today's feature is the ability to add a relief to Text Elements.

It's part of the Demo_All_Widgets.py code along with the new Frame Element.

The first line of the layout reads:
sg.Text('All graphic widgets in one form!', size=(30, 1), justification='center', font=("Helvetica", 25), relief=sg.RELIEF_RIDGE)

text relief

Listbox bind_return_key

Previously Listboxes always submitted when the return key was pressed. Now it's controlled using a new bind_return_key. Listbox is like the other Elements now. I also added double-clicking! I find myself double clicking the listbox and nothing happens. I have to click a button or press return key. Now you'll get control back on double-click if you've set bind_return_key

For fun... my desktop

I bet some nuclear power plants have less gauges and controls. 1/2 of one of my monitors. 3 of those widgets are PySimpleGUI powered.

mydesktop

Combining Form and Layout calls

There are a handful of design patterns that we all have been using.
Two of the blocking style ones are:

The simple form:

form = sg.FlexForm('My form')
button, value = form.LayoutAndRead(layout)

The perpetual form:

form = sg.FlexForm('My form')
form.Layout(layout)
while True:
      button, value =form.Read()

I have disliked the second one of those since I wrote the code. It felt wordy.
In Python, I am constantly scanning trying to simplify, compact, make easier. Nothing is more fun than combining function calls. So I was elated when I stumbled in to a code change that allows this new pattern:

form = sg.FlexForm('My form').Layout(layout)

while True:
      button, value =form.Read()

It was a super simple change to the code, and damn, the result is awesome.

You can expect this one to get released quickly and have the demos, cookbook updated too.

Table Demos - CSV & Pandas

It's great when community members write some of this stuff... I get a lot of behind the scenes help from you guys whether it's advice on naming, determining new parameters, how to implement a new element. Otherion wrote a couple of Table Element demos. One uses the CSV library the other pandas. There are more bugs to work out with the table element. I'm not happy with now I used the size parameter and I'm not sure the autosizing it sizing correctly. These Demos will make excellent patterns for folks wanting to work with tables. I have a 3rd one that I'll post soon that works with databases!

Shorter Button Names

The upcoming release will include new shorter names for buttons. You'll still be able to use all the same names as before. However, they'll change in the Demos, particularly new demos, and the Cookbook.

This comes from 2 things. 1 - I'm fundamentally lazy. You may have noticed my frequent use of sg.T() and sg.In() instead of sg.Text and sg.InputText. 2 - I saw the incredibly wordy looking programs the students made. They were calculator programs so naturally the UI was crammed with buttons. There were 20+ sg.ReadFormButton() calls in every program. Ugh, too much clutter.

The change required me to shuffle around some parameters in the Button Element. I learned a big lesson as well in NOT relying on positional arguments when making internal function calls. I have more cleanup to do. I needed to make the Button Element have the text in the first position if I was to steal it and make it a user callable function rather than only internally used. It's such a great name, Button() that it seemed a shame to hide.

Here are the new names:
SimpleButton becomes Button
ReadFormButton becomes ReadButton or RButton

You can easily guess which of these you'll see me using the most.

Thus, all of the buttons, in their shortest form, are:

Button
RButton
RealtimeButton

If someone right a program with a ton of RealtimeButton then maybe I'll shorten it too. I can't think of another name for that one.

Again, you do not need to change your code. The wordy-buttons will continue to work, but won't be used in examples anymore.

Tooltips

snap0351

Thanks to the help of @rtrrtr we now have tooltips on all of the Elements... or almost all of them... or the ones that matter.

If you find a tooltip parameter in the call to the Element, then you can add a tooltip to it.

This includes the shortcut buttons like Submit(), Yes(), etc.

It really helps when someone supplies code like this. It enables me to hook in the new feature quickly and easily.

Since this touched every Element and shortcut, there's a good chance I f-ed something up, so be on the lookout.

As usual, it's in the Master Branch. I'll let it sit for a day or two and then off to PyPI it'll go along with the other features and bug fixes made since 3.4.1

3.5.0

Another day, another truckload of features. Seemed like plenty of stuff saved up over the past few days that it's worthy of a released. Seems like pretty much everyone wants to run the pip installed version rather than pulling the latest Master Branch. So, I'm going to push stuff out there and hope that if it breaks someone speaks up quickly. So far that's what happened, someone speaks up when something breaks. Keep speaking up!

The feature list

  • Tool Tips for all elements
  • Clickable text
  • Text Element relief setting
  • Keys as targets for buttons
  • New names for buttons:
    • Button = SimpleButton
    • RButton = ReadButton = ReadFormButton
  • Double clickable list entries
  • Auto sizing table widths works now
  • Feature DELETED - Scaling. Removed from all elements

The biggest reason I wanted it out is so I can use Button and RButton! That's going to save a lot of keystrokes and it'll compact the code. Maybe I should make Btn? Or how about just B? LOL
Then there's tooltips which multiple people asked for.

I also killed off Scaling in this release. That touched SO many parts of the code so I hope it survived OK. If you were using the scaling feature..... uhm, I'm sorry? I don't think anyone is however.

Enjoy!

Graph Element

This is the latest Recipe addition to the Cookbook. I created a 10-line program that created this lovely screenshot.

graph element

import math
import PySimpleGUI as sg

layout = [[sg.Graph(canvas_size=(400, 400), graph_bottom_left=(-100,-100), graph_top_right=(100,100), background_color='white', key='graph')],]

form = sg.FlexForm('Graph of Sine Function').Layout(layout)
form.Finalize()
graph = form.FindElement('graph')

for x in range(-100,100):
    y = math.sin(x/20)*50
    graph.DrawPoint((x,y))

button, values = form.Read()

What I like about working with these Graph Elements is that I don't have to worry about translating into on-screen coordinates. It's always a pain in the ass dealing with the converting into screen coordinates. Having that removed so that I'm working in my desired coordinates is really satisfying.

In this case I wanted a graph that went from -100 to 100 in both X and Y axis. Defining those values as well as the size of the screen area to use is all done in the call to Graph.
sg.Graph(canvas_size=(400, 400), graph_bottom_left=(-100,-100), graph_top_right=(100,100), background_color='white', key='graph')

The actual graphing of the data points is this little loop, again, working in my own coordinates to draw the points:

for x in range(-100,100):
    y = math.sin(x/20)*50
    graph.DrawPoint((x,y))

And add just a couple more lines of code and you can get axis and another graph

for x in range(-100,100):
    y = x**2/20-100
    graph.DrawPoint((x,y))
    y = math.sin(x/20)*50
    graph.DrawPoint((x,y), color='red')

graph 2 graphs

3.5.1 (the "oh shit" release)

It only hit me today how "broken" 3.5.0 was! I didn't realize that older Python3 installs were flat out broken... that PySimpleGUI wouldn't run at all! Doh! It was due to this issue:
#298

PyInstaller LIVES.... PyInstaller + PySimpleGUI = WinForms

Gosh, a HUGE mega-thank you is owed to @mrsunday334 and @hpca01 get PyInstaller working.

This is a pretty epic kind of event.

pyinstaller -wF your_program.py

This simple line will make a single .EXE file than when executed opens straight into the GUI. No secondary dos prompt window. AND the .exe file is small at 9 MB in total.

This is huge for IT people that have wanted to deploy their tools to users but installing Python is out of the question.

Posted on Reddit - Not above begging for upvotes

I took a chance and posted about the PyInstaller news on Reddit. I done so well there, but I have picked up some great contributors so I'll take the rocks with the roses.

If you want to see how I fared or want to, ahem, upvote, here's where you'll find the post...

https://www.reddit.com/r/Python/comments/9i41la/i_duplicated_a_winforms_experience_in_python/


After 20 minutes I had 3 upvotes going for me.... which lasted for a few more minutes before out came the downvotes. Not sure why I bother except that I do pick up some great supporters. It's just discouraging when some people can't handle being supportive of someone else's effort or success.

It seemed like only yesterday....

Noticed release history while doing the big update to Readme file. It actually seems like eons ago when theses features were added:

Jul 16 (10 weeks ago) All parameters to Elements changed from CamelCase to lower_case
Jul 26 (9 weeks ago) Slider, Listbox elements. Color options
Aug 9 (7 weeks ago) Dictionaries... yes, dictionaries were added only 7 weeks ago.
Aug 16 (6 weeks ago) Columns
Aug 25 (5 weeks ago) Keyboard and mouse events

And the real shocker for me....
Jul 10 (11 weeks ago) First release to PyPI.. Release 1.0
Over 13,000 downloads since release 1.0 (not a huge number, but beats my expectations)

Thank you to everyone! GREAT feature suggestions, awesome support and encouragement. And it just keeps getting better....

Added PyInstaller Recipe to Cookbook

This is such a cool feature! Had to include it in the Cookbook.

3.5.2

A community member discovered a crippling bug. Elements inside of Frame Elements were not being returned in the return values. That means Frames are badly broken. Can't have that sitting around for long.

Also made the Finalize method chainable. I have updated all of the Demo programs that use it.

This means that form creation, layout and finalize can be a single line of Python code. It's simple to understand and compacts the code by another line. I'm really enjoying using the chaining capability!

form = sg.FlexForm('My form').Layout(layout).Finalize()

This will get you a form that is completely 'formed' so that you can can address elements using Update.

An example can be found in Demo_Canvas.

Prior to the Read, we want to get the Canvas Element so that it can be drawn on.

form = sg.FlexForm('Canvas test').Layout(layout).Finalize()
cir = form.FindElement('canvas').TKCanvas.create_oval(50, 50, 100, 100)

Without the Finalize the Canvas Element cannot be found.
Hoping that this is an accepted practice. It makes things nicer looking and easy to understand in my opinion.

Removed LookAndFeel capability for Macs

Sorry Mac people, I need to take away the ability to injure yourself. The button problems are forcing me to do this. If you want to customize the look, you can always do it using the SetOptions function.

Hokey YouTube Video

https://www.youtube.com/watch?v=0jUvMfRmuog

I've been seeing people post SO many whacky and terrible programming tutorial videos that I just had to try it myself.

I also got a screen capture tool for another project and I've been itching to use it.

In my video I write a guess the number game in under 2:30.

I had to delete the first attempt because you can't see the window that it made.

3.6.0

I jammed 3.6.0 so that I could openly post in documents the new PySimpleGUI method, Window, without it crashing when people used it because the PyPI doesn't have it.

When I made the YouTube video I had not thought through that if someone tried to run the code it wouldn't run. DOH! So, out the door it went...without release notes. DOH!

Whatever... it's done...

Windows, Not Forms

We're all creating windows, damnit, not forms.

It dawned on me that FlexForm is a dumb, non-descriptive name for our windows.

So, I made the executive decision to change from FlexForm calls to Window calls.

I LOVE the result, especially if you change the variable names too. It "feels" like a real GUI now!

window = sg.Window('My window!').Layout(layout)
button, values = window.Read()

I've had a bitch of a time replacing the 1,300 spots that Form appears in the documentation alone. I had to examine and fix each one as they were unique situations. But, it's DONE, at least for the docs.

Now it's on to the Demo programs.

I feel like I'm living in "1984" and am going back and changing history, "Forms are no longer used, we will use Window from now on"... as I go through all these documents and erase all references to forms.

Next up are the Demo programs. They all needed to be "refreshed" anyway.

I'm learning that this package is evolving at a fast pace. These design patterns that used to feel so permanent, aren't.

The good news for existing users is that I'm leaving the old names alone. My goal is to catch the new wave of users and get them steered into using the naming conventions that I want people to use. They wont' know any better than to use the new names.

Demo Refresh

Went through each Demo program, all 68 of them, and made 2 changes.

  1. Changed all exit calls to sys.exit calls so that PyInstaller doesn't crash when extiing
  2. Reworked all of the PySimpleGUI calls to follow the same design pattern.

The new way of doing things that are in the Demos now matches the Readme and Cookbooks.

There were these 3 basic design patterns (Learn it, Love it, Live it)

Simple Read Window Call

layout = [[ some layout ]]

window = sg.Window('My new window').Layout(layout)
button, value = window.Read()

Persistent Window with Event Loop

layout = [[ some layout ]]

window = sg.Window('My new window').Layout(layout)

while True:
    button, value = window.Read()

If Element needs updating prior to Event Loop (window needs to be finalized)

layout = [[ some layout ]]

window = sg.Window('My new window').Layout(layout).Finalize()

# need a finalize to do things like scribble on a canvas
cir = window.FindElement('canvas').TKCanvas.create_oval(50, 50, 100, 100)

while True:
    button, value = window.Read()

I found myself sometimes not adding the Finalize() onto the end of the and instead writing it on another line just so it's clear a Finalize was required for an upcoming function call.

Generally speaking, these design patterns cover 90%+ of the use cases

It would be nice if we all agreed on some version of these so that PSG code looks similar whenever possible.

I'm thoroughly enjoying the way the latest code reads or I wouldn't be motivated to make these billions of tiny changes.

The chained methods were a huge help in reducing the number lines of code and improved readability.

Some beginners may be puzzled over the chaining, but due to the number of Cookbook examples and amount of Demo code, they will generally not be starting from scratch and will experience these in a functioning program.

The Suggested Design Patterns

You'll find a new Demo. I'm using this as my "Template" for my programs now. Would be nice to get something we can agree on

# DESIGN PATTERN 1 - Simple Window
import PySimpleGUI as sg

layout = [[ sg.Text('My layout') ]]

window = sg.Window('My window').Layout(layout)
button, value = window.Read()

# DESIGN PATTERN 2 - Persistent Window
import PySimpleGUI as sg

layout = [[ sg.Text('My layout') ]]

window = sg.Window('My new window').Layout(layout)

while True:     # Event Loop
    button, value = window.Read()
    if button is None:
        break

# DESIGN PATTERN 3 - Persistent Window with "early update" required
import PySimpleGUI as sg

layout = [[ sg.Text('My layout') ]]

window = sg.Window('My new window').Layout(layout).Finalize()

while True:     # Event Loop
    button, value = window.Read()
    if button is None:
        break

New Tab Update

I was gluing elements inside of frames to the bottom instead of to the top. The result was clearly incorrect. It's been fixed, but the fix involved changing how ALL elements are packed all windows. In other words, it's a risky change.

I'm anxious to get the Tabs feature released on PyPI because it's been broken for so long and perhaps this was a make or break feature for someone.. I'm really looking forward to seeing the creations people come up with!

Once I get the documentation ready for Tabs tonight, I'll release to PyPI.

Overseas Adoption of PySimpleGUI

It's fun to see how different people, and different cultures, are using PSG. There are some interesting, obscure ones. I ran across this site that has a GUI portion of their Python class that mentions PSG.

http://www.digisoln.com/?py3

snap0353

I'm in great company and seemed to be the choice given for doing Desktop GUI work. The other choices were console and Flash.

It's clear that the documentation and sample programs were not just copied and used. Someone wrote some code to explain some of the basic Elements
http://www.digisoln.com/?py3&lesson=GUI__moreFormElements


Then there was these encouraging words that came via a Reddit message:

I came across your package last week from the Chinese Linux and open-source communities, posted in the social media platform called wechat. These two posts about your package have been read 4253 and 679 times, respectively. Obviously, your package is getting a lot of attention.

Posts: https://mp.weixin.qq.com/s/2tR7uhG-bXuT0TecqgAPKA https://mp.weixin.qq.com/s/o8CfyXgm03gs07jbngpBAw


And finally, a mention on Twitter....
Somehow PSG and Soccer go together.... it's kinda weird, but I'll take weird :-)

https://www.tweet247.net/australia/vflw

Tony #-e^(iπ) (7 hours ago)
@Asher_Wolf Seeing the Hawks VFLW and VFLM teams win ... and continuing to get my head around python - pySimpleGUI at the moment for developing user interfaces for solutions..

3.8.0

Tabs tabs and more tabs... that's what I hope to see in some of the new GUIs people are building.

Tabs are FINALLY done as close to "right" as I can currently get them. I was anxious to get rid of the old, hacked together version of Tabs which drove the getting the new Tab Element done and out the door. That and it's such a cool feature! I expect that some nice looking advanced stuff coming from the community.

Check out this bit of recursive Window building! What fun being able to put an Output Element into a small tab in the Window.

tabs with output

As pointed out in the readme not all of the color options are available I expect that will change as soon as I can figure out what needs to be done to get it to work.

As always... ENJOY!

PySimpleGUI27 - 1.0.0

It's officially released, the Python 2.7 version of PySimpleGUI

I didn't wake up this morning thinking I would release a 2.7 version. In fact, I had ruled out 2.7 long ago... swearing not to support it.

But, I see the large numbers of people installing on their 2.7 machines AND someone gave me significant instructions that got me over the hump. The rest was grunt work.

I was able to pip2 install it on my windows machine, but my environment is not fully set up to do the import correctly.

If someone can check to see if it works that would be awesome.

The package name for the 2.7 version is
PySimpleGUI27

Not sure how to get the word out in this one. I'll have to retrace my steps perhaps for the Python 3 marketing effort.

A morning without Issues

Was shocked this morning to see no issues logged.... whew! I thought for sure there would be tons of questions about the new PySimpleGUI27 release. I see plenty of PyPI installs already so I know it's being used 👍

2.7 Pent-up Demand

On the first day of availability, with only a single Reddit announcement, the 2.7 version of PySimpleGUI for 406 downloads. That's a pretty strong showing for day 1 with little marketing.

The Python 3 version almost topped 1,000 with 993 downloads yesterday.

Together there were 1,399 installs yesterday, the most so far for a single day.

OK, so maybe I am watching the popularity. It helps me understand where hear about PySimpleGUI and thus were I should make announcements about cool new stuff.

It's already easy....

I made an error by creating the function window.UpdateElements() this week and am removing it from the SDK.

I find I need to keep myself from over-doing the "make it easy" mantra. I'm learning that it's already easy is sometimes the answer.

Take for example Graph Axis. I wanted to add axis markers to my sine graph. I was toying with the idea of making methods to the Graph Element that would help draw the axis. However, when I thought about what an axis and the markers are, and I coded it up instead within the application, I quickly learned that it's easy for the user to make their own axis markers.

It was a lot easier when I added the DrawText method... (there was no way to draw text until I added it)

Here's my graph:

graph markers

Pretty spiffy, huh?

While the code to draw the axis is longer than the code to make the plot, it's still quite straightforward and easy to follow:

# Draw axis
graph.DrawLine((-100,0), (100,0))
graph.DrawLine((0,-100), (0,100))

# Draw markers and text X-axis
for x in range(-100, 101, 20):
    graph.DrawLine((x,-3), (x,3))
    if x != 0:
        graph.DrawText( x, (x,-10), color='green')

#Draw markers and text Y-axis
for y in range(-100, 101, 20):
    graph.DrawLine((-3,y), (3,y))
    if y != 0:
        graph.DrawText( y, (-10,y), color='blue'

3.8.2 + 1.0.4

These dual release are going to be the death of me... so will the dual code bases.

There may be a "Freezing" of 2.7 in terms of features until I can get the dual code base problem solved.

I wanted to get a couple of features out today. In particular I want to turn off grab_anywhere. While I really like this feature and thus defaulted it to being on.... it would seem other people find it puzzling. They simply don't understand why their window moves then clicking on a field.

With the widening of the users by 2.7 and I'm seeing actual classes starting to use the package, I want to get it stable and as wrapped-up as I can get it. I dunno about other people, but it feels like PySimpleGUI is at a "good place". The renaming is done, the design patterns look tight and neat. All of the major elements are done and even some of the advanced complex ones.

There are a number of "soft" areas that need some work. So, while it's fun to crank out new capabilities, there is some cleanup to be done. The docs went through major round of cleaning up, so I don't see more happening there. The areas I'm think of are:

  • A united code base
  • Graph methods are f-ing up with 2.7 (points are drawn like lines, the pixels don't seem square, etc)
  • Finish checking 2.7 demos
  • Finish tabs (colors are not done)
  • I know I'm forgetting stuff.. I have a 2-page list written down and a huge issues list

Programming Class Lesson Examples Posted

I have been conversing on Twitter with a teacher that is putting together a lesson plan for next year that includes PySimpleGUI! It's exciting that someone has signed on to give it a try in a teaching environment. This was a primary goal of the entire project.

I have posted some of his examples here on the GitHub under the folder ProgrammingClassExamples. I'm sure he would accept any feedback people have.

I'm finding it fascinating to see how other people are using the SDK. It's already being used in ways I had not thought of... it's a little scary to be honest.

One thing I really liked about the examples is that he picked up the latest design patterns and naming conventions and is following them. (Window, stringing together the Window and Layout calls, etc). It's nice looking code in my opinion. Go give one or two of them a try. Help out our up future software stars.

Old-Style Tabs Are Disappearing - Please port to new-style

The function call ShowTabbedForm and all other functions relating to the old style of tabs are soon going to be completely removed from the code. You should immediately move to the new-style of tabs if you haven't already.

I want to avoid someone finding old docs or reading the code and then using the old, unsupported and 1/2 broken functions.

Out with the old! In with the new Tabs!

Nobody said it would be easy

Last night I tried my hand at my first pull request and I have to say I failed miserably.

I struggled with the GitHub tools. I eventually went through line by line using PyCharm and made the merge that way.

It was a 3-hour process and now that it's done, I still have to go through and write a test harness to test the changes.

This is a part of the project I had not counted on being difficult.

I do want to say a big 'thank you' to @venim for making several changes to the code that I incorporated, and for being patient as I work through this process.

I hope to finish all the changes and testing them today so that I can get a PyPI release out.

The Popups in the current release still have grab_anywhere turned on by default. They need to default to off.

I forget which at the moment, but a few of the Demo programs will not run with the PyPI release due to new features.

3.8.4

3.83. was a bad release... sorry about that if you picked it up. I did not run through all the tests and I missed testing a merge that I did... incorrectly. For a couple hours the PyPI code had broken menus. It's working now.

Release contents include:

3.8.3

  • Listbox, Slider, Combobox, Checkbox, Spin, Tab Group - if change_submits is set, will return the Element's key rather than ''
  • Added change_subm3.8.3its capability to Checkbox, Tab Group
  • Combobox - Can set value to an Index into the Values table rather than the Value itself
  • Warnings added to Drawing routines for Graph element (rather than crashing)
  • Window - can "force top level" window to be used rather than a normal window. Means that instead of calling Tk to get a window, will call TopLevel to get the window
  • Window Disable / Enable - Disables events (button clicks, etc) for a Window. Use this when you open a second window and want to disable the first window from doing anything. This will simulate a 'dialog box'
  • Tab Group returns a value with Window is Read. Return value is the string of the selected tab
  • Turned off grab_anywhere for Popups
  • New parameter, default_extension, for PopupGetFile
  • Keyboard shortcuts for menu items. Can hold ALT key to select items in men
  • Removed old-style Tabs - Risky change because it hit fundamental window packing and creation. Will also break any old code using this style tab (sorry folks this is how progress happens)

Hide / UnHide Windows

A couple of new Windows methods.
Hide and UnHide work as the name says. It will completely hide a window, include removing it from the taskbar.
Several people have requested a Window disable. I implemented a Disable / Enable pair, but it's not working as well as I had hoped. This is one way to make sure people don't interact with your window while you have another window open.

Menu Shortcuts

If you're making an application that has a menu, you can make it look really professional by using Alt-key shortcuts. You can thank @vemin for this code. This menu definition:

    # ------ Menu Definition ------ #
    menu_def = [['&File', ['&Open', '&Save', '---', 'Properties', 'E&xit' ]],
                ['&Edit', ['Paste', ['Special', 'Normal',], 'Undo'],],
                ['&Help', '&About...'],]

made this professional looking window.

menus with shortcuts

And all it took was adding an & in front of the letter you want to underline.

So, go nuts... fool your friends into thinking you wrote a WinForms app. Ha ha ha! No WinForms needed here in order to get a nice looking Window.

107 Pages

That's how long the ReadMe is when pasted into Microsoft word. That doesn't count the Cookbook which adds another 45 pages. I've created a PDF from the Cookbook and uploaded it to the Docs folder

The question is whether or not people read them. I really don't know if the docs are actively used.


Speaking of documentation and Cookbooks, I created a One Minute Cookbook. The Recipes are shown in a table format with a screenshot. Here's an overview of a few pages.

one minute cookbook

one min cookbook all pages

Personally, I love the docs – when I am looking at using one of PSG's features it is nice to be able to quickly find a realistic usage case and some suggested best practices. Along with the demos, they make it easy to quickly dive into things.

PyCompactGUI

Every time I see a post on Reddit where someone has coded up a GUI in their favorite framework, I like to see if I can duplicate the results using PSG.

This is NOT an attempt to knock anyone else's efforts. I have bundles of respect for anyone with the courage to take what they've produced and put it up for public comment. It takes bravery, this I can state from experience.

There was a cool one posted yesterday that takes my CPU meter one step further. It's a graphics display of system stats. The poster wrote it in Qt. I found this particularly interesting.

https://www.reddit.com/r/learnpython/comments/9k3weg/i_just_made_my_first_python_gui_app_and_im_super/

I was able to use their module that does all of the stats gathering using psutil. I wasn't able to duplicate the stats however as that module kept crashing on certain stats, even when I ran it on Linux as the poster stated they did. For those stats, I re-used the CPU count.

This is the poster's Qt screen:

snap0374

And this is the screen from PSG:

snap0377

The layouts are almost identical.

Of course the question that I am seeking the answer to is "how much code" was required.
Not counting the stats collection, just looking at the GUI portion:

Qt - 213 lines of code
PSG - 43 lines of code

I made no attempt to compact code by removing blank lines, however if I did remove the blank lines from the total, the number would be 34 lines of actual code.

Rather than post the code as a file, I'm going to just paste the code here. I don't want to put it in the main GitHub, but I do want to share it to see if maybe I could have done something better.

One reason for the compactness is the data_dict dictionary. With it I'm able to loop through getting Element Keys and the function that should be called to get the value to be displayed using the Key. This compacted the event loop down to only 2 lines of code above the normal Read / Check for quit.

I'm actually really surprised at how short it ended up being, which is why I'm posting it here as an example.

You can knock this package for all the things it lacks, but 'results' is not one of its weak points. It's really hard to argue with the end-results.

#!/usr/bin/env python
import PySimpleGUI as sg
from modules import *

sg.SetOptions(element_padding=(3,1), auto_size_buttons=False, button_element_size=(12,1))

cpu_frame = [[sg.T('Number of CPUs'), sg.T('',key='_cpus')],
             [sg.T('Clock Speed'),sg.T('', key='_clock')],
             [sg.T('CPU Utilization'), sg.T('', key='_util')],
             [sg.T('')]]

power_frame = [[sg.T('CPU Temp'), sg.T('',key='_ctemp')],
             [sg.T('GPU Temp'),sg.T('', key='_gtemp')],
             [sg.T('CPU Fan'), sg.T('', key='_cfan')],
             [sg.T('GPU Fan'), sg.T('', key='_gfan')]]

ram_frame = [[sg.T('Total'), sg.T('',key='_rtotal')],
             [sg.T('Used'),sg.T('', key='_rused')],
             [sg.T('Available'), sg.T('', key='_ravail')],
             [sg.T('Percent Utilized'), sg.T('', key='_rutil')]]

storage_frame = [[sg.T('Total'), sg.T('',key='_stotal')],
             [sg.T('Used'),sg.T('', key='_sused')],
             [sg.T('Available'), sg.T('', key='_savail')],
             [sg.T('Percent Utilized'), sg.T('', key='_sutil')]]

layout = [[sg.Frame('CPU', cpu_frame), sg.Frame('Power', power_frame)],
          [sg.Frame('RAM', ram_frame), sg.Frame('Storage', storage_frame)],
          [ sg.RButton('Refesh', pad=((350,0),0)), sg.Button('Exit', pad=((10,0),0))]]

window = sg.Window('PC Status Details Under the Hood', auto_size_text=False, default_element_size=(15,1)).Layout(layout)

data_dict = {'_cpus': cpu_count, '_clock' :cpu_count, '_util':cpu_utilization,
             '_ctemp': cpu_count, '_gtemp': cpu_count, '_cfan': cpu_count, '_gfan':cpu_count,
             '_rtotal': ram_total, '_rused': ram_used, '_ravail': ram_available, '_rutil':ram_utilization,
             '_stotal': storage_total, '_sused': storage_used, '_savail': storage_available, '_sutil':storage_utilization}

while True:     # Event Loop
    button, value = window.Read()
    if button is None or value is None:
        break
    for key, value in data_dict.items():
        window.FindElement(key).Update(value())

New 3.8.5 release posting to PyPI today

I'm posting a new version today to PyPI. Anyone have a feature they want to make sure is included?

Currently it has these:

  • Fix for Menus.
  • Fixed table colors. Now they work
  • Fixed returning keys for tabs
  • Window Hide / UnHide methods
  • Changed all Popups to remove context manager

The only "new" functionality Table Hide / UnHide.

Update errors

Would like to know if anyone is using a try block around calls to Element.Update()

I made an error checking change could cause a problem with your code. Please post if use try's with Update.

Use PyCharm's macro capabilities!

Maybe I'm the only one making lots of GUIs on my scratchboards, if so, you can ignore this. I find myself throwing together GUIs a lot while trying to help people, making new Demos, etc.

I got tired of typing the same template code or opening a template .py file, copying, pasting, etc.

PyCharm to the rescue. I used their "Live Template" feature.

I type Control+J and I see this

snap0383

If I choose the simple one I get this typed into my window:
snap0380

And if I choose persistent I see this one

snap0381

"poof! Instant running GUI"

Confirmation GUI

I was adding an item to my toolbar, a Release to PyPI one to be specific and I want to be SURE before something like that happens. So I added this if statement.

if (sg.PopupYesNo('Are you sure?', keep_on_top=True) == 'Yes'):
    print('Doing important stuff here')
else:
    print('** Cancelled **')

I got this little box popped up on top of everything else
snap0384

Debug your GUI using the GUI

3.8.6

  • Fix for Menus.
  • Fixed table colors. Now they work
  • Fixed returning keys for tabs
  • Window Hide / UnHide methods
  • Changed all Popups to remove context manager
  • Error checking for Element.Update calls ( no more crashes when calling Update on a bad element!)

tab_location Setting For TabGroup Element

Something for all you advanced Tab-users. You can now specify the location your tabs will show up by setting the tab_location parameter in you TabGroup Element. Choices are top, bottom, left, right.

snap0388
snap0387
snap0386
snap0385

PySimpleGUI Tutorial on YouTube

It seems like some people want to learn by watching other people code on YouTube.... so, I took a chance and stuck my neck out by making a video that shows how to build a CPU Meter using PySimpleGUI.

Here's my Reddit post if you're interested.
https://www.reddit.com/r/Python/comments/9kkine/tutorial_build_a_cpu_utilization_meter_using/

Personally, I don't think I could stand watching me code for 5 minutes, but who knows, maybe other people like this kind of stuff.

Coding Convention

I've presented a number of Templates and Design Patterns in the documentation, cookbook and demo files.

I openly steal good ideas from the PSG community. I just found a new one that I really like that concerns keys that I'm swiping and modifying that came from @jfongattw.

We're all using keys a lot more since they are used to identify elements. I have modified the way I am naming my keys. I am adding '_' to the beginning and ending of my key values. This makes spotting keys in the code trivial (I like trivial).

The tutorial I did earlier today used keys like this:
[sg.Text('', size=(8,2), font='Helvetica 20', justification='center', key='_text_')],

Later when I needed to update that element:
window.FindElement('_text_').Update(f'CPU {cpu_percent:02.0f}%')

I like this enough that I'm going through the code and docs to rename all my keys this way. I would like to set this as the design pattern newcomers to adopt in their key values. If you're using keys, give it a try and let us know what you think.

New "advanced" widgets

I've been on the lookout for new ways of displaying information. It would be nice to be able to build a Dashboard using PySimpleGUI. I can do this using both Matplotlib as well as other methods.
I just stumbled on an interesting one. This program uses Pillow to create a PNG of a speedometer. I just ran it with a value of 87. The result was this:

new_gauge

I should be able to adapt this to output to an Image Element.

https://github.com/Andrew-Shay/python-gauge

Another COOL METER!

I found this posted on StackOverflow... it's amazing what people post sometimes. Sometimes it's an entire implementation, like this one!

import tkinter as tk
from math import pi, cos, sin


class Meter(tk.Frame):
    def __init__(self, master=None, **kw):
        tk.Frame.__init__(self, master, **kw)

        self.meter = []
        self.angle = []
        self.var = tk.IntVar(self, 0)

        self.canvas = tk.Canvas(self, width=200, height=110,
                                borderwidth=2, relief='sunken',
                                bg='white')
        self.scale = tk.Scale(self, orient='horizontal', from_=0, to=100, variable=self.var)

        for j, i in enumerate(range(0, 100, 5)):
            self.meter.append(self.canvas.create_line(100, 100, 10, 100,
                                                      fill='grey%i' % i,
                                                      width=3,
                                                      arrow='last'))
            self.angle.append(0)
            self.canvas.lower(self.meter[j])
            self.updateMeterLine(0.2, j)

        self.canvas.create_arc(10, 10, 190, 190, extent=108, start=36,
                               style='arc', outline='red')

        self.canvas.pack(fill='both')
        self.scale.pack()

        self.var.trace_add('write', self.updateMeter)  # if this line raises an error, change it to the old way of adding a trace: self.var.trace('w', self.updateMeter)
        self.updateMeterTimer()

    def updateMeterLine(self, a, l=0):
        """Draw a meter line (and recurse for lighter ones...)"""
        oldangle = self.angle[l]
        self.angle[l] = a
        x = 100 - 90 * cos(a * pi)
        y = 100 - 90 * sin(a * pi)
        self.canvas.coords(self.meter[l], 100, 100, x, y)
        l += 1
        if l < len(self.meter):
            self.updateMeterLine(oldangle, l)

    def updateMeter(self, name1, name2, op):
        """Convert variable to angle on trace"""
        mini = self.scale.cget('from')
        maxi = self.scale.cget('to')
        pos = (self.var.get() - mini) / (maxi - mini)
        self.updateMeterLine(pos * 0.6 + 0.2)

    def updateMeterTimer(self):
        """Fade over time"""
        self.var.set(self.var.get())
        self.after(20, self.updateMeterTimer)


if __name__ == '__main__':
    root = tk.Tk()
    meter = Meter(root)
    meter.pack()
    root.mainloop()

New Demo Program - LED Status Indicators

Slowly trying to duplicate what I see on other GUIs out there. One popular use for GUIs is to display status or show a Dashboard. A "Stoplight indicator"or LED indicator is a popular widget on Dashboards.

I created a couple of little functions that make it easy to add these to your Windows.

This layout

layout = [[sg.Text('My layout')],
          [sg.Text('CPU Use'), LEDIndicator('_cpu_')],
          [sg.Text('RAM'), LEDIndicator('_ram_')],
          [sg.Text('Temperature'), LEDIndicator('_temp_')],
          [sg.Text('Server 1'), LEDIndicator('_server1_')],
          [sg.RButton('Read The Window'), sg.Exit()]]

Produced this window:

led indicators

To change one of the indicators:
SetLED(window, '_cpu_', 'green')

UNIFIED CODE BASE!

A HUGE thanks is owed to @rtrrtr for help with Pasteurize!! THIS solved SO many problems.

I now have a single code base. I generate the PySimpleGUI27.py file from my core PySimpleGUI.py file. No more completely separate files. Whew! It was really stressful running 2 code bases. The 2 version was lagging already and I wasn't going to be porting stuff over anytime soon.

Now I'm going to publish the thing on PyPI and see if it works!

I've just uploaded it to Master.. but will soon pop it up on PyPI. Experience tells me that having it in Master doesn't actually buy much usage or early testing. Few people download from Master, especially for Version 2.7.

So, I'm going to roll the dice. I'm going to do a unified PyPI release... both at the same time so they're in perfect sync. Yea, I'm cranking through the release numbers, but, heck, I'm cranking through the releases so it's not like I'm inflating the numbers. These are hard earned releases damnit.

3.9.0 & 1.1.0 The first unified release

It's done.... a single PySimpleGUI codebase release.

Let's hope it doesn't go south on us. I think it should be fine, but I've thought that many times when disaster was moments away.

The only feature change for the P3 version is Tab Locations, a really cool feature in my opinion and one I hope people will explore. Surely there's some cool GUI layouts that must exist using tabs on the left or bottom of windows. Try them out. I may need to add more options for locations. You'll soon see there's a top and bottom on the left side :-)

Enjoy!

1.1.1 Ooopss....

I forgot to put in the readme that for the 2.7 version you need to pip install future

Love your enthusiasm, this is a great project.

Why thank you! I'm certainly "into this project". Glad to see you're a fan of it too. When looking at the results of the project alone, it's a rather remarkable capability. I've never seen anything like it, in any language. Cross-platform GUI development across Windows, Mac and Linux is downright easy / trivial using PSG. Someway, maybe someday, it can be extended to Android and iOS. That would be awesome!

Demos demos demos

I've been adding more demos lately. I've not said much here about them. We're up to 76 Demo programs. Two I added tonight that I like are Pyplot programs that both create bar charts. I thought that maybe a few people would be inspired by the simplicity that they may jump in and try making some of their own. You've got more toes than there are lines of code.

Check out how downright trivial it is to produce these charts. Who said Excel was the best at all-things-numbers. I dunno about you, but I've struggled over the past 5 or 6 years to create simple graphs in Excel. They've made it hard. Cheat and use Python instead next time.

I've started to create Demos in pairs. One for the super-simple case and then another that's more complex. For these bar charts, they are both pretty simple.

The way these demos work is that you paste the Pyplot code into the marked section.

# ------------------------------- PASTE YOUR MATPLOTLIB CODE HERE -------------------------------

import numpy as np
import matplotlib.pyplot as plt

values_to_plot = (20, 35, 30, 35, 27)
ind = np.arange(len(values_to_plot))
width = 0.4

p1 = plt.bar(ind, values_to_plot, width)

plt.ylabel('Y-Axis Values')
plt.title('Plot Title')
plt.xticks(ind, ('Item 1', 'Item 2', 'Item 3', 'Item 4', 'Item 5'))
plt.yticks(np.arange(0, 81, 10))
plt.legend((p1[0],), ('Data Group 1',))


# ------------------------------- END OF YOUR MATPLOTLIB CODE -------------------------------

snag-0012

A slightly more complex version

#------------------------------- PASTE YOUR MATPLOTLIB CODE HERE -------------------------------
import matplotlib.pyplot as plt
import numpy as np
label = ['Adventure', 'Action', 'Drama', 'Comedy', 'Thriller/Suspense', 'Horror', 'Romantic Comedy', 'Musical',
         'Documentary', 'Black Comedy', 'Western', 'Concert/Performance', 'Multiple Genres', 'Reality']
no_movies = [941, 854, 4595, 2125, 942, 509, 548, 149, 1952, 161, 64, 61, 35, 5]

index = np.arange(len(label))
plt.bar(index, no_movies)
plt.xlabel('Genre', fontsize=5)
plt.ylabel('No of Movies', fontsize=5)
plt.xticks(index, label, fontsize=5, rotation=30)
plt.title('Market Share for Each Genre 1995-2017')

#------------------------------- END OF YOUR MATPLOTLIB CODE -------------------------------

snag-0011

Themes for Tabs

You enable them by adding the theme parameter to the TabGroup element.

sg.TabGroup([[sg.Tab('Tab 1', tab1_layout), sg.Tab('Tab 2', tab2_layout)]],theme=sg.THEME_XPNATIVE)

New feature of the day.... themes for tabs.
Make your tabbed windows look even better by throwing a theme onto theme.

You have 8 to choose from on Windows and 5 to choose from on Linux. I dunno about Mac.... likely only 1 for you Mac people (and you should be happy with that ;-)

I was surprised to see the code crash and burn when using 3 of the themes on Linux. Those 3 are winnative, vista and xpnative. Yes, all windows terms, but damn, can't you at least use those designs on Linux. Linux "borrows" stuff from Windows all the time.

Choices for Windows

No theme parameter

theme none

THEME_VISTA
theme vista

THEME_CLASSIC
theme classic

THEME_CLAM
theme clam

THEME_ALT
theme alt

THEME_DEFAULT
theme default

THEME_WINNATIVE
theme winnative

Linux Themes

No theme specified
theme none linux

THEME_DEFAULT
theme default linux

THEME_CLASSIC
theme classic linux

THEME_CLAM
theme clam linux

THEME_ALT
theme alt linux

As usual, the docs are lagging in telling you about this.... so consider it a treat for you "announcement" readers. It'll be released on PyPI soon. There are getting to be enough features for a release. The Tab features are drawing to a close, despite not yet figuring out how to set the tab background color (admitting de-feet)

Ideas for new features

I read a lot of sites, looking for information about ttk or tkinter features I've not yet implemented or that I can implement better.

Today I found this rather remarkable site.

https://pyinmyeye.blogspot.com/

I thought it may inspire some of us to come up with more creative features.... not that I've run out of features!! There is still much work to do in implementing the Tree Element and fixing up the Table Element. Still, it's fun to be able to provide a rich menu of things for you to add to your GUIs.

We've got a good thing going and I need your help and encouragement in order to keep new stuff coming. I clearly am not coming up with these things on my own.

www.PySimpleGUI.org Documentation Improved

Remember that you can quickly get to the read-the-docs for PSG by going to www.PySimpleGUI.org . This is where I send people as an introduction to the package. www.PySimpleGUI.com on the other hand brings you to the GitHub. http://tutorial.PySimpleGUI.org will get you the tutorial.

I went through the "readme" which is actually the User Manual, and updated the outline levels so that now you can quickly jump to individual Element definitions.

The TOC looks like this for the section that covers the Elements:

snag-0042

Clicking on the Checkbox Element brings you straight to the parameters definition for the Element:

snag-0043

While not a huge change to in terms of the number of characters changed, the usefulness of this document just jumped way up.

New coding convention

I've proposed a couple of coding conventions that I've adopted. I'm just now starting this one so I dunno if I'll stick with it.

The Window definitions sometimes have a number of parameters set. While the Elements also have lots of parameters, you can't really do much to improve readability because they are in the middle of a window layout definition.

I've started to break apart the parameters and putting them one per line, just like I did the call definitions on the ReadMe file.

# Make a window
window = sg.Window('My window',
                   default_element_size=(20,1), 
                   auto_size_text=False, 
                   return_keyboard_events=True, 
                   text_justification='right').Layout(layout)

I think the readability greatly outweighs the downside of taking up more lines of code.

Hoping I can remember to do this! If you see I'm not in something new I'm posting, please say something. I'll do this to the Demo programs, Cookbook, tutorial and readme file as I'm doing other updates.

New Killer Demo!

Another day, another PSG demo....

Today something that we can all actually USE for a change.

It's a process killer using psutil. I've checked it out on both Windows and Linux and it's working great. Sorry Mac people, you're likely left out of the party since all the cool features are broken on mac 👎

The filename is
Demo_psutil_Kill_Processes.py

Follow the on-screen directions.
You can kill more than 1 process by selecting more than 1 in the listbox. To do this, hold the control key while making your selection.

If you have suggestions on making it better, speak up. I thought about making it a "stay on top window" as these utilities tend to be more useful if on top of the windows you want to kill.

I'm creating a hot-key to launch this program and am giving up using taskmanager for this task.

Enjoy!