Compare commits

...
Sign in to create a new pull request.

846 commits

Author SHA1 Message Date
PySimpleGUI
a0d3e7ce1f
Merge pull request #6613 from PySimpleGUI/Dev-latest
Ooops... forgot to update the Udemy coupon in the readme too.
2023-11-26 17:23:44 -05:00
PySimpleGUI
aae672824c Ooops... forgot to update the Udemy coupon in the readme too. 2023-11-26 17:23:25 -05:00
PySimpleGUI
117f40917d
Merge pull request #6611 from PySimpleGUI/Dev-latest
Bumped the version number (forgot to with the Udemy coupon)
2023-11-25 12:57:32 -05:00
PySimpleGUI
bf4630ec65 Bumped the version number (forgot to with the Udemy coupon) 2023-11-25 12:57:17 -05:00
PySimpleGUI
2bda3e1950
Merge pull request #6610 from PySimpleGUI/Dev-latest
New Udemy Coupon Code
2023-11-25 12:54:09 -05:00
PySimpleGUI
a2cd9fb702 New Udemy Coupon Code 2023-11-25 12:53:49 -05:00
PySimpleGUI
634eb9c652
Merge pull request #6609 from PySimpleGUI/Dev-latest
Make the multiple open demo program more useful
2023-11-23 14:28:46 -05:00
PySimpleGUI
05939b2725 Make the multiple open demo program more useful 2023-11-23 14:28:24 -05:00
PySimpleGUI
3f96ecf9ae Automated Update! 2023-11-19 18:30:26 +00:00
PySimpleGUI
148f548565
Merge pull request #6595 from PySimpleGUI/Dev-latest
Fixed docstring for execute_command_subprocess.  The command descript…
2023-11-13 13:15:38 -05:00
PySimpleGUI
e949083fda Fixed docstring for execute_command_subprocess. The command description was incorrect 2023-11-13 13:15:23 -05:00
PySimpleGUI
93358382b4 Automated Update! 2023-11-10 18:30:24 +00:00
PySimpleGUI
e59310d5fc Automated Update! 2023-11-07 18:30:22 +00:00
PySimpleGUI
2b8941fad9
Merge pull request #6579 from PySimpleGUI/Dev-latest
One more change to sizer so that it uses pad instead of size.
2023-10-29 13:23:31 -04:00
PySimpleGUI
cb39c58f98 One more change to sizer so that it uses pad instead of size. 2023-10-29 13:23:16 -04:00
PySimpleGUI
51f43ce318
Merge pull request #6578 from PySimpleGUI/Dev-latest
Added doctring and destroy previous right click menu to set_right_cli…
2023-10-29 13:11:11 -04:00
PySimpleGUI
85f3f472f7 Added doctring and destroy previous right click menu to set_right_click_menu AND Changed Sizer element to use Canvas instead of Column element 2023-10-29 13:10:57 -04:00
PySimpleGUI
e1f2d7f2d8
Merge pull request #6576 from PySimpleGUI/Dev-latest
New udemy coupon.
2023-10-27 12:13:37 -04:00
PySimpleGUI
bed18263e6 New udemy coupon. 2023-10-27 12:13:19 -04:00
PySimpleGUI
104cd14f35
Merge pull request #6575 from PySimpleGUI/Dev-latest
Update readthedocs.yml
2023-10-27 11:49:15 -04:00
PySimpleGUI
1ee5a7f9d2 Update readthedocs.yml 2023-10-27 11:49:01 -04:00
PySimpleGUI
6699f514a0
Merge pull request #6574 from PySimpleGUI/Dev-latest
New yaml file for readthedocs
2023-10-27 11:47:43 -04:00
PySimpleGUI
0f16031512 New yaml file for readthedocs 2023-10-27 11:47:21 -04:00
PySimpleGUI
cb324f35fc
Merge pull request #6573 from PySimpleGUI/Dev-latest
New Udemy Coupon Code
2023-10-27 11:37:19 -04:00
PySimpleGUI
f78e4913a2 New Udemy Coupon Code 2023-10-27 11:36:53 -04:00
PySimpleGUI
9b63e2e661 Automated Update! 2023-10-26 17:30:26 +00:00
PySimpleGUI
29127a73ee Automated Update! 2023-10-23 17:30:23 +00:00
PySimpleGUI
746b79d61a Automated Update! 2023-10-21 17:30:27 +00:00
PySimpleGUI
5131c537f5 Automated Update! 2023-10-20 17:30:27 +00:00
PySimpleGUI
79e9b6198e
Merge pull request #6554 from PySimpleGUI/Dev-latest
Fixed numpy deprecated problems.   Checking in improvement made long …
2023-10-16 08:58:12 -04:00
PySimpleGUI
fe31a0a7ed Fixed numpy deprecated problems. Checking in improvement made long ago buit forgot to check in 2023-10-16 08:57:47 -04:00
PySimpleGUI
57b72ba938
Merge pull request #6540 from PySimpleGUI/Dev-latest
Remove extra space accidently added (learned you can put spaces after…
2023-10-05 16:26:37 -04:00
PySimpleGUI
7f485c5f78 Remove extra space accidently added (learned you can put spaces after periods in Python?) 2023-10-05 16:26:20 -04:00
PySimpleGUI
03ed1948e2
Merge pull request #6539 from PySimpleGUI/Dev-latest
Replaced PIL's deprecated constant ANTIALIAS with LANCZOS
2023-10-05 16:12:38 -04:00
PySimpleGUI
3776730709 Replaced PIL's deprecated constant ANTIALIAS with LANCZOS 2023-10-05 16:11:51 -04:00
PySimpleGUI
77ba1eb26f
Merge pull request #6538 from PySimpleGUI/Dev-latest
Dev latest
2023-10-05 15:04:43 -04:00
PySimpleGUI
ddebd7a5c6 Added init for _mouse_offset_x and y in case tkinter doesn't call the mouse down callback 2023-10-05 15:03:52 -04:00
PySimpleGUI
5f8735d1f3 Fix for grab anywhere window movement and control+left_mouse_drag. Window move smoother, including the Move-All-Windows feature. Thank you JASON for the help! 2023-10-02 13:12:48 -04:00
PySimpleGUI
41e137e797
Merge pull request #6529 from PySimpleGUI/Dev-latest
New Udemy coupons... added earlier but forgot to post to GitHub
2023-10-02 09:52:25 -04:00
PySimpleGUI
2470d10afc New Udemy coupons... added earlier but forgot to post to GitHub 2023-10-02 09:52:10 -04:00
PySimpleGUI
dee0c81b58
Merge pull request #6512 from PySimpleGUI/Dev-latest
Dev latest
2023-09-21 16:10:57 -04:00
PySimpleGUI
4504ea77c3 New Udemy Coupon 2023-09-21 16:09:33 -04:00
PySimpleGUI
ce32fe3814 Automated Update! 2023-09-09 17:30:27 +00:00
PySimpleGUI
48c7b673c1 Automated Update! 2023-09-06 17:30:28 +00:00
PySimpleGUI
ed128a36f5 fixed bool instead of string in doctring 2023-08-31 12:24:21 -04:00
PySimpleGUI
ee972660c0
Merge pull request #6494 from PySimpleGUI/Dev-latest
Added  Added no_buffering option to popup_animated
2023-08-31 12:18:58 -04:00
PySimpleGUI
3907e7636e Added Added no_buffering option to popup_animated 2023-08-31 12:18:43 -04:00
PySimpleGUI
9cf9258835
Merge pull request #6488 from PySimpleGUI/Dev-latest
Made Table Element Header mouse-over and clicked be the inverse of th…
2023-08-28 07:09:54 -04:00
PySimpleGUI
0459adac69 Made Table Element Header mouse-over and clicked be the inverse of the normal header colors. Makes for a much nicer experience 2023-08-28 07:09:38 -04:00
PySimpleGUI
cf3345303d Automated Update! 2023-08-26 17:30:18 +00:00
PySimpleGUI
5761be84d8
Merge pull request #6484 from PySimpleGUI/Dev-latest
Rebuilt the call reference based on new set_index_color parms
2023-08-21 17:33:45 -04:00
PySimpleGUI
0b6eb6d5b3 Rebuilt the call reference based on new set_index_color parms 2023-08-21 17:33:27 -04:00
PySimpleGUI
4a5e2316e0
Merge pull request #6483 from PySimpleGUI/Dev-latest
Added highlight colors to the set_index_color method. Parms highlight…
2023-08-21 17:31:23 -04:00
PySimpleGUI
77ea65b8de Added highlight colors to the set_index_color method. Parms highlight_text_color & highlight_background_color control changing the highlight colors 2023-08-21 17:31:08 -04:00
PySimpleGUI
0f32107272
Merge pull request #6482 from PySimpleGUI/Dev-latest
New Udemy Coupon.  Added Listbox.set_index_color and Listbox.select_i…
2023-08-20 17:20:22 -04:00
PySimpleGUI
393050c1ae New Udemy Coupon. Added Listbox.set_index_color and Listbox.select_index to the SDK Call Reference 2023-08-20 17:20:05 -04:00
PySimpleGUI
31e8c51fba
Merge pull request #6481 from PySimpleGUI/Dev-latest
Added Listbox.select_index and Listbox.set_index_color
2023-08-19 11:53:22 -04:00
PySimpleGUI
2ece7d4ad5 Added Listbox.select_index and Listbox.set_index_color 2023-08-19 11:53:08 -04:00
PySimpleGUI
c34d28bcd4
Merge pull request #6480 from PySimpleGUI/Dev-latest
Fixed spelling errors... resuse should have been reuse
2023-08-16 09:35:14 -04:00
PySimpleGUI
1d3126f884 Fixed spelling errors... resuse should have been reuse 2023-08-16 09:34:58 -04:00
PySimpleGUI
81638809c8
Merge pull request #6478 from PySimpleGUI/Dev-latest
Fixed bug in Button.update.  Corrected when activeforeground and acti…
2023-08-14 12:22:29 -04:00
PySimpleGUI
c51d670956 Fixed bug in Button.update. Corrected when activeforeground and activebackground are set. Removing them in version above was a mistake 2023-08-14 12:22:12 -04:00
PySimpleGUI
db4fe52ec8
Merge pull request #6477 from PySimpleGUI/Dev-latest
Fixed bug in Button.update.  Was setting the activeforeground and act…
2023-08-13 11:47:30 -04:00
PySimpleGUI
f292d757de Fixed bug in Button.update. Was setting the activeforeground and activebackground which broke the mouseover or mouse press colors 2023-08-13 11:47:16 -04:00
PySimpleGUI
a39e180d13
Merge pull request #6473 from PySimpleGUI/Dev-latest
Allow window resizing when in single photo mode.  Updated the PIL res…
2023-08-10 12:45:21 -04:00
PySimpleGUI
854bdccdd3 Allow window resizing when in single photo mode. Updated the PIL resizing to much more recent resizing code. 2023-08-10 12:44:33 -04:00
PySimpleGUI
73a1b085ee
Merge pull request #6460 from PySimpleGUI/Dev-latest
Addition of black2 theme, Fix typo of text in _widget_was_created
2023-07-31 12:32:21 -04:00
PySimpleGUI
5035d24f2c Addition of black2 theme, Fix typo of text in _widget_was_created 2023-07-31 12:31:59 -04:00
PySimpleGUI
3c3312f5a2
Merge pull request #6444 from PySimpleGUI/Dev-latest
New tagline.  Updated call reference using newest docstrings
2023-07-12 17:21:12 -04:00
PySimpleGUI
aaf391508c New tagline. Updated call reference using newest docstrings 2023-07-12 17:20:56 -04:00
PySimpleGUI
76e4071239
Merge pull request #6436 from PySimpleGUI/Dev-latest
Changed Table click events to be generated on Button Release instead …
2023-07-04 08:50:24 -04:00
PySimpleGUI
2ce3c7f75e Changed Table click events to be generated on Button Release instead of Button (down) 2023-07-04 08:50:08 -04:00
PySimpleGUI
415f55c3a7
Merge pull request #6435 from PySimpleGUI/Dev-latest
Another try at correcting the Table.get docstring
2023-07-03 18:50:08 -04:00
PySimpleGUI
3de64e7d99 Another try at correcting the Table.get docstring 2023-07-03 18:49:55 -04:00
PySimpleGUI
e41be1c157
Merge pull request #6434 from PySimpleGUI/Dev-latest
Corrected the Table.get docstring to reflect that it returns a list o…
2023-07-03 18:47:20 -04:00
PySimpleGUI
d97777b262 Corrected the Table.get docstring to reflect that it returns a list of ints 2023-07-03 18:47:04 -04:00
PySimpleGUI
884d49a14f Automated Update! 2023-06-25 17:30:19 +00:00
PySimpleGUI
05d22968ae
Merge pull request #6425 from PySimpleGUI/Dev-latest
Changed Python GUIs for Humans to just GUIs for Humans
2023-06-23 10:36:20 -04:00
PySimpleGUI
891b0a5b36 Changed Python GUIs for Humans to just GUIs for Humans 2023-06-23 10:36:02 -04:00
PySimpleGUI
0fd1e011a1
Merge pull request #6421 from PySimpleGUI/Dev-latest
Fix for popup_get_file when using no_window=True. Now returns None if…
2023-06-19 11:23:16 -04:00
PySimpleGUI
130d5492f0 Fix for popup_get_file when using no_window=True. Now returns None if cancelled or window closed 2023-06-19 11:23:02 -04:00
PySimpleGUI
c11e950415
Merge pull request #6412 from PySimpleGUI/Dev-latest
New Udemy Coupon
2023-06-14 12:43:08 -04:00
PySimpleGUI
549330d0aa New Udemy Coupon 2023-06-14 12:42:47 -04:00
PySimpleGUI
654c2d2930
Merge pull request #6410 from PySimpleGUI/Dev-latest
Fix for crash when no headings specified for a table by casting value…
2023-06-13 17:42:34 -04:00
PySimpleGUI
8004b258a9 Fix for crash when no headings specified for a table by casting values into strings 2023-06-13 17:42:20 -04:00
PySimpleGUI
7f22061c3f
Merge pull request #6405 from PySimpleGUI/Dev-latest
Fix in pinning demo
2023-06-09 06:31:31 -04:00
PySimpleGUI
4a883851e6 Fix in pinning demo 2023-06-09 06:31:15 -04:00
PySimpleGUI
d3372dda27
Merge pull request #6397 from PySimpleGUI/Dev-latest
Fix for Combo.update background color changing incorrect widget setting.
2023-05-29 11:31:38 -04:00
PySimpleGUI
0ff0efa3c6 Fix for Combo.update background color changing incorrect widget setting. 2023-05-29 11:31:21 -04:00
PySimpleGUI
8b16f3183c
Merge pull request #6396 from PySimpleGUI/Dev-latest
Dev latest
2023-05-29 10:21:35 -04:00
PySimpleGUI
eeb95398e0 Added a function around the functional example 2023-05-29 10:21:17 -04:00
PySimpleGUI
b62648aa23 Expanded class wrapper demo to explain it's not a recommended design pattern. When initially released there was no explanation accompanying the code. 2023-05-29 10:19:32 -04:00
PySimpleGUI
79a3b85e73 Automated Update! 2023-05-25 17:30:21 +00:00
PySimpleGUI
e5d0c3d471 Automated Update! 2023-05-24 17:30:18 +00:00
PySimpleGUI
935285f715
Merge pull request #6384 from PySimpleGUI/Dev-latest
Dev latest
2023-05-21 19:39:33 -04:00
PySimpleGUI
955a7cba07 Additional of release notes for 4.60.5 dot release posted to PyPI 2023-05-21 19:39:16 -04:00
PySimpleGUI
e7b380ee7e Show Critical upgrade service messages. Removed the extra upgrade from github button from tab. 2023-05-21 19:38:07 -04:00
PySimpleGUI
ca66e38c99
Merge pull request #6383 from PySimpleGUI/Dev-latest
Only enable the Mac alpha channel 0.99 patch when tkinter version is …
2023-05-20 08:30:50 -04:00
PySimpleGUI
d368af0547 Only enable the Mac alpha channel 0.99 patch when tkinter version is 8.6.12. This will help 8.6.13 and later systems with window quality 2023-05-20 08:30:26 -04:00
PySimpleGUI
3952e1a438
Merge pull request #6382 from PySimpleGUI/Dev-latest
Addition of right click menu erase, save image and display of crosshairs
2023-05-18 12:05:22 -04:00
PySimpleGUI
440a34888f Addition of right click menu erase, save image and display of crosshairs 2023-05-18 12:05:07 -04:00
PySimpleGUI
003a03dfeb
Merge pull request #6380 from PySimpleGUI/Dev-latest
Added check for None and COLOR_SYSTEM_DEFAULT to fix a crash problem
2023-05-16 12:52:52 -04:00
PySimpleGUI
f3a7e10ce0 Added check for None and COLOR_SYSTEM_DEFAULT to fix a crash problem 2023-05-16 12:52:36 -04:00
PySimpleGUI
db1f02af2f
Merge pull request #6377 from PySimpleGUI/Dev-latest
Dev latest
2023-05-14 12:22:52 -04:00
PySimpleGUI
fe41f3cd1f New Udemy Coupon 2023-05-14 12:22:32 -04:00
PySimpleGUI
d7c24da2bf Automated Update! 2023-05-12 17:30:17 +00:00
PySimpleGUI
2e6b74f0f1 Input element - fix for bug with text color & logic wasn't quite right with the "read for disabled" stuff in the update as well as when making window 2023-05-11 15:37:47 -04:00
PySimpleGUI
74098a440b
Merge pull request #6370 from PySimpleGUI/Dev-latest
Custom Titlebar - Support for disable close, disable resizing, disabl…
2023-05-09 09:21:30 -04:00
PySimpleGUI
43c49380a2 Custom Titlebar - Support for disable close, disable resizing, disable minimize. Better distro support and display of information from Upgrade Service 2023-05-09 09:21:12 -04:00
PySimpleGUI
def60b9ba8
Merge pull request #6356 from PySimpleGUI/Dev-latest
Added formatted_datetime_now function for easy formatting current dat…
2023-04-26 16:29:39 -04:00
PySimpleGUI
7cf4c102fe Added formatted_datetime_now function for easy formatting current date and time. Added code for Intelligent Upgrade Service but not enabling any popups while testing. Added timer_stop_usec that returns timer value in microseconds. 2023-04-26 16:29:09 -04:00
PySimpleGUI
ee794099bf
Merge pull request #6354 from PySimpleGUI/Dev-latest
Changed enter_submits to True so that the bind_return_key works corre…
2023-04-26 09:47:28 -04:00
PySimpleGUI
cb0da5887d Changed enter_submits to True so that the bind_return_key works correctly. 2023-04-26 09:47:14 -04:00
PySimpleGUI
fe7fbcbc44
Merge pull request #6350 from PySimpleGUI/Dev-latest
Moved update animation call to after check for window closed. Was get…
2023-04-22 10:13:50 -04:00
PySimpleGUI
fb5fdbdd5c Moved update animation call to after check for window closed. Was getting an error because attempt to update animation was happening after window was closed 2023-04-22 10:13:36 -04:00
PySimpleGUI
041c5ba4e6
Merge pull request #6348 from PySimpleGUI/Dev-latest
Fix for Input Elements unresponsive on MacOS 13.2.1 Ventura when no-t…
2023-04-21 18:25:25 -04:00
PySimpleGUI
71c50d40b4 Fix for Input Elements unresponsive on MacOS 13.2.1 Ventura when no-titlebar is enabled 2023-04-21 18:25:09 -04:00
PySimpleGUI
5efbff1cb8 Automated Update! 2023-04-21 17:30:19 +00:00
PySimpleGUI
a78498fcca
Merge pull request #6347 from PySimpleGUI/Dev-latest
Window threading changed so that end_key is now optional.  BE CAREFUL…
2023-04-21 07:00:12 -04:00
PySimpleGUI
f06fcdc0a6 Window threading changed so that end_key is now optional. BE CAREFUL when leaving it out as you won't be backward compatible. 2023-04-21 06:59:52 -04:00
PySimpleGUI
982cb755ba Automated Update! 2023-04-20 17:30:22 +00:00
PySimpleGUI
8b4e19a0cd Automated Update! 2023-04-19 17:30:25 +00:00
PySimpleGUI
8729971855
Update issue-form---must-fill-in-this-form-with-every-new-issue-submitted.md 2023-04-18 06:27:38 -04:00
PySimpleGUI
cdba184ed8
Merge pull request #6339 from PySimpleGUI/Dev-latest
Changed Radio activeforeground to be same as text color so mouseover …
2023-04-18 03:58:29 -04:00
PySimpleGUI
ad3465d9ba Changed Radio activeforeground to be same as text color so mouseover won't change color (previously did this for the Checkbox element) 2023-04-18 03:58:16 -04:00
PySimpleGUI
0bcd49a1b7
Merge pull request #6330 from PySimpleGUI/Dev-latest
Dev latest
2023-04-11 07:24:10 -04:00
PySimpleGUI
f1cd369302 New Udemy Coupon. Fix for bug in and better info in Watermark 2023-04-11 07:23:53 -04:00
PySimpleGUI
ad76b5deeb New Udemy Coupon 2023-04-11 07:22:47 -04:00
PySimpleGUI
635baca3cd Automated Update! 2023-03-27 17:30:35 +00:00
PySimpleGUI
74c1f7b337 Automated Update! 2023-03-25 17:30:34 +00:00
PySimpleGUI
5052aece6a Automated Update! 2023-03-17 17:30:25 +00:00
PySimpleGUI
4fe61e42d2 Automated Update! 2023-03-16 17:30:23 +00:00
PySimpleGUI
5b784253f5 Automated Update! 2023-03-15 17:30:30 +00:00
PySimpleGUI
15e56bd47d
Merge pull request #6303 from PySimpleGUI/Dev-latest
Fixed typo in coupon at top of SDK reference.  Picked up the changes …
2023-03-13 06:32:43 -04:00
PySimpleGUI
f97de3468b Fixed typo in coupon at top of SDK reference. Picked up the changes for GitHub's readme. 2023-03-13 06:32:31 -04:00
PySimpleGUI
e902230468
Merge pull request #6302 from PySimpleGUI/Dev-latest
Dev latest
2023-03-13 06:17:53 -04:00
PySimpleGUI
d8d5227240 New Udemy Coupon added 2023-03-13 06:17:36 -04:00
PySimpleGUI
2eed0afaeb New SDK call ref with net set_ibeam_color method added. New Udemy Coupon added to docs 2023-03-13 06:16:07 -04:00
PySimpleGUI
a10d9d3430
Merge pull request #6301 from PySimpleGUI/Dev-latest
Applied the Input I-Beam color fix to Multiline and Spin elements.  A…
2023-03-13 05:55:15 -04:00
PySimpleGUI
07f772c680 Applied the Input I-Beam color fix to Multiline and Spin elements. Added new method set_ibeam_color as another way to set this color (in addition to set_cursor) so that it's more explicit 2023-03-13 05:54:59 -04:00
PySimpleGUI
fcd03f4b6f
Merge pull request #6298 from PySimpleGUI/Dev-latest
Fixed problem where the insert cursor (I-beam) was being set to the t…
2023-03-12 08:39:29 -04:00
PySimpleGUI
a22884e2e3 Fixed problem where the insert cursor (I-beam) was being set to the theme's color not the color indicated by the individual Input element. 2023-03-12 08:39:17 -04:00
PySimpleGUI
d72a7672c1
Merge pull request #6287 from PySimpleGUI/Dev-latest
Added nightlight thickness parm to Checkbox so focus ring thickness c…
2023-03-09 05:49:58 -05:00
PySimpleGUI
3507b2708b Added nightlight thickness parm to Checkbox so focus ring thickness can be controlled when creating element 2023-03-09 05:49:42 -05:00
PySimpleGUI
cd7967fe4a
Merge pull request #6286 from PySimpleGUI/Dev-latest
Combo.update - added text and background color. Also made font parm w…
2023-03-09 05:43:37 -05:00
PySimpleGUI
4d02f3a515 Combo.update - added text and background color. Also made font parm work correctly with the dropdown list. (TRICKY!) 2023-03-09 05:43:20 -05:00
PySimpleGUI
3e0ade9797
Merge pull request #6285 from PySimpleGUI/Dev-latest
Demo Program to show new Watermark features
2023-03-07 20:14:23 -05:00
PySimpleGUI
3b7a17f6b6 Demo Program to show new Watermark features 2023-03-07 20:14:08 -05:00
PySimpleGUI
27e073b03c
Merge pull request #6279 from PySimpleGUI/Dev-latest
Fixed Mac crash due to "Bold" font modifier in watermark feature
2023-03-06 14:21:22 -05:00
PySimpleGUI
d447633ec3 Fixed Mac crash due to "Bold" font modifier in watermark feature 2023-03-06 14:21:06 -05:00
PySimpleGUI
15af7b7d06
Merge pull request #6277 from PySimpleGUI/Dev-latest
New Global Settings Feature - Window watermarking.... Use global sett…
2023-03-06 09:01:35 -05:00
PySimpleGUI
c24d8b6b87 New Global Settings Feature - Window watermarking.... Use global settings window to control or force on/off when making a window. 2023-03-06 09:00:57 -05:00
PySimpleGUI
f0eab8c1bd
Merge pull request #6268 from PySimpleGUI/Dev-latest
Changed Checkbox to not change color on mouseover on Linux.  Added th…
2023-03-01 12:11:59 -05:00
PySimpleGUI
8bd030f1a1 Changed Checkbox to not change color on mouseover on Linux. Added the optional window data row for internal texting ONLY 2023-03-01 12:10:23 -05:00
PySimpleGUI
34b935a196
Merge pull request #6266 from PySimpleGUI/Dev-latest
New Demo Program - CPU Utilization shown on a very nice VU Meter Graphic
2023-02-28 06:28:15 -05:00
PySimpleGUI
efa236369f New Demo Program - CPU Utilization shown on a very nice VU Meter Graphic 2023-02-28 06:27:57 -05:00
PySimpleGUI
af9794b2c2
Merge pull request #6261 from PySimpleGUI/Dev-latest
New Demo Program - Table with checkmarks
2023-02-25 13:21:39 -05:00
PySimpleGUI
8e6fa8100a New Demo Program - Table with checkmarks 2023-02-25 13:21:26 -05:00
PySimpleGUI
4a5f2d2907
Merge pull request #6258 from PySimpleGUI/Dev-latest
Dev latest
2023-02-24 08:58:55 -05:00
PySimpleGUI
8f74aa5c8d Picking up the latest Multiline & Output element feature that's on GitHub - new parameter autoscroll_only_at_bottom 2023-02-24 08:58:41 -05:00
PySimpleGUI
ba0e5fed78 Addition of Timer API calls 2023-02-24 08:58:02 -05:00
PySimpleGUI
3275279f9c Addition of Timer API Calls 2023-02-24 08:57:48 -05:00
PySimpleGUI
0cf29cc20f Addition of Timer API Calls section 2023-02-24 08:57:26 -05:00
PySimpleGUI
fdbdd18120
Merge pull request #6257 from PySimpleGUI/Dev-latest
Added autoscroll_only_at_bottom to Output element too
2023-02-24 04:51:39 -05:00
PySimpleGUI
73c692ebcc Added autoscroll_only_at_bottom to Output element too 2023-02-24 04:51:25 -05:00
PySimpleGUI
5ae9d3c88a
Merge pull request #6256 from PySimpleGUI/Dev-latest
Added autoscroll_only_at_bottom parameter to Multiline element
2023-02-24 04:37:50 -05:00
PySimpleGUI
ad67fe233e Added autoscroll_only_at_bottom parameter to Multiline element 2023-02-24 04:37:37 -05:00
PySimpleGUI
83bdad20f8
Merge pull request #6252 from PySimpleGUI/Dev-latest
Picked up docstring changes for Window.timer_start in the call reference
2023-02-23 12:01:45 -05:00
PySimpleGUI
1ae844e7fc Picked up docstring changes for Window.timer_start in the call reference 2023-02-23 12:01:31 -05:00
PySimpleGUI
2de8770897
Merge pull request #6251 from PySimpleGUI/Dev-latest
Added the variable name constants EVENT_TIMER and TIMER_KEY  to the W…
2023-02-23 12:00:41 -05:00
PySimpleGUI
2cc5b70aed Added the variable name constants EVENT_TIMER and TIMER_KEY to the Window.start_timer docstring 2023-02-23 12:00:25 -05:00
PySimpleGUI
2a4831ac63
Merge pull request #6250 from PySimpleGUI/Dev-latest
Changed Output Element in call reference.  Previously was steering us…
2023-02-23 11:56:35 -05:00
PySimpleGUI
86afe5ae57 Changed Output Element in call reference. Previously was steering users away from Output Element and to use Multiline instead. Now that the Output element is based directly on Multiline, this recommendation is no longer needed. 2023-02-23 11:56:20 -05:00
PySimpleGUI
6b9cb23b6d
Merge pull request #6249 from PySimpleGUI/Dev-latest
Addition of  the Window Timer API Calls currently on GitHub
2023-02-23 11:52:08 -05:00
PySimpleGUI
c4e37eff04 Addition of the Window Timer API Calls currently on GitHub 2023-02-23 11:51:55 -05:00
PySimpleGUI
62eb1f5781
Merge pull request #6245 from PySimpleGUI/Dev-latest
Ooops... forgot to bump version number
2023-02-21 11:59:12 -05:00
PySimpleGUI
98f383bffb Ooops... forgot to bump version number 2023-02-21 11:58:59 -05:00
PySimpleGUI
25ed11c581
Merge pull request #6244 from PySimpleGUI/Dev-latest
Changed layout error message (added "sometimes" to description))
2023-02-21 11:46:45 -05:00
PySimpleGUI
57528fdb5c Changed layout error message (added "sometimes" to description)) 2023-02-21 11:46:31 -05:00
PySimpleGUI
6aabac7637
Merge pull request #6242 from PySimpleGUI/Dev-latest
changed TabGroup.get to use the same method as the values dictionary …
2023-02-19 14:58:04 -05:00
PySimpleGUI
c8da36c9e3 changed TabGroup.get to use the same method as the values dictionary does that was just added in prior check-in 2023-02-19 14:57:49 -05:00
PySimpleGUI
3a7d72354a
Merge pull request #6241 from PySimpleGUI/Dev-latest
Fixed problem with TabGroup not identifying the currently active tab …
2023-02-19 14:05:10 -05:00
PySimpleGUI
f07d658e87 Fixed problem with TabGroup not identifying the currently active tab in the Values Dictionary is the label is blank on the Tab 2023-02-19 14:04:56 -05:00
PySimpleGUI
c88bd1f2ec Automated Update! 2023-02-14 18:30:24 +00:00
PySimpleGUI
a3936a60a9
Merge pull request #6231 from PySimpleGUI/Dev-latest
Tree Element - new parameter click_toggles_select
2023-02-13 18:00:34 -05:00
PySimpleGUI
83745112a6 Tree Element - new parameter click_toggles_select 2023-02-13 18:00:20 -05:00
PySimpleGUI
c963e86d3e Automated Update! 2023-02-12 18:30:19 +00:00
PySimpleGUI
8f76e053f0
Merge pull request #6225 from PySimpleGUI/Dev-latest
Removed second print on Mac for Alpha 0.99 patch
2023-02-12 11:52:47 -05:00
PySimpleGUI
282559db46 Removed second print on Mac for Alpha 0.99 patch 2023-02-12 11:52:33 -05:00
PySimpleGUI
185d0997bb
Merge pull request #6224 from PySimpleGUI/Dev-latest
Removed print when Mac Alpha Channel of 0.99 is applied.  Was acciden…
2023-02-11 13:59:09 -05:00
PySimpleGUI
a138621f9a Removed print when Mac Alpha Channel of 0.99 is applied. Was accidently let in for testing. 2023-02-11 13:58:57 -05:00
PySimpleGUI
e34564fb38
Merge pull request #6223 from PySimpleGUI/Dev-latest
Added a lambda example
2023-02-11 09:09:02 -05:00
PySimpleGUI
a059d92c8e Added a lambda example 2023-02-11 09:08:50 -05:00
PySimpleGUI
e3211b18ab
Merge pull request #6216 from PySimpleGUI/Dev-latest
New coupon added to call reference.  Forgot it needed changing too.  …
2023-02-07 19:14:48 -05:00
PySimpleGUI
dc84814eb2 New coupon added to call reference. Forgot it needed changing too. The rest of the docs seem to pick up the new coupon ok now. 2023-02-07 19:14:36 -05:00
PySimpleGUI
199901cc4c
Merge pull request #6214 from PySimpleGUI/Dev-latest
Dev latest
2023-02-07 18:33:00 -05:00
PySimpleGUI
800decc53f Update PySimpleGUI.py 2023-02-07 18:32:44 -05:00
PySimpleGUI
e047ffe684 New Udemy Coupon Code 2023-02-07 18:32:38 -05:00
PySimpleGUI
83bb20ff3d
Merge pull request #6212 from PySimpleGUI/Dev-latest
New Demo Program Custom Images Dark Theme
2023-02-07 11:37:18 -05:00
PySimpleGUI
517262690f New Demo Program Custom Images Dark Theme 2023-02-07 11:37:05 -05:00
PySimpleGUI
d84cd10c04
Merge pull request #6211 from PySimpleGUI/Dev-latest
And updated version of the "Edit Me" right menu design pattern
2023-02-07 07:17:24 -05:00
PySimpleGUI
f3270e00ec And updated version of the "Edit Me" right menu design pattern 2023-02-07 07:17:07 -05:00
PySimpleGUI
336d3baeb9
Merge pull request #6209 from PySimpleGUI/Dev-latest
Fixed typo in docstring
2023-02-06 11:44:07 -05:00
PySimpleGUI
7da029ebf8 Fixed typo in docstring 2023-02-06 11:43:54 -05:00
PySimpleGUI
85e11e88b7
Merge pull request #6205 from PySimpleGUI/Dev-latest
Hacked the version numbering (again... sorry!) to try to mediate the …
2023-02-05 06:30:26 -05:00
PySimpleGUI
078fc3b1d4 Hacked the version numbering (again... sorry!) to try to mediate the confusion about what's posted to PyPI. 2023-02-05 06:16:23 -05:00
PySimpleGUI
71d1c850f8
Merge pull request #6203 from PySimpleGUI/Dev-latest
New Demo Program - automatically save and load Input element values u…
2023-02-04 17:45:43 -05:00
PySimpleGUI
e764cc07b8 New Demo Program - automatically save and load Input element values using User Settings API 2023-02-04 17:45:33 -05:00
PySimpleGUI
2af2d59c4d Automated Update! 2023-01-30 18:30:24 +00:00
PySimpleGUI
16aea9c37f Automated Update! 2023-01-29 18:30:26 +00:00
PySimpleGUI
5b0f6950a3 Automated Update! 2023-01-28 18:30:26 +00:00
PySimpleGUI
81abea7164
Merge pull request #6190 from PySimpleGUI/Dev-latest
Error handling  for when no editor has been configured
2023-01-25 07:58:05 -05:00
PySimpleGUI
de383504e0 Error handling for when no editor has been configured 2023-01-25 07:57:50 -05:00
PySimpleGUI
2d9a91911b
Merge pull request #6183 from PySimpleGUI/Dev-latest
Get the latest doctrings and post to the online documentation in the …
2023-01-22 10:24:11 -05:00
PySimpleGUI
cef6e8e0cd Get the latest doctrings and post to the online documentation in the call reference 2023-01-22 10:23:55 -05:00
PySimpleGUI
58e2e936a3
Merge pull request #6182 from PySimpleGUI/Dev-latest
Fixed bind_return_key docstrings in the pre-defined buttons. Made the…
2023-01-22 10:12:05 -05:00
PySimpleGUI
de3beca51a Fixed bind_return_key docstrings in the pre-defined buttons. Made the Button bind_return_key docstring more descriptive 2023-01-22 10:11:51 -05:00
PySimpleGUI
84024bc302
Merge pull request #6180 from PySimpleGUI/Dev-latest
Added selected_text_color and selected_background_color to Multline e…
2023-01-21 15:09:00 -05:00
PySimpleGUI
2492b2353d Added selected_text_color and selected_background_color to Multline element 2023-01-21 15:08:45 -05:00
PySimpleGUI
6762f9c395
Merge pull request #6178 from PySimpleGUI/Dev-latest
Fixed bug in Combo.update - width wasn't getting updated to match new…
2023-01-20 17:55:06 -05:00
PySimpleGUI
7e88e04cee Fixed bug in Combo.update - width wasn't getting updated to match new values 2023-01-20 17:54:50 -05:00
PySimpleGUI
0e9442353c
Merge pull request #6172 from PySimpleGUI/Dev-latest
Added selected_text_color & selected_background_color to Input elemen…
2023-01-18 14:14:05 -05:00
PySimpleGUI
59cbf63116 Added selected_text_color & selected_background_color to Input element as an experiment 2023-01-18 14:13:43 -05:00
PySimpleGUI
ed8d867e76
Merge pull request #6169 from PySimpleGUI/Dev-latest
Made the Debugger's use of popups change the theme to the same dark g…
2023-01-15 10:39:45 -05:00
PySimpleGUI
4ca5cf084a Made the Debugger's use of popups change the theme to the same dark gray theme used in the rest of the debugger windows. Fixed bug introduced when constants were moved into the class. 2023-01-15 10:39:30 -05:00
PySimpleGUI
edbc55262b
Merge pull request #6167 from PySimpleGUI/Dev-latest
Get the latest docstrings from PySimpleGUI on github so that the SDK …
2023-01-13 14:30:47 -05:00
PySimpleGUI
805727fed9 Get the latest docstrings from PySimpleGUI on github so that the SDK docs online match. 2023-01-13 14:30:33 -05:00
PySimpleGUI
8effae33f4
Merge pull request #6166 from PySimpleGUI/Dev-latest
Experimental change to Table.get.  Using the tkinter widget's selecti…
2023-01-13 12:02:09 -05:00
PySimpleGUI
6a64f8cfd2 Experimental change to Table.get. Using the tkinter widget's selection method. Looks like it could work. 2023-01-13 12:01:52 -05:00
PySimpleGUI
6b20da8c59
Merge pull request #6164 from PySimpleGUI/Dev-latest
Moved debugger constants to sinde of the debugger class. Simplified t…
2023-01-12 21:06:44 -05:00
PySimpleGUI
529c285489 Moved debugger constants to sinde of the debugger class. Simplified the locals and globals popups. 2023-01-12 21:06:16 -05:00
PySimpleGUI
ad78b3b1ac
Merge pull request #6162 from PySimpleGUI/Dev-latest
Added begin_at_sunday_plus to the docstring for CalendarButton
2023-01-12 13:37:56 -05:00
PySimpleGUI
81c16c6b5f Added begin_at_sunday_plus to the docstring for CalendarButton 2023-01-12 13:37:32 -05:00
PySimpleGUI
d03347d39c
Merge pull request #6161 from PySimpleGUI/Dev-latest
Disables "Take me to error" button if no editor is configured
2023-01-12 06:23:48 -05:00
PySimpleGUI
b216a25480 Disables "Take me to error" button if no editor is configured 2023-01-12 06:23:28 -05:00
PySimpleGUI
81127fae93
Merge pull request #6160 from PySimpleGUI/Dev-latest
Tree element - if no headings are specified (set to None) then the he…
2023-01-12 06:11:26 -05:00
PySimpleGUI
d0c558f5c8 Tree element - if no headings are specified (set to None) then the header will not be added 2023-01-12 06:11:05 -05:00
PySimpleGUI
73fa593c25
Merge pull request #6153 from PySimpleGUI/Dev-latest
Demo Program - Time Chooser (ONE more time!)
2023-01-06 16:12:54 -05:00
PySimpleGUI
d9e42ed2e7 Demo Program - Time Chooser (ONE more time!) 2023-01-06 16:12:40 -05:00
PySimpleGUI
ca0e825e88
Merge pull request #6152 from PySimpleGUI/Dev-latest
Delete Demo_Time_Chooser.py
2023-01-06 16:11:55 -05:00
PySimpleGUI
2821880b3c
Delete Demo_Time_Chooser.py 2023-01-06 16:11:28 -05:00
PySimpleGUI
3ca7703fcd
Merge pull request #6151 from PySimpleGUI/Dev-latest
Dev latest
2023-01-06 16:09:59 -05:00
PySimpleGUI
c8d01725f1 Demo Program - Time Chooser 2023-01-06 16:09:39 -05:00
PySimpleGUI
7fdee8f91b
Delete Demo_Time_Chooser.py 2023-01-06 16:08:54 -05:00
PySimpleGUI
268686635f
Merge pull request #6150 from PySimpleGUI/Dev-latest
Dev latest
2023-01-06 16:04:51 -05:00
PySimpleGUI
0c77b57659 Demo Program - Time chooser 2023-01-06 16:04:33 -05:00
PySimpleGUI
a309549dbb
Merge pull request #6149 from PySimpleGUI/revert-6146-Dev-latest
Revert "Demo program of an example window to choose a time"
2023-01-06 16:03:42 -05:00
PySimpleGUI
54d6d68a03
Revert "Demo program of an example window to choose a time" 2023-01-06 16:03:34 -05:00
PySimpleGUI
54d8f698d7
Merge pull request #6148 from PySimpleGUI/revert-6147-Dev-latest
Revert "Added option to enable/disable manual entry"
2023-01-06 16:03:16 -05:00
PySimpleGUI
79b6b74f78
Revert "Added option to enable/disable manual entry" 2023-01-06 16:03:05 -05:00
PySimpleGUI
02f3ae25be Revert "Demo program of an example window to choose a time"
This reverts commit 86976f50c3.
2023-01-06 16:02:08 -05:00
PySimpleGUI
c3a6db921f Revert "Added option to enable/disable manual entry"
This reverts commit 73a6629045.
2023-01-06 16:01:52 -05:00
MikeTheWatchGuy
cc08622d06
Merge pull request #6147 from PySimpleGUI/Dev-latest
Added option to enable/disable manual entry
2023-01-06 15:54:02 -05:00
PySimpleGUI
73a6629045 Added option to enable/disable manual entry 2023-01-06 15:53:48 -05:00
MikeTheWatchGuy
5f312f3ae9
Merge pull request #6146 from PySimpleGUI/Dev-latest
Demo program of an example window to choose a time
2023-01-06 15:49:32 -05:00
PySimpleGUI
86976f50c3 Demo program of an example window to choose a time 2023-01-06 15:49:00 -05:00
PySimpleGUI
a964716404
Merge pull request #6145 from PySimpleGUI/Dev-latest
Renamed QuickMeter to _QuickMeter so users will not be confused in th…
2023-01-06 12:51:44 -05:00
PySimpleGUI
ca26ac8f37 Renamed QuickMeter to _QuickMeter so users will not be confused in thinking it's meant to used directly. 2023-01-06 12:51:27 -05:00
PySimpleGUI
62fec93502 Automated Update! 2023-01-05 18:30:30 +00:00
PySimpleGUI
b6aa5b5406
Merge pull request #6135 from PySimpleGUI/Dev-latest
Make the Image element expand so that the buttons will not jump aroun…
2023-01-03 14:17:16 -05:00
PySimpleGUI
92d77a5ba8 Make the Image element expand so that the buttons will not jump around as much. 2023-01-03 14:16:52 -05:00
PySimpleGUI
ee54470f9a
Merge pull request #6128 from PySimpleGUI/Dev-latest
popup_get_date - exposed the fonts as parameters to help with a Mac f…
2022-12-29 06:47:30 -05:00
PySimpleGUI
9a55191b08 popup_get_date - exposed the fonts as parameters to help with a Mac font bug 2022-12-29 06:47:13 -05:00
PySimpleGUI
0782708507
Merge pull request #6126 from PySimpleGUI/Dev-latest
Addition of Window.timer_get_active_timers to get a list of the curre…
2022-12-28 10:08:08 -05:00
PySimpleGUI
4180f59c4c Addition of Window.timer_get_active_timers to get a list of the currently active timers for a window. Added to the demo program. 2022-12-28 10:07:53 -05:00
PySimpleGUI
493530dc14
Merge pull request #6124 from PySimpleGUI/Dev-latest
New Demo Program using new Window.timer_stop and Window.timer_stop
2022-12-27 07:32:43 -05:00
PySimpleGUI
747ff76d08 New Demo Program using new Window.timer_stop and Window.timer_stop 2022-12-27 07:32:30 -05:00
PySimpleGUI
8c30a5fd72
Merge pull request #6121 from PySimpleGUI/Dev-latest
Added Window.timer_stop_all method
2022-12-25 12:17:22 -05:00
PySimpleGUI
560ab62e88 Added Window.timer_stop_all method 2022-12-25 12:17:07 -05:00
PySimpleGUI
7bdabeb998
Merge pull request #6120 from PySimpleGUI/Dev-latest
Window Timer Feature and Demo Program
2022-12-25 11:32:08 -05:00
PySimpleGUI
cf27988cbb Window Timer Feature and Demo Program 2022-12-25 11:31:50 -05:00
PySimpleGUI
8357653c81
Merge pull request #6117 from PySimpleGUI/Dev-latest
New Demo Program - generate periodic timer events
2022-12-23 08:45:20 -05:00
PySimpleGUI
6e4be7bb60 New Demo Program - generate periodic timer events 2022-12-23 08:45:01 -05:00
PySimpleGUI
de58236c7a
Merge pull request #6116 from PySimpleGUI/Dev-latest
New Udemy coupon
2022-12-23 03:12:28 -05:00
PySimpleGUI
e7a6465a08 New Udemy coupon 2022-12-23 03:12:11 -05:00
PySimpleGUI
05d9773737
Merge pull request #6113 from PySimpleGUI/Dev-latest
Added button_color parm to ButtonMenu.update
2022-12-21 12:08:12 -05:00
PySimpleGUI
051a0a1952 Added button_color parm to ButtonMenu.update 2022-12-21 12:07:55 -05:00
PySimpleGUI
d39a13d355
Merge pull request #6110 from PySimpleGUI/Dev-latest
Simplified the multithreaded demo and introduced the tuple key design…
2022-12-19 16:56:12 -05:00
PySimpleGUI
9d0041a73b Simplified the multithreaded demo and introduced the tuple key design pattern for threading 2022-12-19 16:55:58 -05:00
PySimpleGUI
20edf9f858 Automated Update! 2022-12-19 18:30:27 +00:00
PySimpleGUI
8af1193f0c
Merge pull request #6106 from PySimpleGUI/Dev-latest
Cleaned up user settings api code for porting
2022-12-17 13:47:06 -05:00
PySimpleGUI
b3a5e6dfbf Cleaned up user settings api code for porting 2022-12-17 13:46:53 -05:00
PySimpleGUI
3c3fc1f7ac
Merge pull request #6102 from PySimpleGUI/Dev-latest
User serttings - Deletion of entry added a silent-on-error option.  p…
2022-12-15 08:24:51 -05:00
PySimpleGUI
5711c9f9de User serttings - Deletion of entry added a silent-on-error option. popup_quick_message - changed default keep_on_top to True 2022-12-15 08:24:35 -05:00
PySimpleGUI
18a044f162
Merge pull request #6100 from PySimpleGUI/Dev-latest
Addition of right click menu and set size of combo boxes to be 30 ent…
2022-12-14 08:50:07 -05:00
PySimpleGUI
eef70d2aaf Addition of right click menu and set size of combo boxes to be 30 entries long. 2022-12-14 08:49:53 -05:00
PySimpleGUI
3b258ba639
Merge pull request #6098 from PySimpleGUI/Dev-latest
Made button_color parameter docstring consistent across all calls - (…
2022-12-13 15:04:59 -05:00
PySimpleGUI
9d1e4a8c93 Made button_color parameter docstring consistent across all calls - (str, str) | str 2022-12-13 15:04:43 -05:00
PySimpleGUI
99fd18335e
Merge pull request #6093 from PySimpleGUI/Dev-latest
2 new options for find_element method
2022-12-12 16:10:47 -05:00
PySimpleGUI
17f8d76a60 2 new options for find_element method 2022-12-12 16:10:32 -05:00
PySimpleGUI
8b61ab6f11
Merge pull request #6087 from PySimpleGUI/Dev-latest
Fixed menu definition (Help should have had a list like the other ent…
2022-12-10 16:29:43 -05:00
PySimpleGUI
5accdda30f Fixed menu definition (Help should have had a list like the other entries). Added key to the menu, etc. It's been a long time since updated. 2022-12-10 16:29:28 -05:00
PySimpleGUI
1c4574908b
Merge pull request #6085 from PySimpleGUI/Dev-latest
Added zoom and subsample parms to PIL function (was recently supplied…
2022-12-07 10:07:16 -05:00
PySimpleGUI
70085de109 Added zoom and subsample parms to PIL function (was recently supplied in an issue as a way to simulate the subsample parm found in tkinter port) 2022-12-07 10:07:01 -05:00
PySimpleGUI
27566df25a
Merge pull request #6077 from PySimpleGUI/Dev-latest
Fixed Multiline Element docstrings
2022-12-04 12:30:45 -05:00
PySimpleGUI
e2083920ee Fixed Multiline Element docstrings 2022-12-04 12:30:30 -05:00
PySimpleGUI
d117aabecd
Merge pull request #6073 from PySimpleGUI/Dev-latest
Dev latest
2022-12-01 13:50:35 -05:00
PySimpleGUI
f8f05796aa Typo in rtype was tripping up PyCharm (had a space in the middle of the class name) 2022-12-01 13:50:15 -05:00
PySimpleGUI
d7b16be284 Removed the Base64 encode as it's not required. The raw image data can be passed directly to the Image Element 2022-12-01 13:49:33 -05:00
PySimpleGUI
98140066fc
Merge pull request #6067 from PySimpleGUI/Dev-latest
New Demo Program - Display an image located at URL online (thanks to …
2022-11-30 08:46:55 -05:00
PySimpleGUI
fac982124d New Demo Program - Display an image located at URL online (thanks to @Necrosis000 for opening an issue to ask how) 2022-11-30 08:45:39 -05:00
PySimpleGUI
5b20cc1cee Automated Update! 2022-11-28 18:30:25 +00:00
PySimpleGUI
a410f19659
Merge pull request #6065 from PySimpleGUI/Dev-latest
Fix for not correctly setting Element.ttk_style_name and Element.ttk_…
2022-11-28 06:46:07 -05:00
PySimpleGUI
f869052f8e Fix for not correctly setting Element.ttk_style_name and Element.ttk_style 2022-11-28 06:45:50 -05:00
PySimpleGUI
ab993d49ba
Merge pull request #6064 from PySimpleGUI/Dev-latest
Made version window non-blocking
2022-11-26 07:01:39 -05:00
PySimpleGUI
331774cb5f Made version window non-blocking 2022-11-26 07:01:24 -05:00
PySimpleGUI
4e760967cd
Merge pull request #6062 from PySimpleGUI/Dev-latest
Swapped Push, VPush with Stretch, VStretch as the function name inste…
2022-11-24 16:50:42 -05:00
PySimpleGUI
67863949af Swapped Push, VPush with Stretch, VStretch as the function name instead of being the alias 2022-11-24 16:50:07 -05:00
PySimpleGUI
96be8aea51
Merge pull request #6056 from PySimpleGUI/Dev-latest
New enoji into the repo, the emoji browser, etc
2022-11-23 13:55:01 -05:00
PySimpleGUI
eeeb7ac9ba New enoji into the repo, the emoji browser, etc 2022-11-23 13:54:37 -05:00
PySimpleGUI
a97468db15
Merge pull request #6055 from PySimpleGUI/Dev-latest
New emoji
2022-11-23 13:26:35 -05:00
PySimpleGUI
471f6d1ec4 New emoji 2022-11-23 13:26:18 -05:00
PySimpleGUI
e597fd0a90
Merge pull request #6053 from PySimpleGUI/Dev-latest
Udemy code (missed the cookbook)
2022-11-21 14:30:44 -05:00
PySimpleGUI
40c6d737e3 Udemy code (missed the cookbook) 2022-11-21 14:30:15 -05:00
PySimpleGUI
eeb9eb9070
Merge pull request #6052 from PySimpleGUI/Dev-latest
New Udemy code
2022-11-21 14:27:04 -05:00
PySimpleGUI
7862cf7110 New Udemy code 2022-11-21 14:26:31 -05:00
PySimpleGUI
5a3fda96e7 Automated Update! 2022-11-21 18:30:41 +00:00
PySimpleGUI
2c6c726962 Automated Update! 2022-11-20 18:30:25 +00:00
PySimpleGUI
9f5db18951 Automated Update! 2022-11-19 18:30:30 +00:00
PySimpleGUI
cde0fa74af
Merge pull request #6048 from PySimpleGUI/Dev-latest
Working on the search problem....
2022-11-19 09:25:38 -05:00
PySimpleGUI
ed34934872 Working on the search problem.... 2022-11-19 09:25:23 -05:00
PySimpleGUI
4cd7b03c9b
Merge pull request #6046 from PySimpleGUI/Dev-latest
Rolling back last change
2022-11-18 23:31:50 -05:00
PySimpleGUI
cb1dd38250 Rolling back last change 2022-11-18 23:30:02 -05:00
PySimpleGUI
fda1ca8e20
Merge pull request #6045 from PySimpleGUI/Dev-latest
Working on the broken search feature in readthedocs
2022-11-18 23:24:27 -05:00
PySimpleGUI
a85b8d46b0 Working on the broken search feature in readthedocs 2022-11-18 23:24:14 -05:00
PySimpleGUI
7402936eab
Merge pull request #6043 from PySimpleGUI/Dev-latest
Update to make main GUI window less visible. Added a blocking popup a…
2022-11-18 16:53:26 -05:00
PySimpleGUI
6c00c133b8 Update to make main GUI window less visible. Added a blocking popup at the end. 2022-11-18 16:53:12 -05:00
PySimpleGUI
155738a19d
Merge pull request #6042 from PySimpleGUI/Dev-latest
Dev latest
2022-11-18 10:11:41 -05:00
PySimpleGUI
3b9176cbb1 More cleanup 2022-11-18 10:11:27 -05:00
PySimpleGUI
77b0f906eb Another change to fix docs search problem. 2022-11-18 10:11:13 -05:00
PySimpleGUI
dad366884d
Merge pull request #6041 from PySimpleGUI/Dev-latest
More repo cleanup
2022-11-18 10:00:08 -05:00
PySimpleGUI
a8221cad50 More repo cleanup 2022-11-18 09:59:54 -05:00
PySimpleGUI
bd7b6d894c
Merge pull request #6040 from PySimpleGUI/Dev-latest
Cleaning up the repo a bit by removing older folders
2022-11-18 09:52:51 -05:00
PySimpleGUI
265ce998ef Cleaning up the repo a bit by removing older folders 2022-11-18 09:52:40 -05:00
PySimpleGUI
878e94c10a
Rename _requirements.txt to requirements.txt 2022-11-18 09:49:29 -05:00
PySimpleGUI
30af9fc52c
Rename requirements.txt to _requirements.txt 2022-11-18 09:47:14 -05:00
PySimpleGUI
37ab4d70ac
Merge pull request #6039 from PySimpleGUI/Dev-latest
Dev latest
2022-11-18 09:18:25 -05:00
PySimpleGUI
4f192944c8 Hopefully a fix for the documentation search problem! 2022-11-18 09:18:06 -05:00
PySimpleGUI
32acd89856 Fixed Neon Yellow 1 theme 2022-11-17 14:47:30 -05:00
PySimpleGUI
33edf9ad64
Merge pull request #6036 from PySimpleGUI/Dev-latest
New Demo Program - Make windows and PySimpleGUI calls from a thread.
2022-11-15 06:32:11 -05:00
PySimpleGUI
5133225298 New Demo Program - Make windows and PySimpleGUI calls from a thread. 2022-11-15 06:31:53 -05:00
PySimpleGUI
be17021dcf
Merge pull request #6032 from PySimpleGUI/Dev-latest
Addition of image_zoom to Tab element - completes addition of zoom op…
2022-11-14 06:47:44 -05:00
PySimpleGUI
aa8478f124 Addition of image_zoom to Tab element - completes addition of zoom option for elements with images 2022-11-14 06:47:30 -05:00
PySimpleGUI
5adb01ce25
Merge pull request #6031 from PySimpleGUI/Dev-latest
Fix for set_vscroll_position not working on Scrollable-Columns.
2022-11-13 16:09:36 -05:00
PySimpleGUI
e9c3750f1e Fix for set_vscroll_position not working on Scrollable-Columns. 2022-11-13 16:09:22 -05:00
PySimpleGUI
1f8270c4c6
Merge pull request #6029 from PySimpleGUI/Dev-latest
Button get image_source parm (finally). Button, ButtonMenu gains zoom…
2022-11-13 08:49:06 -05:00
PySimpleGUI
f69322799d Button get image_source parm (finally). Button, ButtonMenu gains zoom parm. 2022-11-13 08:48:51 -05:00
PySimpleGUI
42335d486f
Merge pull request #6024 from PySimpleGUI/Dev-latest
New Demo Program - a multi-threaded example using a queue to send dat…
2022-11-12 11:02:23 -05:00
PySimpleGUI
95fd3c53a2 New Demo Program - a multi-threaded example using a queue to send data to your application 2022-11-12 11:02:09 -05:00
PySimpleGUI
52052a8b9d
Merge pull request #6022 from PySimpleGUI/Dev-latest
Added zoom parameter to Image Element
2022-11-11 10:55:08 -05:00
PySimpleGUI
14e8cbae3d Added zoom parameter to Image Element 2022-11-11 10:54:53 -05:00
PySimpleGUI
6aeb8a94a1
Merge pull request #6021 from PySimpleGUI/Dev-latest
New Demo showing how to redraw figures on a Graph if the window resizes
2022-11-11 10:36:09 -05:00
PySimpleGUI
5722f1ab09 New Demo showing how to redraw figures on a Graph if the window resizes 2022-11-11 10:35:56 -05:00
PySimpleGUI
b886e7d7a1
Merge pull request #6020 from PySimpleGUI/Dev-latest
Adding setup.py used for PyPI releases
2022-11-11 10:16:26 -05:00
PySimpleGUI
99743b9347 Adding setup.py used for PyPI releases 2022-11-11 10:16:12 -05:00
PySimpleGUI
ad7b83cf44
Merge pull request #6019 from PySimpleGUI/Dev-latest
Experimenting with a blank setup.py
2022-11-11 09:01:40 -05:00
PySimpleGUI
b1b11ab819 Experimenting with a blank setup.py 2022-11-11 09:01:26 -05:00
PySimpleGUI
b85128f752
Merge pull request #6018 from PySimpleGUI/Dev-latest
Added execute_py_get_running_interpreter.  Fixed docstrings for execu…
2022-11-08 16:28:39 -05:00
PySimpleGUI
4b9cbd240a Added execute_py_get_running_interpreter. Fixed docstrings for execute_py_get_interpreter 2022-11-08 16:28:25 -05:00
PySimpleGUI
3d6229dad5 Automated Update! 2022-11-07 18:30:21 +00:00
PySimpleGUI
8b23740fca Automated Update! 2022-11-06 20:37:16 +00:00
PySimpleGUI
c3bab8a351
Merge pull request #6014 from PySimpleGUI/Dev-latest
Dark Blue 18 theme added
2022-11-06 06:11:58 -05:00
PySimpleGUI
28df2058ed Dark Blue 18 theme added 2022-11-06 06:11:44 -05:00
PySimpleGUI
d9f73b7ead
Merge pull request #6013 from PySimpleGUI/Dev-latest
Added font to Input element's update method
2022-11-05 06:22:26 -04:00
PySimpleGUI
97d7515a0e Added font to Input element's update method 2022-11-05 06:22:11 -04:00
PySimpleGUI
241e9d2f8a
Merge pull request #6011 from PySimpleGUI/Dev-latest
Menu element - delete menu items if a new menu definition is sent to …
2022-11-04 14:51:34 -04:00
PySimpleGUI
891bc93317 Menu element - delete menu items if a new menu definition is sent to Menu.update 2022-11-04 14:51:18 -04:00
PySimpleGUI
e620bdb22c
Merge pull request #6004 from PySimpleGUI/Dev-latest
New Demo Program - shows using objects instead of strings with Listbox
2022-11-03 08:12:35 -04:00
PySimpleGUI
0178e9b14f New Demo Program - shows using objects instead of strings with Listbox 2022-11-03 08:12:20 -04:00
PySimpleGUI
091900fb9b
Merge pull request #6003 from PySimpleGUI/Dev-latest
Cleaned up a very old demo.
2022-11-02 08:39:29 -04:00
PySimpleGUI
1f6a96cf99 Cleaned up a very old demo. 2022-11-02 08:39:13 -04:00
PySimpleGUI
570e20b398
Merge pull request #6001 from PySimpleGUI/Dev-latest
Enabled resizing of table
2022-11-01 15:12:06 -04:00
PySimpleGUI
2d019612fe Enabled resizing of table 2022-11-01 15:11:50 -04:00
PySimpleGUI
9a606c0a7a
Merge pull request #5999 from PySimpleGUI/Dev-latest
Dev latest
2022-10-31 13:56:48 -04:00
PySimpleGUI
bb4cbc8e85 Fixed popup_error_with_traceback docstring 2022-10-31 13:56:31 -04:00
PySimpleGUI
02f8fc44bf Fixed docstring for popup_error_with_traceback 2022-10-31 13:55:50 -04:00
PySimpleGUI
4a43ca9ff3
Merge pull request #5998 from PySimpleGUI/Dev-latest
Added drop_whitespace to the docstring for popup.  Added popup_error_…
2022-10-31 13:42:42 -04:00
PySimpleGUI
25349c3724 Added drop_whitespace to the docstring for popup. Added popup_error_with_traceback to popups 2022-10-31 13:42:28 -04:00
PySimpleGUI
e21d222e2e
Merge pull request #5997 from PySimpleGUI/Dev-latest
Added displaying detailed Exception information to popup_error_with_t…
2022-10-31 08:18:26 -04:00
PySimpleGUI
e21896fce3 Added displaying detailed Exception information to popup_error_with_traceback 2022-10-31 08:18:10 -04:00
PySimpleGUI
5195fee765
Merge pull request #5995 from PySimpleGUI/Dev-latest
Dev latest
2022-10-29 16:55:43 -04:00
PySimpleGUI
9f10f7f5e0 Changed message displayed in error window when an element reuse is detected in a layout. 2022-10-29 16:55:24 -04:00
PySimpleGUI
bb62b9b7ad Added drop_whitespace parm to popup docstring. Parm has been there for a while, but was not in the docstring. 2022-10-29 09:11:52 -04:00
PySimpleGUI
c9500acc3b
Merge pull request #5993 from PySimpleGUI/Dev-latest
Added handling of multiple arguments
2022-10-27 15:55:16 -04:00
PySimpleGUI
68b5272bb6 Added handling of multiple arguments 2022-10-27 15:54:58 -04:00
PySimpleGUI
7850d16642
Merge pull request #5987 from PySimpleGUI/Dev-latest
Demo Program - shows a GUI if no arguments are provided when executed
2022-10-26 07:09:03 -04:00
PySimpleGUI
4e24b582f1 Demo Program - shows a GUI if no arguments are provided when executed 2022-10-26 07:08:45 -04:00
PySimpleGUI
be497ae8ff Automated Update! 2022-10-22 14:43:33 -04:00
PySimpleGUI
443cbf8420 Automated Update! 2022-10-22 14:31:37 -04:00
PySimpleGUI
3de2b4aa56
Merge pull request #5981 from PySimpleGUI/Dev-latest
Added saving the new tk.Menu in the widget member variable in Menu.up…
2022-10-22 10:18:22 -04:00
PySimpleGUI
744ea8eccd Added saving the new tk.Menu in the widget member variable in Menu.update 2022-10-22 10:18:07 -04:00
PySimpleGUI
8d5a32ff2c
Merge pull request #5977 from PySimpleGUI/Dev-latest
Removed very old setup.py file
2022-10-20 18:42:09 -04:00
PySimpleGUI
b406df0d6c Removed very old setup.py file 2022-10-20 18:41:52 -04:00
PySimpleGUI
4c27fb2cbd
Merge pull request #5974 from PySimpleGUI/Dev-latest
Some neon color themes
2022-10-17 17:32:32 -04:00
PySimpleGUI
27618d1393 Some neon color themes 2022-10-17 17:32:12 -04:00
PySimpleGUI
e9a2285288
Merge pull request #5968 from PySimpleGUI/Dev-latest
Latest user screenshots so that the bot can take over!
2022-10-16 11:07:46 -04:00
PySimpleGUI
f1bf250742 Latest user screenshots so that the bot can take over! 2022-10-16 11:07:29 -04:00
PySimpleGUI
23717fdf42
Merge pull request #5966 from PySimpleGUI/Dev-latest
Added SYMBOL_BULLET - Unicode Bullet character
2022-10-15 15:32:39 -04:00
PySimpleGUI
c6c77ccf01 Added SYMBOL_BULLET - Unicode Bullet character 2022-10-15 15:32:17 -04:00
PySimpleGUI
07ab15770a
Merge pull request #5959 from PySimpleGUI/Dev-latest
Version bump to match PyPI emergency release
2022-10-11 11:59:20 -04:00
PySimpleGUI
b9761311f6 Version bump to match PyPI emergency release 2022-10-11 11:59:06 -04:00
PySimpleGUI
a480f7a717
Merge pull request #5955 from PySimpleGUI/Dev-latest
Changed how Trinket is detected
2022-10-10 19:05:04 -04:00
PySimpleGUI
3915830985 Changed how Trinket is detected 2022-10-10 19:04:46 -04:00
PySimpleGUI
807b1e6bf2
Merge pull request #5954 from PySimpleGUI/Dev-latest
Fix in test harness... shouldn't have been setting the force modal op…
2022-10-08 17:48:23 -04:00
PySimpleGUI
1127106d75 Fix in test harness... shouldn't have been setting the force modal option after popup test. 2022-10-08 17:48:08 -04:00
PySimpleGUI
9e4a5e4bd6
Merge pull request #5951 from PySimpleGUI/Dev-latest
Dev latest
2022-10-05 05:18:42 -04:00
PySimpleGUI
2a470045f2 Added Window.is_hidden 2022-10-05 05:18:23 -04:00
PySimpleGUI
af97d49f91 Added missing Udemy coupon to call reference 2022-10-05 05:14:27 -04:00
PySimpleGUI
ce5ccb0df6
Merge pull request #5946 from PySimpleGUI/Dev-latest
New Udemy Coupon Code (D5570C66DBD8E42C7963)
2022-10-04 18:44:44 -04:00
PySimpleGUI
70ba9b7569 New Udemy Coupon Code (D5570C66DBD8E42C7963) 2022-10-04 18:44:28 -04:00
PySimpleGUI
9d7d07e9f3
Merge pull request #5939 from PySimpleGUI/Dev-latest
Added latest delivery of Emojis (last batch for a while)
2022-09-28 15:59:44 -04:00
PySimpleGUI
6514982490 Added latest delivery of Emojis (last batch for a while) 2022-09-28 15:59:30 -04:00
PySimpleGUI
d0e8617abf
Merge pull request #5938 from PySimpleGUI/Dev-latest
New emoji's and new parameter to the popup_error_with_traceback so yo…
2022-09-28 15:21:46 -04:00
PySimpleGUI
185fa370db New emoji's and new parameter to the popup_error_with_traceback so you can specify an emoji rather than one being chosen at random. 2022-09-28 15:21:31 -04:00
PySimpleGUI
94c561a3bc
Merge pull request #5937 from PySimpleGUI/Dev-latest
More emojis?  YES More Emojis!
2022-09-28 12:25:22 -04:00
PySimpleGUI
4c3fd1977d More emojis? YES More Emojis! 2022-09-28 12:25:09 -04:00
PySimpleGUI
7c9a66f7c0
Merge pull request #5935 from PySimpleGUI/Dev-latest
Sets the active foreground and active background for Menus and Button…
2022-09-27 11:29:24 -04:00
PySimpleGUI
1b7bc347b3 Sets the active foreground and active background for Menus and ButtonMenus and MenubarCustom. For ButtonMenu and MenubarCustom this includes the button itself as well as the menu items. 2022-09-27 11:29:11 -04:00
PySimpleGUI
9c63abb8c5
Merge pull request #5923 from PySimpleGUI/Dev-latest
Added filtering out option, home and end keys, and displaying number …
2022-09-24 15:27:37 -04:00
PySimpleGUI
9fb0d87181 Added filtering out option, home and end keys, and displaying number of selected rows to the Demo Program for displaying CSV files. 2022-09-24 15:27:25 -04:00
PySimpleGUI
591d05ce88
Merge pull request #5922 from PySimpleGUI/Dev-latest
popup_get_text - addition of history feature so at same level as othe…
2022-09-24 08:21:13 -04:00
PySimpleGUI
2482dff2d6 popup_get_text - addition of history feature so at same level as other popup_get functions 2022-09-24 08:20:54 -04:00
PySimpleGUI
6d41b8395c
Merge pull request #5912 from PySimpleGUI/Dev-latest
Simplified logic for checkbox and text click handling/updating
2022-09-22 02:04:16 -04:00
PySimpleGUI
4ebc727679 Simplified logic for checkbox and text click handling/updating 2022-09-22 02:04:05 -04:00
PySimpleGUI
d4c8fc4850
Merge pull request #5911 from PySimpleGUI/Dev-latest
Changed keys into tuples.  Made Text AND Image clickable so will be l…
2022-09-22 01:41:29 -04:00
PySimpleGUI
92bac182bd Changed keys into tuples. Made Text AND Image clickable so will be like a normal checkbox element 2022-09-22 01:41:18 -04:00
PySimpleGUI
32078421c6
Merge pull request #5905 from PySimpleGUI/Dev-latest
Better text alignment in the test harness.  Fixed crash in SystemTray…
2022-09-20 14:38:03 -04:00
PySimpleGUI
aaa6d0e79d Better text alignment in the test harness. Fixed crash in SystemTray.show_message that happened if the time value was specified as an int 2022-09-20 14:37:49 -04:00
PySimpleGUI
5d70b94e47
Merge pull request #5904 from PySimpleGUI/Dev-latest
Fixed Text docstring.  Show the Python Executable in the main test ha…
2022-09-20 13:39:36 -04:00
PySimpleGUI
696a181129 Fixed Text docstring. Show the Python Executable in the main test harness 2022-09-20 13:39:20 -04:00
PySimpleGUI
bd0d18b380
Merge pull request #5899 from PySimpleGUI/Dev-latest
Better exception handling... keep the app going rather than breaking …
2022-09-17 10:54:55 -04:00
PySimpleGUI
86a09c2fe0 Better exception handling... keep the app going rather than breaking from event loop. 2022-09-17 10:54:42 -04:00
PySimpleGUI
e7fe7b4cbf
Merge pull request #5898 from PySimpleGUI/Dev-latest
Dev latest
2022-09-17 07:45:32 -04:00
PySimpleGUI
bcc799ce4a New emoji toolbar 2022-09-17 07:45:16 -04:00
PySimpleGUI
2222b00bd1 It's emoji Saturday... another batch 2022-09-17 07:44:15 -04:00
PySimpleGUI
0e2ddaf7fd
Merge pull request #5895 from PySimpleGUI/Dev-latest
Removed the new right_justify_buttons from popup and replaced with bu…
2022-09-16 15:15:37 -04:00
PySimpleGUI
cd9b5e4b93 Removed the new right_justify_buttons from popup and replaced with button_justification 2022-09-16 15:15:25 -04:00
PySimpleGUI
5fe61b7499
Merge pull request #5893 from PySimpleGUI/Dev-latest
Added Element.save_element_screenshot_to_disk
2022-09-15 19:11:41 -04:00
PySimpleGUI
961f7ba137 Added Element.save_element_screenshot_to_disk 2022-09-15 19:11:29 -04:00
PySimpleGUI
8227dc60d1
Merge pull request #5892 from PySimpleGUI/Dev-latest
Trying out a format that will add a table of contents
2022-09-15 12:29:02 -04:00
PySimpleGUI
686937e8f9 Trying out a format that will add a table of contents 2022-09-15 12:28:48 -04:00
PySimpleGUI
b2817f8608
Merge pull request #5891 from PySimpleGUI/Dev-latest
Added 2 parms to popup - right_justify_buttons and drop_whitespace
2022-09-15 12:05:01 -04:00
PySimpleGUI
7745cffbfb Added 2 parms to popup - right_justify_buttons and drop_whitespace 2022-09-15 12:04:48 -04:00
PySimpleGUI
c940a9c8b4
Merge pull request #5888 from PySimpleGUI/Dev-latest
Shortened the Japanese readme tab name so they call fit without cusin…
2022-09-14 13:26:48 -04:00
PySimpleGUI
2b4d2067a5 Shortened the Japanese readme tab name so they call fit without cusing the cropped header problem. 2022-09-14 13:26:34 -04:00
PySimpleGUI
d8ac92ab1e
Merge pull request #5887 from PySimpleGUI/Dev-latest
Added back 1 more tab
2022-09-14 13:20:17 -04:00
PySimpleGUI
0e0e5f8135 Added back 1 more tab 2022-09-14 13:20:02 -04:00
PySimpleGUI
ab49e2eb5a
Merge pull request #5886 from PySimpleGUI/Dev-latest
Adding back screenshot tabs since header working correctly now (BE SU…
2022-09-14 13:13:08 -04:00
PySimpleGUI
065163fc73 Adding back screenshot tabs since header working correctly now (BE SURE AND CLEAR YOUR BROSER CACHE!) 2022-09-14 13:12:48 -04:00
PySimpleGUI
860b258748
Merge pull request #5885 from PySimpleGUI/Dev-latest
removed the demo screenshost tab
2022-09-14 13:06:08 -04:00
PySimpleGUI
73cc4de08b removed the demo screenshost tab 2022-09-14 13:05:53 -04:00
PySimpleGUI
da0b84be09
Merge pull request #5884 from PySimpleGUI/Dev-latest
Renamed the user screenshots to reduce number of tabs
2022-09-14 13:02:11 -04:00
PySimpleGUI
142e3cba53 Renamed the user screenshots to reduce number of tabs 2022-09-14 13:01:56 -04:00
PySimpleGUI
678453d23d
Merge pull request #5883 from PySimpleGUI/Dev-latest
Remove the second user screenshots tab
2022-09-14 12:53:14 -04:00
PySimpleGUI
d06d59c0f1 Remove the second user screenshots tab 2022-09-14 12:52:59 -04:00
PySimpleGUI
091740af51
Merge pull request #5882 from PySimpleGUI/Dev-latest
More tab renaming
2022-09-14 12:51:13 -04:00
PySimpleGUI
7ae9e0c2e7 More tab renaming 2022-09-14 12:50:49 -04:00
PySimpleGUI
0370306fe6
Merge pull request #5881 from PySimpleGUI/Dev-latest
renamed user screenshots tabs to shorten the header
2022-09-14 12:48:36 -04:00
PySimpleGUI
cdcbbd5cc0 renamed user screenshots tabs to shorten the header 2022-09-14 12:48:22 -04:00
PySimpleGUI
9c48aefecf
Merge pull request #5880 from PySimpleGUI/Dev-latest
Removed requirements from readthedocs.yml due to scrolling of TOC pro…
2022-09-14 12:45:03 -04:00
PySimpleGUI
953992a962 Removed requirements from readthedocs.yml due to scrolling of TOC problem 2022-09-14 12:44:47 -04:00
PySimpleGUI
5ed9fd4888
Merge pull request #5874 from PySimpleGUI/Dev-latest
New Demo Program demonstrating using images for "Can Buttons"
2022-09-14 08:38:59 -04:00
PySimpleGUI
888e393886 New Demo Program demonstrating using images for "Can Buttons" 2022-09-14 08:38:31 -04:00
PySimpleGUI
231ff526b7
Merge pull request #5873 from PySimpleGUI/Dev-latest
Added coverage of case where no matching python file found.
2022-09-13 18:57:25 -04:00
PySimpleGUI
74ae30d8a1 Added coverage of case where no matching python file found. 2022-09-13 18:57:14 -04:00
PySimpleGUI
f363bf97c1
Merge pull request #5872 from PySimpleGUI/Dev-latest
Back to using a table and also using the correct py or pyw filename
2022-09-13 18:53:55 -04:00
PySimpleGUI
4244c7bca0 Back to using a table and also using the correct py or pyw filename 2022-09-13 18:53:41 -04:00
PySimpleGUI
a16a7d477d
Merge pull request #5871 from PySimpleGUI/Dev-latest
Switch from table to using header so that a table of contents is gene…
2022-09-13 18:38:29 -04:00
PySimpleGUI
86ba815e0f Switch from table to using header so that a table of contents is generated 2022-09-13 18:38:14 -04:00
PySimpleGUI
b5bb47d17b
Merge pull request #5870 from PySimpleGUI/Dev-latest
Added back the user screenshots tabs
2022-09-13 16:13:13 -04:00
PySimpleGUI
537998b48b Added back the user screenshots tabs 2022-09-13 16:13:00 -04:00
PySimpleGUI
b1d1847c7b
Merge pull request #5869 from PySimpleGUI/Dev-latest
Change width of videos
2022-09-13 14:31:55 -04:00
PySimpleGUI
cd277b5540 Change width of videos 2022-09-13 14:31:43 -04:00
PySimpleGUI
217a6468f1
Merge pull request #5868 from PySimpleGUI/Dev-latest
New screenshots from the screenshots repo
2022-09-13 14:28:19 -04:00
PySimpleGUI
d1571a3dd9 New screenshots from the screenshots repo 2022-09-13 14:28:08 -04:00
PySimpleGUI
4b24b7b3c1
Merge pull request #5866 from PySimpleGUI/Dev-latest
Fix link to image
2022-09-12 09:20:21 -04:00
PySimpleGUI
f8c461d011 Fix link to image 2022-09-12 09:20:07 -04:00
PySimpleGUI
33159bc552
Merge pull request #5865 from PySimpleGUI/Dev-latest
Fix screenshots location
2022-09-12 09:12:50 -04:00
PySimpleGUI
856d110996 Fix screenshots location 2022-09-12 09:12:36 -04:00
PySimpleGUI
cee4a417c7
Merge pull request #5864 from PySimpleGUI/Dev-latest
Trying out a new screenshots tab
2022-09-12 09:01:57 -04:00
PySimpleGUI
72afe193a7 Trying out a new screenshots tab 2022-09-12 09:01:43 -04:00
PySimpleGUI
ec758db906
Merge pull request #5862 from PySimpleGUI/Dev-latest
More doc rework...
2022-09-11 14:47:40 -04:00
PySimpleGUI
4d4d31ee72 More doc rework... 2022-09-11 14:47:28 -04:00
PySimpleGUI
1a22c3f103
Merge pull request #5861 from PySimpleGUI/Dev-latest
Added back the docs_modification folder... should have only removed t…
2022-09-11 14:42:55 -04:00
PySimpleGUI
b91ef6510d Added back the docs_modification folder... should have only removed the dependencies setting 2022-09-11 14:42:10 -04:00
PySimpleGUI
258e0dcb35
Merge pull request #5860 from PySimpleGUI/Dev-latest
Remove docs_modification for test
2022-09-11 14:37:29 -04:00
PySimpleGUI
b90dd922e7 Remove docs_modification for test 2022-09-11 14:37:18 -04:00
PySimpleGUI
d522aa91eb
Merge pull request #5859 from PySimpleGUI/Dev-latest
Problem with SDK ref following pinning mkdocs to 1.3.1 so pulling tha…
2022-09-11 14:35:27 -04:00
PySimpleGUI
8124dbe5c8 Problem with SDK ref following pinning mkdocs to 1.3.1 so pulling that out for a test 2022-09-11 14:35:13 -04:00
PySimpleGUI
13d2e3422a
Merge pull request #5858 from PySimpleGUI/Dev-latest
Rename the user screenshots to temporarily remove them from the docs.
2022-09-11 14:30:49 -04:00
PySimpleGUI
05e336a2a5 Rename the user screenshots to temporarily remove them from the docs. 2022-09-11 14:30:31 -04:00
PySimpleGUI
b840a5b741
Merge pull request #5857 from PySimpleGUI/Dev-latest
Minor edit
2022-09-11 13:55:29 -04:00
PySimpleGUI
70697281ef Minor edit 2022-09-11 13:55:17 -04:00
PySimpleGUI
2f1ffee12e
Merge pull request #5856 from PySimpleGUI/Dev-latest
Use latest version of mkdocs
2022-09-11 13:46:17 -04:00
PySimpleGUI
19a41b9b38 Use latest version of mkdocs 2022-09-11 13:46:05 -04:00
PySimpleGUI
2170b4a19f
Merge pull request #5855 from PySimpleGUI/Dev-latest
Use latest version of mkdocs to fix header problem
2022-09-11 13:45:05 -04:00
PySimpleGUI
9ba3c8042e Use latest version of mkdocs to fix header problem 2022-09-11 13:44:52 -04:00
PySimpleGUI
fb61584c0b
Merge pull request #5853 from PySimpleGUI/Dev-latest
Fix for docstring - type should have been int not bool for new starti…
2022-09-10 19:34:08 -04:00
PySimpleGUI
f24d4b585c Fix for docstring - type should have been int not bool for new starting_row_number parm 2022-09-10 19:33:50 -04:00
PySimpleGUI
9805f004c2
Merge pull request #5852 from PySimpleGUI/Dev-latest
Addition of starting_row_number to the Table element
2022-09-10 19:16:26 -04:00
PySimpleGUI
c64022522e Addition of starting_row_number to the Table element 2022-09-10 19:16:10 -04:00
PySimpleGUI
b6f55ad830
Merge pull request #5850 from PySimpleGUI/Dev-latest
Fix for problem with spaces in filename and using an editor specified…
2022-09-10 16:01:46 -04:00
PySimpleGUI
669b739696 Fix for problem with spaces in filename and using an editor specified in the Demo Browser's settings 2022-09-10 16:01:32 -04:00
PySimpleGUI
8ec1ca1fb9
Merge pull request #5844 from PySimpleGUI/Dev-latest
Tighten up the table parms
2022-09-08 16:55:46 -04:00
PySimpleGUI
9af024cd82 Tighten up the table parms 2022-09-08 16:55:33 -04:00
PySimpleGUI
da047a0c99
Merge pull request #5843 from PySimpleGUI/Dev-latest
New Demo Program - CSV Table Display
2022-09-08 16:40:53 -04:00
PySimpleGUI
5be4ac34a9 New Demo Program - CSV Table Display 2022-09-08 16:40:39 -04:00
PySimpleGUI
2539e2cbb0
Merge pull request #5841 from PySimpleGUI/Dev-latest
Added support for Custom Titlebar to the Window.set_title method
2022-09-07 09:29:19 -04:00
PySimpleGUI
e9a9f299fc Added support for Custom Titlebar to the Window.set_title method 2022-09-07 09:29:02 -04:00
PySimpleGUI
f1bcd8fe49
Merge pull request #5840 from PySimpleGUI/Dev-latest
Add the now standard "save last location" code that most of the "Desk…
2022-09-07 09:18:36 -04:00
PySimpleGUI
9a31a75be1 Add the now standard "save last location" code that most of the "Desktop Widget" demo programs have 2022-09-07 09:18:20 -04:00
PySimpleGUI
4f1429cc97
Merge pull request #5839 from PySimpleGUI/Dev-latest
Added TabGroup visibility control in both the init and added an updat…
2022-09-06 12:00:22 -04:00
PySimpleGUI
6c480dcf1c Added TabGroup visibility control in both the init and added an update method. 2022-09-06 11:59:45 -04:00
PySimpleGUI
3e6cd243e3
Merge pull request #5835 from PySimpleGUI/Dev-latest
Addition of TITLEBAR_TEXT_KEY
2022-09-05 15:15:12 -04:00
PySimpleGUI
35fabbaa09 Addition of TITLEBAR_TEXT_KEY 2022-09-05 15:14:54 -04:00
PySimpleGUI
8ae79ac25c
Merge pull request #5832 from PySimpleGUI/Dev-latest
Update of the Emoji Toolbar demo program
2022-09-04 13:04:38 -04:00
PySimpleGUI
f89e652d56 Update of the Emoji Toolbar demo program 2022-09-04 13:04:26 -04:00
PySimpleGUI
bae0152eaa
Merge pull request #5831 from PySimpleGUI/Dev-latest
Dev latest
2022-09-04 11:00:08 -04:00
PySimpleGUI
f37b826586 New theme Dark Grey 16, New batch of emojis :-) 2022-09-04 10:59:53 -04:00
PySimpleGUI
8a405a2eaa EMOJIS! Another batch arrived with more on the way 2022-09-04 10:45:56 -04:00
PySimpleGUI
a80a9436dc
Merge pull request #5830 from PySimpleGUI/Dev-latest
Added interpreter information to the get_versions function for better…
2022-09-03 11:01:15 -04:00
PySimpleGUI
adc4709f34 Added interpreter information to the get_versions function for better debugging. A couple of docstrings fixes. 2022-09-03 11:00:32 -04:00
PySimpleGUI
9497746ab1
Merge pull request #5826 from PySimpleGUI/Dev-latest
Removed entries without screenshots
2022-08-30 19:25:08 -04:00
PySimpleGUI
16c8e685c7 Removed entries without screenshots 2022-08-30 19:24:53 -04:00
PySimpleGUI
86cec41af4
Merge pull request #5825 from PySimpleGUI/Dev-latest
Reversed order of screenshot so newest at top
2022-08-30 19:21:13 -04:00
PySimpleGUI
80d2d463f8 Reversed order of screenshot so newest at top 2022-08-30 19:20:44 -04:00
PySimpleGUI
8cefdad2d6
Merge pull request #5822 from PySimpleGUI/Dev-latest
New Combo parameter - enable_per_char_events.  When True, will get an…
2022-08-29 17:58:44 -04:00
PySimpleGUI
9b409083ee New Combo parameter - enable_per_char_events. When True, will get an event for every character that's typed 2022-08-29 17:58:31 -04:00
PySimpleGUI
3cf96acf03
Merge pull request #5819 from PySimpleGUI/Dev-latest
Newest Udemy code
2022-08-28 19:24:38 -04:00
PySimpleGUI
30d4241a34 Newest Udemy code 2022-08-28 19:24:24 -04:00
PySimpleGUI
2bd702f4f8
Merge pull request #5818 from PySimpleGUI/Dev-latest
User Screenshots - no text only images
2022-08-27 16:02:12 -04:00
PySimpleGUI
e0e1ba855f User Screenshots - no text only images 2022-08-27 16:01:57 -04:00
PySimpleGUI
2364090661
Merge pull request #5817 from PySimpleGUI/Dev-latest
Trying a more compact format for screenshots
2022-08-27 09:21:48 -04:00
PySimpleGUI
1135563ee2 Trying a more compact format for screenshots 2022-08-27 09:21:18 -04:00
PySimpleGUI
559333fcc2
Merge pull request #5815 from PySimpleGUI/Dev-latest
Adding user screenshots from issue 10 (EXCITING!)
2022-08-26 12:43:03 -04:00
PySimpleGUI
e7744edb45 Adding user screenshots from issue 10 (EXCITING!) 2022-08-26 12:42:46 -04:00
PySimpleGUI
c3f937b294
Merge pull request #5813 from PySimpleGUI/Dev-latest
Updated the Output Element's docstring
2022-08-25 19:47:01 -04:00
PySimpleGUI
9648b9034c Updated the Output Element's docstring 2022-08-25 19:46:41 -04:00
PySimpleGUI
2049d258f3
Merge pull request #5812 from PySimpleGUI/Dev-latest
Output Element - automatically reroutes cprint to the output element …
2022-08-25 18:29:38 -04:00
PySimpleGUI
2ecb45481b Output Element - automatically reroutes cprint to the output element now as well as stdout, stderr 2022-08-25 18:29:20 -04:00
PySimpleGUI
af372a27a2
Merge pull request #5811 from PySimpleGUI/Dev-latest
Addition of vsb_style_name and hsb_style_name to elements so that the…
2022-08-25 11:19:45 -04:00
PySimpleGUI
9a27c36234 Addition of vsb_style_name and hsb_style_name to elements so that theme/colors of element's ttk scrollbars can be changed 2022-08-25 11:19:25 -04:00
PySimpleGUI
45e55b43f6
Merge pull request #5801 from PySimpleGUI/Dev-latest
Fix for the stdout and stderr rerouting bug. Now correctly restores s…
2022-08-21 18:53:16 -04:00
PySimpleGUI
0861d66339 Fix for the stdout and stderr rerouting bug. Now correctly restores stdout & stderr when a window is closed or routing is changed. 2022-08-21 18:53:01 -04:00
PySimpleGUI
dbf8183070
Merge pull request #5800 from PySimpleGUI/Dev-latest
Fixed docstring error in set_options.  A quick & dirty addition of sh…
2022-08-21 17:32:41 -04:00
PySimpleGUI
43702eff5f Fixed docstring error in set_options. A quick & dirty addition of shortcut character for buttons. Due to backwards compatibility, must be enabled using set_options. 2022-08-21 17:32:25 -04:00
PySimpleGUI
f7056a327c
Merge pull request #5798 from PySimpleGUI/Dev-latest
Removed the error popup that happened when Multline elements were try…
2022-08-20 20:35:38 -04:00
PySimpleGUI
add16aa4ee Removed the error popup that happened when Multline elements were trying to print to a closed window. Was causing problem that required task manager to kill the window as a solution. Added Sizegrip onto the SDK Help Window. START of the fixes for restoring re-routed stdout and stderr 2022-08-20 20:35:22 -04:00
PySimpleGUI
8a68674026
Merge pull request #5786 from PySimpleGUI/Dev-latest
Increased button pressed display font size.
2022-08-14 16:55:01 -04:00
PySimpleGUI
332042d7d0 Increased button pressed display font size. 2022-08-14 16:54:45 -04:00
PySimpleGUI
433d71421e
Merge pull request #5785 from PySimpleGUI/Dev-latest
Added output of button click to the window itself
2022-08-14 16:43:53 -04:00
PySimpleGUI
7510d18518 Added output of button click to the window itself 2022-08-14 16:43:33 -04:00
PySimpleGUI
0bd7b8e74a
Merge pull request #5784 from PySimpleGUI/Dev-latest
New Demo Program -  Simulated Buttons With Highlighting
2022-08-14 16:37:58 -04:00
PySimpleGUI
4b971f7d0a New Demo Program - Simulated Buttons With Highlighting 2022-08-14 16:37:39 -04:00
PySimpleGUI
8cbd4a355a
Merge pull request #5780 from PySimpleGUI/Dev-latest
Support for Custom Titlebar added to Window.minimize, Window.maximize…
2022-08-12 17:09:11 -04:00
PySimpleGUI
8c53d1c400 Support for Custom Titlebar added to Window.minimize, Window.maximize, Window.normal 2022-08-12 17:08:42 -04:00
PySimpleGUI
c0e952c930
Merge pull request #5769 from PySimpleGUI/Dev-latest
Added Window.get_scaling to get the current scaling value from tktiner
2022-08-08 09:51:27 -04:00
PySimpleGUI
1e3e721f36 Added Window.get_scaling to get the current scaling value from tktiner 2022-08-08 09:51:08 -04:00
PySimpleGUI
9692dd1ea2
Merge pull request #5766 from PySimpleGUI/Dev-latest
Update Demo_Invisible_Elements_Pinning.py
2022-08-07 07:36:31 -04:00
PySimpleGUI
6eb14b7408 Update Demo_Invisible_Elements_Pinning.py 2022-08-07 07:36:15 -04:00
PySimpleGUI
1c2aa9dd77
Merge pull request #5760 from PySimpleGUI/Dev-latest
Addition of quick_check parm to Window.is_closed to bypass the root.u…
2022-08-06 11:02:32 -04:00
PySimpleGUI
768e73a71c Addition of quick_check parm to Window.is_closed to bypass the root.update tkinter call. For complex windows this can take a huge amount of time. This quick_check is now used in the element update methods instead of calling tktinter. 2022-08-06 11:02:13 -04:00
PySimpleGUI
bba37766a7
Merge pull request #5757 from PySimpleGUI/Dev-latest
Better docstring description of ProgressBar and one_line_progress_met…
2022-08-05 15:23:16 -04:00
PySimpleGUI
95f5c643b0 Better docstring description of ProgressBar and one_line_progress_meter paremeter bar_color. Addition of select parm to Combo.update 2022-08-05 15:23:02 -04:00
PySimpleGUI
3fc99031fd
Merge pull request #5756 from PySimpleGUI/Dev-latest
Exception protection if something happens in the drawing of a figure.…
2022-08-05 13:48:32 -04:00
PySimpleGUI
244cff57a4 Exception protection if something happens in the drawing of a figure. Added to code to ensure previously packed canvas is not packed again. 2022-08-05 13:48:11 -04:00
PySimpleGUI
6dd947b9cc
Merge pull request #5753 from PySimpleGUI/Dev-latest
Combo element - if readonly, set select color so that it's not notice…
2022-08-03 13:05:22 -04:00
PySimpleGUI
8ef45d6643 Combo element - if readonly, set select color so that it's not noticeable since no selecting will be happening 2022-08-03 13:05:02 -04:00
PySimpleGUI
f272da19b8
Merge pull request #5752 from PySimpleGUI/Dev-latest
Addition of Window.key_is_good - a quick and easy check for a good key
2022-08-03 09:23:33 -04:00
PySimpleGUI
f466284325 Addition of Window.key_is_good - a quick and easy check for a good key 2022-08-03 09:23:14 -04:00
PySimpleGUI
bc81040fe0
Merge pull request #5751 from PySimpleGUI/Dev-latest
Output element now sets auto_refresh=True.
2022-08-01 15:15:45 -04:00
PySimpleGUI
790c811161 Output element now sets auto_refresh=True. 2022-08-01 15:15:26 -04:00
PySimpleGUI
0afa04f1ea
Merge pull request #5746 from PySimpleGUI/Dev-latest
Added check for window closes to elements update method
2022-07-30 16:06:05 -04:00
PySimpleGUI
f71aa97c51 Added check for window closes to elements update method 2022-07-30 16:05:48 -04:00
PySimpleGUI
c7b2cfcc45
Merge pull request #5745 from PySimpleGUI/Dev-latest
Update of the email send Demo Program
2022-07-30 15:59:38 -04:00
PySimpleGUI
29ef2b4b25 Update of the email send Demo Program 2022-07-30 15:59:25 -04:00
PySimpleGUI
463e121634
Merge pull request #5744 from PySimpleGUI/Dev-latest
If for debug print with no_button and non_blocking
2022-07-29 07:32:10 -04:00
PySimpleGUI
6bf2426c55 If for debug print with no_button and non_blocking 2022-07-29 07:31:52 -04:00
PySimpleGUI
2fb75ffae4
Merge pull request #5741 from PySimpleGUI/Dev-latest
Removed the expansion call and notebook pack from Tab code to see if …
2022-07-28 15:19:23 -04:00
PySimpleGUI
540cfa9e1c Removed the expansion call and notebook pack from Tab code to see if it fixes a TabGroup Expansion problem 2022-07-28 15:19:01 -04:00
PySimpleGUI
37231510f6
Merge pull request #5740 from PySimpleGUI/Dev-latest
Releases notes for 4.60.3 so that readthedocs will build
2022-07-27 17:45:34 -04:00
PySimpleGUI
85be5ae0a9 Releases notes for 4.60.3 so that readthedocs will build 2022-07-27 17:45:20 -04:00
PySimpleGUI
c9b273c934
Merge pull request #5739 from PySimpleGUI/Dev-latest
Changes that posted to PyPI as 4.60.3
2022-07-27 17:32:36 -04:00
PySimpleGUI
4227cc3c91 Changes that posted to PyPI as 4.60.3 2022-07-27 17:32:21 -04:00
PySimpleGUI
209680701f
Merge pull request #5737 from PySimpleGUI/Dev-latest
Fix for Mac version check... oy.... sloppy work... sorry about that....
2022-07-27 11:18:45 -04:00
PySimpleGUI
59cf979031 Fix for Mac version check... oy.... sloppy work... sorry about that.... 2022-07-27 11:18:32 -04:00
PySimpleGUI
fb7854c254
Merge pull request #5736 from PySimpleGUI/Dev-latest
Fixed problem checking for MacOS version for the 12.3+ problem.  Chan…
2022-07-27 08:37:29 -04:00
PySimpleGUI
f02c2c6f02 Fixed problem checking for MacOS version for the 12.3+ problem. Change is being released as .406.3 so version here is also bumping to 4.60.3.66 2022-07-27 08:37:13 -04:00
PySimpleGUI
70c8f26c9c
Merge pull request #5732 from PySimpleGUI/Dev-latest
Bumping version to 4.60.2.65 to reflect that the 4.60.2 dot release i…
2022-07-26 15:23:31 -04:00
PySimpleGUI
c64c82c254 Bumping version to 4.60.2.65 to reflect that the 4.60.2 dot release is already in this code. 2022-07-26 15:23:16 -04:00
PySimpleGUI
4260a4661f
Merge pull request #5731 from PySimpleGUI/Dev-latest
Doc update so that 4.60.2 is in release notes
2022-07-26 15:15:28 -04:00
PySimpleGUI
2db64b8367 Doc update so that 4.60.2 is in release notes 2022-07-26 15:15:01 -04:00
PySimpleGUI
226d4a39ad
Merge pull request #5730 from PySimpleGUI/Dev-latest
Addition of Mac OS 12.3 Patch that sets Alpha channel to 0.99 by defa…
2022-07-26 10:21:24 -04:00
PySimpleGUI
0a26d35faf Addition of Mac OS 12.3 Patch that sets Alpha channel to 0.99 by default. Added control to Mac Control Panel in PySimpleGUI Settings 2022-07-26 10:21:09 -04:00
PySimpleGUI
43aaed1fd9
Merge pull request #5724 from PySimpleGUI/Dev-latest
Don't hide window when creating if the location is None (uses the OS …
2022-07-25 13:53:15 -04:00
PySimpleGUI
1dfb36f84a Don't hide window when creating if the location is None (uses the OS default location so no need to hide since not moving) 2022-07-25 13:52:56 -04:00
PySimpleGUI
b28fe017b5
Merge pull request #5723 from PySimpleGUI/Dev-latest
Demo program for read all windows that was evidently not checked in....
2022-07-25 12:29:50 -04:00
PySimpleGUI
2a9fc313bc Demo program for read all windows that was evidently not checked in.... 2022-07-25 12:29:26 -04:00
PySimpleGUI
f90ce637aa
Merge pull request #5715 from PySimpleGUI/Dev-latest
New checklist item (have upgraded to newest release of PySimpleGUI fr…
2022-07-23 19:11:48 -04:00
PySimpleGUI
af7aa7ab9f New checklist item (have upgraded to newest release of PySimpleGUI from PyPI added to the log a GitHub issue GUI), fixed problem with some versions of tkinter not supporting justification of listbboxes 2022-07-23 19:11:34 -04:00
PySimpleGUI
2dba726a7a
Update issue-form---must-fill-in-this-form-with-every-new-issue-submitted.md 2022-07-23 18:56:15 -04:00
PySimpleGUI
b38ad064d3
Merge pull request #5712 from PySimpleGUI/Dev-latest
Happily removed the "NOT available on the MAC" designation in the fil…
2022-07-22 17:26:58 -04:00
PySimpleGUI
fde83bb0cb Happily removed the "NOT available on the MAC" designation in the file_types in docstrings. 2022-07-22 17:26:41 -04:00
PySimpleGUI
a837c27ddd
Merge pull request #5711 from PySimpleGUI/Dev-latest
Dev latest
2022-07-22 15:23:24 -04:00
PySimpleGUI
f405e9488c New coupon + latest SDK changes on GitHub picked up 2022-07-22 15:23:08 -04:00
PySimpleGUI
ccde400f29 Change of doc addresses to PySimpleGUI.org. New Udemy coupon code 2022-07-22 15:22:11 -04:00
PySimpleGUI
6438e573df
Merge pull request #5709 from PySimpleGUI/Dev-latest
Addition of set_option parameter hide_window_when_creating. If set to…
2022-07-21 11:48:46 -04:00
PySimpleGUI
b81e406663 Addition of set_option parameter hide_window_when_creating. If set to False then window will not be hidden while creating and moving 2022-07-21 11:48:12 -04:00
PySimpleGUI
5d960c3dc8
Merge pull request #5708 from PySimpleGUI/Dev-latest
Fix for crash if COLOR_SYSTEM_DEFAULT specified in parameter disabled…
2022-07-20 13:06:21 -04:00
PySimpleGUI
c1fac73612 Fix for crash if COLOR_SYSTEM_DEFAULT specified in parameter disabled_readonly_background_color or disabled_readonly_text_color for Input Element. Also applied similar fix for Tab element's focus color 2022-07-20 13:06:06 -04:00
PySimpleGUI
f883868828
Merge pull request #5706 from PySimpleGUI/Dev-latest
Rework of main.html
2022-07-20 10:21:49 -04:00
PySimpleGUI
9540947b48 Rework of main.html 2022-07-20 10:21:34 -04:00
PySimpleGUI
7e0f042d9f
Merge pull request #5705 from PySimpleGUI/Dev-latest
Pick up latest docstrings
2022-07-20 09:52:18 -04:00
PySimpleGUI
5e938d0792 Pick up latest docstrings 2022-07-20 09:52:00 -04:00
PySimpleGUI
85e18deee9
Merge pull request #5704 from PySimpleGUI/Dev-latest
Addition of "Show all file types" option, Expansion of elements for w…
2022-07-20 09:46:41 -04:00
PySimpleGUI
bc9fa18855 Addition of "Show all file types" option, Expansion of elements for window resizing (old change that doesn't seem to have been checked in 🤦‍♂️) 2022-07-20 09:46:18 -04:00
PySimpleGUI
35e5e23dbe
Merge pull request #5702 from PySimpleGUI/Dev-latest
Very Short Demo Program that saves the last value entered into Input …
2022-07-19 08:46:25 -04:00
PySimpleGUI
ece20996a3 Very Short Demo Program that saves the last value entered into Input element that is then used as the default in the future. 2022-07-19 08:46:01 -04:00
PySimpleGUI
23b69a923c
Merge pull request #5701 from PySimpleGUI/Dev-latest
Removed unnecessary check for isinstance of tuple.... a new pattern l…
2022-07-18 13:49:24 -04:00
PySimpleGUI
186ddb8722 Removed unnecessary check for isinstance of tuple.... a new pattern lately with tuples as keys. 2022-07-18 13:49:11 -04:00
PySimpleGUI
672ed9755b
Merge pull request #5700 from PySimpleGUI/Dev-latest
Removed unnecessary user settings for the window position
2022-07-18 12:31:27 -04:00
PySimpleGUI
c9cdf53176 Removed unnecessary user settings for the window position 2022-07-18 12:31:09 -04:00
PySimpleGUI
31f4a9b558
Merge pull request #5699 from PySimpleGUI/Dev-latest
New demo - add and delete rows from layouts. Based on the Fed Ex Pack…
2022-07-18 12:24:21 -04:00
PySimpleGUI
bf9d1214f0 New demo - add and delete rows from layouts. Based on the Fed Ex Package Tracker Demo Program 2022-07-18 12:24:03 -04:00
PySimpleGUI
9681968974
Merge pull request #5698 from PySimpleGUI/Dev-latest
Bad spelling this early in the day
2022-07-18 06:46:36 -04:00
PySimpleGUI
d039a27418 Bad spelling this early in the day 2022-07-18 06:46:09 -04:00
PySimpleGUI
e1dbdeecf6
Merge pull request #5697 from PySimpleGUI/Dev-latest
Fix spelling error
2022-07-18 06:44:58 -04:00
PySimpleGUI
e60f243503 Fix spelling error 2022-07-18 06:44:45 -04:00
PySimpleGUI
b3a1ec1804
Merge pull request #5696 from PySimpleGUI/Dev-latest
Images for new docs
2022-07-18 06:43:35 -04:00
PySimpleGUI
4fd596cd74 Images for new docs 2022-07-18 06:43:21 -04:00
PySimpleGUI
a8c4001e40
Merge pull request #5695 from PySimpleGUI/Dev-latest
GIF of psgtest for new docs
2022-07-18 06:28:43 -04:00
PySimpleGUI
019c8bb930 GIF of psgtest for new docs 2022-07-18 06:28:24 -04:00
PySimpleGUI
d055bc6e43
Merge pull request #5694 from PySimpleGUI/Dev-latest
Addition of without_titlebar paramter to Window.current_location.  De…
2022-07-17 12:53:29 -04:00
PySimpleGUI
2c79871bef Addition of without_titlebar paramter to Window.current_location. Defaults to False. If True, then the location of the main portion of the window 2022-07-17 12:53:12 -04:00
PySimpleGUI
1a228d708e
Merge pull request #5692 from PySimpleGUI/Dev-latest
Corrected Text Element's update method docstring to indicate value ca…
2022-07-16 19:14:44 -04:00
PySimpleGUI
99fac15540 Corrected Text Element's update method docstring to indicate value can be "Any" type not just string 2022-07-16 19:14:27 -04:00
PySimpleGUI
177470e009
Merge pull request #5689 from PySimpleGUI/Dev-latest
image for new docs
2022-07-15 06:12:40 -04:00
PySimpleGUI
5ba4a5b099 image for new docs 2022-07-15 06:12:17 -04:00
PySimpleGUI
47980d6923
Merge pull request #5688 from PySimpleGUI/Dev-latest
images for new docs
2022-07-15 05:54:30 -04:00
PySimpleGUI
8c315807ab images for new docs 2022-07-15 05:54:11 -04:00
PySimpleGUI
499a019aac
Merge pull request #5685 from PySimpleGUI/Dev-latest
New docs screenshots
2022-07-13 10:27:01 -04:00
PySimpleGUI
9e85401d53 New docs screenshots 2022-07-13 10:26:46 -04:00
PySimpleGUI
15e3b5d55b
Merge pull request #5682 from PySimpleGUI/Dev-latest
Fixed output filename so named using the resized values (also releasi…
2022-07-12 15:02:11 -04:00
PySimpleGUI
c008805e97 Fixed output filename so named using the resized values (also releasing to the standalone repo and the pypi psgresizer package) 2022-07-12 15:01:54 -04:00
PySimpleGUI
7f6890c85c
Merge pull request #5679 from PySimpleGUI/Dev-latest
Updated to use built-in threading call, tuples for thread keys, relat…
2022-07-08 11:16:53 -04:00
PySimpleGUI
ba8b71ea25 Updated to use built-in threading call, tuples for thread keys, relative window position 2022-07-08 11:16:40 -04:00
PySimpleGUI
9b59796dd5
Merge pull request #5678 from PySimpleGUI/Dev-latest
Addition of double-clicking and showing the get_liast_clicked_positio…
2022-07-08 08:13:30 -04:00
PySimpleGUI
16df165603 Addition of double-clicking and showing the get_liast_clicked_position function. 2022-07-08 08:13:13 -04:00
PySimpleGUI
dcc18abb51
Merge pull request #5676 from PySimpleGUI/Dev-latest
Fix for not getting the background color from the container when exte…
2022-07-06 15:07:13 -04:00
PySimpleGUI
9db1b63c01 Fix for not getting the background color from the container when extending a layout using Window.extend_layout 2022-07-06 15:07:00 -04:00
PySimpleGUI
c2d72ee260
Merge pull request #5675 from PySimpleGUI/Dev-latest
Bumping version number to 4.60.1.55 to help with the confusion about …
2022-07-06 12:47:53 -04:00
PySimpleGUI
1dbbc39340 Bumping version number to 4.60.1.55 to help with the confusion about the dot release that happened. 2022-07-06 12:47:36 -04:00
PySimpleGUI
2dacb0c11f
Merge pull request #5671 from PySimpleGUI/Dev-latest
Added endblock
2022-07-05 11:20:51 -04:00
PySimpleGUI
5ebdda0e42 Added endblock 2022-07-05 11:20:37 -04:00
PySimpleGUI
a66883f4f4
Merge pull request #5670 from PySimpleGUI/Dev-latest
Fixed main.html
2022-07-05 11:16:46 -04:00
PySimpleGUI
7381699d8c Fixed main.html 2022-07-05 11:16:31 -04:00
PySimpleGUI
1ab67bcfc0
Merge pull request #5669 from PySimpleGUI/Dev-latest
Docs internal update
2022-07-05 11:11:50 -04:00
PySimpleGUI
fd8c01a828 Docs internal update 2022-07-05 11:11:33 -04:00
PySimpleGUI
b3ea8e4568
Merge pull request #5668 from PySimpleGUI/Dev-latest
Allow Browse/Chooser buttons to use target keys that are tuples
2022-07-04 10:07:38 -04:00
PySimpleGUI
7b739eca08 Allow Browse/Chooser buttons to use target keys that are tuples 2022-07-04 10:07:24 -04:00
PySimpleGUI
b7b9005dcd
Merge pull request #5667 from PySimpleGUI/Dev-latest
Addition of disable to Simple Tabs Demo
2022-07-03 16:34:04 -04:00
PySimpleGUI
a26a9c5854 Addition of disable to Simple Tabs Demo 2022-07-03 16:33:51 -04:00
PySimpleGUI
77d9c2f4b1
Merge pull request #5666 from PySimpleGUI/Dev-latest
Added alpha_channel to set_options - changes the default alpha channe…
2022-07-03 15:37:24 -04:00
PySimpleGUI
70fc4a6382 Added alpha_channel to set_options - changes the default alpha channel used to create all windows 2022-07-03 15:37:10 -04:00
PySimpleGUI
a55c2d2efe
Merge pull request #5665 from PySimpleGUI/Dev-latest
New coupon
2022-07-03 12:33:37 -04:00
PySimpleGUI
86bab67f83 New coupon 2022-07-03 12:33:23 -04:00
PySimpleGUI
e41f88df93
Merge pull request #5664 from PySimpleGUI/Dev-latest
Dev latest
2022-07-03 12:16:30 -04:00
PySimpleGUI
f8188f68ab Test harness - setting dictionary multline made write-only, new coupon code. 2022-07-03 12:16:14 -04:00
PySimpleGUI
c6e13e5ddb New Udemy Coupon & picking up latest PySimpleGUI SDK API calls 2022-07-03 12:13:24 -04:00
PySimpleGUI
314478e3ca
Merge pull request #5663 from PySimpleGUI/Dev-latest
Remove the eCookbook test.... a much better way coming soon....
2022-07-03 09:44:24 -04:00
PySimpleGUI
71d3885cea Remove the eCookbook test.... a much better way coming soon.... 2022-07-03 09:44:08 -04:00
PySimpleGUI
dfb2ee72b1
Merge pull request #5657 from PySimpleGUI/Dev-latest
ecookbook restoring the folders for testing...
2022-06-30 15:55:11 -04:00
PySimpleGUI
9f40a47d30 ecookbook restoring the folders for testing... 2022-06-30 15:54:57 -04:00
PySimpleGUI
d9993df5e9
Merge pull request #5656 from PySimpleGUI/Dev-latest
Flattened ecookbook.... nothing official... testing some things out...
2022-06-30 15:44:10 -04:00
PySimpleGUI
0574702876 Flattened ecookbook.... nothing official... testing some things out... 2022-06-30 15:43:56 -04:00
PySimpleGUI
ee05d5b129
Merge pull request #5655 from PySimpleGUI/Dev-latest
Test eCookbook Integration
2022-06-30 15:30:44 -04:00
PySimpleGUI
05fd8ca891 Test eCookbook Integration 2022-06-30 15:30:25 -04:00
PySimpleGUI
0ed90a1dfd
Merge pull request #5652 from PySimpleGUI/Dev-latest
Added justification parameter to Listbox Element
2022-06-27 13:34:48 -04:00
PySimpleGUI
43ea63bb7c Added justification parameter to Listbox Element 2022-06-27 13:34:25 -04:00
PySimpleGUI
be574eeb83
Merge pull request #5650 from PySimpleGUI/Dev-latest
Added background_color parm to vtop, vcenter, vbottom helper function…
2022-06-25 08:43:19 -04:00
PySimpleGUI
533ab49c90 Added background_color parm to vtop, vcenter, vbottom helper functions. Added USING the expand_x and expand_y parms to vcenter and vbottom that were in the definition but unused 2022-06-25 06:06:31 -04:00
PySimpleGUI
63d15e9903
Merge pull request #5643 from PySimpleGUI/Dev-latest
Addition of Window.set_size to SDK Call Reference doc
2022-06-24 09:35:27 -04:00
PySimpleGUI
3113cc6d36 Addition of Window.set_size to SDK Call Reference doc 2022-06-24 09:35:07 -04:00
PySimpleGUI
0e8680ce78
Merge pull request #5642 from PySimpleGUI/Dev-latest
Fix for ColorChooser Button filling in None when dialog is cancelled
2022-06-24 09:15:24 -04:00
PySimpleGUI
73d65ffdc1 Fix for ColorChooser Button filling in None when dialog is cancelled 2022-06-24 09:15:05 -04:00
PySimpleGUI
371a883edc
Merge pull request #5641 from PySimpleGUI/Dev-latest
Dev latest
2022-06-23 17:44:53 -04:00
PySimpleGUI
2f706252a0 Added Window.set_size to make the API more rounded out. The Window.size property can still be used as well 2022-06-23 17:44:35 -04:00
PySimpleGUI
0b8ca5257f Use path of __file__ to indicate where the font is stored 2022-06-23 17:44:00 -04:00
PySimpleGUI
3f76d680e1
Merge pull request #5632 from PySimpleGUI/Dev-latest
Simplified code. Made font size selectable using a slider. Removed US…
2022-06-22 15:46:10 -04:00
PySimpleGUI
b65b451c60 Simplified code. Made font size selectable using a slider. Removed USING_QT code. Window now resizable so that font resizing works 2022-06-22 15:45:52 -04:00
PySimpleGUI
4591fb7ac8
Merge pull request #5631 from PySimpleGUI/Dev-latest
Dev latest
2022-06-22 14:34:56 -04:00
PySimpleGUI
62caa3b06e Another movement control for use with "control key". Like the Control+Mouse Drag can move any PySimpleGUI Window, now Control+Arrow will move the window 1 pixel in the indicated direction. These can be turned off in the same way the control drag is enabled/disabled. 2022-06-22 14:34:40 -04:00
PySimpleGUI
8835067a0a Removed a readme doc that's not needed 2022-06-22 14:32:10 -04:00
PySimpleGUI
5569ea7ec2
Merge pull request #5627 from PySimpleGUI/Dev-latest
Addition of try around event loop to catch errors generated by the We…
2022-06-21 15:32:32 -04:00
PySimpleGUI
03922d77b6 Addition of try around event loop to catch errors generated by the Weather API. Simplified/shortened the version information at the bottom 2022-06-21 15:32:17 -04:00
PySimpleGUI
bf2f17e1d9
Merge pull request #5621 from PySimpleGUI/Dev-latest
Delay rerouting stdout, stderr in Output Element and Multiline Elemen…
2022-06-20 05:25:32 -04:00
PySimpleGUI
a526b282cd Delay rerouting stdout, stderr in Output Element and Multiline Element until window is being built 2022-06-20 05:25:17 -04:00
PySimpleGUI
0b803ecd90
Merge pull request #5616 from PySimpleGUI/Dev-latest
Added suggesting use of Demo Browser in the checklist when opening a …
2022-06-18 05:47:15 -04:00
PySimpleGUI
28235c3c85 Added suggesting use of Demo Browser in the checklist when opening a GitHub issue using the built-in GitHub Issue GUI 2022-06-18 05:46:58 -04:00
PySimpleGUI
384bc816c6
Added Demo Browser suggestion to "check the Demo Programs" item 2022-06-18 05:41:15 -04:00
PySimpleGUI
679af95b0e
Merge pull request #5615 from PySimpleGUI/Dev-latest
Further refinement of Menubar's docstring to include font, disabled t…
2022-06-18 04:40:18 -04:00
PySimpleGUI
8a5d7631f8 Further refinement of Menubar's docstring to include font, disabled text color... 2022-06-18 04:39:46 -04:00
PySimpleGUI
194c745e24
Merge pull request #5614 from PySimpleGUI/Dev-latest
Updated call reference doc to match latest docstring changes
2022-06-18 04:32:43 -04:00
PySimpleGUI
6a49a1e68e Updated call reference doc to match latest docstring changes 2022-06-18 04:32:22 -04:00
PySimpleGUI
f04c3729a2
Merge pull request #5613 from PySimpleGUI/Dev-latest
Menubar docstring changed to clarify the bar itself cannot be styled.…
2022-06-18 04:31:12 -04:00
PySimpleGUI
3fa3b52634 Menubar docstring changed to clarify the bar itself cannot be styled. Changed file-signature format 2022-06-18 04:30:55 -04:00
PySimpleGUI
c0e2d8ab98
Merge pull request #5612 from PySimpleGUI/Dev-latest
Several changes - exception handling if problems with weather API.  R…
2022-06-17 04:41:48 -04:00
PySimpleGUI
47e7cfaa9a Several changes - exception handling if problems with weather API. Reshuffled the overall layout. Added a "friend" label if you're watching the weather where one of your friends is located. 2022-06-17 04:41:31 -04:00
PySimpleGUI
eafb9200f5
Merge pull request #5609 from PySimpleGUI/Dev-latest
Backed out previous changes to scrollable columns.  Added print if se…
2022-06-16 12:29:01 -04:00
PySimpleGUI
413cda0e58 Backed out previous changes to scrollable columns. Added print if setting alpha channel fails during initial window creation 2022-06-16 12:28:44 -04:00
PySimpleGUI
0f3db9e612
Merge pull request #5602 from PySimpleGUI/Dev-latest
New Demo Program - Save/Load window inputs using User Settings API (J…
2022-06-15 13:56:58 -04:00
PySimpleGUI
c37147df8c New Demo Program - Save/Load window inputs using User Settings API (JSON file) 2022-06-15 13:56:42 -04:00
PySimpleGUI
77b87a4ab9
Merge pull request #5601 from PySimpleGUI/Dev-latest
New signature format
2022-06-15 04:47:28 -04:00
PySimpleGUI
6e5b8a5385 New signature format 2022-06-15 04:47:08 -04:00
PySimpleGUI
6b42448a9d
Merge pull request #5597 from PySimpleGUI/Dev-latest
Addition of the standard "edit me" and "versions" right click menu
2022-06-12 17:44:28 -04:00
PySimpleGUI
0b911c451c Addition of the standard "edit me" and "versions" right click menu 2022-06-12 17:44:14 -04:00
PySimpleGUI
09cabec59b
Merge pull request #5596 from PySimpleGUI/Dev-latest
Freshened up the themes section.
2022-06-11 16:46:46 -04:00
PySimpleGUI
a3d4bc9261 Freshened up the themes section. 2022-06-11 16:46:27 -04:00
PySimpleGUI
3411eed910
Merge pull request #5594 from PySimpleGUI/Dev-latest
New Table member variable table_ttk_style_name
2022-06-11 09:28:58 -04:00
PySimpleGUI
581b5b6bc7 New Table member variable table_ttk_style_name 2022-06-11 09:28:44 -04:00
PySimpleGUI
c076bc71c4
Merge pull request #5593 from PySimpleGUI/Dev-latest
Dev latest
2022-06-11 09:03:26 -04:00
PySimpleGUI
aae8a54e2c New signature test 2022-06-11 09:03:12 -04:00
PySimpleGUI
f1f60b03a1 Got a few of the Demos up to date with changes standard to many demos (edit me, get versions for example) 2022-06-11 09:01:27 -04:00
PySimpleGUI
0ecf5e3a86
Merge pull request #5592 from PySimpleGUI/Dev-latest
Much needed update to the Demo Programs readme...
2022-06-11 07:42:59 -04:00
PySimpleGUI
dba12e59f2 Much needed update to the Demo Programs readme... 2022-06-11 07:42:43 -04:00
PySimpleGUI
074fc76936
Merge pull request #5590 from PySimpleGUI/Dev-latest
Addition of horizontal_scroll_only parameter for Column elements if s…
2022-06-09 12:58:06 -04:00
PySimpleGUI
ab5d97965b Addition of horizontal_scroll_only parameter for Column elements if scrollable column 2022-06-09 12:57:52 -04:00
PySimpleGUI
8bb44eadf5
Merge pull request #5588 from PySimpleGUI/Dev-latest
Added expand_x and expand_y to all of the shortcut buttons and Browse…
2022-06-09 12:10:05 -04:00
PySimpleGUI
01958bfc07 Added expand_x and expand_y to all of the shortcut buttons and Browser buttons 2022-06-09 12:09:50 -04:00
PySimpleGUI
2b2b2212ec
Merge pull request #5587 from PySimpleGUI/Dev-latest
Added to Button element error message about images that format must b…
2022-06-09 08:11:29 -04:00
PySimpleGUI
a65f6c7a1d Added to Button element error message about images that format must be PNG or GIF 2022-06-09 08:10:49 -04:00
PySimpleGUI
f3e7c9558c
Merge pull request #5583 from PySimpleGUI/Dev-latest
Addition of default_color to ColorChooserButton
2022-06-08 14:32:42 -04:00
PySimpleGUI
d2ef85154a Addition of default_color to ColorChooserButton 2022-06-08 14:32:27 -04:00
PySimpleGUI
50e34b3348
Merge pull request #5580 from PySimpleGUI/Dev-latest
popup_scrolled - addition of button_justification (added because movi…
2022-06-07 12:39:00 -04:00
PySimpleGUI
578f52b433 popup_scrolled - addition of button_justification (added because moving the button to left justified like the other popups, but want to retain the previous look should it be desired) 2022-06-07 12:38:30 -04:00
PySimpleGUI
ecd94860ad
Merge pull request #5579 from PySimpleGUI/Dev-latest
New Demo Program - Custom Checkboxes
2022-06-07 05:44:27 -04:00
PySimpleGUI
e71a18f207 New Demo Program - Custom Checkboxes 2022-06-07 05:44:06 -04:00
PySimpleGUI
b3f8f065d6
Merge pull request #5578 from PySimpleGUI/Dev-latest
Fix in popup_scrolled - was not adding the sizegrip all the time... w…
2022-06-06 14:51:35 -04:00
PySimpleGUI
06b8a97dc5 Fix in popup_scrolled - was not adding the sizegrip all the time... was only adding when no_titlebar. Also made sure it's on the last row instead of making a new row. Addition of no_buttons parameter. If True, no buttons will be included in the window. 2022-06-06 14:51:20 -04:00
PySimpleGUI
64c3c38c0b
Merge pull request #5577 from PySimpleGUI/Dev-latest
Wow... pycharm added a strange import!
2022-06-06 14:34:14 -04:00
PySimpleGUI
b717694e9c Wow... pycharm added a strange import! 2022-06-06 14:33:59 -04:00
PySimpleGUI
85a6a18c25
Merge pull request #5576 from PySimpleGUI/Dev-latest
Added erase_all parameter to cprint.  This works like the same parame…
2022-06-06 14:32:16 -04:00
PySimpleGUI
b8c97d43f6 Added erase_all parameter to cprint. This works like the same parameter as the Debug Print has 2022-06-06 14:32:00 -04:00
PySimpleGUI
05e44e6aa5
Merge pull request #5575 from PySimpleGUI/Dev-latest
Dev latest
2022-06-06 10:49:29 -04:00
PySimpleGUI
5dd1e48f04 New Demo Program - cursor previewer 2022-06-06 10:49:13 -04:00
PySimpleGUI
f837e05dc6 Updated Demo to use the new cursor constant 2022-06-06 10:48:57 -04:00
PySimpleGUI
dc799034fa Updated Cursor Constant List to be a sorted list 2022-06-06 10:48:37 -04:00
PySimpleGUI
5d44e439ed
Merge pull request #5574 from PySimpleGUI/Dev-latest
New constant TKINTER_CURSORS that is a list of the standard tkinter c…
2022-06-06 09:57:28 -04:00
PySimpleGUI
a979e1691e New constant TKINTER_CURSORS that is a list of the standard tkinter cursors 2022-06-06 09:57:11 -04:00
PySimpleGUI
76e7f1b39b
Merge pull request #5573 from PySimpleGUI/Dev-latest
Made upgrade from GitHub window resizable
2022-06-06 08:11:14 -04:00
PySimpleGUI
71fc4144bf Made upgrade from GitHub window resizable 2022-06-06 08:10:58 -04:00
PySimpleGUI
d6a772a9e8
Merge pull request #5571 from PySimpleGUI/Dev-latest
New Demo Program to show how the new enable_window_config_events para…
2022-06-05 14:29:20 -04:00
PySimpleGUI
4ff123583c New Demo Program to show how the new enable_window_config_events parameter works 2022-06-05 14:29:08 -04:00
PySimpleGUI
176812c9da
Merge pull request #5570 from PySimpleGUI/Dev-latest
Dev latest
2022-06-05 14:15:03 -04:00
PySimpleGUI
8e84b218d5 fixed typo in release notes 2022-06-05 14:14:49 -04:00
PySimpleGUI
4b768d72c6 Addition of enable_window_config_events to the Window object - returns an event when the window is moved or resized 2022-06-05 14:13:40 -04:00
PySimpleGUI
3531560b2a
Merge pull request #5564 from PySimpleGUI/Dev-latest
Fixed typo in formula.  Added normal Demo Program header. Changed axi…
2022-06-05 08:08:34 -04:00
PySimpleGUI
ae1fd61041 Fixed typo in formula. Added normal Demo Program header. Changed axis drawing to adapt to size of coordinate, Changed font sizes, Made title and sliders expand in X direction. Draw empty axis upon startup 2022-06-05 08:08:22 -04:00
PySimpleGUI
a2c824eaf1
Merge pull request #5562 from PySimpleGUI/Dev-latest
Removed the filetypes enable/disable from the Mac system settings.  A…
2022-06-04 17:11:01 -04:00
PySimpleGUI
c82747e8d4 Removed the filetypes enable/disable from the Mac system settings. Added fix for filetypes to popup_get_file for Macs 2022-06-04 17:10:47 -04:00
PySimpleGUI
62a3e3b867
Merge pull request #5561 from PySimpleGUI/Dev-latest
Replaced old "All Elements" example with the newest one!  Added a Rec…
2022-06-04 14:35:08 -04:00
PySimpleGUI
48a95eeb2e Replaced old "All Elements" example with the newest one! Added a Recipe showing several ways of handling exceptions in a PySimpleGUI program by using the Debug Print Window and an popup with traceback. 2022-06-04 14:34:56 -04:00
PySimpleGUI
ef6c82e164
Merge pull request #5560 from PySimpleGUI/Dev-latest
Added settings to the right click menu in addition to link in the win…
2022-06-04 13:18:23 -04:00
PySimpleGUI
fefd3949cf Added settings to the right click menu in addition to link in the window. Made Version Window location the same as the program's window. Added exception handling around main event loop that utilizes the Debug Print as a reporting mechanism since there is no console for these applications. Uses the new wait parameter for the debug print 2022-06-04 13:18:09 -04:00
PySimpleGUI
6e4b1aa5d4
Merge pull request #5558 from PySimpleGUI/Dev-latest
New Demo Program - Using User Settings as a Database
2022-06-04 11:56:23 -04:00
PySimpleGUI
0e0a03cdc0 New Demo Program - Using User Settings as a Database 2022-06-04 11:56:00 -04:00
PySimpleGUI
fa0d3e1bc7
Merge pull request #5557 from PySimpleGUI/Dev-latest
Updated docstring for the pin helper function
2022-06-04 07:18:53 -04:00
PySimpleGUI
0a5f252a8d Updated docstring for the pin helper function 2022-06-04 07:18:41 -04:00
PySimpleGUI
428d4d005c
Merge pull request #5555 from PySimpleGUI/Dev-latest
deprecated - note to self.. is spelled with an "E" not an "I"
2022-06-03 16:42:36 -04:00
PySimpleGUI
5be7bfde0f deprecated - note to self.. is spelled with an "E" not an "I" 2022-06-03 16:42:25 -04:00
PySimpleGUI
2d15591cd0
Merge pull request #5554 from PySimpleGUI/Dev-latest
TabGroup docstring update - visible marked as Depricated
2022-06-03 16:40:02 -04:00
PySimpleGUI
3e5ae43886 TabGroup docstring update - visible marked as Depricated 2022-06-03 16:39:48 -04:00
PySimpleGUI
f7c31ab1cf
Merge pull request #5553 from PySimpleGUI/Dev-latest
New logic for checking for the *.* situation for Mac filetypes
2022-06-03 12:23:44 -04:00
PySimpleGUI
cf408bbd98 New logic for checking for the *.* situation for Mac filetypes 2022-06-03 12:23:34 -04:00
PySimpleGUI
48c5cc836e
Merge pull request #5552 from PySimpleGUI/Dev-latest
Added * *.* to the Mac filetypes
2022-06-03 12:14:18 -04:00
PySimpleGUI
967a086605 Added * *.* to the Mac filetypes 2022-06-03 12:14:06 -04:00
PySimpleGUI
06b1b57f2f
Merge pull request #5550 from PySimpleGUI/Dev-latest
Added more specifications for * for Mac file_type testing
2022-06-03 10:58:32 -04:00
PySimpleGUI
55998c7c34 Added more specifications for * for Mac file_type testing 2022-06-03 10:58:21 -04:00
PySimpleGUI
831a7bf72e
Merge pull request #5547 from PySimpleGUI/Dev-latest
New Demo Program - Navigating focus using arrow keys on keyboard
2022-06-03 08:28:58 -04:00
PySimpleGUI
c502543038 New Demo Program - Navigating focus using arrow keys on keyboard 2022-06-03 08:28:26 -04:00
PySimpleGUI
5cc855ba6a
Merge pull request #5544 from PySimpleGUI/Dev-latest
Dev latest
2022-06-02 17:18:10 -04:00
PySimpleGUI
708eaeae91 Fixed "double" operation. Was including the header. Demonstrate that cols_justification can have illegal values 2022-06-02 17:17:54 -04:00
PySimpleGUI
6d163bb085 Better error handling for newly added column justification feature for Table element. Explicitly checks for "center" now instead of assuming not left and not right means center 2022-06-02 17:17:05 -04:00
PySimpleGUI
f3a745bb63
Merge pull request #5543 from PySimpleGUI/Dev-latest
Updated to show some of the newer parms
2022-06-02 13:26:32 -04:00
PySimpleGUI
8e999500ba Updated to show some of the newer parms 2022-06-02 13:26:19 -04:00
PySimpleGUI
4bf7932f76
Merge pull request #5542 from PySimpleGUI/Dev-latest
Table Element - addition of cols_justification parameter - list of st…
2022-06-02 13:12:58 -04:00
PySimpleGUI
4948e4f502 Table Element - addition of cols_justification parameter - list of strings that indicate how each column should be justified 2022-06-02 13:12:38 -04:00
PySimpleGUI
aa09d8c2a1
Merge pull request #5540 from PySimpleGUI/Dev-latest
Fix for bind_return_key when a button has been disabled.  Was generat…
2022-06-02 10:48:54 -04:00
PySimpleGUI
39e729c03b Fix for bind_return_key when a button has been disabled. Was generating an event. Now will not generate an event if a button is disabled. 2022-06-02 10:48:38 -04:00
PySimpleGUI
eddbe0843c
Merge pull request #5537 from PySimpleGUI/Dev-latest
New Udemy coupon (on top of the sale)... have fun kids!
2022-06-02 06:41:26 -04:00
PySimpleGUI
20924d97f9 New Udemy coupon (on top of the sale)... have fun kids! 2022-06-02 06:41:07 -04:00
PySimpleGUI
76af6444f8
Merge pull request #5536 from PySimpleGUI/Dev-latest
Added Edit Me to the test harness Right Click Menu
2022-06-01 21:39:23 -04:00
PySimpleGUI
3bc17e75a8 Added Edit Me to the test harness Right Click Menu 2022-06-01 21:39:09 -04:00
PySimpleGUI
834c286d54
Merge pull request #5533 from PySimpleGUI/Dev-latest
Update to the latest coding guidelines.  Use PPM encoding as it's bee…
2022-06-01 15:44:31 -04:00
PySimpleGUI
11319709e1 Update to the latest coding guidelines. Use PPM encoding as it's been shown to be more efficient 2022-06-01 15:44:19 -04:00
PySimpleGUI
313da2d5d5
Merge pull request #5532 from PySimpleGUI/Dev-latest
Dev latest
2022-06-01 14:09:59 -04:00
PySimpleGUI
051fa57d15 Changed bool logic for mac filetypes fix 2022-06-01 14:09:42 -04:00
PySimpleGUI
638cd0f97e A new approach for the Mac FileBrowse with file_type crash that doesn't use the system settings. 2022-06-01 13:59:59 -04:00
PySimpleGUI
a52db075d9
Merge pull request #5527 from PySimpleGUI/Dev-latest
Added platform and platform version to the get_versions function and …
2022-05-30 12:31:14 -04:00
PySimpleGUI
fc42b0d45c Added platform and platform version to the get_versions function and the psgver command 2022-05-30 12:30:53 -04:00
PySimpleGUI
ad5b82654f
Merge pull request #5526 from PySimpleGUI/Dev-latest
Fix for continuous mouse up events from Graph element when reading wi…
2022-05-29 18:58:02 -04:00
PySimpleGUI
1140e01230 Fix for continuous mouse up events from Graph element when reading with timeout=0 (THANK YOU @davesmivers for the find and fix!) 2022-05-29 18:57:49 -04:00
PySimpleGUI
18d656b0bd
Merge pull request #5525 from PySimpleGUI/Dev-latest
New Demo Program - using a Frame element to draw a "Recording Area" f…
2022-05-29 18:48:21 -04:00
PySimpleGUI
78fabef418 New Demo Program - using a Frame element to draw a "Recording Area" frame on the screen for making videos 2022-05-29 18:48:07 -04:00
PySimpleGUI
01d6561d35
Merge pull request #5524 from PySimpleGUI/Dev-latest
(None, None) added to Window docstring as a valid location parameter …
2022-05-29 18:43:29 -04:00
PySimpleGUI
f9c244dffe (None, None) added to Window docstring as a valid location parameter setting 2022-05-29 18:43:11 -04:00
PySimpleGUI
dbdefb3c10
Merge pull request #5522 from PySimpleGUI/Dev-latest
Addition of Window.ubind
2022-05-29 08:44:12 -04:00
PySimpleGUI
96a4e9a983 Addition of Window.ubind 2022-05-29 08:43:55 -04:00
PySimpleGUI
1b4ad34987
Merge pull request #5519 from PySimpleGUI/Dev-latest
New Graph Element - drag a square around with mouse... thanks to @dav…
2022-05-28 06:23:40 -04:00
PySimpleGUI
8f5b4793c2 New Graph Element - drag a square around with mouse... thanks to @davesmivers for original base code.... 2022-05-28 06:23:21 -04:00
PySimpleGUI
070fe55107
Merge pull request #5514 from PySimpleGUI/Dev-latest
Addition of wrap_lines to Multiline element.  Addition of wrap_lines …
2022-05-27 09:07:14 -04:00
PySimpleGUI
495dd3988d Addition of wrap_lines to Multiline element. Addition of wrap_lines and hotizontal_scroll to Output element 2022-05-27 09:06:58 -04:00
PySimpleGUI
24bde45954
Merge pull request #5510 from PySimpleGUI/Dev-latest
Fixed Spin element docstring - readonly was incorrect
2022-05-26 05:38:51 -04:00
PySimpleGUI
544e38be13 Fixed Spin element docstring - readonly was incorrect 2022-05-26 05:38:41 -04:00
PySimpleGUI
4d0d90eb18
Merge pull request #5509 from PySimpleGUI/Dev-latest
Added wrap parameter to the Spin element, added temporary code for a …
2022-05-26 05:23:42 -04:00
PySimpleGUI
84cf2611c0 Added wrap parameter to the Spin element, added temporary code for a verification feature 2022-05-26 05:23:31 -04:00
PySimpleGUI
16402d8b46
Merge pull request #5505 from PySimpleGUI/Dev-latest
Addition of Window.set_resizable
2022-05-24 06:23:58 -04:00
PySimpleGUI
1f5fb16bc4 Addition of Window.set_resizable 2022-05-24 06:23:43 -04:00
PySimpleGUI
6af5235283
Merge pull request #5500 from PySimpleGUI/Dev-latest
4.60.1 patch release added to release notes
2022-05-22 15:52:23 -04:00
PySimpleGUI
9f87cdbb25 4.60.1 patch release added to release notes 2022-05-22 15:52:09 -04:00
PySimpleGUI
22d8b7bcd4
Merge pull request #5496 from PySimpleGUI/Dev-latest
Addition of Push and element_justification Recipes
2022-05-21 06:57:33 -04:00
PySimpleGUI
8a8ae3df15 Addition of Push and element_justification Recipes 2022-05-21 06:57:21 -04:00
PySimpleGUI
e8794f1c5e
Merge pull request #5492 from PySimpleGUI/Dev-latest
Added readonly to Input.update - note to be careful with disable too
2022-05-20 15:25:28 -04:00
PySimpleGUI
562eb86fbc Added readonly to Input.update - note to be careful with disable too 2022-05-20 15:25:11 -04:00
PySimpleGUI
847430a509
Merge pull request #5491 from PySimpleGUI/Dev-latest
Fix for crash when specifying horizontal scroll in Listbox element
2022-05-19 17:47:09 -04:00
PySimpleGUI
b85ad8e12a Fix for crash when specifying horizontal scroll in Listbox element 2022-05-19 17:46:54 -04:00
PySimpleGUI
c99896edba
Merge pull request #5490 from PySimpleGUI/Dev-latest
Added a reminder to call contents_changed to the Column docstring
2022-05-19 16:38:20 -04:00
PySimpleGUI
48bb8fe24c Added a reminder to call contents_changed to the Column docstring 2022-05-19 16:38:05 -04:00
PySimpleGUI
ccd08b8e0a
Merge pull request #5489 from PySimpleGUI/Dev-latest
Show an error if None is specified as values parameter in Listbox ele…
2022-05-19 16:26:00 -04:00
PySimpleGUI
0ecc48f4f7 Show an error if None is specified as values parameter in Listbox element 2022-05-19 16:25:42 -04:00
PySimpleGUI
41e9e2121b
Merge pull request #5473 from PySimpleGUI/Dev-latest
Added Trinket specific code for Title and Menubar. Compressed entire …
2022-05-16 06:08:30 -04:00
PySimpleGUI
6ad6d6583f Added Trinket specific code for Title and Menubar. Compressed entire window just a tad to fit better onto small screens/Trinket 2022-05-16 06:08:06 -04:00
PySimpleGUI
151c85a52c
Merge pull request #5470 from PySimpleGUI/Dev-latest
New Window location parameter value of None will cause NO location to…
2022-05-15 12:39:42 -04:00
PySimpleGUI
303c3c0ad2 New Window location parameter value of None will cause NO location to be set for the window. The OS will decide. It's to help with the GNOME window manager issue 2022-05-15 12:39:31 -04:00
PySimpleGUI
0f6dc9de90
Merge pull request #5469 from PySimpleGUI/Dev-latest
Removed old code that used Popen and instead uses the PySimpleGUI Exe…
2022-05-14 15:10:41 -04:00
PySimpleGUI
a35687ac51 Removed old code that used Popen and instead uses the PySimpleGUI Exec API calls for an all-in-one demo. Added expansion of the Multilline and a SizeGrip so that it's obvious to user the window is resizable. 2022-05-14 15:10:37 -04:00
PySimpleGUI
5fa5adc73e
Merge pull request #5467 from PySimpleGUI/Dev-latest
Added new Mac Control Panel option to control accessing the file_type…
2022-05-13 09:52:46 -04:00
PySimpleGUI
6267f27f5b Added new Mac Control Panel option to control accessing the file_types parm in Browse and popup_get_file. Also removed the previous attempt to fix the Linux "jumping window" problem. 2022-05-13 09:52:35 -04:00
PySimpleGUI
00397d411f
Merge pull request #5464 from PySimpleGUI/Dev-latest
Added a wait_visibility call to fix the Linux "jumping window" proble…
2022-05-11 11:19:08 -04:00
PySimpleGUI
02fb5e7341 Added a wait_visibility call to fix the Linux "jumping window" problem.... highly experimental change (thank you chr0nic for your hard work) 2022-05-11 11:18:54 -04:00
PySimpleGUI
6096a5eeea
Merge pull request #5462 from PySimpleGUI/Dev-latest
Moved around the location the icon is set.  Set the icon using set_gl…
2022-05-10 09:15:20 -04:00
PySimpleGUI
04c6f88ecb Moved around the location the icon is set. Set the icon using set_global_icon so that popups also use the custom icohn 2022-05-10 09:15:09 -04:00
PySimpleGUI
e67527b2a4
Merge pull request #5461 from PySimpleGUI/Dev-latest
Addition of SizeGrip element (makes resizing the window oh-so-nice! A…
2022-05-09 17:00:47 -04:00
PySimpleGUI
7a74089157 Addition of SizeGrip element (makes resizing the window oh-so-nice! Also makes clear window is resizable) 2022-05-09 17:00:35 -04:00
PySimpleGUI
05f24d565a
Merge pull request #5454 from PySimpleGUI/Dev-latest
Fill in the details fields next to OS in the Open GitHub Issue function
2022-05-08 14:09:39 -04:00
PySimpleGUI
5ee22c0568 Fill in the details fields next to OS in the Open GitHub Issue function 2022-05-08 14:09:25 -04:00
360 changed files with 17720 additions and 8972 deletions

View file

@ -60,11 +60,13 @@ Anything else you think would be helpful?
These items may solve your problem. Please check those you've done by changing - [ ] to - [X] These items may solve your problem. Please check those you've done by changing - [ ] to - [X]
- [ ] Searched main docs for your problem www.PySimpleGUI.org - [ ] Searched main docs for your problem www.PySimpleGUI.org
- [ ] Looked for Demo Programs that are similar to your goal Demos.PySimpleGUI.org - [ ] Looked for Demo Programs that are similar to your goal. It is recommend you use the Demo Browser! Demos.PySimpleGUI.org
- [ ] None of your GUI code was generated by an AI algorithm like GPT
- [ ] If not tkinter - looked for Demo Programs for specific port - [ ] If not tkinter - looked for Demo Programs for specific port
- [ ] For non tkinter - Looked at readme for your specific port if not PySimpleGUI (Qt, WX, Remi) - [ ] For non tkinter - Looked at readme for your specific port if not PySimpleGUI (Qt, WX, Remi)
- [ ] Run your program outside of your debugger (from a command line) - [ ] Run your program outside of your debugger (from a command line)
- [ ] Searched through Issues (open and closed) to see if already reported Issues.PySimpleGUI.org - [ ] Searched through Issues (open and closed) to see if already reported Issues.PySimpleGUI.org
- [ ] Have upgraded to the latest release of PySimpleGUI on PyPI (lastest official version)
- [ ] Tried using the PySimpleGUI.py file on GitHub. Your problem may have already been fixed but not released - [ ] Tried using the PySimpleGUI.py file on GitHub. Your problem may have already been fixed but not released
#### Detailed Description #### Detailed Description

Binary file not shown.

Before

Width:  |  Height:  |  Size: 184 KiB

View file

@ -1,233 +0,0 @@
import PySimpleGUI as sg
import os
import sys
import chess
import chess.pgn
import copy
import chess.uci
CHESS_PATH = '.' # path to the chess pieces
BLANK = 0 # piece names
PAWNB = 1
KNIGHTB = 2
BISHOPB = 3
ROOKB = 4
KINGB = 5
QUEENB = 6
PAWNW = 7
KNIGHTW = 8
BISHOPW = 9
ROOKW = 10
KINGW = 11
QUEENW = 12
initial_board = [[ROOKB, KNIGHTB, BISHOPB, QUEENB, KINGB, BISHOPB, KNIGHTB, ROOKB],
[PAWNB, ] * 8,
[BLANK, ] * 8,
[BLANK, ] * 8,
[BLANK, ] * 8,
[BLANK, ] * 8,
[PAWNW, ] * 8,
[ROOKW, KNIGHTW, BISHOPW, QUEENW, KINGW, BISHOPW, KNIGHTW, ROOKW]]
blank = os.path.join(CHESS_PATH, 'blank.png')
bishopB = os.path.join(CHESS_PATH, 'nbishopb.png')
bishopW = os.path.join(CHESS_PATH, 'nbishopw.png')
pawnB = os.path.join(CHESS_PATH, 'npawnb.png')
pawnW = os.path.join(CHESS_PATH, 'npawnw.png')
knightB = os.path.join(CHESS_PATH, 'nknightb.png')
knightW = os.path.join(CHESS_PATH, 'nknightw.png')
rookB = os.path.join(CHESS_PATH, 'nrookb.png')
rookW = os.path.join(CHESS_PATH, 'nrookw.png')
queenB = os.path.join(CHESS_PATH, 'nqueenb.png')
queenW = os.path.join(CHESS_PATH, 'nqueenw.png')
kingB = os.path.join(CHESS_PATH, 'nkingb.png')
kingW = os.path.join(CHESS_PATH, 'nkingw.png')
images = {BISHOPB: bishopB, BISHOPW: bishopW, PAWNB: pawnB, PAWNW: pawnW, KNIGHTB: knightB, KNIGHTW: knightW,
ROOKB: rookB, ROOKW: rookW, KINGB: kingB, KINGW: kingW, QUEENB: queenB, QUEENW: queenW, BLANK: blank}
def open_pgn_file(filename):
pgn = open(filename)
first_game = chess.pgn.read_game(pgn)
moves = [move for move in first_game.main_line()]
return moves
def render_square(image, key, location):
if (location[0] + location[1]) % 2:
color = '#B58863'
else:
color = '#F0D9B5'
return sg.RButton('', image_filename=image, size=(1, 1), button_color=('white', color), pad=(0, 0), key=key)
def redraw_board(window, board):
for i in range(8):
for j in range(8):
color = '#B58863' if (i + j) % 2 else '#F0D9B5'
piece_image = images[board[i][j]]
elem = window.FindElement(key=(i, j))
elem.Update(button_color=('white', color),
image_filename=piece_image, )
def PlayGame():
menu_def = [['&File', ['&Open PGN File', 'E&xit']],
['&Help', '&About...'], ]
# sg.SetOptions(margins=(0,0))
sg.ChangeLookAndFeel('GreenTan')
# create initial board setup
psg_board = copy.deepcopy(initial_board)
# the main board display layout
board_layout = [[sg.T(' ')] + [sg.T('{}'.format(a), pad=((23, 27), 0), font='Any 13') for a in 'abcdefgh']]
# loop though board and create buttons with images
for i in range(8):
row = [sg.T(str(8 - i) + ' ', font='Any 13')]
for j in range(8):
piece_image = images[psg_board[i][j]]
row.append(render_square(piece_image, key=(i, j), location=(i, j)))
row.append(sg.T(str(8 - i) + ' ', font='Any 13'))
board_layout.append(row)
# add the labels across bottom of board
board_layout.append([sg.T(' ')] + [sg.T('{}'.format(a), pad=((23, 27), 0), font='Any 13') for a in 'abcdefgh'])
# setup the controls on the right side of screen
openings = (
'Any', 'Defense', 'Attack', 'Trap', 'Gambit', 'Counter', 'Sicillian', 'English', 'French', 'Queen\'s openings',
'King\'s Openings', 'Indian Openings')
board_controls = [[sg.RButton('New Game', key='New Game'), sg.RButton('Draw')],
[sg.RButton('Resign Game'), sg.RButton('Set FEN')],
[sg.RButton('Player Odds'), sg.RButton('Training')],
[sg.Drop(openings), sg.Text('Opening/Style')],
[sg.CBox('Play As White', key='_white_')],
[sg.Drop([2, 3, 4, 5, 6, 7, 8, 9, 10], size=(3, 1), key='_level_'), sg.Text('Difficulty Level')],
[sg.Text('Move List')],
[sg.Multiline([], do_not_clear=True, autoscroll=True, size=(15, 10), key='_movelist_')],
]
# layouts for the tabs
controls_layout = [[sg.Text('Performance Parameters', font='_ 20')],
[sg.T('Put stuff like AI engine tuning parms on this tab')]]
statistics_layout = [[sg.Text('Statistics', font=('_ 20'))],
[sg.T('Game statistics go here?')]]
board_tab = [[sg.Column(board_layout)]]
# the main window layout
layout = [[sg.Menu(menu_def, tearoff=False)],
[sg.TabGroup([[sg.Tab('Board', board_tab),
sg.Tab('Controls', controls_layout),
sg.Tab('Statistics', statistics_layout)]], title_color='red'),
sg.Column(board_controls)],
[sg.Text('Click anywhere on board for next move', font='_ 14')]]
window = sg.Window('Chess',
default_button_element_size=(12, 1),
auto_size_buttons=False,
icon='kingb.ico').Layout(layout)
filename = sg.PopupGetFile('\n'.join(('To begin, set location of AI EXE file',
'If you have not done so already, download the engine',
'Download the StockFish Chess engine at: https://stockfishchess.org/download/')),
file_types=(('Chess AI Engine EXE File', '*.exe'),))
if filename is None:
sys.exit()
engine = chess.uci.popen_engine(filename)
engine.uci()
info_handler = chess.uci.InfoHandler()
engine.info_handlers.append(info_handler)
board = chess.Board()
move_count = 1
move_state = move_from = move_to = 0
# ---===--- Loop taking in user input --- #
while not board.is_game_over():
if board.turn == chess.WHITE:
engine.position(board)
# human_player(board)
move_state = 0
while True:
button, value = window.Read()
if button in (None, 'Exit'):
exit()
if button == 'New Game':
sg.Popup('You have to restart the program to start a new game... sorry....')
break
psg_board = copy.deepcopy(initial_board)
redraw_board(window, psg_board)
move_state = 0
break
level = value['_level_']
if type(button) is tuple:
if move_state == 0:
move_from = button
row, col = move_from
piece = psg_board[row][col] # get the move-from piece
button_square = window.FindElement(key=(row, col))
button_square.Update(button_color=('white', 'red'))
move_state = 1
elif move_state == 1:
move_to = button
row, col = move_to
if move_to == move_from: # cancelled move
color = '#B58863' if (row + col) % 2 else '#F0D9B5'
button_square.Update(button_color=('white', color))
move_state = 0
continue
picked_move = '{}{}{}{}'.format('abcdefgh'[move_from[1]], 8 - move_from[0],
'abcdefgh'[move_to[1]], 8 - move_to[0])
if picked_move in [str(move) for move in board.legal_moves]:
board.push(chess.Move.from_uci(picked_move))
else:
print('Illegal move')
move_state = 0
color = '#B58863' if (move_from[0] + move_from[1]) % 2 else '#F0D9B5'
button_square.Update(button_color=('white', color))
continue
psg_board[move_from[0]][move_from[1]] = BLANK # place blank where piece was
psg_board[row][col] = piece # place piece in the move-to square
redraw_board(window, psg_board)
move_count += 1
window.FindElement('_movelist_').Update(picked_move + '\n', append=True)
break
else:
engine.position(board)
best_move = engine.go(searchmoves=board.legal_moves, depth=level, movetime=(level * 100)).bestmove
move_str = str(best_move)
from_col = ord(move_str[0]) - ord('a')
from_row = 8 - int(move_str[1])
to_col = ord(move_str[2]) - ord('a')
to_row = 8 - int(move_str[3])
window.FindElement('_movelist_').Update(move_str + '\n', append=True)
piece = psg_board[from_row][from_col]
psg_board[from_row][from_col] = BLANK
psg_board[to_row][to_col] = piece
redraw_board(window, psg_board)
board.push(best_move)
move_count += 1
sg.Popup('Game over!', 'Thank you for playing')
# Download the StockFish Chess engine at: https://stockfishchess.org/download/
# engine = chess.uci.popen_engine(r'E:\DownloadsE\stockfish-9-win\Windows\stockfish_9_x64.exe')
# engine.uci()
# info_handler = chess.uci.InfoHandler()
# engine.info_handlers.append(info_handler)
# level = 2
PlayGame()

View file

@ -1,160 +0,0 @@
import PySimpleGUI as sg
import os
import chess
import chess.pgn
import copy
import time
button_names = ('close', 'cookbook', 'cpu', 'github', 'pysimplegui', 'run', 'storage', 'timer')
CHESS_PATH = '.' # path to the chess pieces
BLANK = 0 # piece names
PAWNB = 1
KNIGHTB = 2
BISHOPB = 3
ROOKB = 4
KINGB = 5
QUEENB = 6
PAWNW = 7
KNIGHTW = 8
BISHOPW = 9
ROOKW = 10
KINGW = 11
QUEENW = 12
initial_board = [[ROOKB, KNIGHTB, BISHOPB, KINGB, QUEENB, BISHOPB, KNIGHTB, ROOKB ],
[PAWNB,]*8,
[BLANK,]*8,
[BLANK,]*8,
[BLANK,]*8,
[BLANK,]*8,
[PAWNW,]*8,
[ROOKW, KNIGHTW, BISHOPW, KINGW, QUEENW, BISHOPW, KNIGHTW, ROOKW]]
blank = os.path.join(CHESS_PATH, 'blank.png')
bishopB = os.path.join(CHESS_PATH, 'nbishopb.png')
bishopW = os.path.join(CHESS_PATH, 'nbishopw.png')
pawnB = os.path.join(CHESS_PATH, 'npawnb.png')
pawnW = os.path.join(CHESS_PATH, 'npawnw.png')
knightB = os.path.join(CHESS_PATH, 'nknightb.png')
knightW = os.path.join(CHESS_PATH, 'nknightw.png')
rookB = os.path.join(CHESS_PATH, 'nrookb.png')
rookW = os.path.join(CHESS_PATH, 'nrookw.png')
queenB = os.path.join(CHESS_PATH, 'nqueenB.png')
queenW = os.path.join(CHESS_PATH, 'nqueenW.png')
kingB = os.path.join(CHESS_PATH, 'nkingb.png')
kingW = os.path.join(CHESS_PATH, 'nkingw.png')
images = {BISHOPB: bishopB, BISHOPW: bishopW, PAWNB: pawnB, PAWNW: pawnW, KNIGHTB: knightB, KNIGHTW: knightW,
ROOKB: rookB, ROOKW: rookW, KINGB: kingB, KINGW: kingW, QUEENB: queenB, QUEENW: queenW, BLANK: blank}
def open_pgn_file(filename):
pgn = open(filename)
first_game = chess.pgn.read_game(pgn)
moves = [move for move in first_game.main_line()]
return moves
def render_square(image, key, location):
if (location[0] + location[1]) % 2:
color = '#B58863'
else:
color = '#F0D9B5'
return sg.RButton('', image_filename=image, size=(1, 1), button_color=('white', color), pad=(0, 0), key=key)
def redraw_board(window, board):
for i in range(8):
for j in range(8):
color = '#B58863' if (i+j) % 2 else '#F0D9B5'
piece_image = images[board[i][j]]
elem = window.FindElement(key=(i,j))
elem.Update(button_color = ('white', color),
image_filename=piece_image,)
def PlayGame():
menu_def = [['&File', ['&Open PGN File', 'E&xit' ]],
['&Help', '&About...'],]
# sg.SetOptions(margins=(0,0))
sg.ChangeLookAndFeel('GreenTan')
# create initial board setup
board = copy.deepcopy(initial_board)
# the main board display layout
board_layout = [[sg.T(' ')] + [sg.T('{}'.format(a), pad=((23,27),0), font='Any 13') for a in 'abcdefgh']]
# loop though board and create buttons with images
for i in range(8):
row = [sg.T(str(8-i)+' ', font='Any 13')]
for j in range(8):
piece_image = images[board[i][j]]
row.append(render_square(piece_image, key=(i,j), location=(i,j)))
row.append(sg.T(str(8-i)+' ', font='Any 13'))
board_layout.append(row)
# add the labels across bottom of board
board_layout.append([sg.T(' ')] + [sg.T('{}'.format(a), pad=((23,27),0), font='Any 13') for a in 'abcdefgh'])
# setup the controls on the right side of screen
openings = ('Any', 'Defense', 'Attack', 'Trap', 'Gambit','Counter', 'Sicillian', 'English','French', 'Queen\'s openings', 'King\'s Openings','Indian Openings')
board_controls = [[sg.RButton('New Game', key='Open PGN File'), sg.RButton('Draw')],
[sg.RButton('Resign Game'), sg.RButton('Set FEN')],
[sg.RButton('Player Odds'),sg.RButton('Training') ],
[sg.Drop(openings),sg.Text('Opening/Style')],
[sg.CBox('Play a White', key='_white_')],
[sg.Text('Move List')],
[sg.Multiline([], do_not_clear=True, autoscroll=True, size=(15,10),key='_movelist_')],]
# layouts for the tabs
controls_layout = [[sg.Text('Performance Parameters', font='_ 20')],
[sg.T('Put stuff like AI engine tuning parms on this tab')]]
statistics_layout = [[sg.Text('Statistics', font=('_ 20'))],
[sg.T('Game statistics go here?')]]
board_tab = [[sg.Column(board_layout)]]
# the main window layout
layout = [[sg.Menu(menu_def, tearoff=False)],
[sg.TabGroup([[sg.Tab('Board',board_tab),
sg.Tab('Controls', controls_layout),
sg.Tab('Statistics', statistics_layout)]], title_color='red'),
sg.Column(board_controls)],
[sg.Text('Click anywhere on board for next move', font='_ 14')]]
window = sg.Window('Chess', default_button_element_size=(12,1), auto_size_buttons=False, icon='kingb.ico').Layout(layout)
# ---===--- Loop taking in user input --- #
i = 0
moves = None
while True:
button, value = window.Read()
if button in (None, 'Exit'):
break
if button == 'Open PGN File':
filename = sg.PopupGetFile('', no_window=True)
if filename is not None:
moves = open_pgn_file(filename)
i = 0
board = copy.deepcopy(initial_board)
window.FindElement('_movelist_').Update(value='')
if button == 'About...':
sg.Popup('Powerd by Engine Kibitz Chess Engine')
if type(button) is tuple and moves is not None and i < len(moves):
move = moves[i] # get the current move
window.FindElement('_movelist_').Update(value='{} {}\n'.format(i+1, str(move)), append=True)
move_from = move.from_square # parse the move-from and move-to squares
move_to = move.to_square
row, col = move_from // 8, move_from % 8
piece = board[row][col] # get the move-from piece
button = window.FindElement(key=(row,col))
for x in range(3):
button.Update(button_color = ('white' , 'red' if x % 2 else 'white'))
window.Refresh()
time.sleep(.05)
board[row][col] = BLANK # place blank where piece was
row, col = move_to // 8, move_to % 8 # compute move-to square
board[row][col] = piece # place piece in the move-to square
redraw_board(window, board)
i += 1
PlayGame()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

View file

@ -1,36 +0,0 @@
[Event "Wch U12"]
[Site "Duisburg"]
[Date "1992.??.??"]
[Round "1"]
[White "Malakhov, Vladimir"]
[Black "Ab Rahman, M."]
[Result "1-0"]
[WhiteElo ""]
[BlackElo ""]
[ECO "A05"]
1.Nf3 Nf6 2.b3 g6 3.Bb2 Bg7 4.g3 d6 5.Bg2 O-O 6.O-O c6 7.d3 e5 8.c4 Ne8 9.Nbd2 f5
10.Qc2 Na6 11.c5 Nxc5 12.Nxe5 Qe7 13.d4 Na6 14.Qc4+ Kh8 15.Nef3 Be6 16.Qc3 f4
17.gxf4 Rxf4 18.Qe3 Rf8 19.Ng5 Nec7 20.Nc4 Rae8 21.Nxe6 Qxe6 22.Qxe6 Rxe6
23.e3 d5 24.Ne5 g5 25.Ba3 Rff6 26.Bh3 Re8 27.Bd7 Rd8 28.Be7 Rxd7 29.Bxf6 1-0
[Event "Wch U12"]
[Site "Duisburg"]
[Date "1992.??.??"]
[Round "2"]
[White "Malakhov, Vladimir"]
[Black "Berescu, Alin"]
[Result "1-0"]
[WhiteElo ""]
[BlackElo ""]
[ECO "D05"]
1.d4 Nf6 2.Nd2 d5 3.Ngf3 e6 4.e3 c5 5.c3 Nbd7 6.Bd3 Bd6 7.O-O O-O 8.Re1 b6
9.e4 dxe4 10.Nxe4 Be7 11.Ne5 Bb7 12.Ng5 g6 13.Qe2 Nxe5 14.dxe5 Nh5 15.Ne4 Qd5
16.f4 Rfd8 17.Bc2 Qc6 18.Be3 Rd7 19.Rad1 Rad8 20.Rxd7 Rxd7 21.Nd2 Ng7 22.Be4 Qc8
23.g4 Qd8 24.Bxb7 Rxb7 25.Ne4 Rd7 26.c4 h5 27.h3 h4 28.Kh2 Ne8 29.f5 Qc7
30.Bf4 Rd4 31.Qf2 Rxc4 32.f6 Qb7 33.Ng5 Bf8 34.b3 Rc3 35.Qd2 Rf3 36.Nxf3 Qxf3
37.Qe3 Qd5 38.Qe4 Qd7 39.Qf3 Nc7 40.Rd1 Nd5 41.Bg5 Qc7 42.Re1 b5 43.Qd1 c4
44.Qc1 Bb4 45.Bd2 Bxd2 46.Qxd2 Nxf6 47.bxc4 bxc4 48.Qd6 Qa5 49.Rf1 Nd5 50.Qd7 Qd2+
51.Kh1 f5 52.exf6 1-0

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 797 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

View file

@ -1,16 +0,0 @@
# PySimpleGUI-Chess A Chess Game Playback Program
![image](https://user-images.githubusercontent.com/46163555/64135781-4c58a600-cdba-11e9-968d-60ddfb4c8952.png)
## Introduction
This is the start of a front-end GUI for an AI engine that plays chess. It simply reads moves the a PGN file and steps through it showing each of the moves on the board.
To play against the AI run the program
Demo_Chess_AGAINST_AI.py
Locate where the pacakge was installed and run the programs from that folder. You need to run from the installed folder so that the images of the chess pieces are located.
## Home Page (GitHub)
[www.PySimpleGUI.com](www.PySimpleGUI.com)

View file

@ -1,2 +0,0 @@
PySimpleGUI==3.9.1
python-chess==0.23.9

Binary file not shown.

Before

Width:  |  Height:  |  Size: 725 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 933 B

View file

@ -5,7 +5,7 @@ import warnings
import PySimpleGUI as sg import PySimpleGUI as sg
__version__ = '1.7.0' __version__ = '1.12.2'
""" """
PySimpleGUI Demo Program Browser PySimpleGUI Demo Program Browser
@ -33,9 +33,15 @@ __version__ = '1.7.0'
Keeps a "history" of the previously chosen folders to easy switching between projects Keeps a "history" of the previously chosen folders to easy switching between projects
Versions:
1.8.0 - Addition of option to show ALL file types, not just Python files
1.12.0 - Fix for problem with spaces in filename and using an editor specified in the demo program settings
1.12.2 - Better error handling for no editor configured
Copyright 2021, 2022 PySimpleGUI.org Copyright 2021, 2022 PySimpleGUI.org
""" """
python_only = True
def get_file_list_dict(): def get_file_list_dict():
""" """
Returns dictionary of files Returns dictionary of files
@ -50,7 +56,7 @@ def get_file_list_dict():
demo_files_dict = {} demo_files_dict = {}
for dirname, dirnames, filenames in os.walk(demo_path): for dirname, dirnames, filenames in os.walk(demo_path):
for filename in filenames: for filename in filenames:
if filename.endswith('.py') or filename.endswith('.pyw'): if python_only is not True or filename.endswith('.py') or filename.endswith('.pyw'):
fname_full = os.path.join(dirname, filename) fname_full = os.path.join(dirname, filename)
if filename not in demo_files_dict.keys(): if filename not in demo_files_dict.keys():
demo_files_dict[filename] = fname_full demo_files_dict[filename] = fname_full
@ -456,7 +462,7 @@ def make_window():
left_col = sg.Column([ left_col = sg.Column([
[sg.Listbox(values=get_file_list(), select_mode=sg.SELECT_MODE_EXTENDED, size=(50,20), bind_return_key=True, key='-DEMO LIST-')], [sg.Listbox(values=get_file_list(), select_mode=sg.SELECT_MODE_EXTENDED, size=(50,20), bind_return_key=True, key='-DEMO LIST-', expand_x=True, expand_y=True)],
[sg.Text('Filter (F1):', tooltip=filter_tooltip), sg.Input(size=(25, 1), focus=True, enable_events=True, key='-FILTER-', tooltip=filter_tooltip), [sg.Text('Filter (F1):', tooltip=filter_tooltip), sg.Input(size=(25, 1), focus=True, enable_events=True, key='-FILTER-', tooltip=filter_tooltip),
sg.T(size=(15,1), k='-FILTER NUMBER-')], sg.T(size=(15,1), k='-FILTER NUMBER-')],
[sg.Button('Run'), sg.B('Edit'), sg.B('Clear'), sg.B('Open Folder'), sg.B('Copy Path')], [sg.Button('Run'), sg.B('Edit'), sg.B('Clear'), sg.B('Open Folder'), sg.B('Copy Path')],
@ -468,7 +474,7 @@ def make_window():
[sg.Text('Find (F3):', tooltip=find_re_tooltip), sg.Input(size=(25, 1),key='-FIND RE-', tooltip=find_re_tooltip),sg.B('Find RE')]], k='-RE COL-')) [sg.Text('Find (F3):', tooltip=find_re_tooltip), sg.Input(size=(25, 1),key='-FIND RE-', tooltip=find_re_tooltip),sg.B('Find RE')]], k='-RE COL-'))
right_col = [ right_col = [
[sg.Multiline(size=(70, 21), write_only=True, key=ML_KEY, reroute_stdout=True, echo_stdout_stderr=True, reroute_cprint=True)], [sg.Multiline(size=(70, 21), write_only=True, expand_x=True, expand_y=True, key=ML_KEY, reroute_stdout=True, echo_stdout_stderr=True, reroute_cprint=True)],
[sg.B('Settings'), sg.Button('Exit')], [sg.B('Settings'), sg.Button('Exit')],
[sg.T('Demo Browser Ver ' + __version__)], [sg.T('Demo Browser Ver ' + __version__)],
[sg.T('PySimpleGUI ver ' + sg.version.split(' ')[0] + ' tkinter ver ' + sg.tclversion_detailed, font='Default 8', pad=(0,0))], [sg.T('PySimpleGUI ver ' + sg.version.split(' ')[0] + ' tkinter ver ' + sg.tclversion_detailed, font='Default 8', pad=(0,0))],
@ -479,7 +485,8 @@ def make_window():
options_at_bottom = sg.pin(sg.Column([[sg.CB('Verbose', enable_events=True, k='-VERBOSE-', tooltip='Enable to see the matches in the right hand column'), options_at_bottom = sg.pin(sg.Column([[sg.CB('Verbose', enable_events=True, k='-VERBOSE-', tooltip='Enable to see the matches in the right hand column'),
sg.CB('Show only first match in file', default=True, enable_events=True, k='-FIRST MATCH ONLY-', tooltip='Disable to see ALL matches found in files'), sg.CB('Show only first match in file', default=True, enable_events=True, k='-FIRST MATCH ONLY-', tooltip='Disable to see ALL matches found in files'),
sg.CB('Find ignore case', default=True, enable_events=True, k='-IGNORE CASE-'), sg.CB('Find ignore case', default=True, enable_events=True, k='-IGNORE CASE-'),
sg.CB('Wait for Runs to Complete', default=False, enable_events=True, k='-WAIT-') sg.CB('Wait for Runs to Complete', default=False, enable_events=True, k='-WAIT-'),
sg.CB('Show ALL file types', default=not python_only, enable_events=True, k='-SHOW ALL FILES-'),
]], ]],
pad=(0,0), k='-OPTIONS BOTTOM-', expand_x=True, expand_y=False), expand_x=True, expand_y=False) pad=(0,0), k='-OPTIONS BOTTOM-', expand_x=True, expand_y=False), expand_x=True, expand_y=False)
@ -490,16 +497,15 @@ def make_window():
layout = [[sg.Text('PySimpleGUI Demo Program & Project Browser', font='Any 20')], layout = [[sg.Text('PySimpleGUI Demo Program & Project Browser', font='Any 20')],
[choose_folder_at_top], [choose_folder_at_top],
# [sg.Column([[left_col],[ lef_col_find_re]], element_justification='l', expand_x=True, expand_y=True), sg.Column(right_col, element_justification='c', expand_x=True, expand_y=True)], # [sg.Column([[left_col],[ lef_col_find_re]], element_justification='l', expand_x=True, expand_y=True), sg.Column(right_col, element_justification='c', expand_x=True, expand_y=True)],
[sg.Pane([sg.Column([[left_col],[ lef_col_find_re]], element_justification='l', expand_x=True, expand_y=True), sg.Column(right_col, element_justification='c', expand_x=True, expand_y=True) ], orientation='h', relief=sg.RELIEF_SUNKEN, k='-PANE-')], [sg.Pane([sg.Column([[left_col],[ lef_col_find_re]], element_justification='l', expand_x=True, expand_y=True), sg.Column(right_col, element_justification='c', expand_x=True, expand_y=True) ], orientation='h', relief=sg.RELIEF_SUNKEN, expand_x=True, expand_y=True, k='-PANE-')],
[options_at_bottom]] [options_at_bottom, sg.Sizegrip()]]
# --------------------------------- Create Window --------------------------------- # --------------------------------- Create Window ---------------------------------
window = sg.Window('PSG Demo & Project Browser', layout, finalize=True, resizable=True, use_default_focus=False, right_click_menu=sg.MENU_RIGHT_CLICK_EDITME_VER_EXIT) window = sg.Window('PSG Demo & Project Browser', layout, finalize=True, resizable=True, use_default_focus=False, right_click_menu=sg.MENU_RIGHT_CLICK_EDITME_VER_EXIT)
window.set_min_size(window.size) window.set_min_size(window.size)
window['-DEMO LIST-'].expand(True, True, True)
window[ML_KEY].expand(True, True, True) # window.bind("<Alt_L><x>", 'Exit') # matches the underscore shown on the Exit button (For now disabled this feature until buttons with underscore released to PyPI)
window['-PANE-'].expand(True, True, True)
window.bind('<F1>', '-FOCUS FILTER-') window.bind('<F1>', '-FOCUS FILTER-')
window.bind('<F2>', '-FOCUS FIND-') window.bind('<F2>', '-FOCUS FIND-')
@ -521,11 +527,12 @@ def main():
The main program that contains the event loop. The main program that contains the event loop.
It will call the make_window function to create the window. It will call the make_window function to create the window.
""" """
global python_only
try: try:
version = sg.version version = sg.version
version_parts = version.split('.') version_parts = version.split('.')
major_version, minor_version = int(version_parts[0]), int(version_parts[1]) major_version, minor_version = int(version_parts[0]), int(version_parts[1])
if major_version < 4 or minor_version < 32: if major_version < 4 or (major_version== 4 and minor_version < 32):
sg.popup('Warning - Your PySimpleGUI version is less then 4.35.0', sg.popup('Warning - Your PySimpleGUI version is less then 4.35.0',
'As a result, you will not be able to use the EDIT features of this program', 'As a result, you will not be able to use the EDIT features of this program',
'Please upgrade to at least 4.35.0', 'Please upgrade to at least 4.35.0',
@ -570,16 +577,16 @@ def main():
sg.cprint(f'Editing using {editor_program}', c='white on red', end='') sg.cprint(f'Editing using {editor_program}', c='white on red', end='')
sg.cprint('') sg.cprint('')
sg.cprint(f'{full_filename}', c='white on purple') sg.cprint(f'{full_filename}', c='white on purple')
# if line != 1: if not get_editor():
if using_local_editor(): sg.popup_error_with_traceback('No editor has been configured', 'You need to configure an editor in order to use this feature', 'You can configure the editor in the Demo Brower Settings or the PySimpleGUI Global Settings')
sg.execute_command_subprocess(editor_program, full_filename)
else: else:
try: if using_local_editor():
sg.execute_editor(full_filename, line_number=int(line)) sg.execute_command_subprocess(editor_program, f'"{full_filename}"')
except: else:
sg.execute_command_subprocess(editor_program, full_filename) try:
# else: sg.execute_editor(full_filename, line_number=int(line))
# sg.execute_editor(full_filename) except:
sg.execute_command_subprocess(editor_program, f'"{full_filename}"')
else: else:
sg.cprint('Editing canceled') sg.cprint('Editing canceled')
elif event == 'Run': elif event == 'Run':
@ -717,6 +724,17 @@ def main():
sg.clipboard_set(full_filename) sg.clipboard_set(full_filename)
elif event == 'Version': elif event == 'Version':
sg.popup_scrolled(sg.get_versions(), keep_on_top=True, non_blocking=True) sg.popup_scrolled(sg.get_versions(), keep_on_top=True, non_blocking=True)
elif event == '-SHOW ALL FILES-':
python_only = not values[event]
file_list_dict = get_file_list_dict()
file_list = get_file_list()
window['-DEMO LIST-'].update(values=file_list)
window['-FILTER NUMBER-'].update(f'{len(file_list)} files')
window['-ML-'].update('')
window['-FIND NUMBER-'].update('')
window['-FIND-'].update('')
window['-FIND RE-'].update('')
window['-FILTER-'].update('')
window.close() window.close()

View file

@ -11,7 +11,7 @@
Displays the values dictionary entry for each element Displays the values dictionary entry for each element
And more! And more!
Copyright 2021 PySimpleGUI Copyright 2021, 2022, 2023 PySimpleGUI
""" """
import PySimpleGUI as sg import PySimpleGUI as sg
@ -36,7 +36,7 @@ def make_window(theme):
sg.Image(data=sg.DEFAULT_BASE64_LOADING_GIF, enable_events=True, key='-GIF-IMAGE-'),], sg.Image(data=sg.DEFAULT_BASE64_LOADING_GIF, enable_events=True, key='-GIF-IMAGE-'),],
[sg.Checkbox('Checkbox', default=True, k='-CB-')], [sg.Checkbox('Checkbox', default=True, k='-CB-')],
[sg.Radio('Radio1', "RadioDemo", default=True, size=(10,1), k='-R1-'), sg.Radio('Radio2', "RadioDemo", default=True, size=(10,1), k='-R2-')], [sg.Radio('Radio1', "RadioDemo", default=True, size=(10,1), k='-R1-'), sg.Radio('Radio2', "RadioDemo", default=True, size=(10,1), k='-R2-')],
[sg.Combo(values=('Combo 1', 'Combo 2', 'Combo 3'), default_value='Combo 1', readonly=True, k='-COMBO-'), [sg.Combo(values=('Combo 1', 'Combo 2', 'Combo 3'), default_value='Combo 1', readonly=False, k='-COMBO-'),
sg.OptionMenu(values=('Option 1', 'Option 2', 'Option 3'), k='-OPTION MENU-'),], sg.OptionMenu(values=('Option 1', 'Option 2', 'Option 3'), k='-OPTION MENU-'),],
[sg.Spin([i for i in range(1,11)], initial_value=10, k='-SPIN-'), sg.Text('Spin')], [sg.Spin([i for i in range(1,11)], initial_value=10, k='-SPIN-'), sg.Text('Spin')],
[sg.Multiline('Demo of a Multi-Line Text Element!\nLine 2\nLine 3\nLine 4\nLine 5\nLine 6\nLine 7\nYou get the point.', size=(45,5), expand_x=True, expand_y=True, k='-MLINE-')], [sg.Multiline('Demo of a Multi-Line Text Element!\nLine 2\nLine 3\nLine 4\nLine 5\nLine 6\nLine 7\nYou get the point.', size=(45,5), expand_x=True, expand_y=True, k='-MLINE-')],
@ -88,20 +88,17 @@ def make_window(theme):
]] ]]
layout[-1].append(sg.Sizegrip()) layout[-1].append(sg.Sizegrip())
window = sg.Window('All Elements Demo', layout, right_click_menu=right_click_menu_def, right_click_menu_tearoff=True, grab_anywhere=True, resizable=True, margins=(0,0), use_custom_titlebar=True, finalize=True, keep_on_top=True, window = sg.Window('All Elements Demo', layout, right_click_menu=right_click_menu_def, right_click_menu_tearoff=True, grab_anywhere=True, resizable=True, margins=(0,0), use_custom_titlebar=True, finalize=True, keep_on_top=True)
# scaling=2.0,
)
window.set_min_size(window.size) window.set_min_size(window.size)
return window return window
def main(): def main():
window = make_window(sg.theme()) window = make_window(sg.theme())
# This is an Event Loop # This is an Event Loop
while True: while True:
event, values = window.read(timeout=100) event, values = window.read(timeout=100)
# keep an animation running so show things are happening # keep an animation running so show things are happening
window['-GIF-IMAGE-'].update_animation(sg.DEFAULT_BASE64_LOADING_GIF, time_between_frames=100)
if event not in (sg.TIMEOUT_EVENT, sg.WIN_CLOSED): if event not in (sg.TIMEOUT_EVENT, sg.WIN_CLOSED):
print('============ Event = ', event, ' ==============') print('============ Event = ', event, ' ==============')
print('-------- Values Dictionary (key=value) --------') print('-------- Values Dictionary (key=value) --------')
@ -110,7 +107,9 @@ def main():
if event in (None, 'Exit'): if event in (None, 'Exit'):
print("[LOG] Clicked Exit!") print("[LOG] Clicked Exit!")
break break
elif event == 'About':
window['-GIF-IMAGE-'].update_animation(sg.DEFAULT_BASE64_LOADING_GIF, time_between_frames=100)
if event == 'About':
print("[LOG] Clicked About!") print("[LOG] Clicked About!")
sg.popup('PySimpleGUI Demo All Elements', sg.popup('PySimpleGUI Demo All Elements',
'Right click anywhere to see right click menu', 'Right click anywhere to see right click menu',
@ -151,7 +150,7 @@ def main():
elif event == 'Edit Me': elif event == 'Edit Me':
sg.execute_editor(__file__) sg.execute_editor(__file__)
elif event == 'Versions': elif event == 'Versions':
sg.popup(sg.get_versions(), keep_on_top=True) sg.popup_scrolled(__file__, sg.get_versions(), keep_on_top=True, non_blocking=True)
window.close() window.close()
exit(0) exit(0)

View file

@ -8,7 +8,8 @@ import PySimpleGUI as sg
Copyright 2022 PySimpleGUI Copyright 2022 PySimpleGUI
""" """
use_custom_titlebar = False
use_custom_titlebar = True if sg.running_trinket() else False
def make_window(theme=None): def make_window(theme=None):
@ -50,7 +51,7 @@ def make_window(theme=None):
[name('Image'), sg.Image(sg.EMOJI_BASE64_HAPPY_THUMBS_UP)], [name('Image'), sg.Image(sg.EMOJI_BASE64_HAPPY_THUMBS_UP)],
[name('Graph'), sg.Graph((125, 50), (0,0), (125,50), k='-GRAPH-')] ] [name('Graph'), sg.Graph((125, 50), (0,0), (125,50), k='-GRAPH-')] ]
layout_r = [[name('Canvas'), sg.Canvas(background_color=sg.theme_button_color()[1], size=(125,50))], layout_r = [[name('Canvas'), sg.Canvas(background_color=sg.theme_button_color()[1], size=(125,40))],
[name('ProgressBar'), sg.ProgressBar(100, orientation='h', s=(10,20), k='-PBAR-')], [name('ProgressBar'), sg.ProgressBar(100, orientation='h', s=(10,20), k='-PBAR-')],
[name('Table'), sg.Table([[1,2,3], [4,5,6]], ['Col 1','Col 2','Col 3'], num_rows=2)], [name('Table'), sg.Table([[1,2,3], [4,5,6]], ['Col 1','Col 2','Col 3'], num_rows=2)],
[name('Tree'), sg.Tree(treedata, ['Heading',], num_rows=3)], [name('Tree'), sg.Tree(treedata, ['Heading',], num_rows=3)],
@ -68,9 +69,9 @@ def make_window(theme=None):
# Note - LOCAL Menu element is used (see about for how that's defined) # Note - LOCAL Menu element is used (see about for how that's defined)
layout = [[Menu([['File', ['Exit']], ['Edit', ['Edit Me', ]]], k='-CUST MENUBAR-',p=0)], layout = [[Menu([['File', ['Exit']], ['Edit', ['Edit Me', ]]], k='-CUST MENUBAR-',p=0)],
[sg.Checkbox('Use Custom Titlebar & Menubar', sg.theme_use_custom_titlebar(), enable_events=True, k='-USE CUSTOM TITLEBAR-')], [sg.T('PySimpleGUI Elements - Use Combo to Change Themes', font='_ 14', justification='c', expand_x=True)],
[sg.T('PySimpleGUI Elements - Use Combo to Change Themes', font='_ 18', justification='c', expand_x=True)], [sg.Checkbox('Use Custom Titlebar & Menubar', use_custom_titlebar, enable_events=True, k='-USE CUSTOM TITLEBAR-', p=0)],
[sg.Col(layout_l), sg.Col(layout_r)]] [sg.Col(layout_l, p=0), sg.Col(layout_r, p=0)]]
window = sg.Window('The PySimpleGUI Element List', layout, finalize=True, right_click_menu=sg.MENU_RIGHT_CLICK_EDITME_VER_EXIT, keep_on_top=True, use_custom_titlebar=use_custom_titlebar) window = sg.Window('The PySimpleGUI Element List', layout, finalize=True, right_click_menu=sg.MENU_RIGHT_CLICK_EDITME_VER_EXIT, keep_on_top=True, use_custom_titlebar=use_custom_titlebar)
@ -87,8 +88,7 @@ while True:
# sg.Print(event, values) # sg.Print(event, values)
if event == sg.WIN_CLOSED or event == 'Exit': if event == sg.WIN_CLOSED or event == 'Exit':
break break
if event == 'Edit Me':
sg.execute_editor(__file__)
if values['-COMBO-'] != sg.theme(): if values['-COMBO-'] != sg.theme():
sg.theme(values['-COMBO-']) sg.theme(values['-COMBO-'])
window.close() window.close()
@ -98,8 +98,10 @@ while True:
sg.set_options(use_custom_titlebar=use_custom_titlebar) sg.set_options(use_custom_titlebar=use_custom_titlebar)
window.close() window.close()
window = make_window() window = make_window()
if event == 'Edit Me':
sg.execute_editor(__file__)
elif event == 'Version': elif event == 'Version':
sg.popup_scrolled(sg.get_versions(), __file__, keep_on_top=True, non_blocking=True) sg.popup_scrolled(__file__, sg.get_versions(), keep_on_top=True, non_blocking=True)
window.close() window.close()

View file

@ -1,22 +1,21 @@
import PySimpleGUI as sg import PySimpleGUI as sg
import random import random
# Bars drawing in PySimpleGUI """
# Demo - Using a Graph Element to make Bar Charts
# .--.
# | | The Graph Element is very versatile. Because you can define your own
# .--.| |.--. coordinate system, it makes producing graphs of many lines (bar, line, etc) very
# | || || | straightforward.
# | || || |
# | || || | In this Demo a "bar" is nothing more than a rectangle drawn in a Graph Element (draw_rectangle).
# .--.| || || |
# .--.| || || || |.--. To make things a little more interesting, this is a barchart with that data values
# | || || || || || | placed as labels atop each bar, another Graph element method (draw_text)
# | || || || || || |
# .--.| || || || || || |.--. Copyright 2022 PySimpleGUI
# | || || || || || || || |.--. """
# | || || || || || || || || |
# '--''--''--''--''--''--''--''--''--'
BAR_WIDTH = 50 # width of each bar BAR_WIDTH = 50 # width of each bar
@ -38,12 +37,13 @@ while True:
graph.erase() graph.erase()
for i in range(7): for i in range(7):
graph_value = random.randint(0, GRAPH_SIZE[1]) graph_value = random.randint(0, GRAPH_SIZE[1]-25) # choose an int just short of the max value to give room for the label
graph.draw_rectangle(top_left=(i * BAR_SPACING + EDGE_OFFSET, graph_value), graph.draw_rectangle(top_left=(i * BAR_SPACING + EDGE_OFFSET, graph_value),
bottom_right=(i * BAR_SPACING + EDGE_OFFSET + BAR_WIDTH, 0), bottom_right=(i * BAR_SPACING + EDGE_OFFSET + BAR_WIDTH, 0),
fill_color=sg.theme_button_color()[1]) fill_color='green')
# fill_color=sg.theme_button_color()[1])
graph.draw_text(text=graph_value, location=(i*BAR_SPACING+EDGE_OFFSET+25, graph_value+10)) graph.draw_text(text=graph_value, location=(i*BAR_SPACING+EDGE_OFFSET+25, graph_value+10), font='_ 14')
# Normally at the top of the loop, but because we're drawing the graph first, making it at the bottom # Normally at the top of the loop, but because we're drawing the graph first, making it at the bottom
event, values = window.read() event, values = window.read()

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,79 @@
import PySimpleGUI as sg
"""
Demo Program - Simulated Buttons with Mouseover Highlights
The purpose of this demo is to teach you 5 unique PySimpleGUI constructs that when combined
create a "Button" that highlights on mouseover regarless of the Operating System.
Because of how tktiner works, mouseover highlighting is inconsistent across operating systems for Buttons.
This is one (dare I say "clever") way to get this effect in your program
1. Binding the Enter and Leave tkinter events
2. Using Tuples as keys
3. Using List Comprehensions to build a layout
4. Using Text Elements to Simulate Buttons
5. Using a "User Defined Element" to make what appears to be a new type of Button in the layout
The KEY to making this work simply is these "Buttons" have a tuple as a key.
The format of the key is ('-B-', button_text)
An element's bind method will make a tuple if the original key is a tuple.
(('-B-', button_text), 'ENTER') will be the event when the mouse is moved over the "Button"
Copyright 2022 PySimpleGUI.org
"""
# sg.theme('dark red')
def TextButton(text):
"""
A User Defined Element. It looks like a Button, but is a Text element
:param text: The text that will be put on the "Button"
:return: A Text element with a tuple as the key
"""
return sg.Text(text, key=('-B-', text), relief='raised', enable_events=True, font='_ 15',text_color=sg.theme_button_color_text(), background_color=sg.theme_button_color_background())
def do_binds(window, button_text):
"""
This is magic code that enables the mouseover highlighting to work.
"""
for btext in button_text:
window[('-B-', btext)].bind('<Enter>', 'ENTER')
window[('-B-', btext)].bind('<Leave>', 'EXIT')
def main():
# Defines the text on the 3 buttons we're making
button_text = ('Button 1', 'Button 2', 'Button 3')
# The window's layout
layout = [[TextButton(text) for text in button_text],
[sg.Text(font='_ 14', k='-STATUS-')],
[sg.Ok(), sg.Exit()]]
window = sg.Window('Custom Mouseover Highlighting Buttons', layout, finalize=True)
# After the window is finalized, then can perform the bindings
do_binds(window, button_text)
# The Event Looop
while True:
event, values = window.read()
print(event, values)
if event == sg.WIN_CLOSED or event == 'Exit':
break
# if the event is a tuple, it's one of our TextButtons
if isinstance(event, tuple):
# if second item is one of the bound strings, then do the mouseeover code
if event[1] in ('ENTER', 'EXIT'):
button_key = event[0]
if event[1] == 'ENTER':
window[button_key].update(text_color=sg.theme_button_color_background(), background_color=sg.theme_button_color_text())
if event[1] == 'EXIT':
window[button_key].update(text_color=sg.theme_button_color_text(), background_color=sg.theme_button_color_background())
else: # a "normal" button click (Text clicked) so print the text which we put into the tuple
window['-STATUS-'].update(f'Button pressed = {event[1]}')
window.close()
if __name__ == '__main__':
main()

View file

@ -1,5 +1,12 @@
#!/usr/bin/env python
import PySimpleGUI as sg import PySimpleGUI as sg
"""
Demo - Base64 Buttons with Images
This is perhaps the easiest, quickest, and safest way to use buttons with images in PySimpleGUI.
By putting the button into your code, then you only have to distribute a single file.
Copyright 2022 PySimpleGUI
"""
# First the button images # First the button images
@ -7,24 +14,19 @@ play = b'iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAABmJLR0QA/wD/AP+gvaeTAAA
stop = b'iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAABmJLR0QA/wD/AP+gvaeTAAAAaklEQVRoge3ZQQqAMAxFwSre/8p6AZFUiXzKzLqLPNJVOwYAvLcVzpztU9Q8zrr/NUW3Y+JsZXsdSjdimY0ISSMkjZA0QtIISSMkjZA0QtIISSMkjZA0QtIISSMkzcxrfMo/ya1lNgIAX1zq+ANHUjXZuAAAAABJRU5ErkJggg==' stop = b'iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAABmJLR0QA/wD/AP+gvaeTAAAAaklEQVRoge3ZQQqAMAxFwSre/8p6AZFUiXzKzLqLPNJVOwYAvLcVzpztU9Q8zrr/NUW3Y+JsZXsdSjdimY0ISSMkjZA0QtIISSMkjZA0QtIISSMkjZA0QtIISSMkzcxrfMo/ya1lNgIAX1zq+ANHUjXZuAAAAABJRU5ErkJggg=='
eject = b'iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAABmJLR0QA/wD/AP+gvaeTAAAByklEQVRoge3YO2gUURSA4S+JRnyACIGADyxERAsb0UKrWIidWIidlSA2YpFWSauNVtrYiIU2YpFCLGwEEWwsBAsLEbFQFARFfKBZizkyK5pkZvZmZ7PeH05z595z/sPszpxdMplMJpMZbDZFLGsm8CxiomWXxqzBQ3QiHmNdq0YNGMc9RQOvIjqxNt6iVy1GcF0h/h47sR1vY+0mRluzq8ElhfBn7O9a34tPce1KC161OK8Q/Y7D/7h+EF9jz7k+etXilELwJ44vsO8ofsTeM33wqsURpdzZCvtPK5s+toRetZjCF4XYTI1zM3HmGw4lt6rJbnxQCF1tcP5ynP2IPQm9arENb0LkDsYa5BjFrcjxDjuS2VVkI16EwH2s6iHXStxVvjy39GxXkfV4Iu3Y0T3OPMWGBDkXZDUeRMHnmEyY+/eA2cEjrE2Y+w/GcDsKvcbWJaixGS+jxixWpC4wgmvK+WlX6gJddM9lN6J2Mi4q56cDKRPPwz7lXHYhVdJp5W+KtmK61yZOYG4AGpnDyV6byWT+ZxZ7Rnf6YlGdeX2XxZ8AVag6AiR9uzZg0U/G0NyR3MigUfU7MmhPr78YmjuSyWQymUxmmPgFokSdfYSQKDwAAAAASUVORK5CYII=' eject = b'iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAABmJLR0QA/wD/AP+gvaeTAAAByklEQVRoge3YO2gUURSA4S+JRnyACIGADyxERAsb0UKrWIidWIidlSA2YpFWSauNVtrYiIU2YpFCLGwEEWwsBAsLEbFQFARFfKBZizkyK5pkZvZmZ7PeH05z595z/sPszpxdMplMJpMZbDZFLGsm8CxiomWXxqzBQ3QiHmNdq0YNGMc9RQOvIjqxNt6iVy1GcF0h/h47sR1vY+0mRluzq8ElhfBn7O9a34tPce1KC161OK8Q/Y7D/7h+EF9jz7k+etXilELwJ44vsO8ofsTeM33wqsURpdzZCvtPK5s+toRetZjCF4XYTI1zM3HmGw4lt6rJbnxQCF1tcP5ynP2IPQm9arENb0LkDsYa5BjFrcjxDjuS2VVkI16EwH2s6iHXStxVvjy39GxXkfV4Iu3Y0T3OPMWGBDkXZDUeRMHnmEyY+/eA2cEjrE2Y+w/GcDsKvcbWJaixGS+jxixWpC4wgmvK+WlX6gJddM9lN6J2Mi4q56cDKRPPwz7lXHYhVdJp5W+KtmK61yZOYG4AGpnDyV6byWT+ZxZ7Rnf6YlGdeX2XxZ8AVag6AiR9uzZg0U/G0NyR3MigUfU7MmhPr78YmjuSyWQymUxmmPgFokSdfYSQKDwAAAAASUVORK5CYII='
sg.theme('Light Green 3') # Set a color theme sg.theme('Light Green 3')
bg = sg.LOOK_AND_FEEL_TABLE[sg.CURRENT_LOOK_AND_FEEL]['BACKGROUND'] # Get the background for the current theme
# Define the window's layout # Define the window's layout
layout = [ [sg.Text('Your Application', font='Any 15')], layout = [[sg.Button(image_data=play, key='-PLAY-', button_color=sg.theme_background_color(), border_width=0),
[sg.Text('Event = '), sg.Text(size=(12,1), key='-OUT-')], sg.Button(image_data=stop, key='-STOP-', button_color=sg.theme_background_color(), border_width=0),
[sg.Button(image_data=play, key='Play', border_width=0, button_color=(bg, bg)), sg.Button(image_data=eject, key='-EXIT-', button_color=sg.theme_background_color(), border_width=0)] ]
sg.Button(image_data=stop, key='Stop', button_color=(bg, bg), border_width=0),
sg.Button(image_data=eject, key='Exit', button_color=(bg, bg), border_width=0)] ]
# Create the window # Create the window
window = sg.Window('Window Title', layout) window = sg.Window('Simple Base64 Buttons', layout)
while True: # Event Loop while True: # Event Loop
event, values = window.read() # type: str, dict event, values = window.read() # type: str, dict
print(event, values) print(event, values)
if event in (sg.WIN_CLOSED, 'Exit'): # If the user exits if event in (sg.WIN_CLOSED, '-EXIT-'): # If the user exits
break break
window['-OUT-'].Update(event) # Output the event to the window window.close() # Exiting so clean up
window.close(); del window # Exiting so clean up

View file

@ -26,7 +26,7 @@ def resize_base64_image(image64, size):
''' '''
image_file = io.BytesIO(base64.b64decode(image64)) image_file = io.BytesIO(base64.b64decode(image64))
img = Image.open(image_file) img = Image.open(image_file)
img.thumbnail(size, Image.ANTIALIAS) img.thumbnail(size, Image.LANCZOS)
bio = io.BytesIO() bio = io.BytesIO()
img.save(bio, format='PNG') img.save(bio, format='PNG')
imgbytes = bio.getvalue() imgbytes = bio.getvalue()

View file

@ -0,0 +1,26 @@
"""
Demo Command Line Application or GUI Application
If your program is run with arguments, then a command line version is used.
If no arguments are given, then a GUI is shown that asks for a filename.
http://www.PySimpleGUI.org
Copyright 2022 PySimpleGUI
"""
import PySimpleGUI as sg
import sys
def main_cli(filename):
print(f'Your filename = {filename}')
def main_gui():
filename = sg.popup_get_file('Please enter a filename:')
main_cli(filename)
if __name__ == '__main__':
if len(sys.argv) < 2:
main_gui()
else:
main_cli(sys.argv[1])

View file

@ -4,25 +4,28 @@ import PySimpleGUI as sg
''' '''
A simple send/response chat window. Add call to your send-routine and print the response A simple send/response chat window. Add call to your send-routine and print the response
If async responses can come in, then will need to use a different design that uses PySimpleGUI async design pattern If async responses can come in, then will need to use a different design that uses PySimpleGUI async design pattern
Copyright 2023 PySimpleGUI
''' '''
sg.theme('GreenTan') # give our window a spiffy set of colors sg.theme('GreenTan') # give our window a spiffy set of colors
layout = [[sg.Text('Your output will go here', size=(40, 1))], layout = [[sg.Text('Your output will go here', size=(40, 1))],
[sg.Output(size=(110, 20), font=('Helvetica 10'))], [sg.Output(size=(110, 20), font=('Helvetica 10'))],
[sg.Multiline(size=(70, 5), enter_submits=False, key='-QUERY-', do_not_clear=False), [sg.Multiline(size=(70, 5), enter_submits=True, key='-QUERY-', do_not_clear=False),
sg.Button('SEND', button_color=(sg.YELLOWS[0], sg.BLUES[0]), bind_return_key=True), sg.Button('SEND', button_color=(sg.YELLOWS[0], sg.BLUES[0]), bind_return_key=True),
sg.Button('EXIT', button_color=(sg.YELLOWS[0], sg.GREENS[0]))]] sg.Button('EXIT', button_color=(sg.YELLOWS[0], sg.GREENS[0]))]]
window = sg.Window('Chat window', layout, font=('Helvetica', ' 13'), default_button_element_size=(8,2), use_default_focus=False) window = sg.Window('Chat window', layout, font=('Helvetica', ' 13'), default_button_element_size=(8,2), use_default_focus=False)
while True: # The Event Loop while True: # The Event Loop
event, value = window.read() event, values = window.read()
if event in (sg.WIN_CLOSED, 'EXIT'): # quit if exit button or X if event in (sg.WIN_CLOSED, 'EXIT'): # quit if exit button or X
break break
if event == 'SEND': if event == 'SEND':
query = value['-QUERY-'].rstrip() query = values['-QUERY-'].rstrip()
# EXECUTE YOUR COMMAND HERE # EXECUTE YOUR COMMAND HERE
print('The command you entered was {}'.format(query), flush=True) print('The command you entered was {}'.format(query), flush=True)
window.close() window.close()

View file

@ -0,0 +1,45 @@
import PySimpleGUI as sg
"""
Demo - Custom Checkboxes done simply
The Base64 Image encoding feature of PySimpleGUI makes it possible to create beautiful GUIs very simply
These 2 checkboxes required 3 extra lines of code than a normal checkbox.
1. Keep track of the current value using the Image Element's Metadata
2. Changle / Update the image when clicked
3. The Base64 image definition
Enable the event on the Image with the checkbox so that you can take action (flip the value)
Copyright 2022 PySimpleGUI
"""
def main():
layout = [[sg.Text('Fancy Checkboxes... Simply')],
[sg.Image(checked, key=('-IMAGE-', 1), metadata=True, enable_events=True), sg.Text(True, enable_events=True, k=('-TEXT-', 1))],
[sg.Image(unchecked, key=('-IMAGE-', 2), metadata=False, enable_events=True), sg.Text(False, enable_events=True, k=('-TEXT-', 2))],
[sg.Button('Go'), sg.Button('Exit')]]
window = sg.Window('Custom Checkboxes', layout, font="_ 14")
while True:
event, values = window.read()
print(event, values)
if event == sg.WIN_CLOSED or event == 'Exit':
break
# if a checkbox is clicked, flip the vale and the image
if event[0] in ('-IMAGE-', '-TEXT-'):
cbox_key = ('-IMAGE-', event[1])
text_key = ('-TEXT-', event[1])
window[cbox_key].metadata = not window[cbox_key].metadata
window[cbox_key].update(checked if window[cbox_key].metadata else unchecked)
# Update the string next to the checkbox
window[text_key].update(window[cbox_key].metadata)
window.close()
if __name__ == '__main__':
checked = b'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'
unchecked = b'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'
main()

View file

@ -4,10 +4,38 @@ import PySimpleGUI as sg
Demo - Class wrapper Demo - Class wrapper
Using a class to encapsulate PySimpleGUI Window creation & event loop Using a class to encapsulate PySimpleGUI Window creation & event loop
This is NOT a recommended design pattern. It mimics the object oriented design that many OO-based
GUI frameworks use, but there is no advantage to structuring you code in his manner. It adds
confusion, not clarity.
The class version is 18 lines of code. The plain version is 13 lines of code.
Two things about the class wrapper jump out as adding confusion:
1. Unneccessary fragmentation of the event loop - the button click code is pulled out of the loop entirely
2. "self" clutters the code without adding value
Copyright 2022 PySimpleGUI Copyright 2022, 2023 PySimpleGUI
""" """
'''
MM'""""'YMM dP
M' .mmm. `M 88
M MMMMMooM 88 .d8888b. .d8888b. .d8888b.
M MMMMMMMM 88 88' `88 Y8ooooo. Y8ooooo.
M. `MMM' .M 88 88. .88 88 88
MM. .dM dP `88888P8 `88888P' `88888P'
MMMMMMMMMMM
M""MMMMM""M oo
M MMMMM M
M MMMMP M .d8888b. 88d888b. .d8888b. dP .d8888b. 88d888b.
M MMMM' .M 88ooood8 88' `88 Y8ooooo. 88 88' `88 88' `88
M MMP' .MM 88. ... 88 88 88 88. .88 88 88
M .dMMM `88888P' dP `88888P' dP `88888P' dP dP
MMMMMMMMMMM
'''
class SampleGUI(): class SampleGUI():
def __init__(self): def __init__(self):
@ -35,3 +63,41 @@ class SampleGUI():
my_gui = SampleGUI() my_gui = SampleGUI()
# run the event loop # run the event loop
my_gui.run() my_gui.run()
'''
M"""""""`YM dP
M mmmm. M 88
M MMMMM M .d8888b. 88d888b. 88d8b.d8b. .d8888b. 88
M MMMMM M 88' `88 88' `88 88'`88'`88 88' `88 88
M MMMMM M 88. .88 88 88 88 88 88. .88 88
M MMMMM M `88888P' dP dP dP dP `88888P8 dP
MMMMMMMMMMM
M""MMMMM""M oo
M MMMMM M
M MMMMP M .d8888b. 88d888b. .d8888b. dP .d8888b. 88d888b.
M MMMM' .M 88ooood8 88' `88 Y8ooooo. 88 88' `88 88' `88
M MMP' .MM 88. ... 88 88 88 88. .88 88 88
M .dMMM `88888P' dP `88888P' dP `88888P' dP dP
MMMMMMMMMMM
'''
def gui_function():
layout = [ [sg.Text('My layout')],
[sg.Input(key='-IN-')],
[sg.Button('Go'), sg.Button('Exit')] ]
window = sg.Window('My new window', layout)
while True: # Event Loop
event, values = window.read()
if event in (sg.WIN_CLOSED, 'Exit'):
break
if event == 'Go':
sg.popup('Go button clicked', 'Input value:', values['-IN-'])
window.close()
gui_function()

View file

@ -0,0 +1,48 @@
import PySimpleGUI as sg
"""
Demo - Preview tkinter cursors
Shows the standard tkinter cursors using Buttons
The name of the cursor is on the Button. Mouse over the Button and you'll see
what that cursor looks like.
This list of cursors is a constant defined in PySimpleGUI. The constant name is:
sg.TKINTER_CURSORS
Copyright 2022 PySimpleGUI
"""
cursors = sg.TKINTER_CURSORS
# Make a layout that's 10 buttons across
NUM_BUTTONS_PER_ROW = 10
layout = [[]]
row = []
for i, c in enumerate(cursors):
# print(i, c)
row.append(sg.Button(c, size=(14,3), k=c))
if ((i+1) % NUM_BUTTONS_PER_ROW) == 0:
layout.append(row)
row = []
# print(row)
# Add on the last, partial row
start = len(cursors)//NUM_BUTTONS_PER_ROW * NUM_BUTTONS_PER_ROW
row = []
for i in range(start, len(cursors)):
row.append(sg.Button(cursors[i], size=(14,3), k=cursors[i]))
layout.append(row)
window = sg.Window('Cursor Previewer',layout, finalize=True)
# set the cursor on each of the buttons that has the name of the cursor as the text
for c in cursors:
window[c].set_cursor(c)
# The ubiquitous event loop...
while True:
event, values = window.read()
if event == sg.WIN_CLOSED:
break
window.close()

View file

@ -9,11 +9,11 @@ import webbrowser
If you want no cursor, set the cursor to the string 'none'. If you want no cursor, set the cursor to the string 'none'.
Copyright 2021 PySimpleGUI Copyright 2021, 2022 PySimpleGUI
""" """
# Here is a more complete list of cursors you can choose from # Here is a more complete list of cursors you can choose from
cursors = ('X_cursor', 'no', 'arrow','based_arrow_down','based_arrow_up','boat','bogosity','bottom_left_corner','bottom_right_corner','bottom_side','bottom_tee','box_spiral','center_ptr','circle','clock','coffee_mug','cross','cross_reverse','crosshair','diamond_cross','dot','dotbox','double_arrow','draft_large','draft_small','draped_box','exchange','fleur','gobbler','gumby','hand1','hand2','heart','icon','iron_cross','left_ptr','left_side','left_tee','leftbutton','ll_angle','lr_angle','man','middlebutton','mouse','no','pencil','pirate','plus','question_arrow','right_ptr','right_side','right_tee','rightbutton','rtl_logo','sailboat','sb_down_arrow','sb_h_double_arrow','sb_left_arrow','sb_right_arrow','sb_up_arrow','sb_v_double_arrow','shuttle','sizing','spider','spraycan','star','target','tcross','top_left_arrow','top_left_corner','top_right_corner','top_side','top_tee','trek','ul_angle','umbrella','ur_angle','watch','xterm','arrow','center_ptr','crosshair','fleur','ibeam','icon','sb_h_double_arrow','sb_v_double_arrow','watch','xterm','no','starting','size','size_ne_sw','size_ns','size_nw_se','size_we','uparrow','wait','arrow','cross','crosshair','ibeam','plus','watch','xterm') cursors = sg.TKINTER_CURSORS
sg.theme('Light Blue 2') sg.theme('Light Blue 2')

View file

@ -274,7 +274,7 @@ def main(location):
[sg.T(size=(5, 1), font='Any 20', justification='c', background_color='black', k='-gauge VALUE-')]] [sg.T(size=(5, 1), font='Any 20', justification='c', background_color='black', k='-gauge VALUE-')]]
window = sg.Window('CPU Usage Widget Square', layout, location=location, no_titlebar=True, grab_anywhere=True, margins=(0, 0), element_padding=(0, 0), alpha_channel=ALPHA, background_color='black', element_justification='c', finalize=True, right_click_menu=sg.MENU_RIGHT_CLICK_EDITME_EXIT, enable_close_attempted_event=True) window = sg.Window('CPU Usage Widget Square', layout, location=location, no_titlebar=True, grab_anywhere=True, margins=(0, 0), element_padding=(0, 0), alpha_channel=ALPHA, background_color='black', element_justification='c', finalize=True, right_click_menu=sg.MENU_RIGHT_CLICK_EDITME_VER_EXIT, enable_close_attempted_event=True)
gauge = Gauge(pointer_color=sg.theme_text_color(), clock_color=sg.theme_text_color(), major_tick_color=sg.theme_text_color(), gauge = Gauge(pointer_color=sg.theme_text_color(), clock_color=sg.theme_text_color(), major_tick_color=sg.theme_text_color(),
minor_tick_color=sg.theme_input_background_color(), pointer_outer_color=sg.theme_text_color(), major_tick_start_radius=45, minor_tick_color=sg.theme_input_background_color(), pointer_outer_color=sg.theme_text_color(), major_tick_start_radius=45,
@ -298,6 +298,8 @@ def main(location):
break break
if event == 'Edit Me': if event == 'Edit Me':
sg.execute_editor(__file__) sg.execute_editor(__file__)
elif event == 'Version':
sg.popup_scrolled(__file__, sg.get_versions(), location=window.current_location(), keep_on_top=True, non_blocking=True)
window.close() window.close()

View file

@ -23,7 +23,7 @@ def main(location):
layout = [[graph]] layout = [[graph]]
window = sg.Window('CPU Usage Widget Square', layout, location=location, no_titlebar=True, grab_anywhere=True, margins=(0, 0), element_padding=(0, 0), alpha_channel=ALPHA, finalize=True, right_click_menu=sg.MENU_RIGHT_CLICK_EDITME_EXIT, enable_close_attempted_event=True) window = sg.Window('CPU Usage Widget Square', layout, location=location, no_titlebar=True, grab_anywhere=True, margins=(0, 0), element_padding=(0, 0), alpha_channel=ALPHA, finalize=True, right_click_menu=sg.MENU_RIGHT_CLICK_EDITME_VER_EXIT, enable_close_attempted_event=True)
text_id2 = graph.draw_text(f'CPU', (GSIZE[0] // 2, GSIZE[1] // 4), font='Any 20', text_location=sg.TEXT_LOCATION_CENTER, color=sg.theme_button_color()[0]) text_id2 = graph.draw_text(f'CPU', (GSIZE[0] // 2, GSIZE[1] // 4), font='Any 20', text_location=sg.TEXT_LOCATION_CENTER, color=sg.theme_button_color()[0])
@ -46,6 +46,8 @@ def main(location):
break break
if event == 'Edit Me': if event == 'Edit Me':
sg.execute_editor(__file__) sg.execute_editor(__file__)
elif event == 'Version':
sg.popup_scrolled(__file__, sg.get_versions(), location=window.current_location(), keep_on_top=True, non_blocking=True)
# erase figures so they can be redrawn # erase figures so they can be redrawn
graph.delete_figure(rect_id) graph.delete_figure(rect_id)
graph.delete_figure(text_id1) graph.delete_figure(text_id1)

View file

@ -1,8 +1,12 @@
import PySimpleGUI as sg import PySimpleGUI as sg
import datetime import datetime
import PIL.Image, PIL.ImageTk import PIL
from PIL import Image
import random import random
import os import os
import io
import base64
""" """
Another simple Desktop Widget using PySimpleGUI Another simple Desktop Widget using PySimpleGUI
@ -16,17 +20,76 @@ import os
* How long to show the image and if you wnt this time to vary semi-randomly * How long to show the image and if you wnt this time to vary semi-randomly
* Folder containing your images * Folder containing your images
Copyright 2021 PySimpleGUI Copyright 2021, 2023 PySimpleGUI
""" """
ALPHA = 0.9 # Initial alpha until user changes ALPHA = 0.9 # Initial alpha until user changes
refresh_font = sg.user_settings_get_entry('-refresh font-', 'Courier 8') refresh_font = sg.user_settings_get_entry('-refresh font-', 'Courier 8')
def convert_to_bytes(file_or_bytes, resize=None):
image = PIL.Image.open(file_or_bytes) def make_square(im, fill_color=(0, 0, 0, 0)):
image.thumbnail(resize) x, y = im.size
photo_img = PIL.ImageTk.PhotoImage(image) size = max(x, y)
return photo_img new_im = Image.new('RGBA', (size, size), fill_color)
new_im.paste(im, (int((size - x) / 2), int((size - y) / 2)))
return new_im
def get_image_size(source):
if isinstance(source, str):
image = PIL.Image.open(source)
elif isinstance(source, bytes):
image = PIL.Image.open(io.BytesIO(base64.b64decode(source)))
else:
image = PIL.Image.open(io.BytesIO(source))
width, height = image.size
return (width, height)
def convert_to_bytes(source, size=(None, None), subsample=None, zoom=None, fill=False):
"""
Will convert into bytes and optionally resize an image that is a file or a base64 bytes object.
Turns into PNG format in the process so that can be displayed by tkinter
:param source: either a string filename or a bytes base64 image object
:type source: (Union[str, bytes])
:param size: optional new size (width, height)
:type size: (Tuple[int, int] or None)
:param subsample: change the size by multiplying width and height by 1/subsample
:type subsample: (int)
:param zoom: change the size by multiplying width and height by zoom
:type zoom: (int)
:param fill: If True then the image is filled/padded so that the image is square
:type fill: (bool)
:return: (bytes) a byte-string object
:rtype: (bytes)
"""
# print(f'converting {source} {size}')
if isinstance(source, str):
image = PIL.Image.open(source)
elif isinstance(source, bytes):
image = PIL.Image.open(io.BytesIO(base64.b64decode(source)))
else:
image = PIL.Image.open(io.BytesIO(source))
width, height = image.size
scale = None
if size != (None, None):
new_width, new_height = size
scale = min(new_height/height, new_width/width)
elif subsample is not None:
scale = 1/subsample
elif zoom is not None:
scale = zoom
resized_image = image.resize((int(width * scale), int(height * scale)), Image.LANCZOS) if scale is not None else image
if fill and scale is not None:
resized_image = make_square(resized_image)
# encode a PNG formatted version of image into BASE64
with io.BytesIO() as bio:
resized_image.save(bio, format="PNG")
contents = bio.getvalue()
encoded = base64.b64encode(contents)
return encoded
def choose_theme(location): def choose_theme(location):
@ -43,6 +106,15 @@ def choose_theme(location):
else: else:
return None return None
def reset_settings():
sg.user_settings_set_entry('-time per image-', 60)
sg.user_settings_set_entry('-random time-', False)
sg.user_settings_set_entry('-image size-', (None, None))
sg.user_settings_set_entry('-image_folder-', None)
sg.user_settings_set_entry('-location-', (None, None))
sg.user_settings_set_entry('-single image-', None)
sg.user_settings_set_entry('-alpha-', ALPHA)
def make_window(location): def make_window(location):
alpha = sg.user_settings_get_entry('-alpha-', ALPHA) alpha = sg.user_settings_get_entry('-alpha-', ALPHA)
@ -61,7 +133,7 @@ def make_window(location):
layout = [[sg.Image(k='-IMAGE-', enable_events=True)], layout = [[sg.Image(k='-IMAGE-', enable_events=True)],
[sg.pin(sg.Column(refresh_info, key='-REFRESH INFO-', element_justification='c', visible=sg.user_settings_get_entry('-show refresh-', True)))]] [sg.pin(sg.Column(refresh_info, key='-REFRESH INFO-', element_justification='c', visible=sg.user_settings_get_entry('-show refresh-', True)))]]
window = sg.Window('Photo Frame', layout, location=location, no_titlebar=True, grab_anywhere=True, margins=(0, 0), element_justification='c', element_padding=(0, 0), alpha_channel=alpha, finalize=True, right_click_menu=right_click_menu, keep_on_top=True, enable_close_attempted_event=True) window = sg.Window('Photo Frame', layout, location=location, no_titlebar=True, grab_anywhere=True, margins=(0, 0), element_justification='c', element_padding=(0, 0), alpha_channel=alpha, finalize=True, right_click_menu=right_click_menu, keep_on_top=True, enable_close_attempted_event=True, enable_window_config_events=True)
return window return window
@ -69,11 +141,10 @@ def make_window(location):
def main(): def main():
loc = sg.user_settings_get_entry('-location-', (None, None)) loc = sg.user_settings_get_entry('-location-', (None, None))
sg.theme(sg.user_settings_get_entry('-theme-', None)) sg.theme(sg.user_settings_get_entry('-theme-', None))
window = make_window(loc)
time_per_image = sg.user_settings_get_entry('-time per image-', 60) time_per_image = sg.user_settings_get_entry('-time per image-', 60)
vary_randomly = sg.user_settings_get_entry('-random time-', False) vary_randomly = sg.user_settings_get_entry('-random time-', False)
width, height = sg.user_settings_get_entry('-image size-', (400,300)) width, height = sg.user_settings_get_entry('-image size-', (None, None))
image_folder = sg.user_settings_get_entry('-image_folder-', None) image_folder = sg.user_settings_get_entry('-image_folder-', None)
try: try:
@ -82,36 +153,26 @@ def main():
image_folder = None image_folder = None
sg.user_settings_set_entry('-image_folder-', None) sg.user_settings_set_entry('-image_folder-', None)
single_image = sg.user_settings_get_entry('-single image-', None) image_name = single_image = sg.user_settings_get_entry('-single image-', None)
if image_folder is None and single_image is None: if image_folder is None and single_image is None:
while True: image_name = single_image = sg.popup_get_file('Choose a starting image', keep_on_top=True)
images = None if not single_image:
image_folder = sg.popup_get_folder('Choose location of your images', location=window.current_location(), keep_on_top=True) if sg.popup_yes_no('No folder entered','Go you want to exit the program entirely?', keep_on_top=True) == 'Yes':
if image_folder is not None: exit()
sg.user_settings_set_entry('-image_folder-', image_folder) if image_folder is not None and single_image is None:
break
else:
if sg.popup_yes_no('No folder entered','Go you want to exit the program entirely?', keep_on_top=True) == 'Yes':
exit()
elif single_image is None:
images = os.listdir(image_folder) images = os.listdir(image_folder)
images = [i for i in images if i.lower().endswith(('.png', '.jpg', '.gif'))] images = [i for i in images if i.lower().endswith(('.png', '.jpg', '.gif'))]
image_name = os.path.join(image_folder, random.choice(images))
else: # means single image is not none else: # means single image is not none
images = None images = None
image_name = single_image
window = make_window(loc)
window_size = window.size
image_data = convert_to_bytes(image_name, (width, height))
while True: # Event Loop while True: # Event Loop
# First update the status information
# for debugging show the last update date time
if single_image is None:
image_name =random.choice(images)
image_data = convert_to_bytes(os.path.join(image_folder, image_name), (width, height))
window['-FOLDER-'].update(image_folder)
else:
image_name = single_image
image_data = convert_to_bytes(single_image, (width, height))
window['-FILENAME-'].update(image_name)
window['-IMAGE-'].update(data=image_data)
window['-REFRESHED-'].update(datetime.datetime.now().strftime("%m/%d/%Y %I:%M:%S %p"))
# -------------- Start of normal event loop -------------- # -------------- Start of normal event loop --------------
timeout = time_per_image * 1000 + (random.randint(int(-time_per_image * 500), int(time_per_image * 500)) if vary_randomly else 0) if single_image is None else None timeout = time_per_image * 1000 + (random.randint(int(-time_per_image * 500), int(time_per_image * 500)) if vary_randomly else 0) if single_image is None else None
event, values = window.read(timeout=timeout) event, values = window.read(timeout=timeout)
@ -120,6 +181,28 @@ def main():
elif event in (sg.WIN_CLOSE_ATTEMPTED_EVENT, 'Exit'): elif event in (sg.WIN_CLOSE_ATTEMPTED_EVENT, 'Exit'):
sg.user_settings_set_entry('-location-', window.current_location()) # The line of code to save the position before exiting sg.user_settings_set_entry('-location-', window.current_location()) # The line of code to save the position before exiting
break break
# First update the status information
# for debugging show the last update date time
if event == sg.TIMEOUT_EVENT:
if single_image is None:
image_name =random.choice(images)
image_data = convert_to_bytes(os.path.join(image_folder, image_name))
window['-FOLDER-'].update(image_folder)
else:
image_name = single_image
image_data = convert_to_bytes(single_image, (width, height))
window['-FILENAME-'].update(image_name)
window['-IMAGE-'].update(data=image_data)
window['-REFRESHED-'].update(datetime.datetime.now().strftime("%m/%d/%Y %I:%M:%S %p"))
if event == sg.WINDOW_CONFIG_EVENT:
new_size = window.size
if new_size != window_size:
print(f'resizing {new_size}')
(width, height) = new_size
image_data = convert_to_bytes(image_data, (width, height))
window['-IMAGE-'].update(data=image_data)
window.size = get_image_size(image_data)
window_size = window.size
if event == 'Edit Me': if event == 'Edit Me':
sg.execute_editor(__file__) sg.execute_editor(__file__)
elif event == 'Choose Image Folder': elif event == 'Choose Image Folder':
@ -175,12 +258,15 @@ def main():
window.close() window.close()
window = make_window(loc) window = make_window(loc)
elif event == 'Choose Single Image': elif event == 'Choose Single Image':
single_image = sg.popup_get_file('Choose single image to show', history=True) image_name = single_image = sg.popup_get_file('Choose single image to show', history=True)
sg.user_settings_set_entry('-single image-', single_image) sg.user_settings_set_entry('-single image-', single_image)
(width, height) = get_image_size(single_image)
sg.user_settings_set_entry('-image size-', (width, height))
image_data = convert_to_bytes(image_name, (width, height))
window['-IMAGE-'].update(data=image_data)
window.size = window_size = (width, height)
window.close() window.close()
if __name__ == '__main__': if __name__ == '__main__':
# reset_settings() # if get corrupted problems, uncomment this
main() main()

View file

@ -275,7 +275,7 @@ def main(location):
[sg.T(size=(8, 1), font='Any 14', justification='c', background_color='black', k='-RAM USED-')], [sg.T(size=(8, 1), font='Any 14', justification='c', background_color='black', k='-RAM USED-')],
] ]
window = sg.Window('CPU Usage Widget Square', layout, location=location, no_titlebar=True, grab_anywhere=True, margins=(0, 0), element_padding=(0, 0), alpha_channel=ALPHA, background_color='black', element_justification='c', finalize=True, right_click_menu=sg.MENU_RIGHT_CLICK_EDITME_EXIT) window = sg.Window('CPU Usage Widget Square', layout, location=location, no_titlebar=True, grab_anywhere=True, margins=(0, 0), element_padding=(0, 0), alpha_channel=ALPHA, background_color='black', element_justification='c', finalize=True, right_click_menu=sg.MENU_RIGHT_CLICK_EDITME_VER_EXIT, enable_close_attempted_event=True)
gauge = Gauge(pointer_color=sg.theme_text_color(), clock_color=sg.theme_text_color(), major_tick_color=sg.theme_text_color(), gauge = Gauge(pointer_color=sg.theme_text_color(), clock_color=sg.theme_text_color(), major_tick_color=sg.theme_text_color(),
minor_tick_color=sg.theme_input_background_color(), pointer_outer_color=sg.theme_text_color(), major_tick_start_radius=45, minor_tick_color=sg.theme_input_background_color(), pointer_outer_color=sg.theme_text_color(), major_tick_start_radius=45,
@ -290,7 +290,7 @@ def main(location):
if gauge.change(): if gauge.change():
new_angle = ram_percent*180/100 new_angle = ram_percent*180/100
window['-gauge VALUE-'].update(f'{ram_percent}') window['-gauge VALUE-'].update(f'{ram_percent}%')
window['-RAM USED-'].update(f'{human_size(ram.used)}') window['-RAM USED-'].update(f'{human_size(ram.used)}')
gauge.change(degree=new_angle, step=180) gauge.change(degree=new_angle, step=180)
gauge.change() gauge.change()
@ -298,10 +298,13 @@ def main(location):
# update the window, wait for a while, then check for exit # update the window, wait for a while, then check for exit
event, values = window.read(timeout=UPDATE_FREQUENCY_MILLISECONDS) event, values = window.read(timeout=UPDATE_FREQUENCY_MILLISECONDS)
if event == sg.WIN_CLOSED or event == 'Exit': if event in (sg.WIN_CLOSE_ATTEMPTED_EVENT, 'Exit'):
sg.user_settings_set_entry('-location-', window.current_location()) # The line of code to save the position before exiting
break break
if event == 'Edit Me': if event == 'Edit Me':
sg.execute_editor(__file__) sg.execute_editor(__file__)
elif event == 'Version':
sg.popup_scrolled(__file__, sg.get_versions(), location=window.current_location(), keep_on_top=True, non_blocking=True)
window.close() window.close()
@ -311,5 +314,5 @@ if __name__ == '__main__':
location = sys.argv[1].split(',') location = sys.argv[1].split(',')
location = (int(location[0]), int(location[1])) location = (int(location[0]), int(location[1]))
else: else:
location = (None, None) location = sg.user_settings_get_entry('-location-', (None, None))
main(location) main(location)

View file

@ -30,7 +30,7 @@ def main(location):
graph = sg.Graph(GSIZE, (0, 0), GSIZE, key='-GRAPH-', enable_events=True) graph = sg.Graph(GSIZE, (0, 0), GSIZE, key='-GRAPH-', enable_events=True)
layout = [[graph]] layout = [[graph]]
window = sg.Window('RAM Usage Widget Square', layout, location=location, no_titlebar=True, grab_anywhere=True, margins=(0, 0), element_padding=(0, 0), alpha_channel=ALPHA, finalize=True, right_click_menu=sg.MENU_RIGHT_CLICK_EDITME_EXIT, enable_close_attempted_event=True) window = sg.Window('RAM Usage Widget Square', layout, location=location, no_titlebar=True, grab_anywhere=True, margins=(0, 0), element_padding=(0, 0), alpha_channel=ALPHA, finalize=True, right_click_menu=sg.MENU_RIGHT_CLICK_EDITME_VER_EXIT, enable_close_attempted_event=True, keep_on_top=True)
while True: # Event Loop while True: # Event Loop
@ -47,8 +47,10 @@ def main(location):
if event != sg.WIN_CLOSED: if event != sg.WIN_CLOSED:
sg.user_settings_set_entry('-location-', window.current_location()) # The line of code to save the position before exiting sg.user_settings_set_entry('-location-', window.current_location()) # The line of code to save the position before exiting
break break
elif event == 'Edit Me': if event == 'Edit Me':
sg.execute_editor(__file__) sg.execute_editor(__file__)
elif event == 'Version':
sg.popup_scrolled(__file__, sg.get_versions(), location=window.current_location(), keep_on_top=True, non_blocking=True)
graph.delete_figure(rect_id) graph.delete_figure(rect_id)
graph.delete_figure(text_id1) graph.delete_figure(text_id1)

View file

@ -0,0 +1,74 @@
#!/usr/bin/env python
import PySimpleGUI as sg
import time
"""
Demo Program - Timer Desktop Widget using Window.timer_start and Window.timer_stop
This is a re-implementation of the original timer desktop widget that used window.read timeouts as
the means of getting timer events.
This program uses the new Window.timer_start to get timer events. It is simpler because:
There is only 1 call to window.read and it's in the standard location in the event loop
The timer pause/run button uses the timer_start and timer_stop calls - perhaps more intuitive
Note that this Demo Program requires PySimpleGUI 4.60.4.132 and greater
Copyright 2022 PySimpleGUI
"""
def time_as_int():
return int(round(time.time() * 100))
# ---------------- Create Form ----------------
sg.theme('Black')
layout = [[sg.Text('')],
[sg.Text('', size=(8, 2), font=('Helvetica', 20),
justification='center', key='text')],
[sg.Button('Pause', key='-RUN-PAUSE-', 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,
element_padding=(0, 0),
finalize=True,
element_justification='c',
right_click_menu=sg.MENU_RIGHT_CLICK_EDITME_EXIT)
current_time, paused_time, paused = 0, 0, False
start_time = time_as_int()
timer_id = window.timer_start(10)
while True:
event, values = window.read()
if event in (sg.WIN_CLOSED, 'Exit'): # ALWAYS give a way out of program
break
# --------- Handle events --------
if event == '-RUN-PAUSE-':
paused = not paused
if paused:
window.timer_stop(timer_id)
paused_time = time_as_int()
else:
timer_id = window.timer_start(10)
start_time = start_time + time_as_int() - paused_time
window['-RUN-PAUSE-'].update('Run' if paused else 'Pause')
elif event == sg.EVENT_TIMER:
current_time = time_as_int() - start_time
if event == '-RESET-':
current_time = 0
start_time = paused_time = time_as_int()
elif event == 'Edit Me':
sg.execute_editor(__file__)
# --------- Display timer_id in window --------
window['text'].update('{:02d}:{:02d}.{:02d}'.format((current_time // 100) // 60,
(current_time // 100) % 60,
current_time % 100))
window.close()

View file

@ -75,8 +75,9 @@ def change_settings(settings, window_location=(None, None)):
nearest_postal = '' nearest_postal = ''
layout = [[sg.T('Enter Zipcode or City for your location')], layout = [[sg.T('Enter Zipcode or City for your location')],
[sg.I(settings.get('-location-', nearest_postal), size=(15, 1), key='-LOCATION-')], [sg.I(settings.get('-location-', nearest_postal), size=(15, 1), key='-LOCATION-'), sg.T('City')],
[sg.I(settings.get('-country-', 'US'), size=(15, 1), key='-COUNTRY-')], [sg.I(settings.get('-country-', 'US'), size=(15, 1), key='-COUNTRY-'), sg.T('Country')],
[sg.I(settings.get('-friends name-', ''), size=(15, 1), key='-FRIENDS NAME-'), sg.T('Who')],
[sg.I(settings.get('-api key-', ''), size=(32, 1), key='-API KEY-')], [sg.I(settings.get('-api key-', ''), size=(32, 1), key='-API KEY-')],
[sg.CBox('Use Metric For Temperatures', default=settings.get('-celsius-', False),key='-CELSIUS-')], [sg.CBox('Use Metric For Temperatures', default=settings.get('-celsius-', False),key='-CELSIUS-')],
[sg.B('Ok', border_width=0, bind_return_key=True), sg.B('Register For a Key', border_width=0, k='-REGISTER-'), sg.B('Cancel', border_width=0)], ] [sg.B('Ok', border_width=0, bind_return_key=True), sg.B('Register For a Key', border_width=0, k='-REGISTER-'), sg.B('Cancel', border_width=0)], ]
@ -96,6 +97,7 @@ def change_settings(settings, window_location=(None, None)):
settings['-country-'] = values['-COUNTRY-'] settings['-country-'] = values['-COUNTRY-']
API_KEY = settings['-api key-'] = values['-API KEY-'] API_KEY = settings['-api key-'] = values['-API KEY-']
settings['-celsius-'] = values['-CELSIUS-'] settings['-celsius-'] = values['-CELSIUS-']
settings['-friends name-'] = values['-FRIENDS NAME-']
else: else:
API_KEY = settings['-api key-'] API_KEY = settings['-api key-']
user_location = settings['-location-'] user_location = settings['-location-']
@ -186,43 +188,42 @@ def metric_row(metric):
sg.Text(APP_DATA[metric], font=('Arial', 10, 'bold'), pad=(0, 0), size=(9, 1), key=metric)] sg.Text(APP_DATA[metric], font=('Arial', 10, 'bold'), pad=(0, 0), size=(9, 1), key=metric)]
def create_window(win_location): def create_window(win_location, settings):
""" Create the application window """ """ Create the application window """
friends_name = settings.get('-friends name-', '')
col1 = sg.Column( col1 = sg.Column(
[[sg.Text(APP_DATA['City'], font=('Arial Rounded MT Bold', 18), pad=((10, 0), (50, 0)), size=(18, 1), background_color=BG_COLOR, text_color=TXT_COLOR, key='City')], [[sg.Text(APP_DATA['City'], font=('Arial Rounded MT Bold', 18), background_color=BG_COLOR, text_color=TXT_COLOR, key='City'),
sg.Text(f' - {friends_name}' if friends_name else '', background_color=BG_COLOR, text_color=TXT_COLOR, font=('Arial Rounded MT Bold', 18),)],
[sg.Text(APP_DATA['Description'], font=('Arial', 12), pad=(10, 0), background_color=BG_COLOR, text_color=TXT_COLOR, key='Description')]], [sg.Text(APP_DATA['Description'], font=('Arial', 12), pad=(10, 0), background_color=BG_COLOR, text_color=TXT_COLOR, key='Description')]],
background_color=BG_COLOR, key='COL1') background_color=BG_COLOR, key='COL1')
col2 = sg.Column( col2 = sg.Column([[sg.Image(data=APP_DATA['Icon'], size=(100, 100), background_color=BG_COLOR, key='Icon')]],
[[sg.Text('×', font=('Arial Black', 16), pad=(0, 0), justification='right', background_color=BG_COLOR, text_color=TXT_COLOR, enable_events=True, key='-QUIT-')], element_justification='center', background_color=BG_COLOR, key='COL2')
[sg.Image(data=APP_DATA['Icon'], pad=((5, 10), (0, 0)), size=(100, 100), background_color=BG_COLOR, key='Icon')]],
element_justification='center', background_color=BG_COLOR, key='COL2')
col3 = sg.Column( col3 = sg.Column([[sg.Text(APP_DATA['Updated'], font=('Arial', 8), background_color=BG_COLOR, text_color=TXT_COLOR, key='Updated')]],
[[sg.Text(APP_DATA['Updated'], font=('Arial', 8), background_color=BG_COLOR, text_color=TXT_COLOR, key='Updated')]], pad=(10, 5), element_justification='left', background_color=BG_COLOR, key='COL3')
pad=(10, 5), element_justification='left', background_color=BG_COLOR, key='COL3')
col4 = sg.Column( col4 = sg.Column(
[[sg.Text('Settings', font=('Arial', 8, 'italic'), background_color=BG_COLOR, text_color=TXT_COLOR, enable_events=True, key='-CHANGE-'), [[sg.Text('Settings', font=('Arial', 8, 'italic'), background_color=BG_COLOR, text_color=TXT_COLOR, enable_events=True, key='-CHANGE-'),
sg.Text('Refresh', font=('Arial', 8, 'italic'), background_color=BG_COLOR, text_color=TXT_COLOR, enable_events=True, key='-REFRESH-')]], sg.Text('Refresh', font=('Arial', 8, 'italic'), background_color=BG_COLOR, text_color=TXT_COLOR, enable_events=True, key='-REFRESH-')]],
pad=(10, 5), element_justification='right', background_color=BG_COLOR, key='COL4') pad=(10, 5), element_justification='right', background_color=BG_COLOR, key='COL4')
top_col = sg.Column([[col1, col2]], pad=(0, 0), background_color=BG_COLOR, key='TopCOL') top_col = sg.Column([[col1, sg.Push(background_color=BG_COLOR), col2, sg.Text('×', font=('Arial Black', 16), pad=(0, 0), justification='right', background_color=BG_COLOR, text_color=TXT_COLOR, enable_events=True, key='-QUIT-')]], pad=(0, 0), background_color=BG_COLOR, key='TopCOL')
bot_col = sg.Column([[col3, col4]], pad=(0, 0), background_color=BG_COLOR, key='BotCOL') bot_col = sg.Column([[col3, col4]],
pad=(0, 0), background_color=BG_COLOR, key='BotCOL')
lf_col = sg.Column( lf_col = sg.Column(
[[sg.Text(APP_DATA['Temp'], font=('Haettenschweiler', 90), pad=((10, 0), (0, 0)), justification='center', key='Temp')]], [[sg.Text(APP_DATA['Temp'], font=('Haettenschweiler', 90), pad=((10, 0), (0, 0)), justification='center', key='Temp')]],
pad=(10, 0), element_justification='center', key='LfCOL') pad=(10, 0), element_justification='center', key='LfCOL')
rt_col = sg.Column( rt_col = sg.Column([metric_row('Feels Like'), metric_row('Wind'), metric_row('Humidity'), metric_row('Precip 1hr'), metric_row('Pressure')],
[metric_row('Feels Like'), metric_row('Wind'), metric_row('Humidity'), metric_row('Precip 1hr'), metric_row('Pressure')], pad=((15, 0), (25, 5)), key='RtCOL')
pad=((15, 0), (25, 5)), key='RtCOL')
layout = [[top_col], layout = [[top_col],
[lf_col, rt_col], [lf_col, rt_col],
[bot_col], [bot_col],
[sg.Text(f'{sg.ver} {sg.framework_version} {sys.version}', font=('Arial', 8), background_color=BG_COLOR, text_color=TXT_COLOR, pad=(0,0))]] [sg.Text(f'PSG: {sg.ver} Tk:{sg.framework_version} Py:{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}', font=('Arial', 8), justification='c', background_color=BG_COLOR, text_color=TXT_COLOR, pad=(0,0), expand_x=True)]]
window = sg.Window(layout=layout, title='Weather Widget', margins=(0, 0), finalize=True, location=win_location, window = sg.Window(layout=layout, title='Weather Widget', margins=(0, 0), finalize=True, location=win_location,
element_justification='center', keep_on_top=True, no_titlebar=True, grab_anywhere=True, alpha_channel=ALPHA, element_justification='center', keep_on_top=True, no_titlebar=True, grab_anywhere=True, alpha_channel=ALPHA,
@ -277,28 +278,36 @@ def main(refresh_rate, win_location):
sg.popup_error('Having trouble with location. Your location: ', location) sg.popup_error('Having trouble with location. Your location: ', location)
exit() exit()
window = create_window(win_location) window = create_window(win_location, settings)
while True: # Event Loop while True: # Event Loop
event, values = window.read(timeout=refresh_in_milliseconds) event, values = window.read(timeout=refresh_in_milliseconds)
if event in (None, '-QUIT-', 'Exit', sg.WIN_CLOSE_ATTEMPTED_EVENT): if event in (None, '-QUIT-', 'Exit', sg.WIN_CLOSE_ATTEMPTED_EVENT):
sg.user_settings_set_entry('-win location-', window.current_location()) # The line of code to save the position before exiting sg.user_settings_set_entry('-win location-', window.current_location()) # The line of code to save the position before exiting
break break
if event == '-CHANGE-': try:
x, y = window.current_location() if event == '-CHANGE-':
settings = change_settings(settings, (x + 200, y+50)) x, y = window.current_location()
elif event == '-REFRESH-': settings = change_settings(settings, (x + 200, y+50))
sg.popup_quick_message('Refreshing...', keep_on_top=True, background_color='red', text_color='white', window.close()
auto_close_duration=3, non_blocking=False, location=(window.current_location()[0]+window.size[0]//2-30, window.current_location()[1]+window.size[1]//2-10)) window = create_window(win_location, settings)
elif event == 'Edit Me': elif event == '-REFRESH-':
sg.execute_editor(__file__) sg.popup_quick_message('Refreshing...', keep_on_top=True, background_color='red', text_color='white',
elif event == 'Versions': auto_close_duration=3, non_blocking=False, location=(window.current_location()[0]+window.size[0]//2-30, window.current_location()[1]+window.size[1]//2-10))
sg.main_get_debug_data() elif event == 'Edit Me':
elif event != sg.TIMEOUT_KEY: sg.execute_editor(__file__)
sg.Print('Unknown event received\nEvent & values:\n', event, values, location=win_location) elif event == 'Versions':
sg.main_get_debug_data()
elif event != sg.TIMEOUT_KEY:
sg.Print('Unknown event received\nEvent & values:\n', event, values, location=win_location)
update_weather() update_weather()
update_metrics(window) update_metrics(window)
except Exception as e:
sg.Print('*** GOT Exception in event loop ***', c='white on red', location=window.current_location(), keep_on_top=True)
sg.Print('File = ', __file__, f'Window title: {window.Title}')
sg.Print('Exception = ', e, wait=True) # IMPORTANT to add a wait/blocking so that the print pauses execution. Otherwise program continue and exits
window.close() window.close()

View file

@ -12,6 +12,7 @@
* If-Else * If-Else
* Dictionaries * Dictionaries
* Functions as keys * Functions as keys
* Lambda as key (callable like functions are)
The handlers in this demo are all functions that are called once the event is detected The handlers in this demo are all functions that are called once the event is detected
@ -22,7 +23,7 @@
event loop rather than functions, then do it in the event loop. event loop rather than functions, then do it in the event loop.
http://www.PySimpleGUI.org http://www.PySimpleGUI.org
Copyright 2021 PySimpleGUI Copyright 2021, 2022, 2023 PySimpleGUI
""" """
import PySimpleGUI as sg import PySimpleGUI as sg
@ -76,7 +77,7 @@ def main():
[sg.Text('Status:'), sg.Text(size=(3, 1), key='-STATUS-')], [sg.Text('Status:'), sg.Text(size=(3, 1), key='-STATUS-')],
[sg.Text(size=(50, 1), key='-OUT-')], [sg.Text(size=(50, 1), key='-OUT-')],
[sg.Button('Simple'), sg.Button('Go'), sg.Button('Stop'), sg.Button('Other', key=do_other), [sg.Button('Simple'), sg.Button('Go'), sg.Button('Stop'), sg.Button('Other', key=do_other),
sg.Button('Tuple', key=(1,2)), sg.Button('Bad')]] sg.Button('Tuple', key=(1,2)), sg.Button('Lambda', key= lambda window: do_other(window)), sg.Button('Bad')]]
window = sg.Window('Dispatchers', layout, font='Default 16', keep_on_top=True) window = sg.Window('Dispatchers', layout, font='Default 16', keep_on_top=True)

View file

@ -1,7 +1,7 @@
import PySimpleGUI as sg import PySimpleGUI as sg
""" """
Demo "Edit Me" Demo "Edit Me" (and Version)
More and more of these Demos are getting an "Edit me" option added. More and more of these Demos are getting an "Edit me" option added.
@ -12,26 +12,26 @@ import PySimpleGUI as sg
You can add this capability to your program by adding a right click menu to your window and calling the You can add this capability to your program by adding a right click menu to your window and calling the
editor that you set up in the global PySimpleGUI options. editor that you set up in the global PySimpleGUI options.
You need to do 2 things to make this work: A constant MENU_RIGHT_CLICK_EDITME_VER_EXIT, when set at the right click menu shows a "Version" and "Edit Me" meny item.
1. Add a right click menu - requires you to add 1 parameter to your Window creation
2. Add 1 if statement to your event loop.
You will need to have first set up your editor by using the menu in sg.main() You will need to have first set up your editor by using the menu in sg.main()
Copyright 2021 PySimpleGUI.org Copyright 2021, 2022, 2023 PySimpleGUI.org
""" """
layout = [[sg.Text('Edit this program by right clicking and choosing "Edit me"')], layout = [[sg.Text('Edit this program by right clicking and choosing "Edit me"')],
[sg.Button('Exit')]] [sg.Button('Exit')]]
window = sg.Window('Edit Me Right Click Menu Demo', layout, right_click_menu=[[''], ['Edit Me', 'Exit',]]) window = sg.Window('Edit Me Right Click Menu Demo', layout, right_click_menu=sg.MENU_RIGHT_CLICK_EDITME_VER_EXIT)
while True: # Event Loop while True: # Event Loop
event, values = window.read() event, values = window.read()
if event == sg.WIN_CLOSED or event == 'Exit': if event == sg.WIN_CLOSED or event == 'Exit':
break break
if event == 'Edit Me': if event == 'Edit Me':
sg.execute_editor(__file__) sg.execute_editor(__file__)
elif event == 'Version':
sg.popup_scrolled(__file__, sg.get_versions(), location=window.current_location(), keep_on_top=True, non_blocking=True)
window.close() window.close()

View file

@ -1,38 +1,36 @@
import PySimpleGUI as sg import PySimpleGUI as sg
# import PySimpleGUIWeb as sg
# import PySimpleGUIWx as sg
# import PySimpleGUIQt as sg
''' '''
Copyright 2019 PySimpleGUI.org Learn how to send emails from PySimpleGUI using the smtplib and email modules
The GUI portion is simple
Based on a send-email script originally written by by Israel Dryer Based on a send-email script originally written by by Israel Dryer
(Thank you Israel for figuring out the hard part of the stmp and email module calls!)
Copyright 2019, 2022 PySimpleGUI
''' '''
# If you are using a mail service that's not gmail, hotmail, live or yahoo:
# then you can enter the smtp server address here so you don't have to keep typing it into the GUI
smtp_host_default = ''
# used for sending the email # used for sending the email
import smtplib as smtp import smtplib as smtp
# used to build the email # used to build the email
from email.message import EmailMessage from email.message import EmailMessage
# create and send email # create and send email
def send_an_email(from_address, to_address, subject, message_text, user, password): def send_an_email(from_address, to_address, subject, message_text, user, password, smtp_host, smtp_port):
# SMTP Servers for popular free services... add your own if needed. Format is: address, port
google_smtp_server = 'smtp.gmail.com', 587
microsoft_smtp_server = 'smtp.office365.com', 587
yahoo_smtp_server = 'smtp.mail.yahoo.com', 587 # or port 465
# open the email server connection
if 'gmail' in user:
smtp_host, smtp_port = google_smtp_server
elif 'hotmail' in user or 'live' in user:
smtp_host, smtp_port = microsoft_smtp_server
elif 'yahoo' in user:
smtp_host, smtp_port = yahoo_smtp_server
else:
sg.popup('Username does not contain a supported email provider')
return
server = smtp.SMTP(host=smtp_host, port=smtp_port) server = smtp.SMTP(host=smtp_host, port=smtp_port)
server.starttls() server.starttls()
server.login(user=user, password=password) try:
server.login(user=user, password=password)
except Exception as e:
sg.popup_error('Error authenticaing your email credentials', e, image=sg.EMOJI_BASE64_WEARY)
server.close()
return
# create the email message headers and set the payload # create the email message headers and set the payload
msg = EmailMessage() msg = EmailMessage()
@ -42,9 +40,15 @@ def send_an_email(from_address, to_address, subject, message_text, user, passwor
msg.set_payload(message_text) msg.set_payload(message_text)
# open the email server and send the message # open the email server and send the message
server.send_message(msg) try:
server.send_message(msg)
except Exception as e:
sg.popup_error('Error sending your email', e, image=sg.EMOJI_BASE64_WEARY)
server.close()
return
server.close() server.close()
sg.popup('Email sent successfully!', image=sg.EMOJI_BASE64_HAPPY_JOY)
''' '''
important notes about using gmail important notes about using gmail
@ -61,33 +65,47 @@ def send_an_email(from_address, to_address, subject, message_text, user, passwor
''' '''
def main(): def main():
smtp_server_dict = {'gmail.com':'smtp.gmail.com','hotmail.com':'smtp.office365.com', 'live.com': 'smtp.office365.com', 'yahoo.com':'smtp.mail.yahoo.com'}
sg.theme('Dark Blue 3') sg.theme('Dark Blue 3')
layout = [[sg.Text('Send an Email', font='Default 18')], layout = [[sg.Text('Send an Email', font='Default 18')],
[sg.T('From:', size=(8,1)), sg.Input(key='-EMAIL FROM-', size=(35,1))], [sg.T('From:', size=(8,1)), sg.Input(key='-EMAIL FROM-', size=(35,1))],
[sg.T('To:', size=(8,1)), sg.Input(key='-EMAIL TO-', size=(35,1))], [sg.T('To:', size=(8,1)), sg.Input(key='-EMAIL TO-', size=(35,1))],
[sg.T('Subject:', size=(8,1)), sg.Input(key='-EMAIL SUBJECT-', size=(35,1))], [sg.T('Subject:', size=(8,1)), sg.Input(key='-EMAIL SUBJECT-', size=(35,1))],
[sg.T('Mail login information', font='Default 18')], [sg.T('Mail login information', font='Default 18')],
[sg.T('User:', size=(8,1)), sg.Input(key='-USER-', size=(35,1))], [sg.T('User:', size=(8,1)), sg.Input(key='-USER-', size=(35,1), enable_events=True)],
[sg.T('Password:', size=(8,1)), sg.Input(password_char='*', key='-PASSWORD-', size=(35,1))], [sg.T('Password:', size=(8,1)), sg.Input(password_char='*', key='-PASSWORD-', size=(35,1))],
[sg.T('SMTP Server Info', font='_ 14')],
[sg.T('SMTP Hostname'), sg.Input(smtp_host_default, s=20, key='-SMTP HOST-'), sg.T('SMTP Port'), sg.In(587, s=4, key='-SMTP PORT-') ],
[sg.Multiline('Type your message here', size=(60,10), key='-EMAIL TEXT-')], [sg.Multiline('Type your message here', size=(60,10), key='-EMAIL TEXT-')],
[sg.Button('Send'), sg.Button('Exit')]] [sg.Button('Send'), sg.Button('Exit')]]
window = sg.Window('Send An Email', layout) window = sg.Window('Send An Email', layout)
while True: # Event Loop while True:
event, values = window.read() event, values = window.read()
if event in (sg.WIN_CLOSED, 'Exit'): if event in (sg.WIN_CLOSED, 'Exit'):
break break
if event == 'Send': if event == 'Send':
if sg.__name__ != 'PySimpleGUIWeb': # auto close popups not yet supported in PySimpleGUIWeb if values['-SMTP HOST-']:
sg.popup_quick_message('Sending your message... this will take a moment...', background_color='red') sg.popup_quick_message('Sending your message... this will take a moment...', background_color='red')
send_an_email(from_address=values['-EMAIL FROM-'], send_an_email(from_address=values['-EMAIL FROM-'],
to_address=values['-EMAIL TO-'], to_address=values['-EMAIL TO-'],
subject=values['-EMAIL SUBJECT-'], subject=values['-EMAIL SUBJECT-'],
message_text=values['-EMAIL TEXT-'], message_text=values['-EMAIL TEXT-'],
user=values['-USER-'], user=values['-USER-'],
password=values['-PASSWORD-']) password=values['-PASSWORD-'],
smtp_host=values['-SMTP HOST-'],
smtp_port = values['-SMTP PORT-'])
else:
sg.popup_error('Missing SMTP Hostname... you have to supply a hostname (gmail, hotmail, live, yahoo are autofilled)')
elif event == '-USER-': # as the email sender is typed in, try to fill in the smtp hostname automatically
for service in smtp_server_dict.keys():
if service in values[event].lower():
window['-SMTP HOST-'].update(smtp_server_dict[service])
break
window.close() window.close()
main() if __name__ == '__main__':
main()

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,60 @@
import PySimpleGUI as sg
"""
Demo - Navigating a window's focus using arrow keys
This Demo Program has 2 features of PySimpleGUI in use:
1. Binding the arrow keys
2. Navigating a window's elements using focus
The first step is to bind the left, right and down arrows to an event.
The call to window.bind will cause events to be generated when these keys are pressed
The next step is to add the focus navigation to your event loop.
When the right key is pressed, the focus moves to the element that should get focus next
When the left arrow key is pressed, the focus moves to the previous element
And when the down arrow is pressed the program exits
Copyright 2022 PySimpleGUI
"""
def main():
layout = [ [sg.Text('My Window')],
[sg.Input(key='-IN-')],
[sg.Input(key='-IN2-')],
[sg.Input(key='-IN3-')],
[sg.Input(key='-IN4-')],
[sg.Input(key='-IN5-')],
[sg.Input(key='-IN6-')],
[sg.Input(key='-IN7-')],
[sg.Button('Go'), sg.Button('Exit')]]
window = sg.Window('Window Title', layout, finalize=True)
# Bind the Left, Right and Down arrow keys to events
window.bind('<Right>', '-NEXT-')
window.bind('<Left>', '-PREV-')
window.bind('<Down>', 'Exit')
while True: # Event Loop
event, values = window.read()
print(event, values)
if event == sg.WIN_CLOSED or event == 'Exit':
break
# Right arrow pressed, so move to the next element that should get focus
if event == '-NEXT-':
next_element = window.find_element_with_focus().get_next_focus()
next_element.set_focus()
# Left arrow pressed, so move to the previous element that should get focus
if event == '-PREV-':
prev_element = window.find_element_with_focus().get_previous_focus()
prev_element.set_focus()
window.close()
if __name__ == '__main__':
main()

View file

@ -1,5 +1,6 @@
import pyglet import pyglet
import PySimpleGUI as sg import PySimpleGUI as sg
import os
""" """
Demo - Using pyglet to get custom fonts into PySimpleGUI Demo - Using pyglet to get custom fonts into PySimpleGUI
@ -17,8 +18,11 @@ import PySimpleGUI as sg
http://scripts.sil.org/OFL http://scripts.sil.org/OFL
""" """
pyglet.font.add_file(r".\OpenFlame.ttf") font_file = os.path.join(os.path.dirname(__file__), "OpenFlame.ttf")
pyglet.font.add_file(font_file)
# sg.execute_command_subprocess(font_file)
font1 = ("Open Flame", 40) # Note - use the font "face name" not the filename when specifying the font font1 = ("Open Flame", 40) # Note - use the font "face name" not the filename when specifying the font
font2 = ("Courier New", 40) font2 = ("Courier New", 40)
font3 = ("Helvetica", 40) font3 = ("Helvetica", 40)

View file

@ -0,0 +1,47 @@
import PySimpleGUI as sg
"""
Demo Frame For Screen Captures
This program can be used to help you record videos.
Because it relies on the "transparent color" feature that's only available on Windows, this Demo is only going
to work the indended way on Windows.
Some video recorders that record a portion of the screen do not show you, at all times, what portion of the screen
is being recorded. This can make it difficult for you to stay within the bounds being recorded.
This demo program is meant to help the situation by showing a thin line that is 20 pixels larger than the area
being recorded.
The top edge of the window has the controls. There's an exit button, a solid "bar" for you to grab with your mouse to move
the frame around your window, and 2 inputs with a "resize" button that enables you to set the frame to the size you want to stay
within.
Copyright 2022 PySimpleGUI.org
"""
def main():
offset = (20, 20) # Number of extra pixels to add to the recording area
default_size = (1920, 1080) # The default size of the recording
location = (None, None) # A specific location to place the window if you want a specific spot
window = sg.Window('Window Title',
[[sg.Button('Exit'), sg.T(sg.SYMBOL_SQUARE * 10, grab=True), sg.I(default_size[0], s=4, k='-W-'), sg.I(default_size[1], s=4, k='-H-'), sg.B('Resize')],
[sg.Frame('', [[]], s=(default_size[0] + offset[0], default_size[1] + offset[1]), k='-FRAME-')]], transparent_color=sg.theme_background_color(),
right_click_menu=['', ['Edit Me', 'Exit']], location=location, no_titlebar=True, keep_on_top=True)
while True: # Event Loop
event, values = window.read()
if event == sg.WIN_CLOSED or event == 'Exit':
break
if event == 'Edit Me':
sg.execute_editor(__file__)
elif event == 'Resize':
window['-FRAME-'].set_size((int(values['-W-']) + offset[0], int(values['-H-']) + offset[1]))
window.close()
if __name__ == '__main__':
main()

View file

@ -0,0 +1,44 @@
import PySimpleGUI as sg
"""
Demo - Drag a rectangle and move
This demo shows how to use a Graph Element to draw a square and move it with the mouse.
It's a very simple, single element program. Like many Demo Programs, it started as
a "Test Harness" that demonstrated a bug that happened with a timeout of 0
was added to the window.read()
Original code comes courtesy of user @davesmivers .... Thanks Dave!!
Copyright 2022 PySimpleGUI
"""
GRAPH_SIZE = (400, 400)
START = (200, 200) # We'll assume X and Y are both this value
SQ_SIZE = 40 # Both width and height will be this value
layout = [[sg.Graph(
canvas_size=GRAPH_SIZE, graph_bottom_left=(0, 0), graph_top_right=GRAPH_SIZE, # Define the graph area
change_submits=True, # mouse click events
drag_submits=True, # mouse move events
background_color='lightblue',
key="-GRAPH-",
pad=0)]]
window = sg.Window("Simple Square Movement", layout, finalize=True, margins=(0,0))
# draw the square we'll move around
square = window["-GRAPH-"].draw_rectangle(START, (START[0]+SQ_SIZE, START[1]+SQ_SIZE), fill_color='black')
while True:
event, values = window.read()
if event == sg.WIN_CLOSED:
break
print(event, values) if event != sg.TIMEOUT_EVENT else None # our normal debug print, but for this demo, don't spam output with timeouts
if event == "-GRAPH-": # if there's a "Graph" event, then it's a mouse movement. Move the square
x, y = values["-GRAPH-"] # get mouse position
window["-GRAPH-"].relocate_figure(square, x - SQ_SIZE // 2, y + SQ_SIZE // 2) # Move using center of square to mouse pos
window.close()

View file

@ -1,5 +1,4 @@
import PySimpleGUI as sg import PySimpleGUI as sg
from PIL import ImageGrab
""" """
Demo - Drawing and moving demo Demo - Drawing and moving demo
@ -7,22 +6,9 @@ from PIL import ImageGrab
This demo shows how to use a Graph Element to (optionally) display an image and then use the This demo shows how to use a Graph Element to (optionally) display an image and then use the
mouse to "drag" and draw rectangles and circles. mouse to "drag" and draw rectangles and circles.
Copyright 2020 PySimpleGUI.org Copyright 2020, 2021, 2022, 2023 PySimpleGUI.org
""" """
def save_element_as_file(element, filename):
"""
Saves any element as an image file. Element needs to have an underlyiong Widget available (almost if not all of them do)
:param element: The element to save
:param filename: The filename to save to. The extension of the filename determines the format (jpg, png, gif, ?)
"""
widget = element.Widget
box = (widget.winfo_rootx(), widget.winfo_rooty(), widget.winfo_rootx() + widget.winfo_width(), widget.winfo_rooty() + widget.winfo_height())
grab = ImageGrab.grab(bbox=box)
grab.save(filename)
def main(): def main():
sg.theme('Dark Blue 3') sg.theme('Dark Blue 3')
@ -38,7 +24,6 @@ def main():
[sg.R('Bring to front', 1, key='-FRONT-', enable_events=True)], [sg.R('Bring to front', 1, key='-FRONT-', enable_events=True)],
[sg.R('Move Everything', 1, key='-MOVEALL-', enable_events=True)], [sg.R('Move Everything', 1, key='-MOVEALL-', enable_events=True)],
[sg.R('Move Stuff', 1, key='-MOVE-', enable_events=True)], [sg.R('Move Stuff', 1, key='-MOVE-', enable_events=True)],
[sg.B('Save Image', key='-SAVE-')],
] ]
layout = [[sg.Graph( layout = [[sg.Graph(
@ -49,20 +34,19 @@ def main():
enable_events=True, enable_events=True,
background_color='lightblue', background_color='lightblue',
drag_submits=True, drag_submits=True,
right_click_menu=[[],['Erase item',]] motion_events=True,
right_click_menu=[[''],['Erase item','Send to back']]
), sg.Col(col, key='-COL-') ], ), sg.Col(col, key='-COL-') ],
[sg.Text(key='-INFO-', size=(60, 1))]] [sg.Text(key='-INFO-', size=(60, 1))]]
window = sg.Window("Drawing and Moving Stuff Around", layout, finalize=True) window = sg.Window("Drawing and Moving Stuff Around", layout, finalize=True)
# get the graph element for ease of use later # get the graph element for ease of use later
graph = window["-GRAPH-"] # type: sg.Graph graph = window["-GRAPH-"] # type: sg.Graph
graph.draw_image(data=logo200, location=(0,400)) graph.draw_image(data=logo200, location=(0,400))
dragging = False dragging = False
start_point = end_point = prior_rect = None start_point = end_point = prior_rect = None
# graph.bind('<Button-3>', '+RIGHT+') crosshair_lines = []
while True: while True:
event, values = window.read() event, values = window.read()
print(event, values) print(event, values)
@ -73,7 +57,14 @@ def main():
graph.set_cursor(cursor='fleur') # not yet released method... coming soon! graph.set_cursor(cursor='fleur') # not yet released method... coming soon!
elif not event.startswith('-GRAPH-'): elif not event.startswith('-GRAPH-'):
graph.set_cursor(cursor='left_ptr') # not yet released method... coming soon! graph.set_cursor(cursor='left_ptr') # not yet released method... coming soon!
if event.endswith('+MOVE'):
window["-INFO-"].update(value=f"mouse {values['-GRAPH-']}")
# Delete crosshairs if any exists
if len(crosshair_lines):
for fig in crosshair_lines:
graph.delete_figure(fig)
crosshair_lines = []
window.refresh()
if event == "-GRAPH-": # if there's a "Graph" event, then it's a mouse if event == "-GRAPH-": # if there's a "Graph" event, then it's a mouse
x, y = values["-GRAPH-"] x, y = values["-GRAPH-"]
if not dragging: if not dragging:
@ -114,25 +105,28 @@ def main():
for fig in drag_figures: for fig in drag_figures:
graph.send_figure_to_back(fig) graph.send_figure_to_back(fig)
window["-INFO-"].update(value=f"mouse {values['-GRAPH-']}") window["-INFO-"].update(value=f"mouse {values['-GRAPH-']}")
elif event.endswith('+UP'): # The drawing has ended because mouse up elif event.endswith('+UP'): # The drawing has ended because mouse up
window["-INFO-"].update(value=f"grabbed rectangle from {start_point} to {end_point}") window["-INFO-"].update(value=f"grabbed rectangle from {start_point} to {end_point}")
start_point, end_point = None, None # enable grabbing a new rect start_point, end_point = None, None # enable grabbing a new rect
dragging = False dragging = False
prior_rect = None prior_rect = None
elif event.endswith('+RIGHT+'): # Righ click # elif event.endswith('+RIGHT+'): # Right click
window["-INFO-"].update(value=f"Right clicked location {values['-GRAPH-']}") # window["-INFO-"].update(value=f"Right clicked location {values['-GRAPH-']}")
elif event.endswith('+MOTION+'): # Righ click # elif event.endswith('+MOTION+'): # Right click
window["-INFO-"].update(value=f"mouse freely moving {values['-GRAPH-']}") # window["-INFO-"].update(value=f"mouse freely moving {values['-GRAPH-']}")
elif event == '-SAVE-': elif event == 'Send to back': # Right clicked menu item
# filename = sg.popup_get_file('Choose file (PNG, JPG, GIF) to save to', save_as=True) figures = graph.get_figures_at_location(values["-GRAPH-"]) # get items in front-to-back order
filename=r'test.jpg' if figures: # make sure at least 1 item found
save_element_as_file(window['-GRAPH-'], filename) graph.send_figure_to_back(figures[-1]) # get the last item which will be the top-most
elif event == 'Erase item': elif event == 'Erase item':
window["-INFO-"].update(value=f"Right click erase at {values['-GRAPH-']}") window["-INFO-"].update(value=f"Right click erase at {values['-GRAPH-']}")
if values['-GRAPH-'] != (None, None): if values['-GRAPH-'] != (None, None):
drag_figures = graph.get_figures_at_location(values['-GRAPH-']) figures = graph.get_figures_at_location(values['-GRAPH-'])
for figure in drag_figures: if figures:
graph.delete_figure(figure) graph.delete_figure(figures[-1]) # delete the one on top
location = values['-GRAPH-']
crosshair_lines = [graph.draw_line((location[0], 0), (location[0], 800), color='red'),
graph.draw_line((0, location[1]), (800, location[1]), color='red')]
window.close() window.close()

File diff suppressed because one or more lines are too long

View file

@ -44,7 +44,7 @@ def convert_to_bytes(file_or_bytes, resize=None):
if resize: if resize:
new_width, new_height = resize new_width, new_height = resize
scale = min(new_height/cur_height, new_width/cur_width) scale = min(new_height/cur_height, new_width/cur_width)
img = img.resize((int(cur_width*scale), int(cur_height*scale)), PIL.Image.ANTIALIAS) img = img.resize((int(cur_width*scale), int(cur_height*scale)), PIL.Image.LANCZOS)
bio = io.BytesIO() bio = io.BytesIO()
img.save(bio, format="PNG") img.save(bio, format="PNG")
del img del img

View file

@ -1,11 +1,30 @@
import PySimpleGUI as sg import PySimpleGUI as sg
import math import math
# Yet another usage of Graph element. """
Demo - Graph Element used to plot a mathematical formula
The Graph element has a flexible coordinate system that you define.
Thie makes is possible for you to work in your coordinates instead of an
arbitrary system.
For example, in a typical mathematics graph, (0,0) is located at the center
of the graph / page / diagram.
This Demo Program shows a graph with (0,0) being at the center of the Graph
area rather than at one of the corners.
It graphs the formula:
y = sine(x/x2) * x1
The values of x1 and x2 can be changed using 2 sliders
Copyright 2018, 2019, 2020, 2021, 2022 PySimpleGUI
"""
SIZE_X = 200 SIZE_X = 200
SIZE_Y = 100 SIZE_Y = 200
NUMBER_MARKER_FREQUENCY = 25 NUMBER_MARKER_FREQUENCY = SIZE_X//8 # How often to put tick marks on the axis
def draw_axis(): def draw_axis():
@ -13,44 +32,45 @@ def draw_axis():
graph.draw_line((0, -SIZE_Y), (0, SIZE_Y)) graph.draw_line((0, -SIZE_Y), (0, SIZE_Y))
for x in range(-SIZE_X, SIZE_X+1, NUMBER_MARKER_FREQUENCY): for x in range(-SIZE_X, SIZE_X+1, NUMBER_MARKER_FREQUENCY):
graph.draw_line((x, -3), (x, 3)) # tick marks graph.draw_line((x, -SIZE_Y/66), (x, SIZE_Y/66)) # tick marks
if x != 0: if x != 0:
# numeric labels # numeric labels
graph.draw_text(str(x), (x, -10), color='green') graph.draw_text(str(x), (x, -SIZE_Y/15), color='green', font='courier 10')
for y in range(-SIZE_Y, SIZE_Y+1, NUMBER_MARKER_FREQUENCY): for y in range(-SIZE_Y, SIZE_Y+1, NUMBER_MARKER_FREQUENCY):
graph.draw_line((-3, y), (3, y)) graph.draw_line((-SIZE_X/66, y), (SIZE_X/66, y))
if y != 0: if y != 0:
graph.draw_text(str(y), (-10, y), color='blue') graph.draw_text(str(y), (-SIZE_X/11, y), color='blue', font='courier 10')
sg.theme('DarkAmber') # Create the graph that will be put into the window. Making outside of layout so have element in a variable
graph = sg.Graph(canvas_size=(500, 500),
# Create the graph that will be put into the window
graph = sg.Graph(canvas_size=(400, 400),
graph_bottom_left=(-(SIZE_X+5), -(SIZE_Y+5)), graph_bottom_left=(-(SIZE_X+5), -(SIZE_Y+5)),
graph_top_right=(SIZE_X+5, SIZE_Y+5), graph_top_right=(SIZE_X+5, SIZE_Y+5),
background_color='white', background_color='white', expand_x=True, expand_y=True,
key='graph') key='-GRAPH-')
# Window layout # Window layout
layout = [[sg.Text('Example of Using Math with a Graph', justification='center', size=(50, 1), relief=sg.RELIEF_SUNKEN)], layout = [[sg.Text('Graph Element Combined with Math!', justification='center', relief=sg.RELIEF_SUNKEN, expand_x=True, font='Courier 18')],
[graph], [graph],
[sg.Text('y = sin(x / x2 * x1)', font='COURIER 18')], [sg.Text('y = sin(x / x2) * x1', font='COURIER 18')],
[sg.Text('x1'), sg.Slider((0, 200), orientation='h', [sg.Text('x1', font='Courier 14'), sg.Slider((0, SIZE_Y), orientation='h', enable_events=True, key='-SLIDER-', expand_x=True)],
enable_events=True, key='-SLIDER-')], [sg.Text('x2', font='Courier 14'), sg.Slider((1, SIZE_Y), orientation='h', enable_events=True, key='-SLIDER2-', expand_x=True)]]
[sg.Text('x2'), sg.Slider((1, 200), orientation='h', enable_events=True, key='-SLIDER2-')]]
window = sg.Window('Graph of Sine Function', layout) window = sg.Window('Graph of Sine Function', layout, finalize=True)
draw_axis() # draw the axis (an empty graph)
while True: while True:
event, values = window.read() event, values = window.read()
if event == sg.WIN_CLOSED: if event == sg.WIN_CLOSED:
break break
graph.erase()
draw_axis() graph.erase() # erase entire graph every time there's a change to a slider
prev_x = prev_y = None draw_axis() # redraw the axis
# plot the function by drawing short line segments
prev_x = prev_y = None
for x in range(-SIZE_X, SIZE_X): for x in range(-SIZE_X, SIZE_X):
y = math.sin(x/int(values['-SLIDER2-']))*int(values['-SLIDER-']) y = math.sin(x/int(values['-SLIDER2-'])) * int(values['-SLIDER-'])
if prev_x is not None: if prev_x is not None:
graph.draw_line((prev_x, prev_y), (x, y), color='red') graph.draw_line((prev_x, prev_y), (x, y), color='red')
prev_x, prev_y = x, y prev_x, prev_y = x, y

View file

@ -0,0 +1,45 @@
import PySimpleGUI as sg
"""
Demo - Graph Element Rescale Figures When Window Resizes
This demo shows how you can redraw your Graph element's figures so that when
you resize the window, all of the figures on the graph resize.
There may be a tkinter method to help do this?
Copyright 2022 PySimpleGUI
"""
gsize = (400,400)
layout = [ [sg.Text('Rescaling a Graph Element When Window is Resized')],
[sg.Graph(gsize, (0,0),gsize, expand_x=True, expand_y=True, k='-G-', background_color='green')],
[sg.Button('Exit'), sg.Sizegrip()] ]
window = sg.Window('Graph Element Scale With Window', layout, finalize=True, resizable=True, enable_window_config_events=True)
graph = window['-G-'] #type: sg.Graph
orig_win_size = window.current_size_accurate()
# Draw the figure desired (will repeat this code later)
fig = window['-G-'].draw_circle((200, 200), 50, fill_color='blue')
while True:
event, values = window.read()
if event == sg.WIN_CLOSED or event == 'Exit':
break
if event == sg.WINDOW_CONFIG_EVENT: # if get a window resized event
# Determine how much the window was resized by and tell the Graph element the new size for the Canvas
new_size = window.current_size_accurate()
dx = orig_win_size[0]-new_size[0]
dy = orig_win_size[1]-new_size[1]
gsize = (gsize[0] - dx, gsize[1] - dy)
orig_win_size = new_size
graph.CanvasSize = gsize
# Erase entire Graph and redraw all figures0
graph.erase()
# Redraw your figures here
fig = window['-G-'].draw_circle((200, 200), 50, fill_color='blue')
window.close()

View file

@ -45,7 +45,7 @@ def convert_to_bytes(file_or_bytes, resize=None):
if resize: if resize:
new_width, new_height = resize new_width, new_height = resize
scale = min(new_height/cur_height, new_width/cur_width) scale = min(new_height/cur_height, new_width/cur_width)
img = img.resize((int(cur_width*scale), int(cur_height*scale)), PIL.Image.ANTIALIAS) img = img.resize((int(cur_width*scale), int(cur_height*scale)), PIL.Image.LANCZOS)
with io.BytesIO() as bio: with io.BytesIO() as bio:
img.save(bio, format="PNG") img.save(bio, format="PNG")
del img del img

View file

@ -0,0 +1,32 @@
import PySimpleGUI as sg
import urllib.request
"""
Display an Image Located at a URL
Downloads and displays a PNG (or GIF) image given a URL
NOTE:
Early versions of tkinter (for example 8.6.6 found in Python 3.6) have trouble with some PNG formats.
Moving to Python 3.7 fixes this or you can use a tool to re-encode the image (e.g. psgresizer) save it and
it will then work OK in Python 3.6.
Example of one of these images - https://www.python.org/static/community_logos/python-logo-master-v3-TM.png
Copyright 2022 PySimpleGUI.org
"""
image_URL = r'https://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png'
layout = [[sg.Image(urllib.request.urlopen(image_URL).read())]]
window = sg.Window('Image From URL', layout)
while True:
event, values = window.read()
if event == sg.WIN_CLOSED or event == 'Exit':
break
window.close()

View file

@ -1,6 +1,5 @@
import PySimpleGUI as sg import PySimpleGUI as sg
from PIL import Image from PIL import Image
import PIL
import os import os
import base64 import base64
import io import io
@ -25,12 +24,19 @@ import webbrowser
Copyright 2021 PySimpleGUI Copyright 2021 PySimpleGUI
""" """
version = '1.3.1' version = '1.6.0'
__version__ = version.split()[0] __version__ = version.split()[0]
''' '''
Change log Change log
1.6.0 12-July-2022
Fixed output filename to match the size indicated under the filename.
1.5.4 10-May-2022
Had to mess around with the entry point due to setuptools
1.5.0 10-May-2022
Moved icon to bottom of file and called set_global_icon so all windows in this application (including popups) will use this icon
1.4.0 16-Nov-2021
Explicitly set the settings filename. I'm still learning about these PyPI .EXE releases. Need to be explicit rather than default
1.3.1 16-Nov-2021 1.3.1 16-Nov-2021
Added correct readme to PyPI Added correct readme to PyPI
1.3.0 16-Nov-2021 1.3.0 16-Nov-2021
@ -49,7 +55,7 @@ def resize(input_file, size, output_file=None, encode_format='PNG'):
new_width, new_height = size new_width, new_height = size
if new_width != width or new_height != height: # if the requested size is different than original size if new_width != width or new_height != height: # if the requested size is different than original size
scale = min(new_height / height, new_width / width) scale = min(new_height / height, new_width / width)
resized_image = image.resize((int(width * scale), int(height * scale)), Image.ANTIALIAS) resized_image = image.resize((int(width * scale), int(height * scale)), Image.LANCZOS)
else: else:
resized_image = image resized_image = image
@ -65,7 +71,6 @@ def resize(input_file, size, output_file=None, encode_format='PNG'):
def main(): def main():
image_resize_icon = b'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'
def update_outfilename(): def update_outfilename():
infile = values['-IN-'] infile = values['-IN-']
@ -76,8 +81,12 @@ def main():
window['-ORIG WIDTH-'].update(image.size[0]) window['-ORIG WIDTH-'].update(image.size[0])
if not values['-WIDTH-']: if not values['-WIDTH-']:
window['-WIDTH-'].update(image.size[0]) window['-WIDTH-'].update(image.size[0])
else:
width = values['-WIDTH-']
if not values['-HEIGHT-']: if not values['-HEIGHT-']:
window['-HEIGHT-'].update(image.size[1]) window['-HEIGHT-'].update(image.size[1])
else:
height = values['-HEIGHT-']
window['-ORIG HEIGHT-'].update(image.size[1]) window['-ORIG HEIGHT-'].update(image.size[1])
infilename = os.path.basename(infile) infilename = os.path.basename(infile)
@ -88,7 +97,7 @@ def main():
outfileext = 'jpg' outfileext = 'jpg'
else: else:
outfileext = infileext[1:] # strip off the . outfileext = infileext[1:] # strip off the .
outfile = f'{infilenameonly}{width}x{height}.{outfileext}' outfile = f'{infilenameonly}_{width}x{height}.{outfileext}'
outfullfilename = os.path.join(os.path.dirname(infile), outfile) outfullfilename = os.path.join(os.path.dirname(infile), outfile)
if values['-DO NOT SAVE-']: if values['-DO NOT SAVE-']:
@ -104,6 +113,9 @@ def main():
# window['-HEIGHT-'].update('') # window['-HEIGHT-'].update('')
window['-NEW FILENAME-'].update() window['-NEW FILENAME-'].update()
sg.user_settings_filename(filename='psgresizer.json')
format_list = ('', 'PNG', 'JPEG', 'BMP', 'ICO', 'GIF', 'TIFF') format_list = ('', 'PNG', 'JPEG', 'BMP', 'ICO', 'GIF', 'TIFF')
new_format_layout = [ new_format_layout = [
[sg.Combo(format_list, default_value=sg.user_settings_get_entry('-new format-', ''), readonly=True, enable_events=True, key='-NEW FORMAT-')]] [sg.Combo(format_list, default_value=sg.user_settings_get_entry('-new format-', ''), readonly=True, enable_events=True, key='-NEW FORMAT-')]]
@ -112,8 +124,8 @@ def main():
[sg.Frame('Input Filename', [[sg.Input(key='-IN-', enable_events=True, s=80), sg.FileBrowse(), ], [sg.Frame('Input Filename', [[sg.Input(key='-IN-', enable_events=True, s=80), sg.FileBrowse(), ],
[sg.T('Original size'), sg.T(k='-ORIG WIDTH-'), sg.T('X'), sg.T(k='-ORIG HEIGHT-')]])], [sg.T('Original size'), sg.T(k='-ORIG WIDTH-'), sg.T('X'), sg.T(k='-ORIG HEIGHT-')]])],
[sg.Frame('Output Filename', [[sg.In(k='-NEW FILENAME-', s=80), sg.FileBrowse(), ], [sg.Frame('Output Filename', [[sg.In(k='-NEW FILENAME-', s=80), sg.FileBrowse(), ],
[sg.In(default_text=sg.user_settings_get_entry('-width-', ''), s=4, k='-WIDTH-'), sg.T('X'), [sg.In(default_text=sg.user_settings_get_entry('-width-', ''), s=4, k='-WIDTH-', enable_events=True), sg.T('X'),
sg.In(default_text=sg.user_settings_get_entry('-height-', ''), s=4, k='-HEIGHT-')]])], sg.In(default_text=sg.user_settings_get_entry('-height-', ''), s=4, k='-HEIGHT-', enable_events=True)]])],
[sg.Frame('Convert To New Format', new_format_layout)], [sg.Frame('Convert To New Format', new_format_layout)],
[sg.CBox('Encode to Base64 and leave on Clipboard', k='-BASE64-', default=sg.user_settings_get_entry('-base64-', True))], [sg.CBox('Encode to Base64 and leave on Clipboard', k='-BASE64-', default=sg.user_settings_get_entry('-base64-', True))],
# [sg.CBox('Use PNG for all Base64 Encoding', default=True, k='-PNG CONVERT-')], # [sg.CBox('Use PNG for all Base64 Encoding', default=True, k='-PNG CONVERT-')],
@ -128,7 +140,7 @@ def main():
sg.T('A PySimpleGUI Application - Go to PySimpleGUI home', font='_ 8', enable_events=True, k='-PYSIMPLEGUI-')], sg.T('A PySimpleGUI Application - Go to PySimpleGUI home', font='_ 8', enable_events=True, k='-PYSIMPLEGUI-')],
] ]
window = sg.Window('Resize Image', layout, icon=image_resize_icon, right_click_menu=sg.MENU_RIGHT_CLICK_EDITME_VER_LOC_EXIT, window = sg.Window('Resize Image', layout, right_click_menu=sg.MENU_RIGHT_CLICK_EDITME_VER_LOC_EXIT,
enable_close_attempted_event=True, finalize=True) enable_close_attempted_event=True, finalize=True)
window['-PSGRESIZER-'].set_cursor('hand1') window['-PSGRESIZER-'].set_cursor('hand1')
window['-PYSIMPLEGUI-'].set_cursor('hand1') window['-PYSIMPLEGUI-'].set_cursor('hand1')
@ -182,6 +194,8 @@ def main():
webbrowser.open_new_tab(r'http://www.PySimpleGUI.com') webbrowser.open_new_tab(r'http://www.PySimpleGUI.com')
elif event == '-PSGRESIZER-': elif event == '-PSGRESIZER-':
webbrowser.open_new_tab(r'https://github.com/PySimpleGUI/psgresizer') webbrowser.open_new_tab(r'https://github.com/PySimpleGUI/psgresizer')
elif event in ('-WIDTH-', '-HEIGHT-'):
update_outfilename()
if event != sg.WIN_CLOSED: if event != sg.WIN_CLOSED:
sg.user_settings_set_entry('-autoclose-', values['-AUTOCLOSE-']) sg.user_settings_set_entry('-autoclose-', values['-AUTOCLOSE-'])
@ -193,5 +207,11 @@ def main():
window.close() window.close()
def main_entry_point():
image_resize_icon = b'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'
sg.set_global_icon(image_resize_icon)
main()
if __name__ == '__main__': if __name__ == '__main__':
main() main_entry_point()

View file

@ -56,7 +56,7 @@ def convert_to_bytes(file_or_bytes, resize=None, fill=False):
if resize: if resize:
new_width, new_height = resize new_width, new_height = resize
scale = min(new_height / cur_height, new_width / cur_width) scale = min(new_height / cur_height, new_width / cur_width)
img = img.resize((int(cur_width * scale), int(cur_height * scale)), PIL.Image.ANTIALIAS) img = img.resize((int(cur_width * scale), int(cur_height * scale)), PIL.Image.LANCZOS)
if fill: if fill:
img = make_square(img, THUMBNAIL_SIZE[0]) img = make_square(img, THUMBNAIL_SIZE[0])
with io.BytesIO() as bio: with io.BytesIO() as bio:

View file

@ -0,0 +1,31 @@
import PySimpleGUI as sg
"""
Demo - Save previously entered value in Input element by using user_settings calls
Tired of typing in the same value or entering the same filename into an Input element?
If so, this may be exactly what you need.
It simply saves the last value you entered so that the next time you start your program, that will be the default
Copyright 2022 PySimpleGUI.org
"""
def main():
sg.user_settings_filename(path='.') # The settings file will be in the same folder as this program
layout = [[sg.T('This is your layout')],
[sg.T('Remembers last value for this:'), sg.In(sg.user_settings_get_entry('-input-', ''), k='-INPUT-')],
[sg.OK(), sg.Button('Exit')]]
# make a window, read it, and automatically close after 1 event happens (button or X to close window)
event, values = sg.Window('Save Input Element Last Value', layout).read(close=True)
# only save the value if OK was clicked
if event == 'OK':
sg.user_settings_set_entry('-input-', values['-INPUT-'])
if __name__ == '__main__':
main()

View file

@ -19,13 +19,12 @@ import PySimpleGUI as sg
For other ports of PySimpleGUI such as the Qt port, the position is remembered by Qt and as a For other ports of PySimpleGUI such as the Qt port, the position is remembered by Qt and as a
result this technique using "pin" is not needed. result this technique using "pin" is not needed.
Copyright 2020 PySimpleGUI.org Copyright 2020, 2022 PySimpleGUI.org
""" """
layout = [ [sg.Text('Hide Button or Multiline. Buttons 1 & 2 hide Button 2')],
layout = [ [sg.Text('Hide Button or Input. Button3 hides Input. Buttons 1 & 2 hide Button 2')], [sg.pin(sg.Multiline(size=(60, 10), key='-MLINE-'))],
[sg.pin(sg.Input(key='-IN-'))], [sg.pin(sg.Button('Button1')), sg.pin(sg.Button('Button2'), shrink=False), sg.B('Toggle Multiline')],
[sg.pin(sg.Button('Button1')), sg.pin(sg.Button('Button2')), sg.B('Button3')],
] ]
window = sg.Window('Visible / Invisible Element Demo', layout) window = sg.Window('Visible / Invisible Element Demo', layout)
@ -40,7 +39,6 @@ while True: # Event Loop
if event in ('Button1', 'Button2'): if event in ('Button1', 'Button2'):
window['Button2'].update(visible=toggle) window['Button2'].update(visible=toggle)
toggle = not toggle toggle = not toggle
if event == 'Button3': elif event == 'Toggle Multiline':
window['-IN-'].update(visible=toggle_in) window['-MLINE-'].update(visible=not window['-MLINE-'].visible)
toggle_in = not toggle_in
window.close() window.close()

View file

@ -0,0 +1,65 @@
import PySimpleGUI as sg
"""
Demo - Add and "Delete" Rows from a window
This is cut-down version of the Fed-Ex package tracking demo
The purpose is to show a technique for making windows that grow by clicking an "Add Row" button
Each row can be individually "deleted".
The reason for using the quotes are "deleted" is that the elements are simply hidden. The effect is the same as deleting them.
Copyright 2022 PySimpleGUI
"""
def item_row(item_num):
"""
A "Row" in this case is a Button with an "X", an Input element and a Text element showing the current counter
:param item_num: The number to use in the tuple for each element
:type: int
:return: List
"""
row = [sg.pin(sg.Col([[sg.B(sg.SYMBOL_X, border_width=0, button_color=(sg.theme_text_color(), sg.theme_background_color()), k=('-DEL-', item_num), tooltip='Delete this item'),
sg.In(size=(20,1), k=('-DESC-', item_num)),
sg.T(f'Key number {item_num}', k=('-STATUS-', item_num))]], k=('-ROW-', item_num)))]
return row
def make_window():
layout = [ [sg.Text('Add and "Delete" Rows From a Window', font='_ 15')],
[sg.Col([item_row(0)], k='-TRACKING SECTION-')],
[sg.pin(sg.Text(size=(35,1), font='_ 8', k='-REFRESHED-',))],
[sg.T(sg.SYMBOL_X, enable_events=True, k='Exit', tooltip='Exit Application'), sg.T('', enable_events=True, k='Refresh', tooltip='Save Changes & Refresh'), sg.T('+', enable_events=True, k='Add Item', tooltip='Add Another Item')]]
right_click_menu = [[''], ['Add Item', 'Edit Me', 'Version']]
window = sg.Window('Window Title', layout, right_click_menu=right_click_menu, use_default_focus=False, font='_ 15', metadata=0)
return window
def main():
window = make_window()
while True:
event, values = window.read() # wake every hour
print(event, values)
if event == sg.WIN_CLOSED or event == 'Exit':
break
if event == 'Add Item':
window.metadata += 1
window.extend_layout(window['-TRACKING SECTION-'], [item_row(window.metadata)])
elif event == 'Edit Me':
sg.execute_editor(__file__)
elif event == 'Version':
sg.popup_scrolled(__file__, sg.get_versions(), location=window.current_location(), keep_on_top=True, non_blocking=True)
elif event[0] == '-DEL-':
window[('-ROW-', event[1])].update(visible=False)
window.close()
if __name__ == '__main__':
main()

View file

@ -0,0 +1,43 @@
import PySimpleGUI as sg
"""
Demo - Listbox Using Objects
Several elements can take not just strings, but objects. The Listsbox is one of them.
This demo show how you can use objects directly in a Listbox in a way that you can access
information about each object that is different than what is shown in the Window.
The important part of this design pattern is the use of the __str__ method in your item objects.
This method is what determines what is shown in the window.
Copyright 2022 PySimpleGUI
"""
class Item():
def __init__(self, internal, shown):
self.internal = internal
self.shown = shown
def __str__(self):
return self.shown
# make list of some objects
my_item_list = [Item(f'Internal {i}', f'shown {i}') for i in range(100)]
layout = [ [sg.Text('Select 1 or more items and click "Go"')],
[sg.Listbox(my_item_list, key='-LB-', s=(20,20), select_mode=sg.LISTBOX_SELECT_MODE_EXTENDED)],
[sg.Output(s=(40,10))],
[sg.Button('Go'), sg.Button('Exit')] ]
window = sg.Window('Listbox Using Objects', layout)
while True:
event, values = window.read()
# print(event, values)
if event == sg.WIN_CLOSED or event == 'Exit':
break
elif event == 'Go':
print('You selected:')
for item in values['-LB-']:
print(item.internal)
window.close()

View file

@ -824,15 +824,26 @@ def AxesGrid():
# The magic function that makes it possible.... glues together tkinter and pyplot using Canvas Widget # The magic function that makes it possible.... glues together tkinter and pyplot using Canvas Widget
def draw_figure(canvas, figure): def draw_figure(canvas, figure):
if not hasattr(draw_figure, 'canvas_packed'):
draw_figure.canvas_packed = {}
figure_canvas_agg = FigureCanvasTkAgg(figure, canvas) figure_canvas_agg = FigureCanvasTkAgg(figure, canvas)
figure_canvas_agg.draw() figure_canvas_agg.draw()
figure_canvas_agg.get_tk_widget().pack(side='top', fill='both', expand=1) widget = figure_canvas_agg.get_tk_widget()
if widget not in draw_figure.canvas_packed:
draw_figure.canvas_packed[widget] = figure
widget.pack(side='top', fill='both', expand=1)
return figure_canvas_agg return figure_canvas_agg
def delete_figure_agg(figure_agg): def delete_figure_agg(figure_agg):
figure_agg.get_tk_widget().forget() figure_agg.get_tk_widget().forget()
try:
draw_figure.canvas_packed.pop(figure_agg.get_tk_widget())
except Exception as e:
print(f'Error removing {figure_agg} from list', e)
plt.close('all') plt.close('all')
# -------------------------------- GUI Starts Here -------------------------------# # -------------------------------- GUI Starts Here -------------------------------#
# fig = your figure you want to display. Assumption is that 'fig' holds the # # fig = your figure you want to display. Assumption is that 'fig' holds the #
# information to display. # # information to display. #
@ -873,6 +884,9 @@ while True:
choice = values['-LISTBOX-'][0] # get first listbox item chosen (returned as a list) choice = values['-LISTBOX-'][0] # get first listbox item chosen (returned as a list)
func = fig_dict[choice] # get function to call from the dictionary func = fig_dict[choice] # get function to call from the dictionary
window['-MULTILINE-'].update(inspect.getsource(func)) # show source code to function in multiline window['-MULTILINE-'].update(inspect.getsource(func)) # show source code to function in multiline
fig = func() # call function to get the figure try:
figure_agg = draw_figure(window['-CANVAS-'].TKCanvas, fig) # draw the figure fig = func() # call function to get the figure
figure_agg = draw_figure(window['-CANVAS-'].TKCanvas, fig) # draw the figure
except Exception as e:
print('Exception in fucntion', e)
window.close() window.close()

View file

@ -837,14 +837,23 @@ def AxesGrid():
def draw_figure(canvas, figure): def draw_figure(canvas, figure):
if not hasattr(draw_figure, 'canvas_packed'):
draw_figure.canvas_packed = {}
figure_canvas_agg = FigureCanvasTkAgg(figure, canvas) figure_canvas_agg = FigureCanvasTkAgg(figure, canvas)
figure_canvas_agg.draw() figure_canvas_agg.draw()
figure_canvas_agg.get_tk_widget().pack(side='top', fill='both', expand=1) widget = figure_canvas_agg.get_tk_widget()
if widget not in draw_figure.canvas_packed:
draw_figure.canvas_packed[widget] = figure
widget.pack(side='top', fill='both', expand=1)
return figure_canvas_agg return figure_canvas_agg
def delete_figure_agg(figure_agg): def delete_figure_agg(figure_agg):
figure_agg.get_tk_widget().forget() figure_agg.get_tk_widget().forget()
try:
draw_figure.canvas_packed.pop(figure_agg.get_tk_widget())
except Exception as e:
print(f'Error removing {figure_agg} from list', e)
plt.close('all') plt.close('all')
@ -881,13 +890,11 @@ layout = [[sg.Text('Matplotlib Plot Test', font=('ANY 18'))],
[sg.Col(col_listbox), col_instructions], ] [sg.Col(col_listbox), col_instructions], ]
# create the form and show it without the plot # create the form and show it without the plot
window = sg.Window('Demo Application - Embedding Matplotlib In PySimpleGUI', window = sg.Window('Demo Application - Embedding Matplotlib In PySimpleGUI', layout, resizable=True, finalize=True)
layout, resizable=True, finalize=True)
canvas_elem = window['-CANVAS-'] canvas_elem = window['-CANVAS-']
multiline_elem = window['-MULTILINE-'] multiline_elem = window['-MULTILINE-']
figure_agg = None figure_agg = None
while True: while True:
event, values = window.read() event, values = window.read()
if event in (sg.WIN_CLOSED, 'Exit'): if event in (sg.WIN_CLOSED, 'Exit'):
@ -902,6 +909,8 @@ while True:
func = fig_dict[choice] func = fig_dict[choice]
# show source code to function in multiline # show source code to function in multiline
window['-MULTILINE-'].update(inspect.getsource(func)) window['-MULTILINE-'].update(inspect.getsource(func))
fig = func() # call function to get the figure try:
figure_agg = draw_figure( fig = func() # call function to get the figure
window['-CANVAS-'].TKCanvas, fig) # draw the figure figure_agg = draw_figure(window['-CANVAS-'].TKCanvas, fig) # draw the figure
except Exception as e:
print('Error in plotting', e)

View file

@ -890,7 +890,7 @@ def convert_to_bytes(file_or_bytes, resize=None):
if resize: if resize:
new_width, new_height = resize new_width, new_height = resize
scale = min(new_height/cur_height, new_width/cur_width) scale = min(new_height/cur_height, new_width/cur_width)
img = img.resize((int(cur_width*scale), int(cur_height*scale)), PIL.Image.ANTIALIAS) img = img.resize((int(cur_width*scale), int(cur_height*scale)), PIL.Image.LANCZOS)
with io.BytesIO() as bio: with io.BytesIO() as bio:
img.save(bio, format="PNG") img.save(bio, format="PNG")
del img del img

View file

@ -39,7 +39,7 @@ def main():
# sg.theme('black') # sg.theme('black')
menu_def = [['&File', ['&Open Ctrl-O', '&Save Ctrl-S', '&Properties', 'E&xit']], menu_def = [['&File', ['&Open Ctrl-O', '&Save Ctrl-S', '&Properties', 'E&xit']],
['&Edit', ['Me', 'Special', 'Normal',['Normal1', 'Normal2'] , 'Undo']], ['&Edit', ['Edit Me', 'Special', 'Normal',['Normal1', 'Normal2'] , 'Undo']],
['!Disabled', ['Special', 'Normal',['Normal1', 'Normal2'], 'Undo']], ['!Disabled', ['Special', 'Normal',['Normal1', 'Normal2'], 'Undo']],
['&Toolbar', ['---', 'Command &1::Command_Key', 'Command &2', '---', 'Command &3', 'Command &4']], ['&Toolbar', ['---', 'Command &1::Command_Key', 'Command &2', '---', 'Command &3', 'Command &4']],
['&Help', ['&About...']], ] ['&Help', ['&About...']], ]
@ -47,7 +47,7 @@ def main():
layout = [[sg.MenubarCustom(menu_def, pad=(0,0), k='-CUST MENUBAR-')], layout = [[sg.MenubarCustom(menu_def, pad=(0,0), k='-CUST MENUBAR-')],
[sg.Multiline(size=(70, 20), reroute_cprint=True, write_only=True, no_scrollbar=True, k='-MLINE-')]] [sg.Multiline(size=(70, 20), reroute_cprint=True, write_only=True, no_scrollbar=True, k='-MLINE-')]]
window = sg.Window("Custom Titlebar with Custom (Simulated) Menubar", layout, use_custom_titlebar=True, keep_on_top=True) window = sg.Window("Custom Titlebar with Custom (Simulated) Menubar", layout, use_custom_titlebar=True, keep_on_top=True, right_click_menu=sg.MENU_RIGHT_CLICK_EDITME_VER_EXIT)
# ------ Event Loop ------ # # ------ Event Loop ------ #
while True: while True:
@ -66,8 +66,10 @@ def main():
sg.popup('About this program', 'Simulated Menubar to accompany a simulated Titlebar', sg.popup('About this program', 'Simulated Menubar to accompany a simulated Titlebar',
'PySimpleGUI Version', sg.get_versions(), grab_anywhere=True, keep_on_top=True) 'PySimpleGUI Version', sg.get_versions(), grab_anywhere=True, keep_on_top=True)
window.reappear() window.reappear()
elif event == 'Me': elif event == 'Edit Me':
sg.execute_editor(__file__) sg.execute_editor(__file__)
elif event == 'Version':
sg.popup_scrolled(__file__, sg.get_versions(), keep_on_top=True, non_blocking=True)
elif event.startswith('Open'): elif event.startswith('Open'):
filename = sg.popup_get_file('file to open', no_window=True) filename = sg.popup_get_file('file to open', no_window=True)
print(filename) print(filename)

View file

@ -51,10 +51,8 @@ def Menubar(menu_def, text_color, background_color, pad=(0, 0)):
def main(): def main():
sg.theme('dark green 7') sg.theme('dark green 7')
sg.theme('dark amber')
# sg.theme('dark purple 3')
menu_def = [['&File', ['&Open Ctrl-O', '&Save Ctrl-S', '&Properties', 'E&xit']], menu_def = [['&File', ['&Open & Ctrl-O', '&Save & Ctrl-S', '&Properties', 'E&xit']],
['&Edit', [['Special', 'Normal',['Normal1', 'Normal2'] ], 'Undo'], ], ['&Edit', [['Special', 'Normal',['Normal1', 'Normal2'] ], 'Undo'], ],
['!Disabled', [['Special', 'Normal',['Normal1', 'Normal2'] ], 'Undo'], ], ['!Disabled', [['Special', 'Normal',['Normal1', 'Normal2'] ], 'Undo'], ],
['&Toolbar', ['---', 'Command &1::Command_Key', 'Command &2', '---', 'Command &3', 'Command &4']], ['&Toolbar', ['---', 'Command &1::Command_Key', 'Command &2', '---', 'Command &3', 'Command &4']],
@ -78,13 +76,13 @@ def main():
layout3 = [[sg.Multiline(size=(70, 20), reroute_stdout=True, reroute_cprint=True, write_only=True)],] layout3 = [[sg.Multiline(size=(70, 20), reroute_stdout=True, reroute_cprint=True, write_only=True)],]
window = sg.Window("Custom Titlebar and Menu", layout, use_custom_titlebar=True, finalize=True) window = sg.Window("Custom Titlebar and Menu", layout, use_custom_titlebar=True, finalize=True, right_click_menu=sg.MENU_RIGHT_CLICK_EDITME_VER_EXIT)
win_loc = window.current_location() win_loc = window.current_location()
window2 = sg.Window("Traditional Titlebar and Menu", layout2, finalize=True, location=(win_loc[0]-window.size[0]-40, win_loc[1])) window2 = sg.Window("Traditional Titlebar and Menu", layout2, finalize=True, location=(win_loc[0]-window.size[0]-40, win_loc[1]), right_click_menu=sg.MENU_RIGHT_CLICK_EDITME_VER_EXIT)
window3 = sg.Window("Output Window", layout3, finalize=True, location=(win_loc[0]-window.size[0]//1.5, win_loc[1]+window.size[1]+30), use_custom_titlebar=True) window3 = sg.Window("Output Window", layout3, finalize=True, location=(int(win_loc[0]-window.size[0]//1.5), int(win_loc[1]+window.size[1]+30)), use_custom_titlebar=True, right_click_menu=sg.MENU_RIGHT_CLICK_EDITME_VER_EXIT)
# ------ Event Loop ------ # # ------ Event Loop ------ #
@ -97,7 +95,11 @@ def main():
if event in (sg.WIN_CLOSED, 'Exit'): if event in (sg.WIN_CLOSED, 'Exit'):
break break
elif event == 'Edit Me':
sg.execute_editor(__file__)
elif event == 'Version':
sg.popup_scrolled(__file__, sg.get_versions(), keep_on_top=True, non_blocking=True)
sg.cprint(f'event = {event}', c='white on red') sg.cprint(f'event = {event}', c='white on red')
sg.cprint(f'values = {values}', c='white on green') sg.cprint(f'values = {values}', c='white on green')

View file

@ -1,10 +1,13 @@
#!/usr/bin/env python #!/usr/bin/env python
import PySimpleGUI as sg import PySimpleGUI as sg
""" """
Demonstration of MENUS! Demo of Menu element, ButtonMenu element and right-click menus
How do menus work? Like buttons is how.
Check out the variable menu_def for a hint on how to The same basic structure is used for all menus in PySimpleGUI.
define menus Each entry is a list of items to display. If any of those items is a list, then a cancade menu is added.
Copyright 2018, 2019, 2020, 2021, 2022 PySimpleGUI
""" """
@ -24,20 +27,22 @@ def test_menus():
sg.set_options(element_padding=(0, 0)) sg.set_options(element_padding=(0, 0))
# ------ Menu Definition ------ # # ------ Menu Definition ------ #
menu_def = [['&File', ['&Open Ctrl-O', '&Save Ctrl-S', '&Properties', 'E&xit']], menu_def = [
['&Edit', ['&Paste', ['Special', 'Normal', ], 'Undo'], ], ['&File', ['&Open Ctrl-O', '&Save Ctrl-S', '&Properties', 'E&xit']],
['&Edit', ['&Paste', ['Special', 'Normal', ], 'Undo', 'Options::this_is_a_menu_key'], ],
['&Toolbar', ['---', 'Command &1', 'Command &2', ['&Toolbar', ['---', 'Command &1', 'Command &2',
'---', 'Command &3', 'Command &4']], '---', 'Command &3', 'Command &4']],
['&Help', '&About...'], ] ['&Help', ['&About...']]
]
right_click_menu = ['Unused', ['Right', '!&Click', '&Menu', 'E&xit', 'Properties']] right_click_menu = ['Unused', ['Right', '!&Click', '&Menu', 'E&xit', 'Properties']]
# ------ GUI Defintion ------ # # ------ GUI Defintion ------ #
layout = [ layout = [
[sg.Menu(menu_def, tearoff=False, pad=(200, 1))], [sg.Menu(menu_def, tearoff=True, font='_ 12', key='-MENUBAR-')],
[sg.Text('Right click me for a right click menu example')], [sg.Text('Right click me for a right click menu example')],
[sg.Output(size=(60, 20))], [sg.Output(size=(60, 20))],
[sg.ButtonMenu('ButtonMenu', right_click_menu, key='-BMENU-'), sg.Button('Plain Button')], [sg.ButtonMenu('ButtonMenu', right_click_menu, key='-BMENU-', text_color='red', disabled_text_color='green'), sg.Button('Plain Button')],
] ]
window = sg.Window("Windows-like program", window = sg.Window("Windows-like program",
@ -55,8 +60,7 @@ def test_menus():
# ------ Process menu choices ------ # # ------ Process menu choices ------ #
if event == 'About...': if event == 'About...':
window.disappear() window.disappear()
sg.popup('About this program', 'Version 1.0', sg.popup('About this program', 'Version 1.0', 'PySimpleGUI Version', sg.get_versions())
'PySimpleGUI Version', sg.version, grab_anywhere=True)
window.reappear() window.reappear()
elif event == 'Open': elif event == 'Open':
filename = sg.popup_get_file('file to open', no_window=True) filename = sg.popup_get_file('file to open', no_window=True)

View file

@ -0,0 +1,46 @@
import PySimpleGUI as sg
"""
Read all windows example
The input elements are shown as output on the other window when "Go" is pressed
The checkboxes on window 1 are mirrored on window 2 if "mirror" checkbox is set
Copyright 2022 PySimpleGUI
"""
layout1 = [ [sg.Text('My Window')],
[sg.Input(k='-IN-'), sg.Text(k='-OUT-')],
[sg.CB('Check 1', k='-CB1-', enable_events=True), sg.CB('Check 2', k='-CB2-', enable_events=True), sg.CB('Mirror on Window 2', enable_events=True, k='-CB3-')],
[sg.Button('Go'), sg.Button('Exit')] ]
window1 = sg.Window('Window 1 Title', layout1, finalize=True, grab_anywhere=True, relative_location=(-600, 0))
layout2 = [ [sg.Text('My Window')],
[sg.Input(k='-IN-'), sg.Text(k='-OUT-')],
[sg.CB('Check 1', k='-CB1-'), sg.CB('Check 2', k='-CB2-')],
[sg.Button('Go'), sg.Button('Exit')] ]
window2 = sg.Window('Window 2 Title', layout2, finalize=True, grab_anywhere=True)
while True: # Event Loop
window, event, values = sg.read_all_windows()
if window is None:
print('exiting because no windows are left')
break
print(window.Title, event, values) if window is not None else None
if event == sg.WIN_CLOSED or event == 'Exit':
window.close()
if event == 'Go':
# Output the input element to the other windwow
try: # try to update the other window
if window == window1:
window2['-OUT-'].update(values['-IN-'])
else:
window1['-OUT-'].update(values['-IN-'])
except:
pass
try:
if window == window1 and values['-CB3-']:
window2['-CB1-'].update(values['-CB1-'])
window2['-CB2-'].update(values['-CB2-'])
except:
pass

View file

@ -0,0 +1,142 @@
import PySimpleGUI as sg
import random
import time
import queue
"""
Demo - Multi-threaded "Data Pump" Design Pattern
Send data to your PySimpleGUI program through a Python Queue, enabling integration with many
different types of data sources.
A thread gets data from a queue object and passes it over to the main event loop.
The external_thread is only used here to generaate random data. It's not part of the
overall "Design Pattern".
The thread the_thread IS part of the design pattern. It reads data from the thread_queue and sends that
data over to the PySimpleGUI event loop.
Copyright 2022 PySimpleGUI
"""
gsize = (400, 400) # size of the graph
THREAD_KEY = '-THREAD-'
THREAD_INCOMING_DATA = '-INCOMING DATA-'
THREAD_EXITNG = '-THREAD EXITING-'
THREAD_EXTERNAL_EXITNG = '-EXTERNAL THREAD EXITING-'
# This queue is where you will send your data that you want to eventually arrive as an event
thread_queue = queue.Queue()
# M""""""""M dP dP
# Mmmm mmmM 88 88
# MMMM MMMM 88d888b. 88d888b. .d8888b. .d8888b. .d888b88
# MMMM MMMM 88' `88 88' `88 88ooood8 88' `88 88' `88
# MMMM MMMM 88 88 88 88. ... 88. .88 88. .88
# MMMM MMMM dP dP dP `88888P' `88888P8 `88888P8
# MMMMMMMMMM
#
# MP""""""`MM oo dP dP oo
# M mmmmm..M 88 88
# M. `YM dP 88d8b.d8b. dP dP 88 .d8888b. d8888P dP 88d888b. .d8888b.
# MMMMMMM. M 88 88'`88'`88 88 88 88 88' `88 88 88 88' `88 88' `88
# M. .MMM' M 88 88 88 88 88. .88 88 88. .88 88 88 88 88 88. .88
# Mb. .dM dP dP dP dP `88888P' dP `88888P8 dP dP dP dP `8888P88
# MMMMMMMMMMM .88
# d8888P
# M""""""'YMM dP MP""""""`MM
# M mmmm. `M 88 M mmmmm..M
# M MMMMM M .d8888b. d8888P .d8888b. M. `YM .d8888b. dP dP 88d888b. .d8888b. .d8888b.
# M MMMMM M 88' `88 88 88' `88 MMMMMMM. M 88' `88 88 88 88' `88 88' `"" 88ooood8
# M MMMM' .M 88. .88 88 88. .88 M. .MMM' M 88. .88 88. .88 88 88. ... 88. ...
# M .MM `88888P8 dP `88888P8 Mb. .dM `88888P' `88888P' dP `88888P' `88888P'
# MMMMMMMMMMM MMMMMMMMMMM
#
def external_thread(thread_queue:queue.Queue):
"""
Represents some external source of data.
You would not include this code as a starting point with this Demo Program. Your data is assumed to
come from somewhere else. The important part is that you add data to the thread_queue
:param thread_queue:
:return:
"""
i = 0
while True:
time.sleep(.01)
point = (random.randint(0,gsize[0]), random.randint(0,gsize[1]))
radius = random.randint(10, 40)
thread_queue.put((point, radius))
i += 1
# M""""""""M dP dP MM""""""""`M
# Mmmm mmmM 88 88 MM mmmmmmmM
# MMMM MMMM 88d888b. 88d888b. .d8888b. .d8888b. .d888b88 M' MMMM .d8888b. 88d888b.
# MMMM MMMM 88' `88 88' `88 88ooood8 88' `88 88' `88 MM MMMMMMMM 88' `88 88' `88
# MMMM MMMM 88 88 88 88. ... 88. .88 88. .88 MM MMMMMMMM 88. .88 88
# MMMM MMMM dP dP dP `88888P' `88888P8 `88888P8 MM MMMMMMMM `88888P' dP
# MMMMMMMMMM MMMMMMMMMMMM
#
# MM"""""""`YM MP""""""`MM MM'"""""`MM MM""""""""`M dP
# MM mmmmm M M mmmmm..M M' .mmm. `M MM mmmmmmmM 88
# M' .M M. `YM M MMMMMMMM M` MMMM dP .dP .d8888b. 88d888b. d8888P .d8888b.
# MM MMMMMMMM MMMMMMM. M M MMM `M MM MMMMMMMM 88 d8' 88ooood8 88' `88 88 Y8ooooo.
# MM MMMMMMMM M. .MMM' M M. `MMM' .M MM MMMMMMMM 88 .88' 88. ... 88 88 88 88
# MM MMMMMMMM Mb. .dM MM. .MM MM .M 8888P' `88888P' dP dP dP `88888P'
# MMMMMMMMMMMM MMMMMMMMMMM MMMMMMMMMMM MMMMMMMMMMMM
def the_thread(window:sg.Window, thread_queue:queue.Queue):
"""
The thread that communicates with the application through the window's events.
Waits for data from a queue and sends that data on to the event loop
:param window:
:param thread_queue:
:return:
"""
while True:
data = thread_queue.get()
window.write_event_value((THREAD_KEY, THREAD_INCOMING_DATA), data) # Data sent is a tuple of thread name and counter
def main():
layout = [ [sg.Text('My Simulated Data Pump')],
[sg.Multiline(size=(60, 20), k='-MLINE-')],
[sg.Graph(gsize, (0, 0), gsize, k='-G-', background_color='gray')],
[sg.Button('Go'), sg.Button('Exit')] ]
window = sg.Window('Simulated Data Pump', layout, right_click_menu=sg.MENU_RIGHT_CLICK_EDITME_VER_EXIT)
graph = window['-G-'] # type: sg.Graph
while True: # Event Loop
event, values = window.read()
# print(event, values)
if event == sg.WIN_CLOSED or event == 'Exit':
break
if event == 'Go':
window.start_thread(lambda: the_thread(window, thread_queue), (THREAD_KEY, THREAD_EXITNG))
window.start_thread(lambda: external_thread(thread_queue), (THREAD_KEY, THREAD_EXTERNAL_EXITNG))
# Events coming from the Thread
elif event[0] == THREAD_KEY:
if event[1] == THREAD_INCOMING_DATA:
point, radius = values[event]
graph.draw_circle(point, radius=radius, fill_color='green')
window['-MLINE-'].print(f'Drawing at {point} radius {radius}', c='white on red')
elif event[1] == THREAD_EXITNG:
window['-MLINE-'].print('Thread has exited')
elif event[1] == THREAD_EXTERNAL_EXITNG:
window['-MLINE-'].print('Data Pump thread has exited')
if event == 'Edit Me':
sg.execute_editor(__file__)
elif event == 'Version':
sg.popup_scrolled(__file__, sg.get_versions(), location=window.current_location(), keep_on_top=True, non_blocking=True)
window.close()
if __name__ == '__main__':
main()

View file

@ -0,0 +1,151 @@
import PySimpleGUI as sg
import time
import threading
"""
Demo - Multi-threaded - Show Windows and perform other PySimpleGUI calls in what appread to be from a thread
Just so that it's clear, you CANNOT make PySimpleGUI calls directly from a thread. There is ONE exception to this
rule. A thread may call window.write_event_values which enables it to communicate to a window through the window.read calls.
The main GUI will not be visible on your screen nor on your taskbar despite running in the background. The calls you
make, such as popup, or even Window.read will create windows that your user will see.
The basic function that you'll use in your thread has this format:
make_delegate_call(lambda: sg.popup('This is a popup', i, auto_close=True, auto_close_duration=2, keep_on_top=True, non_blocking=True))
Everything after the "lambda" looks exactly like a PySimpleGUI call.
If you want to display an entire window, then the suggestion is to put it into a function and pass the function to make_delegate_call
Note - the behavior of variables may be a bit of a surprise as they are not evaluated until the mainthread processes the event. This means
in the example below that the counter variable being passed to the popup will not appear to be counting correctly. This is because the
value shown will be the value at the time the popup is DISPLAYED, not the value when the make_delegate_call was made.
Copyright 2022 PySimpleGUI
"""
# Design decision was to make the window a global. You can just as easily pass it to your function after initizing your window
# But there becomes a problem then of wheere do you place the thread startup code. Using this global decouples them so that
# the thread is not started in the function that makes and executes the GUI
window:sg.Window = None
# M""MMMM""M
# M. `MM' .M
# MM. .MM .d8888b. dP dP 88d888b.
# MMMb dMMM 88' `88 88 88 88' `88
# MMMM MMMM 88. .88 88. .88 88
# MMMM MMMM `88888P' `88888P' dP
# MMMMMMMMMM
#
# M""""""""M dP dP
# Mmmm mmmM 88 88
# MMMM MMMM 88d888b. 88d888b. .d8888b. .d8888b. .d888b88
# MMMM MMMM 88' `88 88' `88 88ooood8 88' `88 88' `88
# MMMM MMMM 88 88 88 88. ... 88. .88 88. .88
# MMMM MMMM dP dP dP `88888P' `88888P8 `88888P8
# MMMMMMMMMM
def the_thread():
"""
This is code that is unique to your application. It wants to "make calls to PySimpleGUI", but it cannot directly do so.
Instead it will send the request to make the call to the mainthread that is running the GUI.
:return:
"""
# Wait for the GUI to start running
while window is None:
time.sleep(.2)
for i in range(5):
time.sleep(.2)
make_delegate_call(lambda: sg.popup('This is a popup', i, relative_location=(0, -300), auto_close=True, auto_close_duration=2, keep_on_top=True, non_blocking=True))
make_delegate_call(lambda: sg.popup_scrolled(__file__, sg.get_versions(), auto_close=True, auto_close_duration=1.5, non_blocking=True))
make_delegate_call(lambda: sg.popup('One last popup before exiting...', relative_location=(-200, -200)))
# when finished and ready to stop, tell the main GUI to exit
window.write_event_value('-THREAD EXIT-', None)
# -------------------------------------------------------------------------------------------------------- #
# The remainder of the code is part of the overall design pattern. You should copy this code
# and use it as the basis for creating this time of delegated PySimpleGUI calls
# M""""""'YMM oo
# M mmmm. `M
# M MMMMM M .d8888b. .d8888b. dP .d8888b. 88d888b.
# M MMMMM M 88ooood8 Y8ooooo. 88 88' `88 88' `88
# M MMMM' .M 88. ... 88 88 88. .88 88 88
# M .MM `88888P' `88888P' dP `8888P88 dP dP
# MMMMMMMMMMM .88
# d8888P
# MM"""""""`YM dP dP
# MM mmmmm M 88 88
# M' .M .d8888b. d8888P d8888P .d8888b. 88d888b. 88d888b.
# MM MMMMMMMM 88' `88 88 88 88ooood8 88' `88 88' `88
# MM MMMMMMMM 88. .88 88 88 88. ... 88 88 88
# MM MMMMMMMM `88888P8 dP dP `88888P' dP dP dP
# MMMMMMMMMMMM
def make_delegate_call(func):
"""
Make a delegate call to PySimpleGUI.
:param func: A lambda expression most likely. It's a function that will be called by the mainthread that's executing the GUI
:return:
"""
if window is not None:
window.write_event_value('-THREAD DELEGATE-', func)
# oo
#
# 88d8b.d8b. .d8888b. dP 88d888b.
# 88'`88'`88 88' `88 88 88' `88
# 88 88 88 88. .88 88 88 88
# dP dP dP `88888P8 dP dP dP
def main():
global window
# create a window. A key is needed so that the values dictionary will return the thread's value as a key
layout = [[sg.Text('', k='-T-')]]
# set the window to be both invisible and have no taskbar icon
window = sg.Window('Invisible window', layout, no_titlebar=True, alpha_channel=0, finalize=True, font='_ 1', margins=(0,0), element_padding=(0,0))
window.hide()
while True:
event, values = window.read()
if event in ('Exit', sg.WIN_CLOSED):
break
# if the event is from the thread, then the value is the function that should be called
if event == '-THREAD DELEGATE-':
try:
values[event]()
except Exception as e:
sg.popup_error_with_traceback('Error calling your function passed to GUI', event, values, e)
elif event == '-THREAD EXIT-':
break
window.close()
# MP""""""`MM dP dP
# M mmmmm..M 88 88
# M. `YM d8888P .d8888b. 88d888b. d8888P dP dP 88d888b.
# MMMMMMM. M 88 88' `88 88' `88 88 88 88 88' `88
# M. .MMM' M 88 88. .88 88 88 88. .88 88. .88
# Mb. .dM dP `88888P8 dP dP `88888P' 88Y888P'
# MMMMMMMMMMM 88
# dP
if __name__ == '__main__':
# first your thread will be started
threading.Thread(target=the_thread, daemon=True).start()
# then startup the main GUI
main()

View file

@ -1,25 +1,23 @@
#!/usr/bin/python3 #!/usr/bin/python3
import threading
import time import time
import PySimpleGUI as sg import PySimpleGUI as sg
""" """
DESIGN PATTERN - Multithreaded Long Tasks GUI Demo Program - Multithreaded Long Tasks GUI
Presents one method for running long-running operations in a PySimpleGUI environment. Presents one method for running long-running operations in a PySimpleGUI environment.
The PySimpleGUI code, and thus the underlying GUI framework, runs as the primary, main thread The PySimpleGUI code, and thus the underlying GUI framework, runs as the primary, main thread
The "long work" is contained in the thread that is being started. The "long work" is contained in the thread that is being started.
July 2020 - Note that this program has been updated to use the new Window.write_event_value method. So that you don't have to import and understand the threading module, this program uses window.start_thread to run a thread.
This method has not yet been ported to the other PySimpleGUI ports and is thus limited to the tkinter ports for now.
Internally to PySimpleGUI, a queue.Queue is used by the threads to communicate with main GUI code The thread is using TUPLES for its keys. This enables you to easily find the thread events by looking at event[0].
The PySimpleGUI code is structured just like a typical PySimpleGUI program. A layout defined, The Thread Keys look something like this: ('-THREAD-', message)
a Window is created, and an event loop is executed. If event [0] == '-THREAD-' then you know it's one of these tuple keys.
Copyright 2022 PySimpleGUI
This design pattern works for all of the flavors of PySimpleGUI including the Web and also repl.it
You'll find a repl.it version here: https://repl.it/@PySimpleGUI/Async-With-Queue-Communicationspy
""" """
@ -28,12 +26,12 @@ def long_operation_thread(seconds, window):
A worker thread that communicates with the GUI through a queue A worker thread that communicates with the GUI through a queue
This thread can block for as long as it wants and the GUI will not be affected This thread can block for as long as it wants and the GUI will not be affected
:param seconds: (int) How long to sleep, the ultimate blocking call :param seconds: (int) How long to sleep, the ultimate blocking call
:param gui_queue: (queue.Queue) Queue to communicate back to GUI that task is completed :param window: (sg.Window) the window to communicate with
:return: :return:
""" """
print('Starting thread - will sleep for {} seconds'.format(seconds)) window.write_event_value(('-THREAD-', 'Starting thread - will sleep for {} seconds'.format(seconds)), None)
time.sleep(seconds) # sleep for a while time.sleep(seconds) # sleep for a while
window.write_event_value('-THREAD-', '** DONE **') # put a message into queue for GUI window.write_event_value(('-THREAD-', '** DONE **'), 'Done!') # put a message into queue for GUI
def the_gui(): def the_gui():
@ -47,7 +45,7 @@ def the_gui():
layout = [[sg.Text('Long task to perform example')], layout = [[sg.Text('Long task to perform example')],
[sg.Output(size=(70, 12))], [sg.Output(size=(70, 12))],
[sg.Text('Number of seconds your task will take'), [sg.Text('Number of seconds your task will take'),
sg.Input(key='-SECONDS-', size=(5, 1)), sg.Input(default_text=5, key='-SECONDS-', size=(5, 1)),
sg.Button('Do Long Task', bind_return_key=True)], sg.Button('Do Long Task', bind_return_key=True)],
[sg.Button('Click Me'), sg.Button('Exit')], ] [sg.Button('Click Me'), sg.Button('Exit')], ]
@ -58,14 +56,14 @@ def the_gui():
event, values = window.read() event, values = window.read()
if event in (sg.WIN_CLOSED, 'Exit'): if event in (sg.WIN_CLOSED, 'Exit'):
break break
elif event.startswith('Do'): elif event == 'Do Long Task':
seconds = int(values['-SECONDS-']) seconds = int(values['-SECONDS-'])
print('Thread ALIVE! Long work....sending value of {} seconds'.format(seconds)) print('Thread ALIVE! Long work....sending value of {} seconds'.format(seconds))
threading.Thread(target=long_operation_thread, args=(seconds, window,), daemon=True).start() window.start_thread(lambda: long_operation_thread(seconds, window), ('-THREAD-', '-THEAD ENDED-'))
elif event == 'Click Me': elif event == 'Click Me':
print('Your GUI is alive and well') print('Your GUI is alive and well')
elif event == '-THREAD-': elif event[0] == '-THREAD-':
print('Got a message back from the thread: ', values[event]) print('Got a message back from the thread: ', event[1])
# if user exits the window, then close the window and exit the GUI func # if user exits the window, then close the window and exit the GUI func
window.close() window.close()

View file

@ -1,5 +1,4 @@
import PySimpleGUI as sg import PySimpleGUI as sg
import threading
import random import random
import time import time
@ -14,37 +13,46 @@ import time
have implemented your own progress meter in your window. have implemented your own progress meter in your window.
Using the write_event_value method enables you to easily do either of these. Using the write_event_value method enables you to easily do either of these.
In this demo, all thread events are a TUPLE with the first item in tuple being THREAD_KEY ---> '-THEAD-'
This allows easy separation of all of the thread-based keys into 1 if statment:
elif event[0] == THREAD_KEY:
Example
(THREAD_KEY, DL_START_KEY) indicates the download is starting and provices the Max value
(THREAD_KEY, DL_END_KEY) indicates the downloading has completed
The main window uses a relative location when making the window so that the one-line-progress-meter has room
Copyright 2021 PySimpleGUI Copyright 2021, 2022 PySimpleGUI
""" """
THREAD_KEY = '-THREAD-'
DL_START_KEY = '-START DOWNLOAD-' DL_START_KEY = '-START DOWNLOAD-'
DL_COUNT_KEY = '-COUNT-' DL_COUNT_KEY = '-COUNT-'
DL_END_KEY = '-END DOWNLOAD-' DL_END_KEY = '-END DOWNLOAD-'
DL_THREAD_EXITNG = '-THREAD EXITING-'
def the_thread(window:sg.Window): def the_thread(window:sg.Window):
""" """
The thread that communicates with the application through the window's events. The thread that communicates with the application through the window's events.
Once a second wakes and sends a new event and associated value to the window Simulates downloading a random number of chinks from 50 to 100-
""" """
max_value = random.randint(50, 100) max_value = random.randint(50, 100)
window.write_event_value(DL_START_KEY, max_value) # Data sent is a tuple of thread name and counter window.write_event_value((THREAD_KEY, DL_START_KEY), max_value) # Data sent is a tuple of thread name and counter
for i in range(max_value): for i in range(max_value):
time.sleep(.1) time.sleep(.1)
window.write_event_value(DL_COUNT_KEY, i) # Data sent is a tuple of thread name and counter window.write_event_value((THREAD_KEY, DL_COUNT_KEY), i) # Data sent is a tuple of thread name and counter
window.write_event_value(DL_END_KEY, max_value) # Data sent is a tuple of thread name and counter window.write_event_value((THREAD_KEY, DL_END_KEY), max_value) # Data sent is a tuple of thread name and counter
def main(): def main():
layout = [ [sg.Text('My Window')], layout = [ [sg.Text('My Multi-threaded PySimpleGUI Program')],
[sg.ProgressBar(100, 'h', size=(30,20), k='-PROGRESS-')], [sg.ProgressBar(100, 'h', size=(30,20), k='-PROGRESS-', expand_x=True)],
[sg.Text(key='-STATUS-')],
[sg.Button('Go'), sg.Button('Exit')] ] [sg.Button('Go'), sg.Button('Exit')] ]
window = sg.Window('Window Title', layout, finalize=True) window = sg.Window('Window Title', layout, finalize=True, relative_location=(0, -300))
window.read(timeout=0)
window.move(window.current_location()[0], window.current_location()[1]-300)
downloading, max_value = False, 0 downloading, max_value = False, 0
while True: # Event Loop while True: # Event Loop
@ -53,17 +61,24 @@ def main():
if event == sg.WIN_CLOSED or event == 'Exit': if event == sg.WIN_CLOSED or event == 'Exit':
break break
if event == 'Go' and not downloading: if event == 'Go' and not downloading:
threading.Thread(target=the_thread, args=(window,), daemon=True).start() window.start_thread(lambda: the_thread(window), (THREAD_KEY, DL_THREAD_EXITNG))
elif event == DL_START_KEY: # Events coming from the Thread
max_value = values[event] elif event[0] == THREAD_KEY:
downloading = True if event[1] == DL_START_KEY:
sg.one_line_progress_meter(f'Downloading {max_value} segments', 0, max_value, 1, f'Downloading {max_value} segments', ) max_value = values[event]
window['-PROGRESS-'].update(0, max_value) downloading = True
elif event == DL_COUNT_KEY: window['-STATUS-'].update('Starting download')
sg.one_line_progress_meter(f'Downloading {max_value} segments', values[event]+1, max_value, 1, f'Downloading {max_value} segments') sg.one_line_progress_meter(f'Downloading {max_value} segments', 0, max_value, 1, f'Downloading {max_value} segments', )
window['-PROGRESS-'].update(values[event]+1, max_value) window['-PROGRESS-'].update(0, max_value)
elif event == DL_END_KEY: elif event[1] == DL_COUNT_KEY:
downloading = False sg.one_line_progress_meter(f'Downloading {max_value} segments', values[event]+1, max_value, 1, f'Downloading {max_value} segments')
window['-STATUS-'].update(f'Got a new current count update {values[event]}')
window['-PROGRESS-'].update(values[event]+1, max_value)
elif event[1] == DL_END_KEY:
downloading = False
window['-STATUS-'].update('Download finished')
elif event[1] == DL_THREAD_EXITNG:
window['-STATUS-'].update('Last step - Thread has exited')
window.close() window.close()

View file

@ -15,7 +15,7 @@ button64 = 'iVBORw0KGgoAAAANSUhEUgAAAoAAAAFACAMAAAAbEz04AAAABGdBTUEAALGPC/xhBQAA
def image_file_to_bytes(image64, size): def image_file_to_bytes(image64, size):
image_file = io.BytesIO(base64.b64decode(image64)) image_file = io.BytesIO(base64.b64decode(image64))
img = Image.open(image_file) img = Image.open(image_file)
img.thumbnail(size, Image.ANTIALIAS) img.thumbnail(size, Image.LANCZOS)
bio = io.BytesIO() bio = io.BytesIO()
img.save(bio, format='PNG') img.save(bio, format='PNG')
imgbytes = bio.getvalue() imgbytes = bio.getvalue()

View file

@ -1,16 +1,18 @@
#!/usr/bin/env python #!/usr/bin/env python
import PySimpleGUI as sg import PySimpleGUI as sg
from PIL import Image
import cv2 as cv import cv2 as cv
import io # from PIL import Image
# import io
""" """
Demo program to open and play a file using OpenCV Demo program to open and play a file using OpenCV
It's main purpose is to show you: It's main purpose is to show you:
1. How to get a frame at a time from a video file using OpenCV 1. How to get a frame at a time from a video file using OpenCV
2. How to display an image in a PySimpleGUI Window 2. How to display an image in a PySimpleGUI Window
For added fun, you can reposition the video using the slider. For added fun, you can reposition the video using the slider.
Copyright 2022 PySimpleGUI
""" """
@ -28,37 +30,39 @@ def main():
# ---===--- define the window layout --- # # ---===--- define the window layout --- #
layout = [[sg.Text('OpenCV Demo', size=(15, 1), font='Helvetica 20')], layout = [[sg.Text('OpenCV Demo', size=(15, 1), font='Helvetica 20')],
[sg.Image(filename='', key='-image-')], [sg.Image(key='-IMAGE-')],
[sg.Slider(range=(0, num_frames), [sg.Slider(range=(0, num_frames), size=(60, 10), orientation='h', key='-SLIDER-')],
size=(60, 10), orientation='h', key='-slider-')], [sg.Push(), sg.Button('Exit', font='Helvetica 14')]]
[sg.Button('Exit', size=(7, 1), pad=((600, 0), 3), font='Helvetica 14')]]
# create the window and show it without the plot # create the window and show it without the plot
window = sg.Window('Demo Application - OpenCV Integration', layout, no_titlebar=False, location=(0, 0)) window = sg.Window('Demo Application - OpenCV Integration', layout, no_titlebar=False, location=(0, 0))
# locate the elements we'll be updating. Does the search only 1 time # locate the elements we'll be updating. Does the search only 1 time
image_elem = window['-image-'] image_elem = window['-IMAGE-']
slider_elem = window['-slider-'] slider_elem = window['-SLIDER-']
timeout = 1000//fps # time in ms to use for window reads
# ---===--- LOOP through video file by frame --- # # ---===--- LOOP through video file by frame --- #
cur_frame = 0 cur_frame = 0
while vidFile.isOpened(): while vidFile.isOpened():
event, values = window.read(timeout=0) event, values = window.read(timeout=timeout)
if event in ('Exit', None): if event in ('Exit', None):
break break
ret, frame = vidFile.read() ret, frame = vidFile.read()
if not ret: # if out of data stop looping if not ret: # if out of data stop looping
break break
# if someone moved the slider manually, the jump to that frame # if someone moved the slider manually, the jump to that frame
if int(values['-slider-']) != cur_frame-1: if int(values['-SLIDER-']) != cur_frame-1:
cur_frame = int(values['-slider-']) cur_frame = int(values['-SLIDER-'])
vidFile.set(cv.CAP_PROP_POS_FRAMES, cur_frame) vidFile.set(cv.CAP_PROP_POS_FRAMES, cur_frame)
slider_elem.update(cur_frame) slider_elem.update(cur_frame)
cur_frame += 1 cur_frame += 1
imgbytes = cv.imencode('.png', frame)[1].tobytes() # ditto imgbytes = cv.imencode('.ppm', frame)[1].tobytes() # can also use png. ppm found to be more efficient
image_elem.update(data=imgbytes) image_elem.update(data=imgbytes)
main()
############# #############
# | | # # | | #
# | | # # | | #
@ -74,6 +78,4 @@ def main():
img.save(bio, format= 'PNG') # save image as png to it img.save(bio, format= 'PNG') # save image as png to it
imgbytes = bio.getvalue() # this can be used by OpenCV hopefully imgbytes = bio.getvalue() # this can be used by OpenCV hopefully
image_elem.update(data=imgbytes) image_elem.update(data=imgbytes)
""" """
main()

View file

@ -2,8 +2,6 @@ import cv2
from PIL import Image from PIL import Image
import numpy as np import numpy as np
import PySimpleGUI as sg import PySimpleGUI as sg
font_size = 6
USING_QT = False
""" """
Interesting program that shows your webcam's image as ASCII text. Runs in realtime, producing a stream of Interesting program that shows your webcam's image as ASCII text. Runs in realtime, producing a stream of
@ -22,40 +20,34 @@ USING_QT = False
pip install opencv-python pip install opencv-python
On Linux / Mac use pip3 instead of pip On Linux / Mac use pip3 instead of pip
Copyright 2022, PySimpleGUI
""" """
# The magic bits that make the ASCII stuff work shamelessly taken from https://gist.github.com/cdiener/10491632 # The magic bits that make the ASCII stuff work shamelessly taken from https://gist.github.com/cdiener/10491632
chars = np.asarray(list(' .,:;irsXA253hMHGS#9B&@')) chars = np.asarray(list(' .,:;irsXA253hMHGS#9B&@'))
SC, GCF, WCF = .1, 1, 7/4 SC, GCF, WCF = .1, 1, 7/4
sg.theme('Black') # make it look cool sg.theme('Black') # make it look cool with white chars on black background
font_size = 6
# define the window layout # define the window layout
# number of lines of text elements. Depends on cameras image size and the variable SC (scaller) # number of lines of text elements. Depends on cameras image size and the variable SC (scaller)
NUM_LINES = 48 NUM_LINES = 48
if USING_QT:
layout = [[sg.Text(i, size_px=(800, 12),
font=('Courier', font_size),
key='-OUT-' + str(i))] for i in range(NUM_LINES)]
else:
layout = [[sg.Text(i, size=(120, 1), font=('Courier', font_size),
pad=(0, 0), key='-OUT-'+str(i))] for i in range(NUM_LINES)]
layout += [[sg.Button('Exit', size=(5, 1)), layout = [[[sg.Text(i, font=('Courier', font_size), pad=(0, 0), key=('-OUT-', i))] for i in range(NUM_LINES)],
sg.Text('GCF', size=(4, 1)), [sg.Text('GCF', s=9, justification='r'), sg.Slider((0.1, 20), resolution=.05, default_value=1, orientation='h', key='-SPIN-GCF-', size=(15, 15))],
sg.Spin([round(i, 2) for i in np.arange(0.1, 20.0, 0.1)], [sg.Text('Font Size', s=9, justification='r'), sg.Slider((4, 20), resolution=1, default_value=font_size, orientation='h', key='-FONT SIZE-', size=(15, 15)),
initial_value=1, key='-SPIN-GCF-', size=(5, 1)), sg.Push(), sg.Button('Exit')]]
sg.Text('WCF', size=(4, 1)),
sg.Slider((1, 4), resolution=.05, default_value=1.75,
orientation='h', key='-SLIDER-WCF-', size=(15, 15))]]
# create the window and show it without the plot # create the window and show it without the plot
window = sg.Window('Demo Application - OpenCV Integration', layout, window = sg.Window('Demo Application - OpenCV - ASCII Chars Output', layout, font='Any 18', resizable=True)
location=(800, 400), font='Any 18')
# ---===--- Event LOOP Read and display frames, operate the GUI --- # # ---===--- Event LOOP Read and display frames, operate the GUI --- #
# Setup the OpenCV capture device (webcam) # Setup the OpenCV capture device (webcam)
cap = cv2.VideoCapture(0) cap = cv2.VideoCapture(0)
while True: while True:
event, values = window.read(timeout=0) event, values = window.read(timeout=0)
@ -66,7 +58,7 @@ while True:
img = Image.fromarray(frame) # create PIL image from frame img = Image.fromarray(frame) # create PIL image from frame
GCF = float(values['-SPIN-GCF-']) GCF = float(values['-SPIN-GCF-'])
WCF = values['-SLIDER-WCF-'] WCF = 1.75
# More magic that coverts the image to ascii # More magic that coverts the image to ascii
S = (round(img.size[0] * SC * WCF), round(img.size[1] * SC)) S = (round(img.size[0] * SC * WCF), round(img.size[1] * SC))
img = np.sum(np.asarray(img.resize(S)), axis=2) img = np.sum(np.asarray(img.resize(S)), axis=2)
@ -74,7 +66,8 @@ while True:
img = (1.0 - img / img.max()) ** GCF * (chars.size - 1) img = (1.0 - img / img.max()) ** GCF * (chars.size - 1)
# "Draw" the image in the window, one line of text at a time! # "Draw" the image in the window, one line of text at a time!
font_size = int(values['-FONT SIZE-'])
for i, r in enumerate(chars[img.astype(int)]): for i, r in enumerate(chars[img.astype(int)]):
window['-OUT-'+str(i)].update("".join(r)) window[('-OUT-', i)].update("".join(r), font=('Courier', font_size))
window.close() window.close()

View file

@ -29,7 +29,7 @@ layout = [ [sg.Graph((100,100), (0,100), (100,0), key='-GRAPH-')],
[sg.T(k='-OUT LOC-')], [sg.T(k='-OUT LOC-')],
[sg.T('F1 copy F2 Exit')]] [sg.T('F1 copy F2 Exit')]]
window = sg.Window('Color Picker', layout, no_titlebar=True, keep_on_top=True, grab_anywhere=True, right_click_menu=sg.MENU_RIGHT_CLICK_EDITME_VER_EXIT, finalize=True) window = sg.Window('Color Picker', layout, no_titlebar=False, keep_on_top=True, grab_anywhere=True, right_click_menu=sg.MENU_RIGHT_CLICK_EDITME_VER_EXIT, finalize=True)
window.bind('<F1>', '-COPY-') window.bind('<F1>', '-COPY-')
window.bind('<F2>', 'Exit') window.bind('<F2>', 'Exit')
@ -45,7 +45,7 @@ while True:
if event == 'Edit Me': if event == 'Edit Me':
sp = sg.execute_editor(__file__) sp = sg.execute_editor(__file__)
elif event == 'Version': elif event == 'Version':
sg.popup_scrolled(__file__, sg.get_versions(), keep_on_top=True, location=window.current_location()) sg.popup_scrolled(__file__, sg.get_versions(), keep_on_top=True, location=window.current_location(), non_blocking=True)
window['-GRAPH-'].erase() window['-GRAPH-'].erase()
x, y = window.mouse_location() x, y = window.mouse_location()

View file

@ -13,51 +13,65 @@ import random
This function is your gateway to using any format of image (not just PNG & GIF) and to This function is your gateway to using any format of image (not just PNG & GIF) and to
resize / convert it so that it can be used with the Button and Image elements. resize / convert it so that it can be used with the Button and Image elements.
Copyright 2020 PySimpleGUI.org Copyright 2020, 2022 PySimpleGUI.org
""" """
def make_square(im, min_size=256, fill_color=(0, 0, 0, 0)): def make_square(im, fill_color=(0, 0, 0, 0)):
x, y = im.size x, y = im.size
size = max(min_size, x, y) size = max(x, y)
new_im = Image.new('RGBA', (size, size), fill_color) new_im = Image.new('RGBA', (size, size), fill_color)
new_im.paste(im, (int((size - x) / 2), int((size - y) / 2))) new_im.paste(im, (int((size - x) / 2), int((size - y) / 2)))
return new_im return new_im
def convert_to_bytes(file_or_bytes, resize=None, fill=False):
def convert_to_bytes(source, size=(None, None), subsample=None, zoom=None, fill=False):
""" """
Will convert into bytes and optionally resize an image that is a file or a base64 bytes object. Will convert into bytes and optionally resize an image that is a file or a base64 bytes object.
Turns into PNG format in the process so that can be displayed by tkinter Turns into PNG format in the process so that can be displayed by tkinter
:param file_or_bytes: either a string filename or a bytes base64 image object :param source: either a string filename or a bytes base64 image object
:type file_or_bytes: (Union[str, bytes]) :type source: (Union[str, bytes])
:param resize: optional new size :param size: optional new size (width, height)
:type resize: (Tuple[int, int] or None) :type size: (Tuple[int, int] or None)
:param fill: If True then the image is filled/padded so that the image is not distorted :param subsample: change the size by multiplying width and height by 1/subsample
:type subsample: (int)
:param zoom: change the size by multiplying width and height by zoom
:type zoom: (int)
:param fill: If True then the image is filled/padded so that the image is square
:type fill: (bool) :type fill: (bool)
:return: (bytes) a byte-string object :return: (bytes) a byte-string object
:rtype: (bytes) :rtype: (bytes)
""" """
if isinstance(file_or_bytes, str): if isinstance(source, str):
img = PIL.Image.open(file_or_bytes) image = Image.open(source)
elif isinstance(source, bytes):
image = Image.open(io.BytesIO(base64.b64decode(source)))
else: else:
try: image = PIL.Image.open(io.BytesIO(source))
img = PIL.Image.open(io.BytesIO(base64.b64decode(file_or_bytes)))
except Exception as e:
dataBytesIO = io.BytesIO(file_or_bytes)
img = PIL.Image.open(dataBytesIO)
cur_width, cur_height = img.size width, height = image.size
if resize:
new_width, new_height = resize scale = None
scale = min(new_height / cur_height, new_width / cur_width) if size != (None, None):
img = img.resize((int(cur_width * scale), int(cur_height * scale)), PIL.Image.ANTIALIAS) new_width, new_height = size
if fill: scale = min(new_height/height, new_width/width)
if resize is not None: elif subsample is not None:
img = make_square(img, resize[0]) scale = 1/subsample
elif zoom is not None:
scale = zoom
resized_image = image.resize((int(width * scale), int(height * scale)), Image.LANCZOS) if scale is not None else image
if fill and scale is not None:
resized_image = make_square(resized_image)
# encode a PNG formatted version of image into BASE64
with io.BytesIO() as bio: with io.BytesIO() as bio:
img.save(bio, format="PNG") resized_image.save(bio, format="PNG")
del img contents = bio.getvalue()
return bio.getvalue() encoded = base64.b64encode(contents)
return encoded
def random_image(): def random_image():
return random.choice(sg.EMOJI_BASE64_LIST) return random.choice(sg.EMOJI_BASE64_LIST)

View file

@ -59,7 +59,7 @@ def convert_to_bytes(file_or_bytes, resize=None):
if resize: if resize:
new_width, new_height = resize new_width, new_height = resize
scale = min(new_height / cur_height, new_width / cur_width) scale = min(new_height / cur_height, new_width / cur_width)
img = img.resize((int(cur_width * scale), int(cur_height * scale)), PIL.Image.ANTIALIAS) img = img.resize((int(cur_width * scale), int(cur_height * scale)), PIL.Image.LANCZOS)
with io.BytesIO() as bio: with io.BytesIO() as bio:
img.save(bio, format="PNG") img.save(bio, format="PNG")
del img del img
@ -69,7 +69,7 @@ def convert_to_bytes(file_or_bytes, resize=None):
# def image_file_to_bytes(filename, size): # def image_file_to_bytes(filename, size):
# try: # try:
# image = Image.open(filename) # image = Image.open(filename)
# image.thumbnail(size, Image.ANTIALIAS) # image.thumbnail(size, Image.LANCZOS)
# bio = io.BytesIO() # a binary memory resident stream # bio = io.BytesIO() # a binary memory resident stream
# image.save(bio, format='PNG') # save image as png to it # image.save(bio, format='PNG') # save image as png to it
# imgbytes = bio.getvalue() # imgbytes = bio.getvalue()
@ -80,7 +80,7 @@ def convert_to_bytes(file_or_bytes, resize=None):
def set_image_to_blank(key): def set_image_to_blank(key):
img = PIL.Image.new('RGB', (100, 100), (255, 255, 255)) img = PIL.Image.new('RGB', (100, 100), (255, 255, 255))
img.thumbnail((1, 1), PIL.Image.ANTIALIAS) img.thumbnail((1, 1), PIL.Image.LANCZOS)
bio = io.BytesIO() bio = io.BytesIO()
img.save(bio, format='PNG') img.save(bio, format='PNG')
imgbytes = bio.getvalue() imgbytes = bio.getvalue()

View file

@ -32,14 +32,14 @@ def main():
# define layout, show and read the window # define layout, show and read the window
col = [[sg.Text(png_files[0], size=(80, 3), key='-FILENAME-')], col = [[sg.Text(png_files[0], size=(80, 3), key='-FILENAME-')],
[sg.Image(filename=png_files[0], key='-IMAGE-')], [sg.Image(filename=png_files[0], key='-IMAGE-', expand_x=True, expand_y=True)],
[sg.Button('Next', size=(8, 2)), sg.Button('Prev', size=(8, 2)), [sg.Button('Next', size=(8, 2)), sg.Button('Prev', size=(8, 2)),
sg.Text('File 1 of {}'.format(len(png_files)), size=(15, 1), key='-FILENUM-')]] sg.Text('File 1 of {}'.format(len(png_files)), size=(15, 1), key='-FILENUM-')]]
col_files = [[sg.Listbox(values=filenames_only, size=(60, 30), key='-LISTBOX-', enable_events=True)], col_files = [[sg.Listbox(values=filenames_only, size=(60, 30), key='-LISTBOX-', enable_events=True)],
[sg.Text('Select a file. Use scrollwheel or arrow keys on keyboard to scroll through files one by one.')]] [sg.Text('Select a file. Use scrollwheel or arrow keys on keyboard to scroll through files one by one.')]]
layout = [[sg.Menu(menu)], [sg.Col(col_files), sg.Col(col)]] layout = [[sg.Menu(menu)], [sg.Col(col_files), sg.Col(col, expand_x=True, expand_y=True)]]
window = sg.Window('Image Browser', layout, return_keyboard_events=True, use_default_focus=False) window = sg.Window('Image Browser', layout, return_keyboard_events=True, use_default_focus=False)

View file

@ -13,16 +13,16 @@ def main():
layout = [[sg.T('Choose 2 files to compare using PyCharm\'s compare utility', font='_ 18')], layout = [[sg.T('Choose 2 files to compare using PyCharm\'s compare utility', font='_ 18')],
[sg.Text('Filename:'), sg.Combo(values=sorted(sg.user_settings_get_entry('-filenames1-', [])), [sg.Text('Filename:'), sg.Combo(values=sorted(sg.user_settings_get_entry('-filenames1-', [])),
default_value=sg.user_settings_get_entry('-last filename chosen1-', None), default_value=sg.user_settings_get_entry('-last filename chosen1-', None),
size=(90,1), auto_size_text=False, k='-COMBO1-'), sg.FileBrowse(), sg.B('Clear History', k='-CLEAR1-')], size=(90,30), auto_size_text=False, k='-COMBO1-'), sg.FileBrowse(), sg.B('Clear History', k='-CLEAR1-')],
[sg.Text('Filename:'),sg.Combo(values=sorted(sg.user_settings_get_entry('-filenames2-', [])), [sg.Text('Filename:'),sg.Combo(values=sorted(sg.user_settings_get_entry('-filenames2-', [])),
default_value=sg.user_settings_get_entry('-last filename chosen2-', None), default_value=sg.user_settings_get_entry('-last filename chosen2-', None),
size=(90,1), auto_size_text=False, k='-COMBO2-'), sg.FileBrowse(), sg.B('Clear History', k='-CLEAR2-')], size=(90,30), auto_size_text=False, k='-COMBO2-'), sg.FileBrowse(), sg.B('Clear History', k='-CLEAR2-')],
[sg.Button('Compare'), sg.Button('Exit'), sg.T('PySimpleGUI ver ' + sg.version.split(' ')[0] + ' tkinter ver ' + sg.tclversion_detailed + 'Python ver ' + sys.version, font='Default 8', pad=(0,0))], [sg.Button('Compare'), sg.Button('Exit'), sg.T('PySimpleGUI ver ' + sg.version.split(' ')[0] + ' tkinter ver ' + sg.tclversion_detailed + 'Python ver ' + sys.version, font='Default 8', pad=(0,0))],
[sg.Text('Note - You must setup the PyCharm information using PySimpleGUI global settings')], [sg.Text('Note - You must setup the PyCharm information using PySimpleGUI global settings')],
[sg.Button('Global Settings')] [sg.Button('Global Settings')]
] ]
window = sg.Window('Compare 2 files using PyCharm', layout) window = sg.Window('Compare 2 files using PyCharm', layout, right_click_menu=sg.MENU_RIGHT_CLICK_EDITME_VER_EXIT)
while True: while True:
event, values = window.read() event, values = window.read()
print(event, values) print(event, values)
@ -45,6 +45,10 @@ def main():
window['-COMBO2-'].update(values=[], value='') window['-COMBO2-'].update(values=[], value='')
elif event == 'Global Settings': elif event == 'Global Settings':
sg.main_global_pysimplegui_settings() sg.main_global_pysimplegui_settings()
if event == 'Edit Me':
sg.execute_editor(__file__)
elif event == 'Version':
sg.popup_scrolled(__file__, sg.get_versions(), non_blocking=True, keep_on_top=True)
window.close() window.close()
if __name__ == '__main__': if __name__ == '__main__':

View file

@ -1,12 +1,14 @@
import subprocess
import sys
import PySimpleGUI as sg import PySimpleGUI as sg
import re import re
""" """
Demo Program - Realtime output of a shell command in the window using ANSI color codes Demo Program - Realtime output of a shell command in the window using ANSI color codes
Shows how you can run a long-running subprocess and have the output Shows how you can run a long-running subprocess and have the output
be displayed in realtime in the window. The output is assumed to have color codes embedded in it be displayed in realtime in the window. The output is assumed to have color codes embedded in it.
The commands you enter will be run as shell commands. The output is then shown with the ANSI strings parsed.
Copyright 2022 PySimpleGUI
""" """
@ -78,50 +80,38 @@ def cut_ansi_string_into_parts(string_with_ansi_codes):
for x in range(0, len(tuple_list)): for x in range(0, len(tuple_list)):
if tuple_list[x][0]: if tuple_list[x][0]:
new_tuple_list += [(tuple_list[x][0], tuple_list[x][1], tuple_list[x][2], tuple_list[x][3])] new_tuple_list += [[tuple_list[x][0], tuple_list[x][1], tuple_list[x][2], tuple_list[x][3]]]
return new_tuple_list return new_tuple_list
def main(): def main():
layout = [ layout = [
[sg.Multiline(size=(110, 30), font='courier 10', background_color='black', text_color='white', key='-MLINE-')], [sg.Multiline(size=(110, 30), font='courier 10', background_color='black', text_color='white', key='-MLINE-', expand_x=True, expand_y=True)],
[sg.T('Promt> '), sg.Input(key='-IN-', focus=True, do_not_clear=False)], [sg.T('Promt> '), sg.Input(key='-IN-', focus=True, do_not_clear=False)],
[sg.Button('Run', bind_return_key=True), sg.Button('Exit')]] [sg.Button('Run', bind_return_key=True), sg.Button('Exit'), sg.Sizegrip()]]
window = sg.Window('Realtime Shell Command Output', layout) window = sg.Window('Realtime Shell Command Output', layout, resizable=True)
while True: # Event Loop while True: # Event Loop
event, values = window.read() event, values = window.read()
# print(event, values)
if event in (sg.WIN_CLOSED, 'Exit'): if event in (sg.WIN_CLOSED, 'Exit'):
break break
elif event == 'Run': elif event == 'Run':
runCommand(cmd=values['-IN-'], window=window) args = values['-IN-'].split(' ')
p = sg.execute_command_subprocess(args[0], *args[1:], wait=False, pipe_output=True, merge_stderr_with_stdout=True )
lines = sg.execute_get_results(p)
for line in lines:
if line is None:
continue
ansi_list = cut_ansi_string_into_parts(line)
for ansi_item in ansi_list:
if ansi_item[1] == 'Reset':
ansi_item[1] = None
window['-MLINE-'].update(ansi_item[0] , text_color_for_value=ansi_item[1], background_color_for_value=ansi_item[2], append=True, autoscroll=True)
window.refresh()
window.close() window.close()
def runCommand(cmd, timeout=None, window=None):
""" run shell command
@param cmd: command to execute
@param timeout: timeout for command execution
@param window: the PySimpleGUI window that the output is going to (needed to do refresh on)
@return: (return code from command, command output)
"""
p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
for line in p.stdout:
line = line.decode(errors='replace' if (sys.version_info) < (3, 5) else 'backslashreplace').rstrip()
ansi_list = cut_ansi_string_into_parts(line)
for ansi_item in ansi_list:
if ansi_item[1] == 'Reset':
ansi_item[1] = None
window['-MLINE-'].update(ansi_item[0] + '\n', text_color_for_value=ansi_item[1], background_color_for_value=ansi_item[2], append=True,
autoscroll=True)
window.refresh()
retval = p.wait(timeout)
return retval
sg.theme('Dark Blue 3')
main() main()

View file

@ -21,7 +21,8 @@ def main():
if event in (sg.WIN_CLOSED, 'Exit'): if event in (sg.WIN_CLOSED, 'Exit'):
break break
elif event == 'Run': elif event == 'Run':
sp = sg.execute_command_subprocess(values['-IN-'], pipe_output=True, wait=False) cmd_list = values['-IN-'].split(' ')
sp = sg.execute_command_subprocess(cmd_list[0], *cmd_list[1:], pipe_output=True, wait=False)
results = sg.execute_get_results(sp, timeout=1) results = sg.execute_get_results(sp, timeout=1)
print(results[0]) print(results[0])

View file

@ -2,18 +2,17 @@ import PySimpleGUI as sg, random
import numpy as np import numpy as np
from typing import List, Any, Union, Tuple, Dict from typing import List, Any, Union, Tuple, Dict
""" """
Sudoku Puzzle Demo Sudoku Puzzle Demo
How to easily generate a GUI for a Sudoku puzzle. How to easily generate a GUI for a Sudoku puzzle.
The Window definition and creation is a single line of code. The Window definition and creation is a single line of code.
Code to generate a playable puzzle was supplied from: Code to generate a playable puzzle was supplied from:
https://github.com/MorvanZhou/sudoku https://github.com/MorvanZhou/sudoku
Copyright 2020 PySimpleGUI.com Copyright 2020 PySimpleGUI.com
""" """
@ -27,7 +26,7 @@ def generate_sudoku(mask_rate):
""" """
while True: while True:
n = 9 n = 9
solution = np.zeros((n, n), np.int) solution = np.zeros((n, n), np.int_)
rg = np.arange(1, n + 1) rg = np.arange(1, n + 1)
solution[0, :] = np.random.choice(rg, n, replace=False) solution[0, :] = np.random.choice(rg, n, replace=False)
try: try:
@ -36,10 +35,11 @@ def generate_sudoku(mask_rate):
col_rest = np.setdiff1d(rg, solution[:r, c]) col_rest = np.setdiff1d(rg, solution[:r, c])
row_rest = np.setdiff1d(rg, solution[r, :c]) row_rest = np.setdiff1d(rg, solution[r, :c])
avb1 = np.intersect1d(col_rest, row_rest) avb1 = np.intersect1d(col_rest, row_rest)
sub_r, sub_c = r//3, c//3 sub_r, sub_c = r // 3, c // 3
avb2 = np.setdiff1d(np.arange(0, n+1), solution[sub_r*3:(sub_r+1)*3, sub_c*3:(sub_c+1)*3].ravel()) avb2 = np.setdiff1d(np.arange(0, n + 1), solution[sub_r * 3:(sub_r + 1) * 3, sub_c * 3:(sub_c + 1) * 3].ravel())
avb = np.intersect1d(avb1, avb2) avb = np.intersect1d(avb1, avb2)
solution[r, c] = np.random.choice(avb, size=1) # solution[r, c] = np.random.choice(avb, size=1)
solution[r, c] = np.random.choice(avb, size=1)[0]
break break
except ValueError: except ValueError:
pass pass
@ -48,7 +48,6 @@ def generate_sudoku(mask_rate):
return puzzle, solution return puzzle, solution
def check_progress(window, solution): def check_progress(window, solution):
""" """
Gives you a visual hint on your progress. Gives you a visual hint on your progress.
@ -65,38 +64,23 @@ def check_progress(window, solution):
solved = True solved = True
for r, row in enumerate(solution): for r, row in enumerate(solution):
for c, col in enumerate(row): for c, col in enumerate(row):
value = window[r,c].get() value = window[r, c].get()
if value: if value:
try: try:
value = int(value) value = int(value)
except: except:
value = 0 value = 0
if value != solution[r][c]: if value != solution[r][c]:
window[r,c].update(background_color='red') window[r, c].update(background_color='red')
solved = False solved = False
else: else:
window[r,c].update(background_color=sg.theme_input_background_color()) window[r, c].update(background_color=sg.theme_input_background_color())
else: else:
solved = False solved = False
window[r, c].update(background_color='yellow') window[r, c].update(background_color='yellow')
return solved return solved
def create_and_show_puzzle(window):
# create and display a puzzle by updating the Input elements
rate = DEFAULT_MASK_RATE
if window['-RATE-'].get():
try:
rate = float(window['-RATE-'].get())
except:
pass
puzzle, solution = generate_sudoku(mask_rate=rate)
for r, row in enumerate(puzzle):
for c, col in enumerate(row):
window[r, c].update(puzzle[r][c] if puzzle[r][c] else '', background_color=sg.theme_input_background_color())
return puzzle, solution
def main(mask_rate=0.7): def main(mask_rate=0.7):
"""" """"
The Main GUI - It does it all. The Main GUI - It does it all.
@ -105,8 +89,19 @@ def main(mask_rate=0.7):
addressing of the individual squares is via a key that's a tuple (0,0) to (8,8) addressing of the individual squares is via a key that's a tuple (0,0) to (8,8)
""" """
def create_and_show_puzzle():
# create and display a puzzle by updating the Input elements
rate = mask_rate
if window['-RATE-'].get():
try:
rate = float(window['-RATE-'].get())
except:
pass
puzzle, solution = generate_sudoku(mask_rate=rate)
for r, row in enumerate(puzzle):
for c, col in enumerate(row):
window[r, c].update(puzzle[r][c] if puzzle[r][c] else '', background_color=sg.theme_input_background_color())
return puzzle, solution
# It's 1 line of code to make a Sudoku board. If you don't like it, then replace it. # It's 1 line of code to make a Sudoku board. If you don't like it, then replace it.
# Dude (Dudette), it's 1-line of code. If you don't like the board, write a line of code. # Dude (Dudette), it's 1-line of code. If you don't like the board, write a line of code.
@ -114,16 +109,18 @@ def main(mask_rate=0.7):
# Get an input element for a position using: window[row, col] # Get an input element for a position using: window[row, col]
# To get a better understanding, take it apart. Spread it out. You'll learn in the process. # To get a better understanding, take it apart. Spread it out. You'll learn in the process.
window = sg.Window('Sudoku', window = sg.Window('Sudoku',
[[sg.Frame('', [[sg.I(random.randint(1,9), justification='r', size=(3,1),enable_events=True, key=(fr*3+r,fc*3+c)) for c in range(3)] for r in range(3)]) for fc in range(3)] for fr in range(3)] + [[sg.Frame('', [[sg.I(random.randint(1, 9), justification='r', size=(3, 1), key=(fr * 3 + r, fc * 3 + c)) for c in range(3)] for r in range(3)]) for fc in
[[sg.B('Solve'), sg.B('Check'), sg.B('Hint'), sg.B('New Game'), sg.T('Mask rate (0-1)'), sg.In(str(mask_rate), size=(3,1),key='-RATE-')],], finalize=True) range(3)] for fr in range(3)] +
[[sg.B('Solve'), sg.B('Check'), sg.B('Hint'), sg.B('New Game')], [sg.T('Mask rate (0-1)'), sg.In(str(mask_rate), size=(3, 1), key='-RATE-')], ],
finalize=True)
# create and display a puzzle by updating the Input elements # create and display a puzzle by updating the Input elements
puzzle, solution = create_and_show_puzzle(window) puzzle, solution = create_and_show_puzzle()
check_showing = False
while True: # The Event Loop while True: # The Event Loop
event, values = window.read() event, values = window.read()
if event == sg.WIN_CLOSED: if event is None:
break break
if event == 'Solve': if event == 'Solve':
@ -131,7 +128,6 @@ def main(mask_rate=0.7):
for c, col in enumerate(row): for c, col in enumerate(row):
window[r, c].update(solution[r][c], background_color=sg.theme_input_background_color()) window[r, c].update(solution[r][c], background_color=sg.theme_input_background_color())
elif event == 'Check': elif event == 'Check':
check_showing = True
solved = check_progress(window, solution) solved = check_progress(window, solution)
if solved: if solved:
sg.popup('Solved! You have solved the puzzle correctly.') sg.popup('Solved! You have solved the puzzle correctly.')
@ -140,17 +136,14 @@ def main(mask_rate=0.7):
try: try:
elem.update(solution[elem.Key[0]][elem.Key[1]], background_color=sg.theme_input_background_color()) elem.update(solution[elem.Key[0]][elem.Key[1]], background_color=sg.theme_input_background_color())
except: except:
pass # Likely because an input element didn't have focus pass # Likely because an input element didn't have focus
elif event == 'New Game': elif event == 'New Game':
puzzle, solution = create_and_show_puzzle(window) puzzle, solution = create_and_show_puzzle()
elif check_showing: # an input was changed, so clear any background colors from prior hints
check_showing = False
for r, row in enumerate(solution):
for c, col in enumerate(row):
window[r, c].update(background_color=sg.theme_input_background_color())
window.close() window.close()
if __name__ == "__main__":
DEFAULT_MASK_RATE = 0.7 # % Of cells to hide if __name__ == "__main__":
main(DEFAULT_MASK_RATE) mask_rate = 0.7 # % Of cells to hide
main(mask_rate)

View file

@ -29,7 +29,7 @@ def resize_base64_image(image64, size):
""" """
image_file = io.BytesIO(base64.b64decode(image64)) image_file = io.BytesIO(base64.b64decode(image64))
img = Image.open(image_file) img = Image.open(image_file)
img.thumbnail(size, Image.ANTIALIAS) img.thumbnail(size, Image.LANCZOS)
bio = io.BytesIO() bio = io.BytesIO()
img.save(bio, format='PNG') img.save(bio, format='PNG')
imgbytes = bio.getvalue() imgbytes = bio.getvalue()

View file

@ -0,0 +1,161 @@
#!/usr/bin/env python
import PySimpleGUI as sg
import csv
import os
import operator
"""
Demo - Simple CSV Table Display
Enables you to easily filter and sort tables that are in a CSV file format
Choose your CSV file and then a table will be displayed.
Clicking on a heading will sort on that column if no value is entered for the filter.
If a filter value is entered and then a heading is clicked, then only rows matchines the filter in that column as are displayed
The filtering is not case sensative so no need to worry about exact matches
Use the checkbox to specify ascending or descending sorting
The first row in your table needs to be the Column Names
Copyright 2022 PySimpleGUI
"""
sg.theme('Dark gray 13')
CSV_FILE = sg.popup_get_file('CSV File to Display', file_types=(("CSV Files", "*.csv"),), initial_folder=os.path.dirname(__file__), history=True)
if CSV_FILE is None:
sg.popup_error('Canceling')
exit()
csv.field_size_limit(2147483647) # enables huge tables
def sort_table(table, cols, descending=False):
""" sort a table by multiple columns
table: a list of lists (or tuple of tuples) where each inner list
represents a row
cols: a list (or tuple) specifying the column numbers to sort by
e.g. (1,0) would sort by column 1, then by column 0
"""
for col in reversed(cols):
try:
table = sorted(table, key=operator.itemgetter(col), reverse=descending)
except Exception as e:
sg.popup_error('Error in sort_table', 'Exception in sort_table', e)
return table
def read_csv_file(filename):
data = []
header_list = []
if filename is not None:
try:
with open(filename, encoding='UTF-16') as infile:
reader = csv.reader(infile,delimiter='\t')
# reader = fix_nulls(filename)
header_list = next(reader)
try:
data = list(reader) # read everything else into a list of rows
except Exception as e:
print(e)
sg.popup_error('Error reading file', e)
return None, None
except:
with open(filename, encoding='utf-8') as infile:
reader = csv.reader(infile, delimiter=',')
# reader = fix_nulls(filename)
header_list = next(reader)
try:
data = list(reader) # read everything else into a list of rows
except Exception as e:
with open(filename) as infile:
reader = csv.reader(infile, delimiter=',')
# reader = fix_nulls(filename)
header_list = next(reader)
try:
data = list(reader) # read everything else into a list of rows
except Exception as e:
print(e)
sg.popup_error('Error reading file', e)
return None, None
return data, header_list
def main():
data, header_list = read_csv_file(CSV_FILE)
sg.popup_quick_message('Building your main window.... one moment....', background_color='#1c1e23', text_color='white', keep_on_top=True, font='_ 30')
# ------ Window Layout ------
layout = [ [sg.Text('Click a heading to sort on that column or enter a filter and click a heading to search for matches in that column')],
[sg.Text(f'{len(data)} Records in table', font='_ 18')],
[sg.Text(k='-RECORDS SHOWN-', font='_ 18')],
[sg.Text(k='-SELECTED-')],
[sg.T('Filter:'), sg.Input(k='-FILTER-', focus=True, tooltip='Not case sensative\nEnter value and click on a col header'),
sg.B('Reset Table', tooltip='Resets entire table to your original data'),
sg.Checkbox('Sort Descending', k='-DESCENDING-'), sg.Checkbox('Filter Out (exclude)', k='-FILTER OUT-', tooltip='Check to remove matching entries when filtering a column'), sg.Push()],
[sg.Table(values=data, headings=header_list, max_col_width=25,
auto_size_columns=True, display_row_numbers=True, vertical_scroll_only=True,
justification='right', num_rows=50,
key='-TABLE-', selected_row_colors='red on yellow', enable_events=True,
expand_x=True, expand_y=True,
enable_click_events=True)],
[sg.Sizegrip()]]
# ------ Create Window ------
window = sg.Window('CSV Table Display', layout, right_click_menu=sg.MENU_RIGHT_CLICK_EDITME_VER_EXIT, resizable=True, finalize=True)
window.bind("<Control_L><End>", '-CONTROL END-')
window.bind("<End>", '-CONTROL END-')
window.bind("<Control_L><Home>", '-CONTROL HOME-')
window.bind("<Home>", '-CONTROL HOME-')
original_data = data # save a copy of the data
# ------ Event Loop ------
while True:
event, values = window.read()
# print(event, values)
if event in (sg.WIN_CLOSED, 'Exit'):
break
if values['-TABLE-']: # Show how many rows are slected
window['-SELECTED-'].update(f'{len(values["-TABLE-"])} rows selected')
else:
window['-SELECTED-'].update('')
if event[0] == '-TABLE-':
# if isinstance(event, tuple):
filter_value = values['-FILTER-']
# TABLE CLICKED Event has value in format ('-TABLE=', '+CLICKED+', (row,col))
if event[0] == '-TABLE-':
if event[2][0] == -1 and event[2][1] != -1: # Header was clicked and wasn't the "row" column
col_num_clicked = event[2][1]
# if there's a filter, first filter based on the column clicked
if filter_value not in (None, ''):
filter_out = values['-FILTER OUT-'] # get bool filter out setting
new_data = []
for line in data:
if not filter_out and (filter_value.lower() in line[col_num_clicked].lower()):
new_data.append(line)
elif filter_out and (filter_value.lower() not in line[col_num_clicked].lower()):
new_data.append(line)
data = new_data
new_table = sort_table(data, (col_num_clicked, 0), values['-DESCENDING-'])
window['-TABLE-'].update(new_table)
data = new_table
window['-RECORDS SHOWN-'].update(f'{len(new_table)} Records shown')
window['-FILTER-'].update('') # once used, clear the filter
window['-FILTER OUT-'].update(False) # Also clear the filter out flag
elif event == 'Reset Table':
data = original_data
window['-TABLE-'].update(data)
window['-RECORDS SHOWN-'].update(f'{len(data)} Records shown')
elif event == '-CONTROL END-':
window['-TABLE-'].set_vscroll_position(100)
elif event == '-CONTROL HOME-':
window['-TABLE-'].set_vscroll_position(0)
elif event == 'Edit Me':
sg.execute_editor(__file__)
elif event == 'Version':
sg.popup_scrolled(__file__, sg.get_versions(), location=window.current_location(), keep_on_top=True, non_blocking=True)
window.close()
if __name__ == '__main__':
main()

View file

@ -0,0 +1,85 @@
#!/usr/bin/env python
import PySimpleGUI as sg
import random
import string
"""
Demo Program - Table with checkboxes
This clever solution was sugged by GitHub user robochopbg.
The beauty of the simplicity is that the checkbox is simply another column in the table. When the checkbox changes
state, then the data in the table is changed and the table is updated in the Table element.
A big thank you again to user robochopbg!
Copyright 2023 PySimpleGUI
"""
# Characters used for the checked and unchecked checkboxes. Feel free to change
BLANK_BOX = ''
CHECKED_BOX = ''
# ------ Some functions to help generate data for the table ------
def word():
return ''.join(random.choice(string.ascii_lowercase) for i in range(10))
def number(max_val=1000):
return random.randint(0, max_val)
def make_table(num_rows, num_cols):
data = [[j for j in range(num_cols)] for i in range(num_rows)]
data[0] = [word() for __ in range(num_cols)]
for i in range(1, num_rows):
data[i] = [BLANK_BOX if random.randint(0,2) % 2 else CHECKED_BOX] + [word(), *[number() for i in range(num_cols - 1)]]
return data
# ------ Make the Table Data ------
data = make_table(num_rows=15, num_cols=6)
headings = [str(data[0][x])+' ..' for x in range(len(data[0]))]
headings[0] = 'Checkbox'
# The selected rows is stored in a set
selected = {i for i, row in enumerate(data[1:][:]) if row[0] == CHECKED_BOX}
# ------ Window Layout ------
layout = [[sg.Table(values=data[1:][:], headings=headings, max_col_width=25, auto_size_columns=False, col_widths=[10, 10, 20, 20 ,30, 5],
display_row_numbers=True, justification='center', num_rows=20, key='-TABLE-', selected_row_colors='red on yellow',
expand_x=False, expand_y=True, vertical_scroll_only=False, enable_click_events=True, font='_ 14'),
sg.Sizegrip()]]
# ------ Create Window ------
window = sg.Window('Table with Checkbox', layout, resizable=True, finalize=True)
# Highlight the rows (select) that have checkboxes checked
window['-TABLE-'].update(values=data[1:][:], select_rows=list(selected))
# ------ Event Loop ------
while True:
event, values = window.read()
if event == sg.WIN_CLOSED:
break
elif event[0] == '-TABLE-' and event[2][0] not in (None, -1): # if clicked a data row rather than header or outside table
row = event[2][0]+1
if data[row][0] == CHECKED_BOX: # Going from Checked to Unchecked
selected.remove(row-1)
data[row][0] = BLANK_BOX
else: # Going from Unchecked to Checked
selected.add(row-1)
data[row ][0] = CHECKED_BOX
window['-TABLE-'].update(values=data[1:][:], select_rows=list(selected)) # Update the table and the selected rows
window.close()

Some files were not shown because too many files have changed in this diff Show more