Latest readme creator flies

This commit is contained in:
PySimpleGUI 2020-04-14 07:27:51 -04:00
parent 314d6e42b0
commit e7b5e5b528
8 changed files with 4330 additions and 4761 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
readme_creator/psg_gui.py

View File

@ -42,11 +42,13 @@ HOW DO I INSERT IMAGES ???
![Awesome Meter](https://img.shields.io/badge/Awesome_meter-100-yellow.svg)
![Python Version](https://img.shields.io/badge/Python-2.7_3.x-yellow.svg)
![Python Version](https://img.shields.io/badge/PySimpleGUI_For_Python_3.x_Version-4.16.0-red.svg?longCache=true&style=for-the-badge)
![Python Version](https://img.shields.io/badge/PySimpleGUIQt_Version-0.30.0-orange.svg?longCache=true&style=for-the-badge)
![Python Version](https://img.shields.io/badge/PySimpleGUIWx_version-0.14.0-orange.svg?longCache=true&style=for-the-badge)
![Python Version](https://img.shields.io/badge/PySimpleGUIWeb_Version-0.33.0-orange.svg?longCache=true&style=for-the-badge)
[![PyPI Version](https://img.shields.io/pypi/v/pysimplegui.svg?style=for-the-badge)](https://pypi.org/project/pysimplegui/) tkinter
[![PyPI Version](https://img.shields.io/pypi/v/pysimpleguiqt.svg?style=for-the-badge)](https://pypi.org/project/pysimpleguiqt/) Qt
[![PyPI Version](https://img.shields.io/pypi/v/pysimpleguiweb.svg?style=for-the-badge)](https://pypi.org/project/pysimpleguiweb/) Web
[![PyPI Version](https://img.shields.io/pypi/v/pysimpleguiwx.svg?style=for-the-badge)](https://pypi.org/project/pysimpleguiwx/) Wx
![GitHub issues](https://img.shields.io/github/issues-raw/PySimpleGUI/PySimpleGUI?color=blue) ![GitHub closed issues](https://img.shields.io/github/issues-closed-raw/PySimpleGUI/PySimpleGUI?color=blue)
[![Commit activity](https://img.shields.io/github/commit-activity/m/PySimpleGUI/PySimpleGUI.svg?style=for-the-badge)](../../commits/master)
[![Last commit](https://img.shields.io/github/last-commit/PySimpleGUI/PySimpleGUI.svg?style=for-the-badge)](../../commits/master)
@ -562,7 +564,7 @@ You won't look stupid posting an Issue on GitHub. It's just the opposite.
**PySimpleGUI is an active project.** Bugs are fixed, features are added, often. Should you run into trouble, **open an issue** on the [GitHub site](http://www.PySimpleGUI.com) and you'll receive help. Posting questions on StackOverflow, Forums, Mailing lists, Reddit, etc, is not the fastest path to support and taking it may very well lead you astray as folks not familiar with the package struggle to help you. You may also run into the common response of "I don't know PySimpleGUI (and perhaps dislike it as a result), but I know you can do that with Qt".
Why only 1 location? It's simple.... it's where the bugs, enhancements, etc are tracked. It's THE spot on the Internet for this project. It's not some freakish being in control, telling people how to do things. It's so that YOU get the best and quickest support possible.
Why only 1 location? It's simple.... it's where the bugs, enhancements, etc are tracked. It's THE spot on the Internet for this project. There's not driven by a freakish being in control, telling people how to do things, reasoning. It's so that YOU get the best and quickest support possible.
So, [open an Issue](https://github.com/PySimpleGUI/PySimpleGUI/issues/new/choose), choose "custom form" and fill it out completely. There are very good reasons behind all of the questions. Cutting corners only cuts your chances of getting help and getting quality help as it's difficult enough to debug remotely. Don't handicap people that want to help by not providing enough information.
@ -571,29 +573,6 @@ So, [open an Issue](https://github.com/PySimpleGUI/PySimpleGUI/issues/new/choose
***Don't sit and stew, trying the same thing over and over***, until you hate life... stop, and post an Issue on the GitHub. Someone **WILL** answer you. Support is included in the purchase price for this package (the quality level matches the price as well I'm afraid). Just don't be too upset when your free support turns out to be a little bit crappy, but it's free and typically good advice.
### PySimpleGUI Trolls
Yea, they're out there. Would have NEVER in a billion years guessed that there would be objection to this package, coming from a small, but vocal, number of people. I naively believed everyone would be supportive, see the value, hold hands around the fire, sing songs, and in the very least be truthful. But, this ain't Kansas and the Internet is well...
If someone is actively discouraging you from using this package, then know you are on the right track and you should give it a try. Stuff like this sometimes happens because the person works for a particular company or they have a GUI package of their own.... that's not popuplar, or they like to tear things down or I dunno... people can be really weird and emotional.
I promise you're not going to be wrecked for life. It will not cause you to be a bad programmer with bad habits. It will not ruin your career. It's not going to teach you bad habits. One person I know got a bonus based on a PySimpleGUI program he wrote.
***How about success being the goal?*** Spend time polishing your GUI and working on your primary code instead of struggling your way through the mountains of documentation in the Qt library, trying to set the color of something. How about getting your program done, working, and in use?
Start with PySimpleGUI, then in the future if you want to code directly in Qt, it's not like you won't be able to learn something else due to your PySimpleGUI knowledge. Unable to write a `while` loop because you already learned using a `for` loop? That seems to be the logic.
If anything, you'll have more knowledge than most people that are just starting because you'll have already built working GUIs, perhaps many of them and understand how to layout an efficient interface as well as having a good education in GUI Widgets and how they work.
Here are the forces likely at work.... said Troll has been programming for a while now and really knows these GUI frameworks. Probably invested a lot of hours learning them and thus has some marketable skills (yes, follow the money).
Enter snotty-nosed high-shool or first year programmer using PySimpleGUI that manages to make GUI windows with great ease... that look, well, pretty much the **same** as the windows Sir Troll ***was*** used to getting paid big bucks to make. What used to be a skill only a select few can do, now 1,000's, 10,000's, or 100,000s more programmers can do, quicker and easier. Bummer Mr. Troll. Bummer.
"***It's supposed to be difficult to write a GUI***" was an actual reason listed why not to use PySimpleGUI by one person offering to help junior programmers learn Qt. Really? It's supposed to be difficult. Huh. Well, not in this Python universe. Maybe in C++ world it works that way??
Just know you're safe in trying and possibly even succeeding in the process.
### Target Audience
PySimpleGUI is trying to serve the 80% of GUI *problems*. The other 20% go straight to tkinter, Qt, WxPython, Remi, or whatever fills that need. That 80% is **a huge problem space**.
@ -764,7 +743,7 @@ Or how about a ***custom GUI*** in 1 line of code? No kidding this is a valid p
```python
import PySimpleGUI as sg
event, values = sg.Window('Get filename example', [[sg.Text('Filename')], [sg.Input(), sg.FileBrowse()], [sg.OK(), sg.Cancel()] ]).Read()
event, values = sg.Window('Get filename example', [[sg.Text('Filename')], [sg.Input(), sg.FileBrowse()], [sg.OK(), sg.Cancel()] ]).read(close=True)
```
![get filename](https://user-images.githubusercontent.com/13696193/44960039-f1018880-aec5-11e8-8a43-3d7f8ff93b67.jpg)
@ -795,7 +774,7 @@ layout = [ [sg.Text('Filename')],
window = sg.Window('Get filename example', layout)
event, values = window.Read()
event, values = window.read()
window.close()
```
@ -874,9 +853,9 @@ Beautiful windows are created, not simply given to you. There are people that d
Some of these have been "polished", others like the Matplotlib example is more a functional example to show you it works.
![batterup2](https://user-images.githubusercontent.com/13696193/50378902-6aa2bb00-060a-11e9-8f2f-d746694fa4ee.gif)
![batterup](https://user-images.githubusercontent.com/46163555/77781297-b624ef80-702b-11ea-857a-b0809f061dc9.png)
![uno_final](https://user-images.githubusercontent.com/13696193/49945232-67952580-feba-11e8-90c8-7dc31c5f7c67.gif)
![Uno](https://user-images.githubusercontent.com/46163555/77781360-d05ecd80-702b-11ea-90f9-cb9fb3339c05.png)
This chess program is capable of running multiple AI chess engines and was written by another user using PySimpleGUI.
@ -902,7 +881,7 @@ In release 4.9 another 32 Color Themes were added... here are the current choice
Make beautiful looking, alpha-blended (partially transparent) Rainmeter-style Desktop Widgets that run in the background.
![cpu cores dashboard 2](https://user-images.githubusercontent.com/13696193/47611749-18964c80-da42-11e8-93c4-6821a6fce488.gif)
![cpumeter](https://user-images.githubusercontent.com/46163555/77781418-ec626f00-702b-11ea-90b3-668fb71d63b5.png)
Want to build a Crossword Puzzle? No problem, the drawing primitives are there for you.
@ -943,7 +922,7 @@ It's possible to create some cool games by simply using the built-in PySimpleGUI
Games haven't not been explored much, yet, using PySimpleGUI.
![pong](https://user-images.githubusercontent.com/13696193/45860012-2d8d0b00-bd33-11e8-9efd-3eaf4c30f324.gif)
![pong](https://user-images.githubusercontent.com/46163555/77781526-1c117700-702c-11ea-901b-4cb5f7a34cb4.png)
# Windows Programs That Look Like Windows Programs
@ -956,7 +935,7 @@ Combining PySimpleGUI with PyInstaller creates something truly remarkable and sp
The application you see below with a working menu was created in 20 lines of Python code. It is a single .EXE file that launches straight into the screen you see. And more good news, the only icon you see on the taskbar is the window itself... there is no pesky shell window. Nice, huh?
![menu demo](https://user-images.githubusercontent.com/13696193/45923097-8fbc4c00-beaa-11e8-87d2-01a5331811c8.gif)
![windowsprogram](https://user-images.githubusercontent.com/46163555/77781479-03a15c80-702c-11ea-9408-903e022e0418.png)
With a simple GUI, it becomes practical to "associate" .py files with the python interpreter on Windows. Double click a py file and up pops a GUI window, a more pleasant experience than opening a dos Window and typing a command line.
@ -987,9 +966,9 @@ This meant classes could be used to build and use it, but classes can not be par
What about those pesky callbacks? They're difficult for beginners to grasp and they're a bit of a pain in the ass to deal with. The way PySimpleGUI got around events was to utilize ***a "message passing" architecture*** instead.
Instead of a user function being called when there's some event, instead the information is "passed" to the user when they call the function `Window.Read()`
Instead of a user function being called when there's some event, instead the information is "passed" to the user when they call the function `Window.read()`
***Everything*** is returned through this `Window.Read` call. Of course the underlying GUI frameworks still perform callbacks, but they all happen inside of PySimpleGUI where they are turned into messages to pass to you.
***Everything*** is returned through this `Window.read` call. Of course the underlying GUI frameworks still perform callbacks, but they all happen inside of PySimpleGUI where they are turned into messages to pass to you.
All of the boilerplate code, the event handling, widget creation, frames containing widgets, etc, are **exactly the same** objects and calls that you would be writing if you wrote directly in tktiner, Qt, etc. With all of this code out of the way and done for you, that leaves you with the task of doing something useful with the information the user entered. THAT, afterall, is the goal here.... getting user information and acting on it.
@ -1222,19 +1201,68 @@ Like above, you may have to install either pip or tkinter. To do this on Python
`sudo apt install python-tkinter`
### Upgrading from GitHub Using PySimpleGUI
Starting in version 4.17.0 there is code in the PySimpleGUI package that upgrades your previously pip installed package using the latest version checked into GitHub.
Previously if you wanted to run the GitHub version, you would:
* Download the PySimpleGUI.py file from GitHub
* Place it in your applications's folder
This required you to go back later and delete this file when you want to move on to the next version released to PyPI.
The new capability is the ability to overwrite your PySimpleGUI.py file that you installed using `pip` with the currently posted version on GitHub. Using this method when you're ready to install the next version from PyPI or you want to maybe roll back to a PyPI release, you only need to run `pip`. You don't have to find and delete any PySimpleGUI.py files.
***Important - Linux Users*** - There is currently a problem using this utility on Linux systems. It's being worked on and a patch will be released as soon as something is figured out.
#### Command Line Upgrade
To upgrade PySimpleGUI from the command line type this command into your dos window
`python -m PySimpleGUI upgrade`
You will first be shown a confirmation window:
![image](https://user-images.githubusercontent.com/46163555/77477572-f0f01300-6df2-11ea-812f-98a36e7c28e0.png)
If you choose yes, then the new version will be installed and you'll see a red "completed" window
![image](https://user-images.githubusercontent.com/46163555/77477619-006f5c00-6df3-11ea-8b01-44b1bea22989.png)
#### GUI Upgrade
The PySimpleGUI Test Harness is another mechanism you can use to upgrade. To start the test harness you "run" the PySimpleGUI package.
`python -m PySimpleGUI.PySimpleGUI`
Of course if you're running Linux you may run `python3` instead.
From your code you can call `PySimpleGUI.main()`. This window may not look exactly like the one you see, but the thing that should be there is the red "Install" button.
![image](https://user-images.githubusercontent.com/46163555/77478381-437dff00-6df4-11ea-994e-a443ff967917.png)
Clicking the install button will bring up the same confirmation window shown as the command line upgrade above.
### Testing your installation and Troubleshooting
Once you have installed, or copied the .py file to your app folder, you can test the installation using python. At the command prompt start up Python.
#### The Quick Test
From your commant line type:
`python -m PySimpleGUI`
The PySimpleGUI Test Harness pictured in the previous section on GUI upgrades is the short program that's built into PySimpleGUI that serves multiple purposes. It exercises many/most of the available Elements, displays version and location data and works as a quick self-test.
Of course if you're on Linux/Mac and need to run using the command `python3` then of course type that.
From your command line type:
`python -m PySimpleGUI.PySimpleGUI`
This will display the same window as these instructions:
If you're on Linux/Mac and need to run using the command `python3` then of course type that.
This will display the test harnes window.
You can also test by using the REPL....
#### Instructions for Testing Python 2.7:
```python
@ -1339,6 +1367,13 @@ See.... written with the "Developer" in mind, at all times. It's about YOU, Mr/
The other ports of PySimpleGUI (Qt, WxPython, Web) have not yet had their docstrings updated. They're NEXT in line to be better documented. Work on a tool has already begun to make that happen sooner than later.
#### Type Checking With Docstrings
In version 4.17.0 a new format started being used for docstrings. This new format more clearly specified the types for each parameter. It will take some time to get all of the parameter types correctly identied and documented.
Pay attention when you're working with PyCharm and you'll see where you may have a mismatch... or where there's a bad docstring, take your pick. It will shade your code in a way that makes mismatched types very clear to see.
## Using - Python 3
To use in your code, simply import....
@ -1358,7 +1393,10 @@ Yes, it's just that easy to have a window appear on the screen using Python. Wi
If you must run 3.7, try 3.7.2. It does work with PySimpleGUI with no known issues.
***PySimpleGUI with Python 3.7.3 and 3.7.4+.*** tkinter is having issues with all the newer releases. Things like Table colors stopped working entirely. It's unclear if there's been a change that makes the tkinter API no longer working which means they are not backwards compatible. That would be a real shame. If so, more work needs to be done in PySimpleGUI
***PySimpleGUI with Python 3.7.3 and 3.7.4+.*** tkinter is having issues with all the newer releases. Things like Table colors stopped working entirely.
March 2020 - Still not quite sure if all issues have been ironed out with tkinter in the 3.7 and 3.8 releases.
## Python 2.7

View File

@ -56,7 +56,7 @@ For the time being, class variables will remain the way they are currently. It
# High Level API Calls - Popup's
"High level calls" are those that start with "Popup". They are the most basic form of communications with the user. They are named after the type of window they create, a pop-up window. These windows are meant to be short lived while, either delivering information or collecting it, and then quickly disappearing.
"High level calls" are those that start with "popup". They are the most basic form of communications with the user. They are named after the type of window they create, a pop-up window. These windows are meant to be short lived while, either delivering information or collecting it, and then quickly disappearing.
Think of Popups as your first windows, sorta like your first bicycle. It worked well, but was limited. It probably wasn't long before you wanted more features and it seemed too limiting for your newly found sense of adventure.
@ -64,28 +64,51 @@ When you've reached the point with Popups that you are thinking of filing a GitH
It's at THIS time that you should immediately turn to the section entitled "Custom Window API Calls - Your First Window". Congratulations, you just graduated and are not an official "GUI Designer". Oh, nevermind that you only started learning Python 2 weeks ago, you're a real GUI Designer now so buck up and start acting like one.
But, for now, let's stick with these 1-line window calls, the Popups.
But, for now, let's stick with these 1-line window calls, the Popups. This is the list of popup calls available to you:
popup_animated
popup_annoying
popup_auto_close
popup_cancel
popup_error
popup_get_file
popup_get_folder
popup_get_text
popup_no_border
popup_no_buttons
popup_no_frame
popup_no_titlebar
popup_no_wait
popup_notify
popup_non_blocking
popup_ok
popup_ok_cancel
popup_quick
popup_quick_message
popup_scrolled
popup_timed
popup_yes_no
## Popup Output
Think of the `Popup` call as the GUI equivalent of a `print` statement. It's your way of displaying results to a user in the windowed world. Each call to Popup will create a new Popup window.
Think of the `popup` call as the GUI equivalent of a `print` statement. It's your way of displaying results to a user in the windowed world. Each call to Popup will create a new Popup window.
`Popup` calls are normally blocking. your program will stop executing until the user has closed the Popup window. A non-blocking window of Popup discussed in the async section.
`popup` calls are normally blocking. your program will stop executing until the user has closed the Popup window. A non-blocking window of Popup discussed in the async section.
Just like a print statement, you can pass any number of arguments you wish. They will all be turned into strings and displayed in the popup window.
There are a number of Popup output calls, each with a slightly different look (e.g. different button labels).
There are a number of Popup output calls, each with a slightly different look or functionality (e.g. different button labels, window options).
The list of Popup output functions are:
- Popup
- PopupOk
- PopupYesNo
- PopupCancel
- PopupOkCancel
- PopupError
- PopupTimed, PopupAutoClose
- PopupNoWait, PopupNonBlocking
- popup
- popup_ok
- popup_yes_no
- popup_cancel
- popup_ok_cancel
- popup_error
- popup_timed, popup_auto_close, popup_quick, popup_quick_message
- popup_no_waitWait, popup_non_blocking
The trailing portion of the function name after Popup indicates what buttons are shown. `PopupYesNo` shows a pair of button with Yes and No on them. `PopupCancel` has a Cancel button, etc.
@ -96,14 +119,14 @@ The function `PopupTimed` or `PopupAutoClose` are popup windows that will automa
Here is a quick-reference showing how the Popup calls look.
```python
sg.Popup('Popup') # Shows OK button
sg.PopupOk('PopupOk') # Shows OK button
sg.PopupYesNo('PopupYesNo') # Shows Yes and No buttons
sg.PopupCancel('PopupCancel') # Shows Cancelled button
sg.PopupOKCancel('PopupOKCancel') # Shows OK and Cancel buttons
sg.PopupError('PopupError') # Shows red error button
sg.PopupTimed('PopupTimed') # Automatically closes
sg.PopupAutoClose('PopupAutoClose') # Same as PopupTimed
sg.popup('Popup') # Shows OK button
sg.popup_ok('PopupOk') # Shows OK button
sg.popup_yes_no('PopupYesNo') # Shows Yes and No buttons
sg.popup_cancel('PopupCancel') # Shows Cancelled button
sg.popup_ok_cancel('PopupOKCancel') # Shows OK and Cancel buttons
sg.popup_error('PopupError') # Shows red error button
sg.popup_timed('PopupTimed') # Automatically closes
sg.popup_auto_close('PopupAutoClose') # Same as PopupTimed
```
Preview of popups:
@ -125,11 +148,8 @@ Preview of popups:
The other output Popups are variations on parameters. Usually the button_type parameter is the primary one changed.
The choices for button_type are (you should not specify these yourself however):
The other output Popups are variations on parameters. Usually the button_type parameter is the primary one changed.
The choices for button_type are:
```
POPUP_BUTTONS_YES_NO
POPUP_BUTTONS_CANCELLED
@ -139,79 +159,82 @@ POPUP_BUTTONS_OK
POPUP_BUTTONS_NO_BUTTONS
```
**Note that you should not call Popup yourself with different button_types.** Rely on the Popup function named that sets that value for you. For example PopupYesNo will set the button type to POPUP_BUTTONS_YES_NO for you.
**Note that you should not call Popup yourself with different button_types.** Rely on the Popup function named that sets that value for you. For example `popup_yes_no` will set the button type to POPUP_BUTTONS_YES_NO for you.
#### Scrolled Output
### Scrolled Output
There is a scrolled version of Popups should you have a lot of information to display.
<!-- <+func.PopupScrolled+> -->
<!-- <+func.popup_scrolled+> -->
```python
PopupScrolled(*args, button_color=None, yes_no=False, auto_close=False, auto_close_duration=None, size=(None, None), location=(None, None), title=None, non_blocking=False)
```
Typical usage:
```python
sg.PopupScrolled(my_text)
sg.popup_scrolled(my_text)
```
![scrolledtextbox 2](https://user-images.githubusercontent.com/13696193/43667324-712aa0d4-9745-11e8-83a9-a0d0570d0865.jpg)
The `PopupScrolled` will auto-fit the window size to the size of the text. Specify `None` in the height field of a `size` parameter to get auto-sized height.
The `popup_scrolled` will auto-fit the window size to the size of the text. Specify `None` in the height field of a `size` parameter to get auto-sized height.
This call will create a scrolled box 80 characters wide and a height dependent upon the number of lines of text.
`sg.PopupScrolled(my_text, size=(80, None))`
`sg.popup_scrolled(my_text, size=(80, None))`
Note that the default max number of lines before scrolling happens is set to 50. At 50 lines the scrolling will begin.
If `non_blocking` parameter is set, then the call will not blocking waiting for the user to close the window. Execution will immediately return to the user. Handy when you want to dump out debug info without disrupting the program flow.
### PopupNoWait
### Non-Blocking Popups - popup_no_wait and the non_blocking parameter
<!-- <+func.PopupNoWait+> -->
<!-- <+func.popup_no_wait+> -->
The Popup call PopupNoWait or PopupNonBlocking will create a popup window and then immediately return control back to you. All other popup functions will block, waiting for the user to close the popup window.
The Popup call PopupNoWait or PopupNonBlocking will create a popup window and then immediately return control back to you. You can turn other popup calls into non-blocking popups if they have a `non_blocking` parameter. Setting `non_blocking` to True will cause the function to return immediately rather than waiting for the window to be closed.
This function is very handy for when you're **debugging** and want to display something as output but don't want to change the programs's overall timing by blocking. Think of it like a `print` statement. There are no return values on one of these Popups.
### Popup Parameter Combinations
So that you don't have to specify a potentially long list common parameters there are a number of popup functions that set combinations of parameters. For example `popup_quick_message` will show a non-blocking popup that autocloses and does not have a titlebar. You could achieve this same end result using the plain `popup` call.
## Popup Input
There are Popup calls for single-item inputs. These follow the pattern of `Popup` followed by `Get` and then the type of item to get. There are 3 of these input Popups to choose from, each with settings enabling customization.
- `PopupGetText` - get a single line of text
- `PopupGetFile` - get a filename
- `PopupGetFolder` - get a folder name
There are Popup calls for single-item inputs. These follow the pattern of `popup_get` followed by the type of item to get. There are 3 of these input Popups to choose from, each with settings enabling customization.
- `popup_get_text` - get a single line of text
- `popup_get_file` - get a filename
- `popup_get_folder` - get a folder name
Use these Popups instead of making a custom window to get one data value, call the Popup input function to get the item from the user. If you find the parameters are unable to create the kind of window you are looking for, then it's time for you to create your own window.
### PopupGetText
### popup_get_text
Use this Popup to get a line of text from the user.
<!-- <+func.PopupGetText+> -->
<!-- <+func.popup_get_text+> -->
```python
import PySimpleGUI as sg
text = sg.PopupGetText('Title', 'Please input something')
sg.Popup('Results', 'The value returned from PopupGetText', text)
text = sg.popup_get_text('Title', 'Please input something')
sg.popup('Results', 'The value returned from PopupGetText', text)
```
![popupgettext](https://user-images.githubusercontent.com/13696193/44957281-8721b880-ae9e-11e8-98cd-d06369f4187e.jpg)
![popup gettext response](https://user-images.githubusercontent.com/13696193/44957282-8721b880-ae9e-11e8-84ae-dc8bb30504a0.jpg)
### PopupGetFile
Gets a filename from the user. There are options to configure the type of dialog box to show. Normally an "Open File" dialog box is shown.
### popup_get_file
<!-- <+func.PopupGetFile+> -->
Gets one or more filenames from the user. There are options to configure the type of dialog box to show. Normally an "Open File" dialog box is shown.
<!-- <+func.popup_get_file+> -->
If configured as an Open File Popup then (save_as is not True) the dialog box will look like this.
@ -227,34 +250,34 @@ If you choose a filename that already exists, you'll get a warning popup box ask
A typical call produces this window.
```python
text = sg.PopupGetFile('Please enter a file name')
sg.Popup('Results', 'The value returned from PopupGetFile', text)
text = sg.popup_get_file('Please enter a file name')
sg.popup('Results', 'The value returned from PopupGetFile', text)
```
![popupgetfile](https://user-images.githubusercontent.com/13696193/44957857-2fd31680-aea5-11e8-8eb7-f6b91c202cc8.jpg)
### PopupGetFolder
### popup_get_folder
The window created to get a folder name looks the same as the get a file name. The difference is in what the browse button does. `PopupGetFile` shows an Open File dialog box while `PopupGetFolder` shows an Open Folder dialog box.
<!-- <+func.PopupGetFolder+> -->
<!-- <+func.popup_get_folder+> -->
This is a typpical call
```python
text = sg.PopupGetFolder('Please enter a folder name')
sg.Popup('Results', 'The value returned from PopupGetFolder', text)
text = sg.popup_get_folder('Please enter a folder name')
sg.popup('Results', 'The value returned from PopupGetFolder', text)
```
![popupgetfolder](https://user-images.githubusercontent.com/13696193/44957861-45484080-aea5-11e8-926c-cf607a45251c.jpg)
### PopupAnimated
### popup_animated
![ring](https://user-images.githubusercontent.com/13696193/51296743-6ee4ad00-19eb-11e9-91f5-cd8086ad1b50.gif)
The animated Popup enables you to easily display a "loading" style animation specified through a GIF file that is either stored in a file or a base64 variable.
<!-- <+func.PopupAnimated+> -->
<!-- <+func.popup_animated+> -->
***To close animated popups***, call PopupAnimated with `image_source=None`. This will close all of the currently open PopupAnimated windows.
@ -263,25 +286,13 @@ The animated Popup enables you to easily display a "loading" style animation spe
# Progress Meters!
We all have loops in our code. 'Isn't it joyful waiting, watching a counter scrolling past in a text window? How about one line of code to get a progress meter, that contains statistics about your code?
```
OneLineProgressMeter(title,
current_value,
max_value,
key,
*args,
orientation=None,
bar_color=DEFAULT_PROGRESS_BAR_COLOR,
button_color=None,
size=DEFAULT_PROGRESS_BAR_SIZE,
border_width=DEFAULT_PROGRESS_BAR_BORDER_WIDTH):
```
<!-- <+func.one_line_progress_meter+> -->
Here's the one-line Progress Meter in action!
```python
for i in range(1,10000):
sg.OneLineProgressMeter('My Meter', i+1, 10000, 'key','Optional message')
sg.one_line_progress_meter('My Meter', i+1, 10000, 'key','Optional message')
```
That line of code resulted in this window popping up and updating.
@ -293,12 +304,12 @@ With a little trickery you can provide a way to break out of your loop using the
***Be sure and add one to your loop counter*** so that your counter goes from 1 to the max value. If you do not add one, your counter will never hit the max value. Instead it will go from 0 to max-1.
# Debug Output (EasyPrint = Print = eprint)
# Debug Output (easy_print = Print = eprint)
Another call in the 'Easy' families of APIs is `EasyPrint`. As is with other commonly used PySimpleGUI calls, there are other names for the same call. You can use `Print` or `eprint` in addition to `EasyPrint`. They all do the same thing, output to a debug window. If the debug window isn't open, then the first call will open it. No need to do anything but stick an 'sg.Print' call in your code. You can even replace your 'print' calls with calls to EasyPrint by simply sticking the statement
```python
print = sg.EasyPrint
print = sg.Print
```
at the top of your code.
@ -321,16 +332,22 @@ import PySimpleGUI as sg
print=sg.Print
for i in range(100):
print(i)
print(i)
```
Just like the standard print call, `EasyPrint` supports the `sep` and `end` keyword arguments. Other names that can be used to call `EasyPrint` include `Print`, `eprint`, If you want to close the window, call the function `EasyPrintClose`.
Just like the standard print call, `easy_print` supports the `sep` and `end` keyword arguments. Other names that can be used to call `easy_print` include `Print`, `eprint`, If you want to close the window, call the function `easy_print_close`.
You can change the size of the debug window using the `SetOptions` call with the `debug_win_size` parameter.
You can change the size of the debug window using the `set_options` call with the `debug_win_size` parameter.
There is an option to tell PySimpleGUI to reroute all of your stdout and stderr output to this window. To do so call EasyPrint with the parameter `do_not_reroute_stdout` set to `False`. After calling it once with this parameter set to True, all future calls to a normal`print` will go to the debug window.
There is an option to tell PySimpleGUI to reroute all of your stdout and stderr output to this window. To do so call easy_print with the parameter `do_not_reroute_stdout` set to `False`. After calling it once with this parameter set to True, all future calls to a normal `print` will go to the debug window.
If you close the debug window it will re-open the next time you Print to it. If you wish to close the window using your code, then you can call either `easy_print_close()` or `PrintClose()`
### Printing To Multiline Elements
Another technique for outputting information that you would normally print is to use the function `Multiline.print`. You'll find it discussed further into this document. The basic idea is that you can easily modify your normal `print` calls to route your printed information to your window.
If you close the debug window it will re-open the next time you Print to it. If you wish to close the window using your code, then you can call either `EasyPrintClose()` or `PrintClose()`
---
# Custom window API Calls (Your First window)
@ -341,7 +358,7 @@ This first section on custom windows is for your typical, blocking, non-persiste
Two other types of windows exist.
1. Persistent window - the `Window.read()` method returns and the window continues to be visible. This is good for applications like a chat window or a timer or anything that stays active on the screen for a while.
2. Asynchronous window - the trickiest of the lot. Great care must be exercised. Examples are an MP3 player or status dashboard. Async windows are updated (refreshed) on a periodic basis. You can spot them easily as they will have a `timeout` parameter on the call to read. `event, values = window.Read(timeout=100)`
2. Asynchronous window - the trickiest of the lot. Great care must be exercised. Examples are an MP3 player or status dashboard. Async windows are updated (refreshed) on a periodic basis. You can spot them easily as they will have a `timeout` parameter on the call to read. `event, values = window.read(timeout=100)`
It's both not enjoyable nor helpful to immediately jump into tweaking each and every little thing available to you. Make some simple windows. Use the Cookbook and the Demo Programs as a way to learn and as a "starting point".
@ -410,7 +427,7 @@ layout = [[sg.Text('Enter a Number')],
[sg.Input()],
[sg.OK()] ]
event, values = sg.Window('Enter a number example', layout).Read()
event, values = sg.Window('Enter a number example', layout).read()
sg.Popup(event, values[0])
```
@ -796,12 +813,12 @@ By default return values are a list of values, one entry for each input field, b
Each of the Elements that are Input Elements will have a value in the list of return values. If you know for sure that the values will be returned as a list, then you could get clever and unpack directly into variables.
event, (filename, folder1, folder2, should_overwrite) = sg.Window('My title', window_rows).Read()
event, (filename, folder1, folder2, should_overwrite) = sg.Window('My title', window_rows).read()
Or, more commonly, you can unpack the return results separately. This is the preferred method because it works for **both** list and dictionary return values.
```python
event, values = sg.Window('My title', window_rows).Read()
event, values = sg.Window('My title', window_rows).read()
event, value_list = window.read()
value1 = value_list[0]
value2 = value_list[1]
@ -820,7 +837,7 @@ For windows longer than 3 or 4 fields you will want to use a dictionary to help
The most common window read statement you'll encounter looks something like this:
`window = sg.Window("My title", layout).Read()`
`window = sg.Window("My title", layout).read()`
To use a dictionary, you will need to:
* Mark each input element you wish to be in the dictionary with the keyword `key`.
@ -955,7 +972,7 @@ Clicking the Submit button caused the window call to return. The call to Popup
**`Note, event values can be None`**. The value for `event` will be the text that is displayed on the button element when it was created or the key for the button. If the user closed the window using the "X" in the upper right corner of the window, then `event` will be `None`. It is ***vitally*** ***important*** that your code contain the proper checks for None.
For "persistent windows", **always give your users a way out of the window**. Otherwise you'll end up with windows that never properly close. It's literally 2 lines of code that you'll find in every Demo Program. While you're at it, make sure a `window.Close()` call is after your event loop so that your window closes for sure.
For "persistent windows", **always give your users a way out of the window**. Otherwise you'll end up with windows that never properly close. It's literally 2 lines of code that you'll find in every Demo Program. While you're at it, make sure a `window.close()` call is after your event loop so that your window closes for sure.
You can see in the results Popup window that the values returned are a dictionary. Each input field in the window generates one item in the return values list. Input fields often return a `string`. Check Boxes and Radio Buttons return `bool`. Sliders return float or perhaps int depending on how you configured it or which port you're using.
@ -1020,7 +1037,7 @@ event, values = window.read()
A non-blocking / Async Read call looks like this:
```python
event, values = window.Read(timeout=100)
event, values = window.read(timeout=100)
```
You can learn more about these async / non-blocking windows toward the end of this document.
@ -1107,7 +1124,7 @@ The first step is to create the window object using the desired window customiza
Note - There is no direct support for "**modal windows**" in PySimpleGUI. All windows are accessable at all times unless you manually change the windows' settings.
**IMPORTANT** - Many of the `Window` methods require you to either call `Window.Read` or `Window.Finalize` (or set `finalize=True` in your `Window` call) before you call the method. This is because these 2 calls are what actually creates the window using the underlying GUI Framework. Prior to one of those calls, the methods are likely to crash as they will not yet have their underlying widgets created.
**IMPORTANT** - Many of the `Window` methods require you to either call `Window.read` or `Window.Finalize` (or set `finalize=True` in your `Window` call) before you call the method. This is because these 2 calls are what actually creates the window using the underlying GUI Framework. Prior to one of those calls, the methods are likely to crash as they will not yet have their underlying widgets created.
### Window Location
@ -1411,7 +1428,7 @@ If you really wanted to crunch things down, you can make it a 2 line program (an
```python
import PySimpleGUI as sg
event, values = sg.Window('To Do List Example', layout=[[sg.Text(f'{i}. '), sg.In(key=i)] for i in range(1,6)] + [[sg.Button('Save'), sg.Button('Exit')]]).Read()
event, values = sg.Window('To Do List Example', layout=[[sg.Text(f'{i}. '), sg.In(key=i)] for i in range(1,6)] + [[sg.Button('Save'), sg.Button('Exit')]]).read()
```
@ -1730,6 +1747,26 @@ If the element is one of the input elements (one that will cause an generate an
Menu items can have keys associated with them as well. See the section on Menus for more information about these special keys. They aren't the same as Element keys. Like all elements, Menu Element have one of these Element keys. The individual menu item keys are different.
### `WRITE_ONLY_KEY` Modifier
Sometimes you have input elements (e.g. `Multiline`) that you are using as an output. The contents of these elements may get very long. You don't need ot "read" these elements and doing so will potentially needlessly return a lot of data.
To tell PySimpleGUI that you do not want an element to return a value when `Window.read` is called, add the string `WRITE_ONLY_KEY` to your key name.
If your `Multiline` element was defined like this originally:
```python
sg.Multiline(size=(40,8), key='-MLINE-')
```
Then to turn off return values for that element, the `Multiline` element would be written like this:
```python
sg.Multiline(size=(40,8), key='-MLINE-' + sg.WRITE_ONLY_KEY)
```
## Common Element Parameters
Some parameters that you will see on almost all Element creation calls include:
@ -1994,6 +2031,43 @@ layout = [[sg.Multiline('This is what a Multi-line Text Element looks like', siz
![multiline](https://user-images.githubusercontent.com/13696193/44959853-b139a180-aec3-11e8-972f-f52188510c88.jpg)
This element has been expanded upon quite a bit over time. Two of the more exciting additions have been
* Ability to output unique text and background colors on a per-character basis
* The `print` method that allows you to easily reroute your normally printed output to a multiline element instead
The `Multiline.print()` call is made using the same element-lookup technique you're used to using to call `update`. One of these lookups generally appear:
```python
window['-MULTILINE KEY-']
```
To change one of your normal prints to output to your multiline element, you simply add the above lookup expression to the front of your print statement.
```python
print('My variables are', a, b, c) # a normal print statement
window['-MULTILINE KEY-'].print('My variables are', a, b, c) # Routed to your multiline element
```
It gets even better though.... you can add color to your prints
```python
# Outputs red text on a yellow background
window['-MULTILINE KEY-'].print('My variables are', a, b, c, text_color='red', background_color='yellow')
```
### Redefine print
Another way to use this print capability is to redefine the `print` statement itself. This will allow you to leave your code entirely as is. By adding this line of code your entire program will output all printed information to a multiline element.
```python
print = lambda *args, **kwargs: window['-MULTILINE KEY-'].print(*args, **kwargs)
```
## Text Input Element | `InputText == Input == In`
@ -2008,7 +2082,7 @@ layout = [[sg.InputText('Default text')]]
#### Note about the `do_not_clear` parameter
This used to really trip people up, but don't think so anymore. The `do_not_clear` parameter is initialized when creating the InputText Element. If set to False, then the input field's contents will be erased after every `Window.Read()` call. Use this setting for when your window is an "Input Form" type of window where you want all of the fields to be erased and start over again every time.
This used to really trip people up, but don't think so anymore. The `do_not_clear` parameter is initialized when creating the InputText Element. If set to False, then the input field's contents will be erased after every `Window.read()` call. Use this setting for when your window is an "Input Form" type of window where you want all of the fields to be erased and start over again every time.
@ -2312,26 +2386,36 @@ All buttons can have their text changed by changing the `button_text` parameter
layout = [[sg.Button('My Button', key='_BUTTON_KEY_')]]
```
With this layout, the event that is returned from a `Window.Read()` call when the button is clicked will be "`_BUTTON_KEY_`"
With this layout, the event that is returned from a `Window.read()` call when the button is clicked will be "`_BUTTON_KEY_`"
### Button Images
Now this is an exciting feature not found in many simplified packages.... images on buttons! You can make a pretty spiffy user interface with the help of a few button images.
Your button images need to be in PNG or GIF format. When you make a button with an image, set the button background to the same color as the background. There's a button color TRANSPARENT_BUTTON that you can set your button color to in order for it to blend into the background. Note that this value is currently the same as the color as the default system background on Windows. If you want to set the button background color to the current system default, use the value COLOR_SYSTEM_DEFAULT as the background color.
This is one of the quickest and easiest ways to transform tkinter from a "1990s looking GUI" into a "modern GUI". If you don't like the default buttons, then simply bring your own button images and use those instead.
This example comes from the `Demo Media Player.py` example program. Because it's a non-blocking button, it's defined as `RButton`. You also put images on blocking buttons by using `Button`.
Your button images need to be in PNG or GIF format. When you make a button with an image, set the button background to the same color as the background. You can get the theme's background color by calling `theme_background_color()`
`TRANSPARENT_BUTTON` - **Important** - This is a legacy value that is misleading. It is currently defined as this constant value:
```python
sg.Button('Restart Song', button_color=sg.TRANSPARENT_BUTTON,
TRANSPARENT_BUTTON = ('#F0F0F0', '#F0F0F0')
```
As you can see it is simply a tuple of 2 gray colors. The effect is that the button text and the button background color to a specific shade of gray. Way back in time, before you could change the background colors and all windows were gray, this value worked. But now that your button can be on any background color, you'll want to set the buttons color to match the background so that your button blends with the background color.
```python
sg.Button('Restart Song', button_color=(sg.theme_background_color(), sg.theme_background_color()),
image_filename=image_restart, image_size=(50, 50), image_subsample=2, border_width=0)
```
Three parameters are used for button images.
There are several parameters in `Button` elements that are used for button images.
```
image_filename - Filename. Can be a relative path
image_size - Size of image file in pixels
image_filename - Filename of image. Can be a relative path
image_data - A Base64 image
image_size - Size of image in pixels
image_subsample - Amount to divide the size by. 2 means your image will be 1/2 the size. 3 means 1/3
```
@ -2340,15 +2424,18 @@ Here's an example window made with button images.
![media file player](https://user-images.githubusercontent.com/13696193/43161977-9ee7cace-8f57-11e8-8ff8-3ea24b69dab9.jpg)
You'll find the source code in the file Demo Media Player. Here is what the button calls look like to create media player window
```python
sg.Button('Pause', button_color=sg.TRANSPARENT_BUTTON,
sg.Button('Pause', button_color=(sg.theme_background_color(), sg.theme_background_color()),
image_filename=image_pause,
image_size=(50, 50),
image_subsample=2,
border_width=0)
```
Experimentation is sometimes required for these concepts to really sink in.
Experimentation is sometimes required for these concepts to really sink in and they can vary depending on the underlying GUI framework.
Button Images do work so play with them. You can use PIL to change the size of your images before passing to PySimpleGUI.
### Realtime Buttons
@ -2361,8 +2448,6 @@ This window has 2 button types. There's the normal "Read Button" (Quit) and 4 "
Here is the code to make, show and get results from this window:
```python
import PySimpleGUI as sg
@ -2384,15 +2469,15 @@ window = sg.Window('Robotics Remote Control', gui_rows)
# your program's main loop
while (True):
# This is the code that reads and updates your window
event, values = window.Read(timeout=50)
event, values = window.read(timeout=50)
print(event)
if event in ('Quit', None):
break
window.Close() # Don't forget to close your window!
window.close() # Don't forget to close your window!
```
This loop will read button values and print them. When one of the Realtime buttons is clicked, the call to `window.Read` will return a button name matching the name on the button that was depressed or the key if there was a key assigned to the button. It will continue to return values as long as the button remains depressed. Once released, the Read will return timeout events until a button is again clicked.
This loop will read button values and print them. When one of the Realtime buttons is clicked, the call to `window.read` will return a button name matching the name on the button that was depressed or the key if there was a key assigned to the button. It will continue to return values as long as the button remains depressed. Once released, the Read will return timeout events until a button is again clicked.
**File Types**
The `FileBrowse` & `SaveAs` buttons have an additional setting named `file_types`. This variable is used to filter the files shown in the file dialog box. The default value for this setting is
@ -2513,7 +2598,7 @@ If you are looking for a way to quickly add the ability to show scrolling text w
**Anything "printed" will be displayed in this element.** This is the "trivial" way to show scrolling text in your window. It's as easy as dropping an Output Element into your window and then calling print as much as you want. The user will see a scrolling area of text inside their window.
***IMPORTANT*** You will NOT see what you `print` until you call either `window.Read` or `window.Refresh`. If you want to immediately see what was printed, call `window.Refresh()` immediately after your print statement.
***IMPORTANT*** You will NOT see what you `print` until you call either `window.read` or `window.Refresh`. If you want to immediately see what was printed, call `window.Refresh()` immediately after your print statement.
```python
@ -2596,7 +2681,7 @@ layout = [[sg.Slider(range=(1,100), default_value=10, orientation='v', size=(8,2
window = sg.Window('Compact 1-line window with column', layout)
event, values = window.read()
window.Close()
window.close()
sg.Popup(event, values, line_width=200)
@ -2798,7 +2883,7 @@ Table and Tree Elements are of the most complex in PySimpleGUI. They have a lot
### `window.read()` return values from Table Element
The values returned from a `Window.Read` call for the Table Element are a list of row numbers that are currently highlighted.
The values returned from a `Window.read` call for the Table Element are a list of row numbers that are currently highlighted.
### The Qt `Table.Get()` call
@ -3317,7 +3402,7 @@ If you're using a read with a timeout value, then an event value of None signifi
If you wanted to test for "no event" in your loop, it would be written like this:
```python
while True:
event, value = window.Read(timeout=10)
event, value = window.read(timeout=10)
if event is None:
break # the use has closed the window
if event == sg.TIMEOUT_KEY:
@ -3360,7 +3445,7 @@ There are 2 methods of interacting with non-blocking windows.
1. Read the window just as you would a normal window
2. "Refresh" the window's values without reading the window. It's a quick operation meant to show the user the latest values
With asynchronous windows the window is shown, user input is read, but your code keeps right on chugging. YOUR responsibility is to call `PySimpleGUI.Read` on a periodic basis. Several times a second or more will produce a reasonably snappy GUI.
With asynchronous windows the window is shown, user input is read, but your code keeps right on chugging. YOUR responsibility is to call `PySimpleGUI.read` on a periodic basis. Several times a second or more will produce a reasonably snappy GUI.
## Exiting (Closing) a Persistent Window
@ -3410,8 +3495,8 @@ sg.SetOptions(element_padding=(0, 0))
layout = [[sg.Text('')],
[sg.Text(size=(8, 2), font=('Helvetica', 20), justification='center', key='text')],
[sg.ReadButton('Pause', key='button', button_color=('white', '#001480')),
sg.ReadButton('Reset', button_color=('white', '#007339'), key='Reset'),
[sg.Button('Pause', key='button', button_color=('white', '#001480')),
sg.Button('Reset', button_color=('white', '#007339'), key='Reset'),
sg.Exit(button_color=('white', 'firebrick4'), key='Exit')]]
window = sg.Window('Running Timer', layout, no_titlebar=True, auto_size_buttons=False, keep_on_top=True, grab_anywhere=True)
@ -3422,7 +3507,7 @@ paused = False
start_time = int(round(time.time() * 100))
while (True):
# --------- Read and update window --------
event, values = window.Read(timeout=10)
event, values = window.read(timeout=10)
current_time = int(round(time.time() * 100)) - start_time
# --------- Display timer in window --------
window['text'].update('{:02d}:{:02d}.{:02d}'.format((current_time // 100) // 60,
@ -3777,7 +3862,7 @@ win1 = sg.Window('Window 1', layout)
win2_active = False
while True:
ev1, vals1 = win1.Read(timeout=100)
ev1, vals1 = win1.read(timeout=100)
win1['-OUTPUT-'].update(vals1[0])
if ev1 is None or ev1 == 'Exit':
break
@ -3790,10 +3875,10 @@ while True:
win2 = sg.Window('Window 2', layout2)
if win2_active:
ev2, vals2 = win2.Read(timeout=100)
ev2, vals2 = win2.read(timeout=100)
if ev2 is None or ev2 == 'Exit':
win2_active = False
win2.Close()
win2.close()
```
@ -3812,7 +3897,7 @@ layout = [[ sg.Text('Window 1'),],
win1 = sg.Window('Window 1', layout)
win2_active=False
while True:
ev1, vals1 = win1.Read(timeout=100)
ev1, vals1 = win1.read(timeout=100)
if ev1 is None:
break
win1.FindElement('-OUTPUT-').update(vals1[0])
@ -3825,9 +3910,9 @@ while True:
win2 = sg.Window('Window 2', layout2)
while True:
ev2, vals2 = win2.Read()
ev2, vals2 = win2.read()
if ev2 is None or ev2 == 'Exit':
win2.Close()
win2.close()
win2_active = False
win1.UnHide()
break
@ -3886,7 +3971,7 @@ while True:
To this non-blocking:
```python
while True:
event, values = window.Read(timeout=200)
event, values = window.read(timeout=200)
if event == sg.TIMEOUT_KEY:
continue
```
@ -3897,7 +3982,7 @@ This timeout value of 200 means that your debugger GUI will be updated 5 times a
### What happens if you don't add a timeout
Let's say you're in a situation where a very intermettent bug has just happened and the debugger would really help you, but you don't have a timeout on your `windows.Read()` call. It's OK. Recall that the way the debugger gets its "cycles" is to borrow from your `Read` calls. What you need to do is alternate between using the debugger and then generating another pass through your event loop.
Let's say you're in a situation where a very intermettent bug has just happened and the debugger would really help you, but you don't have a timeout on your `windows.read()` call. It's OK. Recall that the way the debugger gets its "cycles" is to borrow from your `Read` calls. What you need to do is alternate between using the debugger and then generating another pass through your event loop.
Maybe it's an OK button that will cause your loop to execute again (without exiting). If so, you can use it to help move the debugger along.
@ -3913,13 +3998,13 @@ import PySimpleGUI as sg
window = sg.Window('Testing the Debugger', [[sg.Text('Debugger Tester'), sg.In('Input here'), sg.B('Push Me')]])
while True:
event, values = window.Read(timeout=500)
event, values = window.read(timeout=500)
if event == sg.TIMEOUT_KEY:
continue
if event is None:
break
print(event, values)
window.Close()
window.close()
```
## Debugger Windows
@ -3982,7 +4067,7 @@ There are 3 ways to open the Main Debugger Window
![SNAG-0440](https://user-images.githubusercontent.com/13696193/62797391-a01ceb80-baa9-11e9-845d-3cd02ca0dbcc.jpg)
Notice the the "frame" surrounding this window is labelled "Auto Watches" in blue. Like the Popup window, this debugger window also "Watches" variables, which means continuously updates them as often as you call `Window.Read`.
Notice the the "frame" surrounding this window is labelled "Auto Watches" in blue. Like the Popup window, this debugger window also "Watches" variables, which means continuously updates them as often as you call `Window.read`.
The maximum number of "watches" you can have any any one time is 9.
@ -4005,7 +4090,7 @@ In this example the Custom Watch entered was `values[0]`. After clicking on the
![SNAG-0444](https://user-images.githubusercontent.com/13696193/62797514-e8d4a480-baa9-11e9-9a86-cfe99342dedb.jpg)
We can see the variables we checked as well as the defined expression `values[0]`. If you leave this window open, these values with continuously be updated, on the fly, every time we call the line in our example code `window.Read(timeout=500)`. This means that the Main Debugger Window and these variables we defined will be updated every 500 milliseconds.
We can see the variables we checked as well as the defined expression `values[0]`. If you leave this window open, these values with continuously be updated, on the fly, every time we call the line in our example code `window.read(timeout=500)`. This means that the Main Debugger Window and these variables we defined will be updated every 500 milliseconds.
@ -5494,7 +5579,7 @@ Without further delay... here are all of the Elements and the Window class
### update
<!-- <+StatusBar.update+> -->
## SystemTray Element
## SystemTray
<!-- <+SystemTray.doc+> -->
<!-- <+SystemTray.__init__+> -->
@ -5606,21 +5691,18 @@ Without further delay... here are all of the Elements and the Window class
<!-- <+TabGroup.__init__+> -->
### FindKeyFromTabName
<!-- <+TabGroup.FindKeyFromTabName+> -->
### Get
<!-- <+TabGroup.Get+> -->
### SetFocus
<!-- <+TabGroup.SetFocus+> -->
### SetTooltip
<!-- <+TabGroup.SetTooltip+> -->
### bind
<!-- <+TabGroup.bind+> -->
@ -5807,7 +5889,7 @@ Without further delay... here are all of the Elements and the Window class
### update
<!-- <+Tree.update+> -->
## TreeData Element
## TreeData (for Tree Element)
<!-- <+TreeData.doc+> -->
<!-- <+TreeData.__init__+> -->
@ -6152,7 +6234,6 @@ Without further delay... here are all of the Elements and the Window class
<!-- <+func.easy_print+> -->
<!-- <+func.easy_print_close+> -->
<!-- <+func.eprint+> -->
<!-- <+func.print_to_element+> -->
<!-- <+func.sgprint+> -->
<!-- <+func.sgprint_close+> -->
<!-- <+func.EasyPrint+> -->

View File

@ -1093,7 +1093,7 @@ Quick patch to remove change to popup
Quick patch to remove f-string for 3.5 compat.
## 4.16.0 PySimpleGUI 08-Jan-2020
## 4.16.0 PySimpleGUI 20-Feb-2020
The "LONG time coming" release. System Tray, Read with close + loads more changes
Note - there is a known problem with the built-in debugger created when the new read with close was added
@ -1124,6 +1124,55 @@ Note - there is a known problem with the built-in debugger created when the new
* print_to_element - print-like call that can be used to output to a Multiline element as if it is an Output element
## 4.17.0 PySimpleGUI 24-Mar-2020
The "it's been a minute" release
Improved DocStrings and documentation!
Upgrade utility
"Printing" directly to Multiline
* New upgrade utility to upgrade your installed package using GitHub version
* Can invoke from command line. Run `python -m PySimpleGUI.PySimpleGUI upgrade`
* The test harness GUI has an upgrade button
* Multiline.print - Add multiline element to the front of any print statement. Also supports color output
* Debug informmation like path and version displayed in test harness GUI
* Added back the TRANSPARENT_BUTTON variable until can find a better way to deprecate
* All elements were losing padding when made invisible. Fixed
* Image.update - fixed crash due to not checking for type before getting size
* Image.update_animation_no_buffering - playback GIF animations of any length
* Graph element - Fixed divide by zero error in convert function
* TabGroup will now autonumber keys if none specified
* Measuring strings more accurately during layout
* Using specific font for measurement
* Used to compute TTK button height
* Used to compute Slider length
* Used to compute header widths in Tables, Trees
* Used to compute column widths in Tables, Trees
* Used to compute row heights in Tables
* Removed padx from row frames. Was using window's margins. Now padx & pady = 0. Was causing too every Column element to have extra padding
* Added no_titlebar to one line progress meter
* popup_notify - Creates a "notification window" that is like the System Tray Message window
* shell_with_animation - launch a shell command that runs while an animated GIF is shown
* Fixed problem with debugger not working after the recent close parameter addition to Window.read
## 4.18.0 PySimpleGUI 26-Mar-2020
An "Oh F**k" Release - Table column sizes were bad
* Fixed bug in Table Element's column size computation
* popup_animated has new title parameter
* Checkbox - update can change the text
## 4.18.1 PySimpleGUI 12-Apr-2020
Emergency patch - f-string managed to get into the code resulting crashes on 3.5 systems (Pi's for example)
## 4.18.2 PySimpleGUI 12-Apr-2020
The Epic Fail release.... import error on 3.5 for subprocess.
### Upcoming

9
readme_creator/Makefile Normal file
View File

@ -0,0 +1,9 @@
build:
python3 make_real_readme.py
rm usage.log.txt
build2:
python3 make_real_readme.py
clean:
rm usage.log.txt

View File

@ -1,6 +1,6 @@
#!/usr/bin/python3
version = __version__ = "4.16.15 Unreleased\n update_animation_no_buffering, popup_notify, removed TRANSPARENT_BUTTON, TabGroup now autonumbers keys, Table col width better size based on font, Table measure row height, Upgrade from GitHub utility (experimental), Multiline.print, fix padding lost with visibility, new upgrade utility, upgrade parameter, switched to urllib, more docstrings"
version = __version__ = "4.18.0 Released 26 Mar 2020"
port = 'PySimpleGUI'
@ -222,7 +222,8 @@ def _timeit_summary(func):
Code I write now, outside PySimpleGUI, IS PEP8 compliant.
The variable and function naming in particular are not compliant. There is
liberal use of CamelVariableAndFunctionNames. If you've got a serious enough problem with this
liberal use of CamelVariableAndFunctionNames, but for anything externally facing, there are aliases
available for all functions. If you've got a serious enough problem with 100% PEP8 compliance
that you'll pass on this package, then that's your right and I invite you to do so. However, if
perhaps you're a practical thinker where it's the results that matter, then you'll have no
trouble with this code base. There is consisency however.
@ -276,6 +277,7 @@ OFFICIAL_PYSIMPLEGUI_BUTTON_COLOR = ('white', BLUES[0])
CURRENT_LOOK_AND_FEEL = 'DarkBlue3'
DEFAULT_ERROR_BUTTON_COLOR = ("#FFFFFF", "#FF0000")
DEFAULT_BACKGROUND_COLOR = None
DEFAULT_ELEMENT_BACKGROUND_COLOR = None
@ -297,6 +299,9 @@ DEFAULT_SCROLLBAR_COLOR = None
# A transparent button is simply one that matches the background
# TRANSPARENT_BUTTON = 'This constant has been depricated. You must set your button background = background it is on for it to be transparent appearing'
TRANSPARENT_BUTTON = ('#F0F0F0', '#F0F0F0') # Use (sg.theme_background_color(), sg.theme_background_color()) instead!!!
# --------------------------------------------------------------------------------
# Progress Bar Relief Choices
RELIEF_RAISED = 'raised'
@ -596,7 +601,7 @@ class Element():
:param key: Identifies an Element. Should be UNIQUE to this window.
:type key: (Any)
:param pad: Amount of padding to put around element in pixels (left/right, top/bottom)
:type pad: (int, int) or ((int,int),(int,int))
:type pad: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int)
:param tooltip: text, that will appear when mouse hovers over the element
:type tooltip: (str)
:param visible: set visibility state of the element (Default = True)
@ -1052,7 +1057,7 @@ class InputText(Element):
:param focus: Determines if initial focus should go to this element.
:type focus: (bool)
:param pad: . Amount of padding to put around element. Normally (horizontal pixels, vertical pixels) but can be split apart further into ((horizontal left, horizontal right), (vertical above, vertical below))
:type pad: (int, int) or ((int, int), (int, int)) Tuple(s)
:type pad: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int)
:param use_readonly_for_disable: If True (the default) tkinter state set to 'readonly'. Otherwise state set to 'disabled'
:type use_readonly_for_disable: (bool)
:param right_click_menu: A list of lists of Menu items to show when this element is right clicked. See user docs for exact format.
@ -1182,7 +1187,7 @@ class Combo(Element):
:para key: Used with window.FindElement and with return values to uniquely identify this element
:type key: (Any)
:param: Amount of padding to put around element (left/right, top/bottom) or ((left, right), (top, bottom))
:type pad: (int, int) or ((int, int),(int,int))
:type pad: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int)
:para tooltip: text that will appear when mouse hovers over this element
:type tooltip: (str)
:par readonly: make element readonly (user can't change). True means user cannot change
@ -1331,7 +1336,7 @@ class OptionMenu(Element):
:param key: Used with window.FindElement and with return values to uniquely identify this element
:type key: (Any)
:param pad: Amount of padding to put around element (left/right, top/bottom) or ((left, right), (top, bottom))
:type pad: (int, int) or ((int, int),(int,int))
:type pad: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int)
:param tooltip: (str) text that will appear when mouse hovers over this element
:type tooltip: (str)
:param visible: (bool) set visibility state of the element
@ -1441,7 +1446,7 @@ class Listbox(Element):
:param key: Used with window.FindElement and with return values to uniquely identify this element
:type key: (Any)
:param pad: Amount of padding to put around element (left/right, top/bottom) or ((left, right), (top, bottom))
:type pad: (int, int) or ((int, int),(int,int))
:type pad: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int)
:param tooltip: text, that will appear when mouse hovers over the element
:type tooltip: (str)
:param right_click_menu: A list of lists of Menu items to show when this element is right clicked. See user docs for exact format.
@ -1636,7 +1641,7 @@ class Radio(Element):
:param key: Used with window.FindElement and with return values to uniquely identify this element
:type key: (Any)
:param pad: Amount of padding to put around element (left/right, top/bottom) or ((left, right), (top, bottom))
:type pad: (int, int) or ((int, int),(int,int))
:type pad: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int)
:param tooltip: text, that will appear when mouse hovers over the element
:type tooltip: (str)
:param change_submits: DO NOT USE. Only listed for backwards compat - Use enable_events instead
@ -1766,7 +1771,7 @@ class Checkbox(Element):
:param key: Used with window.FindElement and with return values to uniquely identify this element
:type key: (Any)
:param pad: Amount of padding to put around element (left/right, top/bottom) or ((left, right), (top, bottom))
:type pad: (int, int) or ((int, int),(int,int))
:type pad: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int)
:param tooltip: text, that will appear when mouse hovers over the element
:type tooltip: (str)
:param visible: set visibility state of the element
@ -1811,12 +1816,14 @@ class Checkbox(Element):
"""
return self.TKIntVar.get()
def Update(self, value=None, background_color=None, text_color=None, disabled=None, visible=None):
def Update(self, value=None, text=None, background_color=None, text_color=None, disabled=None, visible=None):
"""
Changes some of the settings for the Checkbox Element. Must call `Window.Read` or `Window.Finalize` prior.
Note that changing visibility may cause element to change locations when made visible after invisible
:param value: if True checks the checkbox, False clears it
:type value: (bool)
:param text: Text to display next to checkbox
:type text: (str)
:param background_color: color of background
:type background_color: (str)
:param text_color: color of the text. Note this also changes the color of the checkmark
@ -1840,6 +1847,9 @@ class Checkbox(Element):
self.TKCheckbutton.configure(state='disabled')
elif disabled == False:
self.TKCheckbutton.configure(state='normal')
if text is not None:
self.Text = str(text)
self.TKCheckbutton.configure(text=self.Text)
if background_color is not None:
self.TKCheckbutton.configure(background=background_color)
self.BackgroundColor = background_color
@ -1917,7 +1927,7 @@ class Spin(Element):
:param key: Used with window.FindElement and with return values to uniquely identify this element
:type key: (Any)
:param pad: Amount of padding to put around element (left/right, top/bottom) or ((left, right), (top, bottom))
:type pad: (int, int) or ((int, int),(int,int))
:type pad: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int)
:param tooltip: text, that will appear when mouse hovers over the element
:type tooltip: (str)
:param visible: set visibility state of the element
@ -2054,7 +2064,7 @@ class Multiline(Element):
:param font: specifies the font family, size, etc
:type font: Union[str, Tuple[str, int]]
:param pad: Amount of padding to put around element (left/right, top/bottom) or ((left, right), (top, bottom))
:type pad: (int, int) or ((int, int),(int,int))
:type pad: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int)
:param tooltip: text, that will appear when mouse hovers over the element
:type tooltip: (str)
:param right_click_menu: A list of lists of Menu items to show when this element is right clicked. See user docs for exact format.
@ -2224,7 +2234,7 @@ class Text(Element):
:param justification: how string should be aligned within space provided by size. Valid choices = `left`, `right`, `center`
:type justification: (str)
:param pad: Amount of padding to put around element (left/right, top/bottom) or ((left, right), (top, bottom))
:type pad: (int, int) or ((int, int),(int,int))
:type pad: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int)
:param key: Used with window.FindElement and with return values to uniquely identify this element to uniquely identify this element
:type key: (Any)
:param right_click_menu: A list of lists of Menu items to show when this element is right clicked. See user docs for exact format.
@ -2329,7 +2339,7 @@ class StatusBar(Element):
:param justification: how string should be aligned within space provided by size. Valid choices = `left`, `right`, `center`
:type justification: (str)
:param pad: Amount of padding to put around element (left/right, top/bottom) or ((left, right), (top, bottom))
:type pad: (int, int) or ((int, int),(int,int))
:type pad: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int)
:param key: Used with window.FindElement and with return values to uniquely identify this element to uniquely identify this element
:type key: (Any)
:param tooltip: text, that will appear when mouse hovers over the element
@ -2511,7 +2521,7 @@ class TKOutput(tk.Frame):
:param font: specifies the font family, size, etc
:type font: Union[str, Tuple[str, int]]
:param pad: Amount of padding to put around element (left/right, top/bottom) or ((left, right), (top, bottom))
:type pad: (int, int) or ((int, int),(int,int))
:type pad: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int)
"""
self.frame = tk.Frame(parent)
tk.Frame.__init__(self, self.frame)
@ -2587,7 +2597,7 @@ class Output(Element):
:param text_color: color of the text
:type text_color: (str)
:param pad: Amount of padding to put around element (left/right, top/bottom) or ((left, right), (top, bottom))
:type pad: (int, int) or ((int, int),(int,int))
:type pad: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int)
:param font: specifies the font family, size, etc
:type font: Union[str, Tuple[str, int]]
:param tooltip: text, that will appear when mouse hovers over the element
@ -2612,6 +2622,12 @@ class Output(Element):
@property
def TKOut(self):
"""
Returns the TKOutput object used to create the element
:return: The TKOutput object
:rtype: (TKOutput)
"""
if self._TKOut is None:
print('*** Did you forget to call Finalize()? Your code should look something like: ***')
print('*** form = sg.Window("My Form").Layout(layout).Finalize() ***')
@ -2645,7 +2661,7 @@ class Output(Element):
"""
return self._TKOut.output.get(1.0, tk.END)
def expand(self, expand_x=False, expand_y=False):
def expand(self, expand_x=False, expand_y=False, expand_row=True):
"""
Causes the Element to expand to fill available space in the X and Y directions. Can specify which or both directions
@ -2666,7 +2682,7 @@ class Output(Element):
self._TKOut.output.pack(expand=True, fill=fill)
self._TKOut.frame.pack(expand=True, fill=fill)
self.ParentRowFrame.pack(expand=True, fill=fill)
self.ParentRowFrame.pack(expand=expand_row, fill=fill)
def __del__(self):
"""
@ -2741,7 +2757,7 @@ class Button(Element):
:param focus: if True, initial focus will be put on this button
:type focus: (bool)
:param pad: Amount of padding to put around element (left/right, top/bottom) or ((left, right), (top, bottom))
:type pad: (int, int) or ((int, int),(int,int))
:type pad: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int)
:param key: Used with window.FindElement and with return values to uniquely identify this element to uniquely identify this element
:type key: (Any)
:param visible: set visibility state of the element
@ -3111,7 +3127,7 @@ class ButtonMenu(Element):
:param font: specifies the font family, size, etc
:type font: Union[str, Tuple[str, int]]
:param pad: Amount of padding to put around element (left/right, top/bottom) or ((left, right), (top, bottom))
:type pad: (int, int) or ((int, int),(int,int))
:type pad: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int)
:param key: Used with window.FindElement and with return values to uniquely identify this element to uniquely identify this element
:type key: (Any)
:param tearoff: Determines if menus should allow them to be torn off
@ -3230,7 +3246,7 @@ class ProgressBar(Element):
:param key: Used with window.FindElement and with return values to uniquely identify this element to uniquely identify this element
:type key: (Any)
:param pad: Amount of padding to put around element (left/right, top/bottom) or ((left, right), (top, bottom))
:type pad: (int, int) or ((int, int),(int,int))
:type pad: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int)
:param visible: set visibility state of the element
:type visible: (bool)
:param metadata: User metadata that can be set to ANYTHING
@ -3317,7 +3333,7 @@ class Image(Element):
:param size: (width, height) size of image in pixels
:type size: Tuple[int, int]
:param pad: Amount of padding to put around element (left/right, top/bottom) or ((left, right), (top, bottom))
:type pad: (int, int) or ((int, int),(int,int))
:type pad: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int)
:param key: Used with window.FindElement and with return values to uniquely identify this element to uniquely identify this element
:type key: (Any)
:param tooltip: text, that will appear when mouse hovers over the element
@ -3515,7 +3531,7 @@ class Canvas(Element):
:param size: (width in char, height in rows) size in pixels to make canvas
:type size: Tuple[int,int]
:param pad: Amount of padding to put around element
:type pad: int
:type pad: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int)
:param key: Used with window.FindElement and with return values to uniquely identify this element
:type key: (Any)
:param tooltip: text, that will appear when mouse hovers over the element
@ -3538,6 +3554,12 @@ class Canvas(Element):
@property
def TKCanvas(self):
"""
Returns the underlying tkiner Canvas widget
:return: The tkinter canvas widget
:rtype: (tk.Canvas)
"""
if self._TKCanvas is None:
print('*** Did you forget to call Finalize()? Your code should look something like: ***')
print('*** window = sg.Window("My Form", layout, finalize=True) ***')
@ -3577,7 +3599,7 @@ class Graph(Element):
:param background_color: background color of the drawing area
:type background_color: (str)
:param pad: Amount of padding to put around element (left/right, top/bottom) or ((left, right), (top, bottom))
:type pad: (int, int) or ((int, int),(int,int))
:type pad: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int)
:param change_submits: * DEPRICATED DO NOT USE! Same as enable_events
:type change_submits: (bool)
:param drag_submits: if True and Events are enabled for the Graph, will report Events any time the mouse moves while button down
@ -3627,8 +3649,12 @@ class Graph(Element):
"""
if None in (x_in, y_in):
return None, None
scale_x = (self.CanvasSize[0] - 0) / (self.TopRight[0] - self.BottomLeft[0])
scale_y = (0 - self.CanvasSize[1]) / (self.TopRight[1] - self.BottomLeft[1])
try:
scale_x = (self.CanvasSize[0] - 0) / (self.TopRight[0] - self.BottomLeft[0])
scale_y = (0 - self.CanvasSize[1]) / (self.TopRight[1] - self.BottomLeft[1])
except:
scale_x = scale_y = 0
new_x = 0 + scale_x * (x_in - self.BottomLeft[0])
new_y = self.CanvasSize[1] + scale_y * (y_in - self.BottomLeft[1])
return new_x, new_y
@ -4130,6 +4156,12 @@ class Graph(Element):
@property
def TKCanvas(self):
"""
Returns the underlying tkiner Canvas widget
:return: The tkinter canvas widget
:rtype: (tk.Canvas)
"""
if self._TKCanvas2 is None:
print('*** Did you forget to call Finalize()? Your code should look something like: ***')
print('*** form = sg.Window("My Form").Layout(layout).Finalize() ***')
@ -4249,7 +4281,7 @@ class Frame(Element):
:param font: specifies the font family, size, etc
:type font: Union[str, Tuple[str, int]]
:param pad: Amount of padding to put around element (left/right, top/bottom) or ((left, right), (top, bottom))
:type pad: (int, int) or ((int, int),(int,int))
:type pad: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int)
:param border_width: width of border around element in pixels
:type border_width: (int)
:param key: Value that uniquely identifies this element from all other elements. Used when Finding an element or in return values. Must be unique to the window
@ -4417,7 +4449,7 @@ class VerticalSeparator(Element):
def __init__(self, pad=None):
"""
:param pad: Amount of padding to put around element (left/right, top/bottom) or ((left, right), (top, bottom))
:type pad: (int, int) or ((int, int),(int,int))
:type pad: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int)
"""
self.Orientation = 'vertical' # for now only vertical works
@ -4455,7 +4487,7 @@ class Tab(Element):
:param font: specifies the font family, size, etc
:type font: Union[str, Tuple[str, int]]
:param pad: Amount of padding to put around element (left/right, top/bottom) or ((left, right), (top, bottom))
:type pad: (int, int) or ((int, int),(int,int))
:type pad: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int)
:param disabled: If True button will be created disabled
:type disabled: (bool)
:param border_width: width of border around element in pixels
@ -4663,7 +4695,7 @@ class TabGroup(Element):
:param enable_events: If True then switching tabs will generate an Event
:type enable_events: (bool)
:param pad: Amount of padding to put around element (left/right, top/bottom) or ((left, right), (top, bottom))
:type pad: (int, int) or ((int, int),(int,int))
:type pad: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int)
:param border_width: width of border around element in pixels
:type border_width: (int)
:param theme: DEPRICATED - You can only specify themes using set options or when window is created. It's not possible to do it on an element basis
@ -4882,7 +4914,7 @@ class Slider(Element):
:param key: Value that uniquely identifies this element from all other elements. Used when Finding an element or in return values. Must be unique to the window
:type key: (any)
:param pad: Amount of padding to put around element (left/right, top/bottom) or ((left, right), (top, bottom))
:type pad: (int, int) or ((int, int),(int,int))
:type pad: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int)
:param tooltip: text, that will appear when mouse hovers over the element
:type tooltip: (str)
:param visible: set visibility state of the element
@ -5106,7 +5138,7 @@ class Column(Element):
:param size: (width, height) size in pixels (doesn't work quite right, sometimes only 1 dimension is set by tkinter
:type size: Tuple[int, int]
:param pad: Amount of padding to put around element (left/right, top/bottom) or ((left, right), (top, bottom))
:type pad: (int, int) or ((int, int),(int,int))
:type pad: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int)
:param scrollable: if True then scrollbars will be added to the column
:type scrollable: (bool)
:param vertical_scroll_only: if Truen then no horizontal scrollbar will be shown
@ -5285,7 +5317,7 @@ class Pane(Element):
:param size: (width, height) w=characters-wide, h=rows-high How much room to reserve for the Pane
:type size: Tuple[int, int]
:param pad: Amount of padding to put around element (left/right, top/bottom) or ((left, right), (top, bottom))
:type pad: (int, int) or ((int, int),(int,int))
:type pad: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int)
:param orientation: 'horizontal' or 'vertical' or ('h' or 'v'). Direction the Pane should slide
:type orientation: (str)
:param show_handle: if True, the handle is drawn that makes it easier to grab and slide
@ -5602,7 +5634,7 @@ class Menu(Element):
:param tearoff: if True, then can tear the menu off from the window ans use as a floating window. Very cool effect
:type tearoff: (bool)
:param pad: Amount of padding to put around element (left/right, top/bottom) or ((left, right), (top, bottom))
:type pad: (int, int) or ((int, int),(int,int))
:type pad: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int)
:param key: Value that uniquely identifies this element from all other elements. Used when Finding an element or in return values. Must be unique to the window
:type key: (any)
:param visible: set visibility state of the element
@ -5746,7 +5778,7 @@ class Table(Element):
:param bind_return_key: if True, pressing return key will cause event coming from Table, ALSO a left button double click will generate an event if this parameter is True
:type bind_return_key: (bool)
:param pad: Amount of padding to put around element (left/right, top/bottom) or ((left, right), (top, bottom))
:type pad: (int, int) or ((int, int),(int,int))
:type pad: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int)
:param key: Used with window.FindElement and with return values to uniquely identify this element to uniquely identify this element
:type key: (Any)
:param tooltip: text, that will appear when mouse hovers over the element
@ -5978,7 +6010,7 @@ class Tree(Element):
:param row_height: height of a single row in pixels
:type row_height: (int)
:param pad: Amount of padding to put around element (left/right, top/bottom) or ((left, right), (top, bottom))
:type pad: (int, int) or ((int, int),(int,int))
:type pad: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int)
:param key: Used with window.FindElement and with return values to uniquely identify this element to uniquely identify this element
:type key: (Any)
:param tooltip: text, that will appear when mouse hovers over the element
@ -6818,6 +6850,9 @@ class Window:
:return: (event, values)
:rtype: Tuple[(Any), Union[Dict[Any:Any]], List[Any], None]
"""
# ensure called only 1 time through a single read cycle
if not Window._read_call_from_debugger:
_refresh_debugger()
results = self._read(timeout=timeout, timeout_key=timeout_key)
if close:
self.close()
@ -6840,9 +6875,7 @@ class Window:
:return: (event, values) (event or timeout_key or None, Dictionary of values or List of values from all elements in the Window)
:rtype: Tuple[(Any), Union[Dict[Any:Any]], List[Any], None]
"""
# ensure called only 1 time through a single read cycle
if not Window._read_call_from_debugger:
_refresh_debugger()
timeout = int(timeout) if timeout is not None else None
if timeout == 0: # timeout of zero runs the old readnonblocking
event, values = self._ReadNonBlocking()
@ -8151,7 +8184,7 @@ def FileBrowse(button_text='Browse', target=(ThisRow, -1), file_types=(("ALL Fil
:param disabled: set disable state for element (Default = False)
:type disabled: (bool)
:param pad: Amount of padding to put around element in pixels (left/right, top/bottom)
:type pad: (int, int) or ((int,int),(int,int))
:type pad: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int)
:param key: key for uniquely identify this element (for window.FindElement)
:type key: Union[str, int, tuple]
:return: returns a button
@ -8191,7 +8224,7 @@ def FilesBrowse(button_text='Browse', target=(ThisRow, -1), file_types=(("ALL Fi
:param font: specifies the font family, size, etc
:type font: Union[str, Tuple[str, int]]
:param pad: Amount of padding to put around element in pixels (left/right, top/bottom)
:type pad: (int, int) or ((int,int),(int,int))
:type pad: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int)
:param key: key for uniquely identify this element (for window.FindElement)
:type key: Union[str, int, tuple]
:return: returns a button
@ -8229,7 +8262,7 @@ def FileSaveAs(button_text='Save As...', target=(ThisRow, -1), file_types=(("ALL
:param font: specifies the font family, size, etc
:type font: Union[str, Tuple[str, int]]
:param pad: Amount of padding to put around element in pixels (left/right, top/bottom)
:type pad: (int, int) or ((int,int),(int,int))
:type pad: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int)
:param key: key for uniquely identify this element (for window.FindElement)
:type key: Union[str, int, tuple]
:return: returns a button
@ -8267,7 +8300,7 @@ def SaveAs(button_text='Save As...', target=(ThisRow, -1), file_types=(("ALL Fil
:param font: specifies the font family, size, etc
:type font: Union[str, Tuple[str, int]]
:param pad: Amount of padding to put around element in pixels (left/right, top/bottom)
:type pad: (int, int) or ((int,int),(int,int))
:type pad: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int)
:param key: key for uniquely identify this element (for window.FindElement)
:type key: Union[str, int, tuple]
:return: returns a button
@ -8300,7 +8333,7 @@ def Save(button_text='Save', size=(None, None), auto_size_button=None, button_co
:type font: Union[str, Tuple[str, int]]
:param focus: if focus should be set to this
:param pad: Amount of padding to put around element in pixels (left/right, top/bottom)
:type pad: (int, int) or ((int,int),(int,int))
:type pad: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int)
:param key: key for uniquely identify this element (for window.FindElement)
:type key: Union[str, int, tuple]
:return: returns a button
@ -8332,7 +8365,7 @@ def Submit(button_text='Submit', size=(None, None), auto_size_button=None, butto
:type font: Union[str, Tuple[str, int]]
:param focus: if focus should be set to this
:param pad: Amount of padding to put around element in pixels (left/right, top/bottom)
:type pad: (int, int) or ((int,int),(int,int))
:type pad: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int)
:param key: key for uniquely identify this element (for window.FindElement)
:type key: Union[str, int, tuple]
:return: returns a button
@ -8365,7 +8398,7 @@ def Open(button_text='Open', size=(None, None), auto_size_button=None, button_co
:type font: Union[str, Tuple[str, int]]
:param focus: if focus should be set to this
:param pad: Amount of padding to put around element in pixels (left/right, top/bottom)
:type pad: (int, int) or ((int,int),(int,int))
:type pad: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int)
:param key: key for uniquely identify this element (for window.FindElement)
:type key: Union[str, int, tuple]
@ -8396,7 +8429,7 @@ def OK(button_text='OK', size=(None, None), auto_size_button=None, button_color=
:type font: Union[str, Tuple[str, int]]
:param focus: if focus should be set to this
:param pad: Amount of padding to put around element in pixels (left/right, top/bottom)
:type pad: (int, int) or ((int,int),(int,int))
:type pad: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int)
:param key: key for uniquely identify this element (for window.FindElement)
:type key: Union[str, int, tuple]
:return: returns a button
@ -8428,7 +8461,7 @@ def Ok(button_text='Ok', size=(None, None), auto_size_button=None, button_color=
:type font: Union[str, Tuple[str, int]]
:param focus: if focus should be set to this
:param pad: Amount of padding to put around element in pixels (left/right, top/bottom)
:type pad: (int, int) or ((int,int),(int,int))
:type pad: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int)
:param key: key for uniquely identify this element (for window.FindElement)
:type key: Union[str, int, tuple]
:return: returns a button
@ -8460,7 +8493,7 @@ def Cancel(button_text='Cancel', size=(None, None), auto_size_button=None, butto
:param bind_return_key: (Default = False)
:param focus: if focus should be set to this
:param pad: Amount of padding to put around element in pixels (left/right, top/bottom)
:type pad: (int, int) or ((int,int),(int,int))
:type pad: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int)
:param key: key for uniquely identify this element (for window.FindElement)
:type key: Union[str, int, tuple]
@ -8491,7 +8524,7 @@ def Quit(button_text='Quit', size=(None, None), auto_size_button=None, button_co
:param bind_return_key: (Default = False)
:param focus: if focus should be set to this
:param pad: Amount of padding to put around element in pixels (left/right, top/bottom)
:type pad: (int, int) or ((int,int),(int,int))
:type pad: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int)
:param key: key for uniquely identify this element (for window.FindElement)
:type key: Union[str, int, tuple]
:return: returns a button
@ -8523,7 +8556,7 @@ def Exit(button_text='Exit', size=(None, None), auto_size_button=None, button_co
:param bind_return_key: (Default = False)
:param focus: if focus should be set to this
:param pad: Amount of padding to put around element in pixels (left/right, top/bottom)
:type pad: (int, int) or ((int,int),(int,int))
:type pad: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int)
:param key: key for uniquely identify this element (for window.FindElement)
:type key: Union[str, int, tuple]
@ -8554,7 +8587,7 @@ def Yes(button_text='Yes', size=(None, None), auto_size_button=None, button_colo
:param bind_return_key: (Default = True)
:param focus: if focus should be set to this
:param pad: Amount of padding to put around element in pixels (left/right, top/bottom)
:type pad: (int, int) or ((int,int),(int,int))
:type pad: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int)
:param key: key for uniquely identify this element (for window.FindElement)
:type key: Union[str, int, tuple]
:return: returns a button
@ -8586,7 +8619,7 @@ def No(button_text='No', size=(None, None), auto_size_button=None, button_color=
:param bind_return_key: (Default = False)
:param focus: if focus should be set to this
:param pad: Amount of padding to put around element in pixels (left/right, top/bottom)
:type pad: (int, int) or ((int,int),(int,int))
:type pad: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int)
:param key: key for uniquely identify this element (for window.FindElement)
:type key: Union[str, int, tuple]
@ -8617,7 +8650,7 @@ def Help(button_text='Help', size=(None, None), auto_size_button=None, button_co
:param bind_return_key: (Default = False)
:param focus: if focus should be set to this
:param pad: Amount of padding to put around element in pixels (left/right, top/bottom)
:type pad: (int, int) or ((int,int),(int,int))
:type pad: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int)
:param key: key for uniquely identify this element (for window.FindElement)
:type key: Union[str, int, tuple]
:return: returns a button
@ -8649,7 +8682,7 @@ def Debug(button_text='', size=(None, None), auto_size_button=None, button_color
:param bind_return_key: (Default = False)
:param focus: if focus should be set to this
:param pad: Amount of padding to put around element in pixels (left/right, top/bottom)
:type pad: (int, int) or ((int,int),(int,int))
:type pad: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int)
:param key: key for uniquely identify this element (for window.FindElement)
:type key: Union[str, int, tuple]
:return: returns a button
@ -8689,7 +8722,7 @@ def SimpleButton(button_text, image_filename=None, image_data=None, image_size=(
:type disabled: (bool)
:param focus: if focus should be set to this
:param pad: Amount of padding to put around element in pixels (left/right, top/bottom)
:type pad: (int, int) or ((int,int),(int,int))
:type pad: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int)
:param key: key for uniquely identify this element (for window.FindElement)
:type key: Union[str, int, tuple]
:return: returns a button
@ -8730,7 +8763,7 @@ def CloseButton(button_text, image_filename=None, image_data=None, image_size=(N
:type disabled: (bool)
:param focus: if focus should be set to this
:param pad: Amount of padding to put around element in pixels (left/right, top/bottom)
:type pad: (int, int) or ((int,int),(int,int))
:type pad: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int)
:param key: key for uniquely identify this element (for window.FindElement)
:type key: Union[str, int, tuple]
:return: returns a button
@ -8774,7 +8807,7 @@ def ReadButton(button_text, image_filename=None, image_data=None, image_size=(No
:type disabled: (bool)
:param focus: if focus should be set to this
:param pad: Amount of padding to put around element in pixels (left/right, top/bottom)
:type pad: (int, int) or ((int,int),(int,int))
:type pad: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int)
:param key: key for uniquely identify this element (for window.FindElement)
:type key: Union[str, int, tuple]
@ -8818,7 +8851,7 @@ def RealtimeButton(button_text, image_filename=None, image_data=None, image_size
:param bind_return_key: (Default = False)
:param focus: if focus should be set to this
:param pad: Amount of padding to put around element in pixels (left/right, top/bottom)
:type pad: (int, int) or ((int,int),(int,int))
:type pad: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int)
:param key: key for uniquely identify this element (for window.FindElement)
:type key: Union[str, int, tuple]
@ -8858,7 +8891,7 @@ def DummyButton(button_text, image_filename=None, image_data=None, image_size=(N
:param bind_return_key: (Default = False)
:param focus: if focus should be set to this
:param pad: Amount of padding to put around element in pixels (left/right, top/bottom)
:type pad: (int, int) or ((int,int),(int,int))
:type pad: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int)
:param key: key for uniquely identify this element (for window.FindElement)
:type key: Union[str, int, tuple]
:return: returns a button
@ -8904,7 +8937,7 @@ def CalendarButton(button_text, target=(None, None), close_when_date_chosen=True
:param bind_return_key: (Default = False)
:param focus: if focus should be set to this
:param pad: Amount of padding to put around element in pixels (left/right, top/bottom)
:type pad: (int, int) or ((int,int),(int,int))
:type pad: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int)
:param key: key for uniquely identify this element (for window.FindElement)
:type key: Union[str, int, tuple]
:param locale:
@ -8954,7 +8987,7 @@ def ColorChooserButton(button_text, target=(None, None), image_filename=None, im
:param bind_return_key: (Default = False)
:param focus: if focus should be set to this
:param pad: Amount of padding to put around element in pixels (left/right, top/bottom)
:type pad: (int, int) or ((int,int),(int,int))
:type pad: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int)
:param key: key for uniquely identify this element (for window.FindElement)
:type key: Union[str, int, tuple]
:return: returns a button
@ -9817,7 +9850,7 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form):
if element.DisabledButtonColor[1] is not None:
button_style.map(style_name, background=[('disabled', element.DisabledButtonColor[1])])
if height > 1:
button_style.configure(style_name, padding=height * _char_width_in_pixels(font))
button_style.configure(style_name, padding=height * _char_width_in_pixels(font)) # should this be height instead?
wraplen = tkbutton.winfo_reqwidth() # width of widget in Pixels
if width != 0:
button_style.configure(style_name, wraplength=wraplen) # set wrap to width of widget
@ -10331,7 +10364,7 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form):
photo = tk.PhotoImage(data=element.Data)
else:
photo = None
print('*ERROR laying out form.... Image Element has no image specified*')
# print('*ERROR laying out form.... Image Element has no image specified*')
if photo is not None:
if element_size == (
@ -10353,19 +10386,20 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form):
element.tktext_label.image = photo
# tktext_label.configure(anchor=tk.NW, image=photo)
element.tktext_label.pack(side=tk.LEFT, padx=elementpad[0], pady=elementpad[1])
if element.Visible is False:
element.tktext_label.pack_forget()
if element.Tooltip is not None:
element.TooltipObject = ToolTip(element.tktext_label, text=element.Tooltip,
timeout=DEFAULT_TOOLTIP_TIME)
if element.EnableEvents:
element.tktext_label.bind('<ButtonPress-1>', element._ClickHandler)
if element.RightClickMenu or toplevel_form.RightClickMenu:
menu = element.RightClickMenu or toplevel_form.RightClickMenu
top_menu = tk.Menu(toplevel_form.TKroot, tearoff=False)
AddMenuItem(top_menu, menu[1], element)
element.TKRightClickMenu = top_menu
element.tktext_label.bind('<Button-3>', element._RightClickMenuCallback)
if element.Visible is False:
element.tktext_label.pack_forget()
if element.Tooltip is not None:
element.TooltipObject = ToolTip(element.tktext_label, text=element.Tooltip,
timeout=DEFAULT_TOOLTIP_TIME)
if element.EnableEvents:
element.tktext_label.bind('<ButtonPress-1>', element._ClickHandler)
if element.RightClickMenu or toplevel_form.RightClickMenu:
menu = element.RightClickMenu or toplevel_form.RightClickMenu
top_menu = tk.Menu(toplevel_form.TKroot, tearoff=False)
AddMenuItem(top_menu, menu[1], element)
element.TKRightClickMenu = top_menu
element.tktext_label.bind('<Button-3>', element._RightClickMenuCallback)
# ------------------------- Canvas placement element ------------------------- #
elif element_type == ELEM_TYPE_CANVAS:
width, height = element_size
@ -10616,6 +10650,7 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form):
else:
anchor = tk.CENTER
column_widths = {}
# create column width list
for row in element.Values:
for i, col in enumerate(row):
col_width = min(len(str(col)), element.MaxColumnWidth)
@ -10656,14 +10691,13 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form):
for i, heading in enumerate(headings):
treeview.heading(heading, text=heading)
if element.AutoSizeColumns:
width = max(column_widths[i], _string_width_in_pixels(font, heading) + 10)
width = max(column_widths[i], len(heading)) * _char_width_in_pixels(font)
else:
try:
width = element.ColumnWidths[i] * _char_width_in_pixels(font)
except:
width = element.DefaultColumnWidth * _char_width_in_pixels(font)
treeview.column(heading, width=width, minwidth=10, anchor=anchor, stretch=0)
# Insert values into the tree
for i, value in enumerate(element.Values):
if element.DisplayRowNumbers:
@ -10769,8 +10803,7 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form):
width = element.ColumnWidths[i]
except:
width = element.DefaultColumnWidth
treeview.column(heading, width=width * _char_width_in_pixels(font), anchor=anchor)
treeview.column(heading, width=width * _char_width_in_pixels(font)+ 10, anchor=anchor)
def add_treeview_data(node):
"""
@ -11145,8 +11178,7 @@ class QuickMeter(object):
active_meters = {}
exit_reasons = {}
def __init__(self, title, current_value, max_value, key, *args, orientation='v', bar_color=(None, None),
button_color=(None, None), size=DEFAULT_PROGRESS_BAR_SIZE, border_width=None, grab_anywhere=False):
def __init__(self, title, current_value, max_value, key, *args, orientation='v', bar_color=(None, None), button_color=(None, None), size=DEFAULT_PROGRESS_BAR_SIZE, border_width=None, grab_anywhere=False, no_titlebar=False):
"""
:param title: text to display in eleemnt
@ -11171,6 +11203,8 @@ class QuickMeter(object):
:type border_width: (int)
:param grab_anywhere: If True: can grab anywhere to move the window (Default = False)
:type grab_anywhere: (bool)
:param no_titlebar: If True: window will be created without a titlebar
:type no_titlebar: (bool)
"""
self.start_time = datetime.datetime.utcnow()
self.key = key
@ -11180,6 +11214,7 @@ class QuickMeter(object):
self.grab_anywhere = grab_anywhere
self.button_color = button_color
self.border_width = border_width
self.no_titlebar = no_titlebar
self.title = title
self.current_value = current_value
self.max_value = max_value
@ -11206,7 +11241,7 @@ class QuickMeter(object):
col2 += [[T('', size=(30, 10), key='_STATS_')],
[Cancel(button_color=self.button_color), Stretch()]]
layout = [Column(col), Column(col2)]
self.window = Window(self.title, grab_anywhere=self.grab_anywhere, border_depth=self.border_width)
self.window = Window(self.title, grab_anywhere=self.grab_anywhere, border_depth=self.border_width, no_titlebar=self.no_titlebar)
self.window.Layout([layout]).Finalize()
return self.window
@ -11257,8 +11292,7 @@ class QuickMeter(object):
return self.stat_messages
def OneLineProgressMeter(title, current_value, max_value, key, *args, orientation='v', bar_color=(None, None),
button_color=None, size=DEFAULT_PROGRESS_BAR_SIZE, border_width=None, grab_anywhere=False):
def OneLineProgressMeter(title, current_value, max_value, key, *args, orientation='v', bar_color=(None, None), button_color=None, size=DEFAULT_PROGRESS_BAR_SIZE, border_width=None, grab_anywhere=False, no_titlebar=False):
"""
:param title: text to display in eleemnt
:type title: (str)
@ -11273,7 +11307,7 @@ def OneLineProgressMeter(title, current_value, max_value, key, *args, orientatio
:param orientation: 'horizontal' or 'vertical' ('h' or 'v' work) (Default value = 'vertical' / 'v')
:type orientation: (str)
:param bar_color: color of a bar line
:type bar_color: str
:type bar_color: Tuple(str, str)
:param button_color: button color (foreground, background)
:type button_color: Tuple[str, str]
:param size: (w,h) w=characters-wide, h=rows-high (Default value = DEFAULT_PROGRESS_BAR_SIZE)
@ -11282,12 +11316,13 @@ def OneLineProgressMeter(title, current_value, max_value, key, *args, orientatio
:type border_width: (int)
:param grab_anywhere: If True: can grab anywhere to move the window (Default = False)
:type grab_anywhere: (bool)
:param no_titlebar: If True: no titlebar will be shown on the window
:type no_titlebar: (bool)
:return: True if updated successfully. False if user closed the meter with the X or Cancel button
:rtype: (bool)
"""
if key not in QuickMeter.active_meters:
meter = QuickMeter(title, current_value, max_value, key, *args, orientation=orientation, bar_color=bar_color,
button_color=button_color, size=size, border_width=border_width, grab_anywhere=grab_anywhere)
meter = QuickMeter(title, current_value, max_value, key, *args, orientation=orientation, bar_color=bar_color, button_color=button_color, size=size, border_width=border_width, grab_anywhere=grab_anywhere, no_titlebar=no_titlebar)
QuickMeter.active_meters[key] = meter
else:
meter = QuickMeter.active_meters[key]
@ -11302,6 +11337,7 @@ def OneLineProgressMeterCancel(key):
Cancels and closes a previously created One Line Progress Meter window
:param key: Key used when meter was created
:type key: (Any)
"""
try:
meter = QuickMeter.active_meters[key]
@ -11414,12 +11450,17 @@ class _DebugWin():
def PrintClose():
"""
Close a previously opened EasyPrint window
"""
EasyPrintClose()
def EasyPrint(*args, size=(None, None), end=None, sep=None, location=(None, None), font=None, no_titlebar=False,
no_button=False, grab_anywhere=False, keep_on_top=False, do_not_reroute_stdout=True, text_color=None, background_color=None):
"""
Works like a "print" statement but with windowing options. Routes output to the "Debug Window"
:param *args: stuff to output
:type *args: (Any)
:param size: (w,h) w=characters-wide, h=rows-high
@ -11461,6 +11502,9 @@ eprint = EasyPrint
def EasyPrintClose():
"""
Close a previously opened EasyPrint window
"""
if _DebugWin.debug_window is not None:
_DebugWin.debug_window.Close()
_DebugWin.debug_window = None
@ -12758,8 +12802,8 @@ def theme(new_theme=None):
"""
Sets / Gets the current Theme. If none is specified then returns the current theme.
This call replaces the ChangeLookAndFeel / change_look_and_feel call which only sets the theme.
:param new_theme: (str) the new theme name to use
:type new_theme: (str)
:return: (str) the currently selected theme
"""
if new_theme is not None:
@ -12773,6 +12817,7 @@ def theme_background_color(color=None):
Used for Windows and containers (Column, Frame, Tab) and tables
:return: (str) - color string of the background color currently in use
:rtype: (str)
"""
if color is not None:
set_options(background_color=color)
@ -12784,6 +12829,7 @@ def theme_element_background_color(color=None):
Sets/Returns the background color currently in use for all elements except containers
:return: (str) - color string of the element background color currently in use
:rtype: (str)
"""
if color is not None:
set_options(element_background_color=color)
@ -12795,6 +12841,7 @@ def theme_text_color(color=None):
Sets/Returns the text color currently in use
:return: (str) - color string of the text color currently in use
:rtype: (str)
"""
if color is not None:
set_options(text_color=color)
@ -12806,6 +12853,7 @@ def theme_text_element_background_color(color=None):
Sets/Returns the background color for text elements
:return: (str) - color string of the text background color currently in use
:rtype: (str)
"""
if color is not None:
set_options(text_element_background_color=color)
@ -12816,6 +12864,7 @@ def theme_input_background_color(color=None):
Sets/Returns the input element background color currently in use
:return: (str) - color string of the input element background color currently in use
:rtype: (str)
"""
if color is not None:
set_options(input_elements_background_color=color)
@ -12827,6 +12876,7 @@ def theme_input_text_color(color=None):
Sets/Returns the input element entry color (not the text but the thing that's displaying the text)
:return: (str) - color string of the input element color currently in use
:rtype: (str)
"""
if color is not None:
set_options(input_text_color=color)
@ -12839,6 +12889,7 @@ def theme_button_color(color=None):
Sets/Returns the button color currently in use
:return: Tuple[str, str] - TUPLE with color strings of the button color currently in use (button text color, button background color)
:rtype: (str)
"""
if color is not None:
set_options(button_color=color)
@ -12850,6 +12901,7 @@ def theme_progress_bar_color(color=None):
Sets/Returns the progress bar colors by the current color theme
:return: Tuple[str, str] - TUPLE with color strings of the ProgressBar color currently in use(button text color, button background color)
:rtype: (str)
"""
if color is not None:
set_options(progress_meter_color=color)
@ -12861,6 +12913,7 @@ def theme_slider_color(color=None):
Sets/Returns the slider color (used for sliders)
:return: (str) - color string of the slider color currently in use
:rtype: (str)
"""
if color is not None:
set_options(scrollbar_color=color)
@ -12873,6 +12926,7 @@ def theme_border_width(border_width=None):
Used by non ttk elements at the moment
:return: (int) - border width currently in use
:rtype: (str)
"""
if border_width is not None:
set_options(border_width=border_width)
@ -12884,6 +12938,7 @@ def theme_slider_border_width(border_width=None):
Sets/Returns the slider border width currently in use
:return: (int) - border width currently in use
:rtype: (str)
"""
if border_width is not None:
set_options(slider_border_width=border_width)
@ -12895,6 +12950,7 @@ def theme_progress_bar_border_width(border_width=None):
Sets/Returns the progress meter border width currently in use
:return: (int) - border width currently in use
:rtype: (str)
"""
if border_width is not None:
set_options(progress_meter_border_depth=border_width)
@ -12907,6 +12963,7 @@ def theme_element_text_color(color=None):
Sets/Returns the text color used by elements that have text as part of their display (Tables, Trees and Sliders)
:return: (str) - color string currently in use
:rtype: (str)
"""
if color is not None:
set_options(element_text_color=color)
@ -12918,6 +12975,7 @@ def theme_list():
Returns a sorted list of the currently available color themes
:return: List[str] - A sorted list of the currently available color themes
:rtype: (str)
"""
return list_of_look_and_feel_values()
@ -13178,7 +13236,7 @@ def Popup(*args, title=None, button_color=None, background_color=None, text_colo
:param text_color: text color
:type text_color: (str)
:param button_type: NOT USER SET! Determines which pre-defined buttons will be shown (Default value = POPUP_BUTTONS_OK). There are many Popup functions and they call Popup, changing this parameter to get the desired effect.
:type button_type: (enum)
:type button_type: (int)
:param auto_close: If True the window will automatically close
:type auto_close: (bool)
:param auto_close_duration: time in seconds to keep window open before closing it automatically
@ -13428,7 +13486,7 @@ def PopupNonBlocking(*args, title=None, button_type=POPUP_BUTTONS_OK, button_col
:param title: Title to display in the window.
:type title: (str)
:param button_type: Determines which pre-defined buttons will be shown (Default value = POPUP_BUTTONS_OK).
:type button_type: (enum)
:type button_type: (int)
:param button_color: button color (foreground, background)
:type button_color: Tuple[str, str]
:param background_color: color of background
@ -13477,7 +13535,7 @@ def PopupQuick(*args, title=None, button_type=POPUP_BUTTONS_OK, button_color=Non
:param title: Title to display in the window.
:type title: (str)
:param button_type: Determines which pre-defined buttons will be shown (Default value = POPUP_BUTTONS_OK).
:type button_type: (enum)
:type button_type: (int)
:param button_color: button color (foreground, background)
:type button_color: Tuple[str, str]
:param background_color: color of background
@ -13525,7 +13583,7 @@ def PopupQuickMessage(*args, title=None, button_type=POPUP_BUTTONS_NO_BUTTONS, b
:param title: Title to display in the window.
:type title: (str)
:param button_type: Determines which pre-defined buttons will be shown (Default value = POPUP_BUTTONS_OK).
:type button_type: (enum)
:type button_type: (int)
:param button_color: button color (foreground, background)
:type button_color: Tuple[str, str]
:param background_color: color of background
@ -13571,7 +13629,7 @@ def PopupNoTitlebar(*args, title=None, button_type=POPUP_BUTTONS_OK, button_colo
:param title: Title to display in the window.
:type title: (str)
:param button_type: Determines which pre-defined buttons will be shown (Default value = POPUP_BUTTONS_OK).
:type button_type: (enum)
:type button_type: (int)
:param button_color: button color (foreground, background)
:type button_color: Tuple[str, str]
:param background_color: color of background
@ -13622,15 +13680,13 @@ def PopupAutoClose(*args, title=None, button_type=POPUP_BUTTONS_OK, button_color
:param title: Title to display in the window.
:type title: (str)
:param button_type: Determines which pre-defined buttons will be shown (Default value = POPUP_BUTTONS_OK).
:type button_type: (enum)
:type button_type: (int)
:param button_color: button color (foreground, background)
:type button_color: Tuple[str, str]
:param background_color: color of background
:type background_color: (str)
:param text_color: color of the text
:type text_color: (str)
:param auto_close: if True window will close itself
:type auto_close: (bool)
:param auto_close_duration: Older versions only accept int. Time in seconds until window will close
@ -14165,8 +14221,7 @@ def PopupGetText(message, title=None, default_text='', password_char='', size=(N
# --------------------------- PopupAnimated ---------------------------
def PopupAnimated(image_source, message=None, background_color=None, text_color=None, font=None, no_titlebar=True, grab_anywhere=True, keep_on_top=True, location=(None, None), alpha_channel=None,
time_between_frames=0, transparent_color=None):
def PopupAnimated(image_source, message=None, background_color=None, text_color=None, font=None, no_titlebar=True, grab_anywhere=True, keep_on_top=True, location=(None, None), alpha_channel=None, time_between_frames=0, transparent_color=None, title=''):
"""
Show animation one frame at a time. This function has its own internal clocking meaning you can call it at any frequency
and the rate the frames of video is shown remains constant. Maybe your frames update every 30 ms but your
@ -14197,6 +14252,8 @@ def PopupAnimated(image_source, message=None, background_color=None, text_color=
:type time_between_frames: (int)
:param transparent_color: This color will be completely see-through in your window. Can even click through
:type transparent_color: (str)
:param title: Title that will be shown on the window
:type title: (str)
"""
if image_source is None:
for image in Window._animated_popup_dict:
@ -14213,7 +14270,7 @@ def PopupAnimated(image_source, message=None, background_color=None, text_color=
if message:
layout.append([Text(message, background_color=background_color, text_color=text_color, font=font)])
window = Window('Animated GIF', layout, no_titlebar=no_titlebar, grab_anywhere=grab_anywhere,
window = Window(title, layout, no_titlebar=no_titlebar, grab_anywhere=grab_anywhere,
keep_on_top=keep_on_top, background_color=background_color, location=location,
alpha_channel=alpha_channel, element_padding=(0, 0), margins=(0, 0),
transparent_color=transparent_color, finalize=True, element_justification='c')
@ -15142,9 +15199,14 @@ def _upgrade_from_github():
def _upgrade_gui():
try:
cur_ver = version[:version.index('\n')]
except:
cur_ver = version
if popup_yes_no('* WARNING *',
'You are about to upgrade your PySimpleGUI package previously installed via pip to the latest version location on the GitHub server.',
'You are running verrsion {}'.format(version[:version.index('\n')]),
'You are running verrsion {}'.format(cur_ver),
'Are you sure you want to overwrite this release?', title='Are you sure you want to overwrite?',
keep_on_top=True) == 'Yes':
_upgrade_from_github()
@ -15162,7 +15224,11 @@ def main():
# theme('dark brown 2')
# theme('dark red')
# theme('Light Green 6')
ver = version[:version.index('\n')]
try:
ver = version[:version.index('\n')]
except:
ver = version
print('Starting up PySimpleGUI Test Harness\n', 'PySimpleGUI Version ', ver, '\ntcl ver = {}'.format(tkinter.TclVersion),
'tkinter version = {}'.format(tkinter.TkVersion), '\nPython Version {}'.format(sys.version))
@ -15237,7 +15303,7 @@ def main():
tab4 = Tab('Variable Choice', [[Frame('Variable Choice Group', frame4, title_color='blue')]], tooltip='tab 4', title_color='red')
layout1 = [
[Image(data=DEFAULT_BASE64_ICON), Image(data=DEFAULT_BASE64_LOADING_GIF, key='_IMAGE_'),
[Image(data=DEFAULT_BASE64_ICON, enable_events=True, key='-LOGO-'), Image(data=DEFAULT_BASE64_LOADING_GIF, enable_events=True, key='_IMAGE_'),
Text('You are running the PySimpleGUI.py file instead of importing it.\nAnd are thus seeing a test harness instead of your code', font='ANY 15',
tooltip='My tooltip', key='_TEXT1_')],
[Frame('Input Text Group', frame1, title_color='red')],
@ -15358,10 +15424,12 @@ theme(CURRENT_LOOK_AND_FEEL)
# -------------------------------- ENTRY POINT IF RUN STANDALONE -------------------------------- #
if __name__ == '__main__':
# To execute the upgrade from command line, type:
# python -m PySimpleGUI.PySimpleGUI upgrade
if len(sys.argv) > 1 and sys.argv[1] == 'upgrade':
_upgrade_gui()
exit(69)
exit(0)
main()
exit(69)
exit(0)

File diff suppressed because it is too large Load Diff

100
readme_creator/usage.py Normal file
View File

@ -0,0 +1,100 @@
from make_real_readme import main
########################################################################
# __ _ _ #
# / _(_) | | #
# __ __ ___ ___ _ __ | |_ _ __ _ | |__ ___ _ __ ___ #
# \ \ / / / __/ _ \| '_ \| _| |/ _` | | '_ \ / _ \ '__/ _ \ #
# \ V / | (_| (_) | | | | | | | (_| | | | | | __/ | | __/ #
# \_/ \___\___/|_| |_|_| |_|\__, | |_| |_|\___|_| \___| #
# __/ | #
# |___/ #
########################################################################
OUTPUT_FILENAME = 'readme.md'
##-#-#-# ##-#-#-#
# Pre-process logic
##-#-#-# ##-#-#-#
line_break = '<br>'
# line_break can be:
# - '<br>'
# - ' \n '
method = 'with logs'
# method can be:
# - 'simple, no log'
# - 'with logs'
##-#-#-# ##-#-#-#
# Post-process logic
##-#-#-# ##-#-#-#
enable_popup = True
insert_md_section_for__class_methods = False
remove_repeated_sections_classmethods = False
##############
# __ #
# /_ | #
# | | #
# | | #
# | | #
# |_| #
##############
if method == 'simple, no log':
main(logger=None,
insert_md_section_for__class_methods=insert_md_section_for__class_methods,
remove_repeated_sections_classmethods=remove_repeated_sections_classmethods,
files_to_include=[0, 1, 2, 3],
output_name=OUTPUT_FILENAME,
delete_html_comments=True)
################
# ___ #
# |__ \ #
# ) | #
# / / #
# / /_ #
# |____| #
################
if method == 'with logs':
import logging
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
my_file = logging.FileHandler('usage.log.txt', mode='w')
my_file.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(asctime)s>%(levelname)s: %(message)s')
my_file.setFormatter(formatter)
logger.addHandler(my_file)
logger.info('STARTING')
main(logger=logger,
insert_md_section_for__class_methods=insert_md_section_for__class_methods,
remove_repeated_sections_classmethods=remove_repeated_sections_classmethods,
files_to_include=[0, 1, 2, 3],
output_name=OUTPUT_FILENAME,
delete_html_comments=True)
########################################
# _____ #
# | __ \ #
# | |__) |__ _ __ _ _ _ __ #
# | ___/ _ \| '_ \| | | | '_ \ #
# | | | (_) | |_) | |_| | |_) | #
# |_| \___/| .__/ \__,_| .__/ #
# | | | | #
# |_| |_| #
########################################
if enable_popup:
import PySimpleGUI as sg
with open('usage.log.txt', 'r') as ff:
lines = ff.read()
sg.PopupScrolled('Completed making ' + OUTPUT_FILENAME, lines, size=(80,50))