Join GitHub today
GitHub is home to over 50 million developers working together to host and review code, manage projects, and build software together.
Sign upAnnouncements #142
Announcements #142
Comments
New use pattern - Element lookup using Keys
To get an element object from a form, you call 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 The new design pattern is thus:
Later in your code you can update this Text Element by making this call, assuming the variable form is your FlexForm object:
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 HereTry them on your next form. You can expect to see some of these in the Demo programs. 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 AnywhereTonight'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, set 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! 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. |
TablesThis 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. 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:
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: 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 |
|
|
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 programThis 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 FormsUpdated 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 |
Floating Desktop WidgetsI've discovered that in about 30 lines of code you can create a floating desktop widget. If you click the pause button, it switches to Run. 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. |
3.7 SupportThanks 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.00Menus! (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? |
3.1.1There 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 updatedAdded the ability to enable / disable all input elements. 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! |
3.1.2Big change this time around is the ability to disable widgets. All input widgets have an Update method that has the parameter 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 ElementYou 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 ElementAdded another Desktop Widget to the demos. This one shows the CPU utilization. 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. 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 MsgBoxYou can blame the Popup changes on this issue: 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 ElementsFinally have something to show in the form of tables. The element name is 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. 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.
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 EnvironmentI 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. 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.0Released 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 Instead of calling The call sequence becomes this:
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 MetersPySimpleGUI 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. |
3.3.0Yea, 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....
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. |
GraphingNew demo program - graph ping using canvas. 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. |
Progress MetersThanks 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:
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 ElementThis 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:
The draw line draws a line from 1 point to another. The points are specified using your graph coordinates, not the tkinter canvas coordinates. 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. 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:
To draw a line, call DrawLine:
|
Short-term Roadmap - Qt help is coming... hang in there.....I know there are a number of outstanding Qt issues and questions. For those of you waiting, I feel your pain. I thought it would be good to give a little visibility into my near-term priorities and upcoming work. Summary of what's happening
|
New Matplotlib Demo / Updated Matplotlib TemplateWhile putting together some screenshots for the new readme it dawned on me that I've not done anything to make Matplotlib plots look different than the default grey color scheme. After a quick bit of research, I discovered the "Style" setting for plots. This resulted in 2 changes.
The reason for 2 demos is that the template is designed to run on tkinter, Qt, and Remi with no changes other than the import statement. It's a "template" meant to be run anywhere. Changing themes requires restarting a window and this isn't currently possible with the Remi port. So, the demo that has the ability to change both the PySimpleGUI Theme and the Matplotlib Style was created and is targeted to the tkinter port. Here is what the new demo looks like in action: There are a lot of these Matplotlib Styles available and you can try all of the ones installed on your system because the combobox is populated with the values returned by Matplotlib. There was more styles available than I expected! Here's what I get when asked Matplotlib which are available: bmh The Matplotlib Style "dark_background" looks pretty good when paired with the new Dark Grey 11 theme. |
Apologies for the slow progressThis readme rework has been ongoing for over 1 1/2 weeks. It's causing everything else listed earlier for the short-term to get pushed out. Progress is being made, every day, just at a much slower pace than expected. Lots of restarts and re-writes. There have been a number of medical issues that have complicated things considerably, but that's no excuse. Even when the shortened readme is completed, there are still a number of parts of it that I want to complete like a much better "user spotlight" where you can submit images and info about your applications in a better / more visible way than the current primitive User Screenshot issue. While some of the nicer screenshots are being pulled out for this condensed document, there is also a massive scrapped set of images from the over 1,000 GitHub repositories that GitHub lists as using the tkinter port of PySimpleGUI. So, these images don't include any of the other ports. Perhaps I'll get those scrapped soon too. The images, all 3,200 of them, can be viewed here: Some may not be of PySimpleGUI windows themselves and are instead supporting documents or other images in the repo. Apologies for you having to endure those. I've not been able to weed them out, so expect a fair number of them to be my early test images and other images that were used to create the documentation. My hope is that because they are really simple to scroll through, you'll be able to quickly scan and pick out a few that you may draw inspiration from. There are a lot of good things right on the horizon for PySimpleGUI in 2020. The user support has been fantastic and I'm really grateful for everyone's support and patience. I've got a couple of difficult days ahead in my non-online / real world, so I might not be online as often as usual. Just know it's not because I'm ignoring your requests or don't want to help. Back soon and hopefully will be able to wrap up this current set of distractions. Thank you all again. You're the BEST user community on the net! |
ReadmeThe new readme is posted! It doesn't LOOK like 2 weeks of work, but somehow that's what it took. There is some follow-in documentation work that now needs to happen to the primary documentation a well as a new education tab to the main docs. Hopefully it will provide new visitors a little more compact overview than the massive 100's of pages the first readme has. Thanks to everyone that's been patient while I've stepped away for several days at a time. |
4.30.0 Right Around the Corner....Working hard on getting the 4.30.0 release out the door so that I can then (finally) get back on the Qt release. The 4.30.0 release has the new "User Settings" API so there's been work to get that tested and finished up. No official demo has been made yet, but it won't take long to make one. I want to make one that shows realistic use such as saving/loading the program's theme. The most recent hold-up however has been button focus indicators. It's only been today that I discovered what I think will be the right way of dealing with the focus indicators. If left to default values, the buttons and other elements always looked terrible. It's why the "highlight thickness" was set to 0 several releases back. What I didn't realize at that time was that it removed the focus indicators entirely. Linux and Windows differ in focus indicatorsHere are the buttons on the latest test harness when running on Windows. The button with the label "Button" has the focus. Sorry about both a "Sponsor" button and a Buy Me a Coffee. I'll be removing the sponsor one for 4.30.0. :-) Anyway, back to the focus.... WindowsLinuxAs you can easily see, there's a big difference in how focus is communicated. It's only been today that I pieced together that a good approach to use is to use the button colors to color the focus. Linux - new methodIf I use the theme's button colors then the highlights look nice. There's another addition to the test harness that enables you to try out the different themes so that testing these kinds of things is easier. Here's how the highlights look with the Dark Red theme. Notice how the highlight matches the buttons better. The only problem with this color algorithm is that some themes have button text that matches the background color, which will make the highlighting disappear. So, as you can see, I got hung up a little bit while testing the release and as a result have been doing a little more development when I was supposed to just be testing. |
Thank You Japanese Users!Not sure how many users follow Twitter. Almost daily someone from Japan posts a comment about PySimpleGUI, or a new tutorial is posted that's written in Japanese. They're really kind posts and I find them personally uplifting to read. As a way to say "thank you" to these awesome users, I thought perhaps translating the readme file into Japanese using a human being to translate would be a nice gesture. You'll find a Japanese version of the readme located here: There is some question as to how well the translation was done with some people commenting that some of the nuances are not quite right. I'm getting some help from a Twitter user so hopefully, it'll be a bit better soon. I was able to get the code translated at well so that the screenshots look correct. Here's a short potion with a code example: |
New Demos - User Settings & Vertical AdjustmentsTwo new demos have been published this week. The vertical alignment demo can be used with the already published 4.29.0 release. The User Settings APIs demo is best used with the upcoming 4.30.0 release or by running the 4.29.0.17 version that's on GitHub. The documentation for the User Settings APIs will be in the documentation included with the release. It's already written and will be posted with the PyPI release. Vertical Alignment Demo: https://github.com/PySimpleGUI/PySimpleGUI/blob/master/DemoPrograms/Demo_Layout_Vertical.py User Settings Demo: https://github.com/PySimpleGUI/PySimpleGUI/blob/master/DemoPrograms/Demo_User_Settings.py While waiting for the documentation and release to be published, you can use these demos as a design pattern that you can copy and modify. Note that one of the layouts in the Vertical Alignment Demo uses unpacking within a list. Support for unpacking inside of a list was added in 3.5. Because PySimpleGUI is compatible with Python 3.4 I placed that particular example inside of a Try/Except block so that it did not generate a syntax error. Otherwise, you would not be able to run the file at all on a 3.4 system. |
The Joys of LinuxSo the 4.30.0 release was going really well! I've been testing it for the past week on Windows and Linux. Yesterday I was running with the latest Python version 3.9.0 when disaster struck. My PyCharm settings were overwritten on my Linux system. I didn't think it would be the disaster that it's been, but it's been a disaster. Running multiple versions of Python on Linux with PyCharm wasn't a very easy thing to set up initially and I'm struggling to get things going again. The good news is that the new highlighting for Linux buttons, checkboxes, and radio buttons worked great. 3.9.0 worked fine with PySimpleGUI as the tkinter version didn't change on Linux and I've been testing it on Windows where it has a tkinter version of 8.6.9. OK, well, back to rebuilding my environment. I really hoped to get the release out this weekend, but it's not looking good now. Maybe I'll come out of this with a more robust Linux setup, or maybe it'll just be a lost weekend.... hoping for the more robust option.... Back Up & RunningThankfully adding the interpreters back worked out OK when I added them as virtual environments. I recently started to use I was able to add back the 3.6.9 and 3.9.0 interpreters and am back to testing the release! PyCharm makes it easy to switch around the versions of the interpreter to use. Focus OutlinesPart of the delay of 4.30.0 was due to the last-minute addition of the focus outline was what started this mess. I wanted to get focus indicators working correctly on Linux. They're done entirely different than on Windows. On Linux, there is a "highlight" that is used to show focus. This setting is not used on Windows.... thus the need to do more testing this time around on Linux than usual. The default colors are derived from the Theme's colors. I know someone's going to want to set it to some other color than what PySimpleGUI sets, so a new paramter was added to Button elements.... :param highlight_colors: colors to use when button has focus (highlight, background). None will use computed colors. Only used by Linux and only for non-TTK button
:type highlight_colors: Tuple[str, str] |
New Demo - GitHub File CopierI decided to post a utility I use every day. I wasn't sure if others would find it to be of value, but maybe someone will. Minimally it shows another example GUI and how to implement it using PySimpleGUI. I think these are the highlights of features you may be interested in:
UsesThe Demo Programs area is getting to be pretty big and I'm constantly modifying existing demos or creating a new one. I was using PyCharm to browse these files, choose to edit, and also to copy from my working folder to the GitHub folder. It has been much easier using this little application than using PyCharm. If you're managing a list of files that you modify often and copy to a GitHub folder, then perhaps it'll be of interest to you. I run the GUI version of GitHub, not the command line version. As a result, I have a button that launches GitHub. This makes for a smooth overall process. I select the files I want to check into GitHub, click the copy button, then click the Launch GitHub button where I can then add a comment, etc, and check the files into GitHub. Oveall it's less than 100 lines of code. It's made for a very efficient process for dealing with these Demo Programs. By having a filter I'm able to quickly locate one or more Demo Programs. I can then run, edit or copy them. It's a lot quicker than browsing via PyCharm. |
It Could Be So Much BetterI'm pretty sure a number of users have thought that, a number of times. Parts of the documentation are too long, too old, or suck. There are piles of problems in some releases. And, the 2020 pace has not been as productive as 2019. In some ways, opening up the project to pull requests would help the project from a workload perspective. What it would do for me personally is change the amount of time I spend on each activity. I try and give everything I have to this project. Adding something doesn't mean I can work harder and add it for free. Something else has to be done less. The amount of time is constant. The % of each activity is what changes. I enjoy this project. There are a number of you that enjoy it too. I get some really heartwarming emails that tell me I'm on the right track, even if a speeding train isn't on that track at the moment. I enjoy the mix of activities. What I don't enjoy is merging in other's code and then being responsible for it using it. I don't want to do code reviews. I don't want to be responsible for someone else's code or documentation. So, I'm choosing not to do that. I would be unhappy and as a result, the project would ultimately suffer. I basically work for free and as a result, it seems like I should have a pretty big influence on how my time on this project is spent. There are a select few that do help, some paid, others not. I hired a translator to create the Japanese version of the readme this past week. There are some times where I do get some help, but it's unusual, and I like it that way. I'm going to do the best I can for the project. You've got my promise on that one. I'm dedicated to making it a great experience for everyone. I hope you're satisfied with the results you've achieved so far and I'm looking forward to a bright future ahead. Thank you to everyone for your support, in whatever form that takes. Could PySimpleGUI be better? Of course, it can be a lot better. And, maybe I'll be able to do enough for everyone to be happy and successful. If I'm not able to get it and keep it at "good enough", then, well, it's been a lot of fun and I hope people have had a grand time. I sure have. |
Theme Color Swathes DemoPosted another theme-related demo. There are some image editing / paint programs with an eye-dropper tool to grab colors from another part of the screen. To make it easier to grab colors from PySimpleGUI themes, I made this program that displays the colors found in each theme as a series of smudges of each color. It enables easily sampling of colors by a dropper. InteractivityYou can interact with the window in these ways:
While only 54 lines of code, there's a lot happening in this demo, including a couple of clever uses for PySimpleGUI components. Tuple Keys to Achieve Unique KeysFor example, when you click on a color, it will return an event. Because we want the color when a left click is made, there are a lot of ways of making this happen. You could put it into the A tuple is used so that the first value in the tuple is unique in the layout. A sequential counter is all that's needed. The second value in the tuple is the color code itself. So, if an event is a tuple, we know that the color is in the second position of the tuple. |
4.30 Likely Tomorrow....Still working on the documentation. Added the swatches demo above to the code as another theme previewer option. You can get to it from the test harness or can call it directly. Getting the release notes together now. Have a few more doc changes to make and then will be good to go. It's all tested on multiple versions of Python, multiple operating systems and the Pi too. Looking forward to getting it out, and onto Qt. |
GitHub Stars - Nominate Your Favorite GitHub UsersI just learned about a program that GitHub has called "GitHub Stars". You can nominate up to 3 developers. I had no trouble listing 3 people that I found particularly helpful that I thought were also impactful to the community at large. Take a moment from your busy day to say "thank you" to some of your favorite developers by nominating them. Science has shown a direct link between gratitude and happiness. Seriously....... being thankful can make you feel happier. Do it for yourself if not for someone else. |
4.30.0 PySimpleGUI 14-Oct-2020User Settings APIs, lots more themes, theme swatch previewer, test harness additions,
|
User Settings - A New Era (for my programs)I'm starting to really see the power these user settings things can have. They essentially add "history" or state that lasts for, forever, essentially. This is a fun new demo program. import PySimpleGUI as sg
"""
Demo - Save previously entered strings as a Combobox entry by using user_settings calls
It's literally 1 parameter in the layout to get the list of previously used entries shown.
Then, when the OK button is clicked, it's 4 more lines of code to save the newly added
name into the saved list.
Copyright 2020 PySimpleGUI.org
"""
def main():
layout = [[sg.T('This is your layout')],
[sg.T('Enter or choose name'), sg.Combo(sorted(sg.user_settings_get_entry('names', [])), size=(20,1), k='-COMBO-')],
[sg.OK(), sg.Button('Exit')]]
event, values = sg.Window('Pattern for saving with Combobox', layout).read(close=True)
if event == 'OK':
sg.user_settings_set_entry('names', list(set(sg.user_settings_get_entry('names', []) + [values['-COMBO-'],])))
print(f"You chose {values['-COMBO-']}")
if __name__ == '__main__':
main()The cool thing about combo boxes is that they are actually a normal text input widget, except they have a drop-down list portion too. Let's say you have a program where you enter some value and maybe it's something you enter the same value for often. Maybe it's your login ID. In this demo, I simply called it "name". When you run the program, this is the window that's shown. You can directly type into the blank area shown for the Combobox. You can also click the down-arrow and see the previously entered values, sorted: A Small Amount of Work for a Better User ExperienceIf you look at what it took to provide this interface to a user, it required a single parameter in your Combo call sg.user_settings_get_entry('names', [])and a single line of code to add a newly entered value to the history of values. sg.user_settings_set_entry('names', list(set(sg.user_settings_get_entry('names', []) + [values['-COMBO-'],]))) |
A "Better" File BrowseHere's a sneak peek at an upcoming demo program. The idea is to improve the standard file browsing experience by recalling not only the last entry made but also retaining/using a history of previous entries. If you only want to use the previously entered value, then you don't need a Combo element for that. You can continue to use an Input element. But if you want to retain and use historical values, you'll want to use a Combo. Here's a rough prototype for an upcoming Demo Program using this technique import PySimpleGUI as sg
"""
Soon-to-be Demo of a Better File / Folder Input Window
This construct is very common in PySimpleGUI.
[sg.InputText(size=(50,1), key='-FILENAME-'), sg.FileBrowse()],
The new user settings APIs can significantly improve the experience.
Two new capabilities are presented in this demo
1. Recalling the last entry
2. Recalling a history of all of the previous entries as a Combo instead of Input Element
"""
# ------------------- The Old Way -------------------
layout = [ [sg.Text('My Window')],
[sg.InputText(size=(50,1), key='-FILENAME-'), sg.FileBrowse()],
[sg.Button('Go'), sg.Button('Exit')] ]
event1, values1 = sg.Window('Window Title', layout).read(close=True)
# ------------------- The New Way -------------------
layout = [ [sg.Text('My Window')],
[sg.Combo(sg.user_settings_get_entry('filenames', []), default_value=sg.user_settings_get_entry('last filename', ''), size=(50,1), key='-FILENAME-'), sg.FileBrowse()],
[sg.Button('Go'), sg.Button('Exit')] ]
event, values = sg.Window('Window Title', layout).read(close=True)
if event == 'Go':
sg.user_settings_set_entry('filenames', list(set(sg.user_settings_get_entry('filenames', []) + [values['-FILENAME-'], ])))
sg.user_settings_set_entry('last filename', values['-FILENAME-'])The first window you'll see is the standard get a filename window. The second window is the one with historical values and looks something like this: |
Hooked on historyI'm officially hooked on the user experience of having a history for elements. My GitHub copy program, that I run all day every day, now has a single-file launch added at the bottom A Shorter Way Coming (I hope)While it's literally one or two lines of code to get this feature, they're a little bit tricky to add. I want to design some "user defined elements" or something along that line of thinking to make these kinds of entry elements easy to make. The Last EntryHaving only the last entry entered into a field is the easiest for a user to implement. When you're testing a piece of code and re-using the same file/entry over and over, having the program remember that value and fill it in automatically is GOLDEN. WOW, what a time saver. Replaced Combo DemoI've replaced the demo that showed only a combobox with history with a demo that shows an Input element that recalls the last entry and a combobox that recalls the entire history. Here's the entire program minus the header comment: import PySimpleGUI as sg
def main():
layout = [[sg.T('This is your layout')],
[sg.T('Enter or choose name'), sg.Combo(sorted(sg.user_settings_get_entry('names', [])), size=(20,1), k='-COMBO-')],
[sg.T('Remembers last value'), sg.In(sg.user_settings_get_entry('input', ''), k='-INPUT-')],
[sg.OK(), sg.Button('Exit')]]
event, values = sg.Window('Pattern for saving with Combobox', layout).read(close=True)
if event == 'OK':
sg.user_settings_set_entry('names', list(set(sg.user_settings_get_entry('names', []) + [values['-COMBO-'],])))
sg.user_settings_set_entry('input', values['-INPUT-'])
print(f"You chose {values['-COMBO-']}")
if __name__ == '__main__':
sg.user_settings_filename(path='.')
main()A User Settings Coding ConventionI'm on the verge of creating a new coding convention for my demos. I'm sure some don't agree with my coding conventions, but, I can't please everyone and I like having a convention that I follow for consistency. I really like being able to scan the code and if I run across a string, anywhere in the code, that looks like this As I scan through the code that uses user settings, I'm faced a similar challenge. Sooooo...... Here's the convention. Still going to place the dashes at the begging and end, but rather than being upper case, user settings will be lower case. Here's the demo code again, using the new user_settings coding convention: import PySimpleGUI as sg
"""
Demo - Save previously entered strings for Input and Combo elements by using user_settings calls
It's literally 1 parameter in the layout to get the list of previously used entries shown.
Then, when the OK button is clicked, it's one line of code to save the newly added
name into the saved list.
Copyright 2020 PySimpleGUI.org
"""
def main():
layout = [[sg.T('This is your layout')],
[sg.T('Enter or choose name'), sg.Combo(sorted(sg.user_settings_get_entry('-names-', [])), size=(20,1), k='-COMBO-')],
[sg.T('Remembers last value'), sg.In(sg.user_settings_get_entry('-input-', ''), k='-INPUT-')],
[sg.OK(), sg.Button('Exit')]]
event, values = sg.Window('Pattern for saving with Combobox', layout).read(close=True)
if event == 'OK':
sg.user_settings_set_entry('-names-', list(set(sg.user_settings_get_entry('-names-', []) + [values['-COMBO-'],])))
sg.user_settings_set_entry('-input-', values['-INPUT-'])
print(f"You chose {values['-COMBO-']}")
if __name__ == '__main__':
sg.user_settings_filename(path='.')
main() |
GitHub File Manager Demo UpdateOver the past few days, a number of changes have been made to the GitHub file manager demo. Most of the changes were the addition of user_settings and the Settings Window. There was also a "grep" feature added. If you type into the "Find" input then the list of files will be narrowed to be only those files that have the string you've entered. The case is ignored so you don't have to worry about getting the case correct. For example, if I want to find all of the demos that make calls to the user_settings API, I can enter "user_settings" into the find input and the file list is shortened to only those files that contain the string entered. Since the constants defined previously are now user settable, you can specify any code editor you want. You're not limited to PyCharm. The assumption is that invoking your program with the file to edit on the command line is all that's required to open it. I tested this with NotePage++ and PyCharm. More User SettingsThe demo program in the last post has continued to get some attention. Decided that it's time for this program to have a real "settings window". This removes the need for constants at the top of the program that provides the location for your GitHub program or your editor. The code had 4 constants at the top. DEMO_PATH = r'C:\Python\PycharmProjects\PSG\DemoPrograms'
GIT_DEMO_PATH = r'C:\Python\PycharmProjects\GitHub\PySimpleGUI\DemoPrograms'
GITHUB_PROGRAM = r'C:/Users/mike/AppData/Local/GitHubDesktop/GitHubDesktop.exe'
PYCHARM_BATCHFILE = r"C:\Program Files\JetBrains\PyCharm Community Edition 2019.1.1\bin\pycharm.bat"These are easy enough for someone to change, but since we're designing GUI programs, why not make our programs in a way that doesn't require them to be edited when switching to a new environment? Those 4 lines of constants have been replaced by this window: I had an epiphany when writing this settings window.
That's exactly what they are in this program. If a function wants to know the name of the GitHub program, it can get this value by making this call: github_program = sg.user_settings_get_entry('-GitHub Program-', '')Instead of using a global variable, user settings becomes a place where global information is stored and shared. DefaultsIf you use the default path and filename for your settings file, then you only need the calls to get and set. It's really safe to use the default values for the path and filename because doing so will place them in a known location for settings files and the name will be unique to the filename. As long as you don't name your .py files the same name, then your settings for that file will be unique. It's made for a very pleasant experience to code in this way. The downside of no longer using constants is that you need a "Settings Window". Settings WindowThey're not as bad to make as you may initially think. We're writing GUI programs so why not toss in a settings window to be kind to your user? This added window is quite simple in reality. It has a layout, a one-shot read, and a block of code to save the settings if the OK button is clicked. There's not even an event loop since it's a one-shot window. The result is that in about 15 lines of code, your user has complete control over their program's settings without needing to modify the source file. That's really great for such a short bit of code! Here is the code for the "Settings Window" shown above. def settings_window():
"""
Show the settings window.
This is where the folder paths and program paths are set.
Returns True if settings were changed
:return: True if settings were changed
:rtype: (bool)
"""
layout = [[sg.T('Program Settings', font='DEFAIULT 18')],
[sg.T('Path to Demos', size=(20,1)), sg.In(sg.user_settings_get_entry('-demos folder-', ''), k='-DEMOS-'), sg.FolderBrowse()],
[sg.T('Path to GitHub Folder', size=(20,1)), sg.In(sg.user_settings_get_entry('-github folder-', ''),k='-GITHUB-'), sg.FolderBrowse()],
[sg.T('Github Program', size=(20,1)), sg.In(sg.user_settings_get_entry('-GitHub Program-', ''),k='-GITHUB PROGRAM-'), sg.FileBrowse()],
[sg.T('Editor Program', size=(20,1)), sg.In(sg.user_settings_get_entry('-Editor Program-', ''),k='-EDITOR PROGRAM-'), sg.FileBrowse()],
[sg.Combo(sg.theme_list(), sg.user_settings_get_entry('-theme-', None), k='-THEME-')],
[sg.B('Ok'), sg.B('Cancel')],
]
window = sg.Window('Settings', layout)
event, values = window.read(close=True)
if event == 'Ok':
sg.user_settings_set_entry('-demos folder-', values['-DEMOS-'])
sg.user_settings_set_entry('-github folder-', values['-GITHUB-'])
sg.user_settings_set_entry('-GitHub Program-', values['-GITHUB PROGRAM-'])
sg.user_settings_set_entry('-Editor Program-', values['-EDITOR PROGRAM-'])
sg.user_settings_set_entry('-theme-', values['-THEME-'])
return True
return FalseThey tend to follow this pattern:
By embedding the Let's look at one of those lines from the layout [sg.T('Path to Demos', size=(20,1)), sg.In(sg.user_settings_get_entry('-demos folder-', ''), k='-DEMOS-'), sg.FolderBrowse()],The If the OK button is clicked, then all of the values from the window are saved as user settings. They are simply a series of calls to Since we were looking at the Demos Folder a moment ago, let's find the matching settings save for that value: sg.user_settings_set_entry('-demos folder-', values['-DEMOS-'])Yes, it's that easy! You simply save the value found in the input element. More AheadIt's safe to assume that in future demos you can expect to see more of these Settings Windows. They make for a much more pleasant user experience than requiring the user to edit the code. It also makes distributing programs that require an API key much more uniform. Your end-user doesn't need to edit the code to input their API key. They can do that by entering the key in a settings window. |
A MIDI Player DemoI'm a user of PySimpleGUI just like you guys. I write quite a bit of code that no one sees or uses. One such program is this "MIDI Looper" program. I thought I would take a moment and share it since it's a unique use of PySimpleGUI and maybe it'll inspire you to write something for use in music. It's best heard rather than seen. https://www.youtube.com/watch?v=auv_DbSQuD8 This program is great for learning songs on a piano, assuming you've got a piano that is capable of being controlled by MIDI. Yamaha makes a piano series called the Disklavier that is controllable via MIDI and is what is shown in the video. There are other manufacturers that make similar pianos including Steinway. Yamaha is probably the best of anything available since they've been doing it longer than everyone else. The GUI could use a bit more work, but since it works "good enough", I'm plenty happy. The 2 areas it could benefit from some work the most are in positioning within a song and the "section looping" specification. |
The Black Code FormatterBlack is all the rage at the moment in Python, particularly in the publishing world. Some tutorial sites require that code be run through Black prior to publication. Formatting is a personal preference, to some degree. There are some things about PySimpleGUI application code that I believe make it a poor candidate for being Black-formatted. Horizontal Code Layout vs. VerticalOne of the primary benefits of PySimpleGUI over the other GUI packages is that the amount of code is greatly reduced. One of the primary ways this is achieved is through the liberal use of parameters. Instead of writing several lines of Python code, the same information is contained in a single parameter passed to a PySimpleGUI call. The result is that code that was many pages vertically now occupies a single page of code that is more horizontal in nature, due to a large number of parameters. An ExampleLet's look at a program that was mentioned a couple of posts back, the GitHub file manager and the new "Settings Window". Here is how that window appears: The code, as written, for the layout of this window is: We all know the way layouts work, they are lists of lists, with each list representing a single "row" of the GUI. Our Window has 7 rows of GUI elements, and it's no mistake nor surprise that the layout is 7 lines of Python code. Yes, these are long lines of Python code, but they're meant to be. If you want to modify something in your layout, you know which line to "dig into". Normally you're not interested in the specifics of the code on each row. Quickly locating code in a source file is an important capability. I'm suggesting that more lines, that are easier to read in a vertical direction, is a bad thing in this situation. Lets's look at how Black reformatted these 7 lines. Our 7-line layout is now 34 lines long. Of course, not only did the layout lengthen, the entire file increased in size. The original was 275 lines in length. The Black formatted version is 406 lines. It's a more than 50% increase in length. The main window's layout also increased to 82 lines from an original 22 lines. It's Not All BadOne thing that having every parameter on a single line does, is give you the option to comment out individual parameters as you're writing code. This can be a powerful format when used judiciously. It's the This bit of code is part of the PySimpleGUI Test Harness. I can quickly turn on and off options using this format. It's SubjectiveOf course, many of you may prefer the more vertically oriented code and that's great. In my opinion, it's better to have these long horizontal lines so that the layouts match the rows of the GUI window and to make navigating the file easier. The tradeoff is that the code may appear more complex because multiple parameters are on a single line. Compactness is near the top of the list for things that I love about Python that was missing in programming languages I used for decades prior to Python. A single-line loop achieved using a list comprehension was an exciting find. Black shatters that compactness. When this: becomes this: It stops feeling like Python code to me. PyCharm Is One AlternativePyCharm's code formatter tends to be much more gentle. There are others out there as well that you might want to try. Your favorite editor may have one built-in as well. Give them a try. See what works best for you. |
THANK YOU FOR THE SUPPORT!!!Over the past couple of weeks, since adding the BuyMeACoffee and a proper Sponsor Button, there have been a lot of generous people pitching in to help. It's SO SO appreciated. It's expensive just keeping the project going with all of the recurring costs. I'm also making a Udemy course so income is helping that effort. All of the help provided goes back into this project, this I can assure you. Best user community on the net! You guys and gals have been so supportive in many ways. I love the emails that you've been sending. Keep them coming, they're really helpful to read. I think the part I like the most about this project is the visual impact I can see that it's having. I literally get to see my work being used to create the things you are dreaming up. It's really motivating to see what you're building, so please keep showing everyone what you're making. If you've got an application to share, post a screenshot here: I'm working on a better way for PySimpleGUI users to share their projects, but I'm not done with it yet. In the meantime, drop your images into the User Screenshots Issue with a link to your Repo. And, don't forget to add screenshots to your readme!!!!! It WILL get more attention, this I can promise you. |
Your Issue Form Just Got Easier....
|
Launching PyCharm on Mint LinuxI've been testing the GitHub File Manager demo. One of the "settings" is the command to launch PyCharm to edit a file. This is the value that works on my Mint distribution:
If you don't find the file there, search your system for |
Have been out.... back this weekend....I'm sorry that I've been away for a couple of days. I've had some pet emergencies happening and it's caused a delay across the board. That means answering the Issues has been delayed, getting the Qt changes tested and posted were delayed. I'm hoping to get caught up this weekend and get a release of PySimpleGUIQt posted for people to try the new Styles code. HUGE thank you to @jason990420 for providing amazing Issue support. And a big thank you to everyone's that's helping by filling in the Issue form, providing test code, etc. It really really helps make the process move smoother when the information is posted and doesn't need to be asked for. |
Qt port updateHere is a before and after shot of the test harness for PySimpleGUIQt. I'm really happy with how close they are and with the changes to the way Stylesheets are being created. There is still a lot of work to go, but am checking in what I've got so far. Hopefully not very many things are broken. I've not dug into the "Update" code very much yet, so give me a little time to get that part right. A huge huge thank you to @nngogol for his expert help. He's got a ton of Qt experience that has been invaluable. He wrote the PySimpleGUI Qt Designer code a couple years back, so he's uniquely qualified and has a great understanding of both PySimpleGUI and Qt. Posted 0.35.0.15. Please let me know if I've broken your app! |
Some Qt Enhancements Posted in Last UpdateAs part of the Styles update, not only did some problems like padding get correctly fixed, a number of new features were added. The biggest welcome may be in setting the Table and Tree headers. You can now set the font and colors for the headers, just like you can in the tkinter port. Both Table and Tree elements got these new parameters: :param header_text_color: sets the text color for the header
:type header_text_color: (str)
:param header_background_color: sets the background color for the header
:type header_background_color: (str)
:param header_font: specifies the font family, size, etc
:type header_font: Union[str, Tuple[str, int]]Menubar elements are also styled now according to the background color of the window and the text color. However, these have not been turned into formal parameters that can be changed... yet. They are simply set to the window's defaults for the time being. It's still quite a bit improved over the previous default. I'm still pondering over how style sheets should be exposed to user code. I definitely want to open up the style sheets for users to modify directly if they so choose. This can already be done by accessing the |
Qt StylesheetsOK, I've been in Stylesheet hell for the day. Pretty much blew most of the day trying to get padding to work correctly with Frames. I'm at a not-so-great point. At the moment Frames have a pad=(0,0). What's worse is that if they are placed inside of a Column element, then the frame loses the border. I've clearly got a bunch of work/learning to do with these stylesheets and with how I'm making Column and Frame elements. Qt seems to be treating stylesheets in a more global way than I expected. The styles are propagating downward, overriding settings made in nested layouts. Not giving up.... but, damn, the going is slow.... Also, added Edit Nov 3..... Last night I realized that I wasn't setting the border correctly on Frames. As a result, it would inherit the setting from the parent. Basically, by not specifically setting the border on the Frame, the Column's border setting (width=0) was getting picked up by the Frame and thus losing its border. The fix was straightforward.... set the border on the Frame. Works great. Back to forward progress. |
Center A Layout In A WindowI was asked (by long-term supporter @M4cs), how to center something in a window. Seeing how the majority of 2020 was spent getting the Tkinter port of PySimpleGUI polished up so that vertical alignment was "finally done right", it seemed like something that should be possible using only PySimpleGUI call... no calls to Tkinter directly allowed., It turned out to be trickier than I thought. As a result, there's a new demo program posted: Here is the code for the demo: import PySimpleGUI as sg
"""
Center a column in a window
Solves a very specific kind of layout.
If you want to have something centered in a Window, this is a good way to do it
The "trick" here is:
* the first row of the layout has a Text element that expands vertically
* the row with the Column has a text element that expands horizontally
This expanding Text element is what will cause the Column element to be centered
Copyright 2020 PySimpleGUI.org
"""
def main():
column_to_be_centered = [ [sg.Text('My Window')],
[sg.Input(key='-IN-')],
[sg.Text(size=(30,1), key='-OUT-')],
[sg.Button('Go'), sg.Button('Exit')] ]
layout = [[sg.Text(key='-EXPAND-', font='ANY 1', pad=(0, 0))], # the thing that expands from top
[sg.Text('', pad=(0,0),key='-EXPAND2-'), # the thing that expands from left
sg.Column(column_to_be_centered, vertical_alignment='center', justification='center', k='-C-')]]
window = sg.Window('Window Title', layout, resizable=True,finalize=True)
window['-C-'].expand(True, True, True)
window['-EXPAND-'].expand(True, True, True)
window['-EXPAND2-'].expand(True, False, True)
while True: # Event Loop
event, values = window.read()
print(event, values)
if event == sg.WIN_CLOSED or event == 'Exit':
break
if event == 'Go':
window['-OUT-'].update(values['-IN-'])
window.close()
if __name__ == '__main__':
main()The thing you want to center is first placed in a Column element. It can be 1 element, like a Button, or an entire layout, as shown in the demo. As mentioned in the comments, the mechanism that makes all this work are 2 elements that will expand as the window is changed. You need something above the Column element and you need something to the left of the Column. Here's the demo in action |




















































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.