From c3a6db921f14f425dd92f161fa9e08de6882b751 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Fri, 6 Jan 2023 16:01:52 -0500 Subject: [PATCH 001/145] Revert "Added option to enable/disable manual entry" This reverts commit 73a66290456bb8e8e2a85be03b2b6402ed6fd524. --- DemoPrograms/Demo_Time_Chooser.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/DemoPrograms/Demo_Time_Chooser.py b/DemoPrograms/Demo_Time_Chooser.py index 89e20a97..eb36b66e 100644 --- a/DemoPrograms/Demo_Time_Chooser.py +++ b/DemoPrograms/Demo_Time_Chooser.py @@ -16,7 +16,7 @@ import PySimpleGUI as sg -def popup_get_time(title='Time Entry', starting_hour=1, starting_minute=0, allow_manual_input=True, font=None): +def popup_get_time(title='Time Entry', starting_hour=1, starting_minute=0, font=None): """ Shows a window that will gather a time of day. @@ -26,8 +26,6 @@ def popup_get_time(title='Time Entry', starting_hour=1, starting_minute=0, allow :type starting_hour: int :param starting_minute: Value to initially show in the minute field :type starting_minute: int - :param allow_manual_input: If True, then the Spin elements can be manually edited - :type allow_manual_input: bool :param font: Font to use for the window :type font: str | tuple :return: Tuple with format: (hour, minute, am-pm string) @@ -38,9 +36,9 @@ def popup_get_time(title='Time Entry', starting_hour=1, starting_minute=0, allow hour_list = [i for i in range(0, 15)] minute_list = [i for i in range(-1, 62)] - layout = [[sg.Spin(hour_list, initial_value=starting_hour, key='-HOUR-', s=3, enable_events=True, readonly=not allow_manual_input), + layout = [[sg.Spin(hour_list, initial_value=starting_hour, key='-HOUR-', s=3, enable_events=True, readonly=False), sg.Text(':'), - sg.Spin(minute_list, initial_value=starting_minute, key='-MIN-', s=3, enable_events=True, readonly=not allow_manual_input), + sg.Spin(minute_list, initial_value=starting_minute, key='-MIN-', s=3, enable_events=True, readonly=False), sg.Combo(['AM', 'PM'], 'AM', readonly=True, key='-AMPM-')], [sg.Button('Ok'), sg.Button('Cancel')]] From 02f3ae25be5cb2b25881e8878f0f27aa25838b58 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Fri, 6 Jan 2023 16:02:08 -0500 Subject: [PATCH 002/145] Revert "Demo program of an example window to choose a time" This reverts commit 86976f50c3c54c8a2b0741acfaeee457d8367e45. --- DemoPrograms/Demo_Time_Chooser.py | 77 ------------------------------- 1 file changed, 77 deletions(-) delete mode 100644 DemoPrograms/Demo_Time_Chooser.py diff --git a/DemoPrograms/Demo_Time_Chooser.py b/DemoPrograms/Demo_Time_Chooser.py deleted file mode 100644 index eb36b66e..00000000 --- a/DemoPrograms/Demo_Time_Chooser.py +++ /dev/null @@ -1,77 +0,0 @@ -import PySimpleGUI as sg - -""" - Demo Time Chooser - - A sample window for choosing a time. - - This particular implementation uses a Spin element. Numerous possibilities exist for entering a time of day. Instead - of Spin elements, Input or Combo Elements could be used. - - If you do not want your user to be able to manually enter values using the keyboard, then set readonly=True in - the Spin elements. - - Copyright 2023 PySimpleGUI -""" - - - -def popup_get_time(title='Time Entry', starting_hour=1, starting_minute=0, font=None): - """ - Shows a window that will gather a time of day. - - :param title: The title that is shown on the window - :type title: str - :param starting_hour: Value to initially show in the hour field - :type starting_hour: int - :param starting_minute: Value to initially show in the minute field - :type starting_minute: int - :param font: Font to use for the window - :type font: str | tuple - :return: Tuple with format: (hour, minute, am-pm string) - :type: (int, int, str) - """ - - max_value_dict = {'-HOUR-':(1, 12), '-MIN-':(0, 59)} - hour_list = [i for i in range(0, 15)] - minute_list = [i for i in range(-1, 62)] - - layout = [[sg.Spin(hour_list, initial_value=starting_hour, key='-HOUR-', s=3, enable_events=True, readonly=False), - sg.Text(':'), - sg.Spin(minute_list, initial_value=starting_minute, key='-MIN-', s=3, enable_events=True, readonly=False), - sg.Combo(['AM', 'PM'], 'AM', readonly=True, key='-AMPM-')], - [sg.Button('Ok'), sg.Button('Cancel')]] - - window = sg.Window(title, layout, font=font) - - while True: - event, values = window.read() - # print(event, values) - if event == sg.WIN_CLOSED or event == 'Cancel': - hours = minutes = ampm = None - break - - if event == '-HOUR-' or event == '-MIN-': - spin_value = values[event] - if spin_value > max_value_dict[event][1]: - values[event] = max_value_dict[event][0] - window[event].update(values[event]) - elif spin_value < max_value_dict[event][0]: - values[event] = max_value_dict[event][1] - window[event].update(values[event]) - if event == 'Ok': - # Do validation on the input values to ensure they're valid - try: - hours = int(values["-HOUR-"]) - minutes = int(values["-MIN-"]) - ampm = values["-AMPM-"] - except: - continue # if not valid, then don't allow exiting the window using OK. - if 1 <= hours <= 12 and 0 <= minutes < 60: # make sure the hour and minute values are in a valid range - break - - window.close() - - return hours, minutes, ampm - -print(popup_get_time(font='_ 15')) \ No newline at end of file From 0c77b57659d372ef0dc42e6ca58ba89c40074073 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Fri, 6 Jan 2023 16:04:33 -0500 Subject: [PATCH 003/145] Demo Program - Time chooser --- DemoPrograms/Demo_Time_Chooser.py | 79 +++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 DemoPrograms/Demo_Time_Chooser.py diff --git a/DemoPrograms/Demo_Time_Chooser.py b/DemoPrograms/Demo_Time_Chooser.py new file mode 100644 index 00000000..89e20a97 --- /dev/null +++ b/DemoPrograms/Demo_Time_Chooser.py @@ -0,0 +1,79 @@ +import PySimpleGUI as sg + +""" + Demo Time Chooser + + A sample window for choosing a time. + + This particular implementation uses a Spin element. Numerous possibilities exist for entering a time of day. Instead + of Spin elements, Input or Combo Elements could be used. + + If you do not want your user to be able to manually enter values using the keyboard, then set readonly=True in + the Spin elements. + + Copyright 2023 PySimpleGUI +""" + + + +def popup_get_time(title='Time Entry', starting_hour=1, starting_minute=0, allow_manual_input=True, font=None): + """ + Shows a window that will gather a time of day. + + :param title: The title that is shown on the window + :type title: str + :param starting_hour: Value to initially show in the hour field + :type starting_hour: int + :param starting_minute: Value to initially show in the minute field + :type starting_minute: int + :param allow_manual_input: If True, then the Spin elements can be manually edited + :type allow_manual_input: bool + :param font: Font to use for the window + :type font: str | tuple + :return: Tuple with format: (hour, minute, am-pm string) + :type: (int, int, str) + """ + + max_value_dict = {'-HOUR-':(1, 12), '-MIN-':(0, 59)} + hour_list = [i for i in range(0, 15)] + minute_list = [i for i in range(-1, 62)] + + layout = [[sg.Spin(hour_list, initial_value=starting_hour, key='-HOUR-', s=3, enable_events=True, readonly=not allow_manual_input), + sg.Text(':'), + sg.Spin(minute_list, initial_value=starting_minute, key='-MIN-', s=3, enable_events=True, readonly=not allow_manual_input), + sg.Combo(['AM', 'PM'], 'AM', readonly=True, key='-AMPM-')], + [sg.Button('Ok'), sg.Button('Cancel')]] + + window = sg.Window(title, layout, font=font) + + while True: + event, values = window.read() + # print(event, values) + if event == sg.WIN_CLOSED or event == 'Cancel': + hours = minutes = ampm = None + break + + if event == '-HOUR-' or event == '-MIN-': + spin_value = values[event] + if spin_value > max_value_dict[event][1]: + values[event] = max_value_dict[event][0] + window[event].update(values[event]) + elif spin_value < max_value_dict[event][0]: + values[event] = max_value_dict[event][1] + window[event].update(values[event]) + if event == 'Ok': + # Do validation on the input values to ensure they're valid + try: + hours = int(values["-HOUR-"]) + minutes = int(values["-MIN-"]) + ampm = values["-AMPM-"] + except: + continue # if not valid, then don't allow exiting the window using OK. + if 1 <= hours <= 12 and 0 <= minutes < 60: # make sure the hour and minute values are in a valid range + break + + window.close() + + return hours, minutes, ampm + +print(popup_get_time(font='_ 15')) \ No newline at end of file From 7fdee8f91b243f4e6861b82724c4ba98ca95fd4c Mon Sep 17 00:00:00 2001 From: PySimpleGUI <46163555+PySimpleGUI@users.noreply.github.com> Date: Fri, 6 Jan 2023 16:08:54 -0500 Subject: [PATCH 004/145] Delete Demo_Time_Chooser.py --- DemoPrograms/Demo_Time_Chooser.py | 79 ------------------------------- 1 file changed, 79 deletions(-) delete mode 100644 DemoPrograms/Demo_Time_Chooser.py diff --git a/DemoPrograms/Demo_Time_Chooser.py b/DemoPrograms/Demo_Time_Chooser.py deleted file mode 100644 index 89e20a97..00000000 --- a/DemoPrograms/Demo_Time_Chooser.py +++ /dev/null @@ -1,79 +0,0 @@ -import PySimpleGUI as sg - -""" - Demo Time Chooser - - A sample window for choosing a time. - - This particular implementation uses a Spin element. Numerous possibilities exist for entering a time of day. Instead - of Spin elements, Input or Combo Elements could be used. - - If you do not want your user to be able to manually enter values using the keyboard, then set readonly=True in - the Spin elements. - - Copyright 2023 PySimpleGUI -""" - - - -def popup_get_time(title='Time Entry', starting_hour=1, starting_minute=0, allow_manual_input=True, font=None): - """ - Shows a window that will gather a time of day. - - :param title: The title that is shown on the window - :type title: str - :param starting_hour: Value to initially show in the hour field - :type starting_hour: int - :param starting_minute: Value to initially show in the minute field - :type starting_minute: int - :param allow_manual_input: If True, then the Spin elements can be manually edited - :type allow_manual_input: bool - :param font: Font to use for the window - :type font: str | tuple - :return: Tuple with format: (hour, minute, am-pm string) - :type: (int, int, str) - """ - - max_value_dict = {'-HOUR-':(1, 12), '-MIN-':(0, 59)} - hour_list = [i for i in range(0, 15)] - minute_list = [i for i in range(-1, 62)] - - layout = [[sg.Spin(hour_list, initial_value=starting_hour, key='-HOUR-', s=3, enable_events=True, readonly=not allow_manual_input), - sg.Text(':'), - sg.Spin(minute_list, initial_value=starting_minute, key='-MIN-', s=3, enable_events=True, readonly=not allow_manual_input), - sg.Combo(['AM', 'PM'], 'AM', readonly=True, key='-AMPM-')], - [sg.Button('Ok'), sg.Button('Cancel')]] - - window = sg.Window(title, layout, font=font) - - while True: - event, values = window.read() - # print(event, values) - if event == sg.WIN_CLOSED or event == 'Cancel': - hours = minutes = ampm = None - break - - if event == '-HOUR-' or event == '-MIN-': - spin_value = values[event] - if spin_value > max_value_dict[event][1]: - values[event] = max_value_dict[event][0] - window[event].update(values[event]) - elif spin_value < max_value_dict[event][0]: - values[event] = max_value_dict[event][1] - window[event].update(values[event]) - if event == 'Ok': - # Do validation on the input values to ensure they're valid - try: - hours = int(values["-HOUR-"]) - minutes = int(values["-MIN-"]) - ampm = values["-AMPM-"] - except: - continue # if not valid, then don't allow exiting the window using OK. - if 1 <= hours <= 12 and 0 <= minutes < 60: # make sure the hour and minute values are in a valid range - break - - window.close() - - return hours, minutes, ampm - -print(popup_get_time(font='_ 15')) \ No newline at end of file From c8d01725f1a26615c93da975565f9af97fa29980 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Fri, 6 Jan 2023 16:09:39 -0500 Subject: [PATCH 005/145] Demo Program - Time Chooser --- DemoPrograms/Demo_Time_Chooser.py | 79 +++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 DemoPrograms/Demo_Time_Chooser.py diff --git a/DemoPrograms/Demo_Time_Chooser.py b/DemoPrograms/Demo_Time_Chooser.py new file mode 100644 index 00000000..89e20a97 --- /dev/null +++ b/DemoPrograms/Demo_Time_Chooser.py @@ -0,0 +1,79 @@ +import PySimpleGUI as sg + +""" + Demo Time Chooser + + A sample window for choosing a time. + + This particular implementation uses a Spin element. Numerous possibilities exist for entering a time of day. Instead + of Spin elements, Input or Combo Elements could be used. + + If you do not want your user to be able to manually enter values using the keyboard, then set readonly=True in + the Spin elements. + + Copyright 2023 PySimpleGUI +""" + + + +def popup_get_time(title='Time Entry', starting_hour=1, starting_minute=0, allow_manual_input=True, font=None): + """ + Shows a window that will gather a time of day. + + :param title: The title that is shown on the window + :type title: str + :param starting_hour: Value to initially show in the hour field + :type starting_hour: int + :param starting_minute: Value to initially show in the minute field + :type starting_minute: int + :param allow_manual_input: If True, then the Spin elements can be manually edited + :type allow_manual_input: bool + :param font: Font to use for the window + :type font: str | tuple + :return: Tuple with format: (hour, minute, am-pm string) + :type: (int, int, str) + """ + + max_value_dict = {'-HOUR-':(1, 12), '-MIN-':(0, 59)} + hour_list = [i for i in range(0, 15)] + minute_list = [i for i in range(-1, 62)] + + layout = [[sg.Spin(hour_list, initial_value=starting_hour, key='-HOUR-', s=3, enable_events=True, readonly=not allow_manual_input), + sg.Text(':'), + sg.Spin(minute_list, initial_value=starting_minute, key='-MIN-', s=3, enable_events=True, readonly=not allow_manual_input), + sg.Combo(['AM', 'PM'], 'AM', readonly=True, key='-AMPM-')], + [sg.Button('Ok'), sg.Button('Cancel')]] + + window = sg.Window(title, layout, font=font) + + while True: + event, values = window.read() + # print(event, values) + if event == sg.WIN_CLOSED or event == 'Cancel': + hours = minutes = ampm = None + break + + if event == '-HOUR-' or event == '-MIN-': + spin_value = values[event] + if spin_value > max_value_dict[event][1]: + values[event] = max_value_dict[event][0] + window[event].update(values[event]) + elif spin_value < max_value_dict[event][0]: + values[event] = max_value_dict[event][1] + window[event].update(values[event]) + if event == 'Ok': + # Do validation on the input values to ensure they're valid + try: + hours = int(values["-HOUR-"]) + minutes = int(values["-MIN-"]) + ampm = values["-AMPM-"] + except: + continue # if not valid, then don't allow exiting the window using OK. + if 1 <= hours <= 12 and 0 <= minutes < 60: # make sure the hour and minute values are in a valid range + break + + window.close() + + return hours, minutes, ampm + +print(popup_get_time(font='_ 15')) \ No newline at end of file From 2821880b3cbbd842ffdf2186f78d4ce413437f02 Mon Sep 17 00:00:00 2001 From: PySimpleGUI <46163555+PySimpleGUI@users.noreply.github.com> Date: Fri, 6 Jan 2023 16:11:28 -0500 Subject: [PATCH 006/145] Delete Demo_Time_Chooser.py --- DemoPrograms/Demo_Time_Chooser.py | 79 ------------------------------- 1 file changed, 79 deletions(-) delete mode 100644 DemoPrograms/Demo_Time_Chooser.py diff --git a/DemoPrograms/Demo_Time_Chooser.py b/DemoPrograms/Demo_Time_Chooser.py deleted file mode 100644 index 89e20a97..00000000 --- a/DemoPrograms/Demo_Time_Chooser.py +++ /dev/null @@ -1,79 +0,0 @@ -import PySimpleGUI as sg - -""" - Demo Time Chooser - - A sample window for choosing a time. - - This particular implementation uses a Spin element. Numerous possibilities exist for entering a time of day. Instead - of Spin elements, Input or Combo Elements could be used. - - If you do not want your user to be able to manually enter values using the keyboard, then set readonly=True in - the Spin elements. - - Copyright 2023 PySimpleGUI -""" - - - -def popup_get_time(title='Time Entry', starting_hour=1, starting_minute=0, allow_manual_input=True, font=None): - """ - Shows a window that will gather a time of day. - - :param title: The title that is shown on the window - :type title: str - :param starting_hour: Value to initially show in the hour field - :type starting_hour: int - :param starting_minute: Value to initially show in the minute field - :type starting_minute: int - :param allow_manual_input: If True, then the Spin elements can be manually edited - :type allow_manual_input: bool - :param font: Font to use for the window - :type font: str | tuple - :return: Tuple with format: (hour, minute, am-pm string) - :type: (int, int, str) - """ - - max_value_dict = {'-HOUR-':(1, 12), '-MIN-':(0, 59)} - hour_list = [i for i in range(0, 15)] - minute_list = [i for i in range(-1, 62)] - - layout = [[sg.Spin(hour_list, initial_value=starting_hour, key='-HOUR-', s=3, enable_events=True, readonly=not allow_manual_input), - sg.Text(':'), - sg.Spin(minute_list, initial_value=starting_minute, key='-MIN-', s=3, enable_events=True, readonly=not allow_manual_input), - sg.Combo(['AM', 'PM'], 'AM', readonly=True, key='-AMPM-')], - [sg.Button('Ok'), sg.Button('Cancel')]] - - window = sg.Window(title, layout, font=font) - - while True: - event, values = window.read() - # print(event, values) - if event == sg.WIN_CLOSED or event == 'Cancel': - hours = minutes = ampm = None - break - - if event == '-HOUR-' or event == '-MIN-': - spin_value = values[event] - if spin_value > max_value_dict[event][1]: - values[event] = max_value_dict[event][0] - window[event].update(values[event]) - elif spin_value < max_value_dict[event][0]: - values[event] = max_value_dict[event][1] - window[event].update(values[event]) - if event == 'Ok': - # Do validation on the input values to ensure they're valid - try: - hours = int(values["-HOUR-"]) - minutes = int(values["-MIN-"]) - ampm = values["-AMPM-"] - except: - continue # if not valid, then don't allow exiting the window using OK. - if 1 <= hours <= 12 and 0 <= minutes < 60: # make sure the hour and minute values are in a valid range - break - - window.close() - - return hours, minutes, ampm - -print(popup_get_time(font='_ 15')) \ No newline at end of file From d9e42ed2e7fd3801396a457de40c4d7f39fbe9d9 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Fri, 6 Jan 2023 16:12:40 -0500 Subject: [PATCH 007/145] Demo Program - Time Chooser (ONE more time!) --- DemoPrograms/Demo_Time_Chooser.py | 79 +++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 DemoPrograms/Demo_Time_Chooser.py diff --git a/DemoPrograms/Demo_Time_Chooser.py b/DemoPrograms/Demo_Time_Chooser.py new file mode 100644 index 00000000..89e20a97 --- /dev/null +++ b/DemoPrograms/Demo_Time_Chooser.py @@ -0,0 +1,79 @@ +import PySimpleGUI as sg + +""" + Demo Time Chooser + + A sample window for choosing a time. + + This particular implementation uses a Spin element. Numerous possibilities exist for entering a time of day. Instead + of Spin elements, Input or Combo Elements could be used. + + If you do not want your user to be able to manually enter values using the keyboard, then set readonly=True in + the Spin elements. + + Copyright 2023 PySimpleGUI +""" + + + +def popup_get_time(title='Time Entry', starting_hour=1, starting_minute=0, allow_manual_input=True, font=None): + """ + Shows a window that will gather a time of day. + + :param title: The title that is shown on the window + :type title: str + :param starting_hour: Value to initially show in the hour field + :type starting_hour: int + :param starting_minute: Value to initially show in the minute field + :type starting_minute: int + :param allow_manual_input: If True, then the Spin elements can be manually edited + :type allow_manual_input: bool + :param font: Font to use for the window + :type font: str | tuple + :return: Tuple with format: (hour, minute, am-pm string) + :type: (int, int, str) + """ + + max_value_dict = {'-HOUR-':(1, 12), '-MIN-':(0, 59)} + hour_list = [i for i in range(0, 15)] + minute_list = [i for i in range(-1, 62)] + + layout = [[sg.Spin(hour_list, initial_value=starting_hour, key='-HOUR-', s=3, enable_events=True, readonly=not allow_manual_input), + sg.Text(':'), + sg.Spin(minute_list, initial_value=starting_minute, key='-MIN-', s=3, enable_events=True, readonly=not allow_manual_input), + sg.Combo(['AM', 'PM'], 'AM', readonly=True, key='-AMPM-')], + [sg.Button('Ok'), sg.Button('Cancel')]] + + window = sg.Window(title, layout, font=font) + + while True: + event, values = window.read() + # print(event, values) + if event == sg.WIN_CLOSED or event == 'Cancel': + hours = minutes = ampm = None + break + + if event == '-HOUR-' or event == '-MIN-': + spin_value = values[event] + if spin_value > max_value_dict[event][1]: + values[event] = max_value_dict[event][0] + window[event].update(values[event]) + elif spin_value < max_value_dict[event][0]: + values[event] = max_value_dict[event][1] + window[event].update(values[event]) + if event == 'Ok': + # Do validation on the input values to ensure they're valid + try: + hours = int(values["-HOUR-"]) + minutes = int(values["-MIN-"]) + ampm = values["-AMPM-"] + except: + continue # if not valid, then don't allow exiting the window using OK. + if 1 <= hours <= 12 and 0 <= minutes < 60: # make sure the hour and minute values are in a valid range + break + + window.close() + + return hours, minutes, ampm + +print(popup_get_time(font='_ 15')) \ No newline at end of file From d0c558f5c8416bfb2c9c6028eebb97e35ec0d9ad Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Thu, 12 Jan 2023 06:11:05 -0500 Subject: [PATCH 008/145] Tree element - if no headings are specified (set to None) then the header will not be added --- PySimpleGUI.py | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index fa0fbc42..35ea4f2b 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -version = __version__ = "4.60.4.135 Unreleased" +version = __version__ = "4.60.4.136 Unreleased" _change_log = """ Changelog since 4.60.0 released to PyPI on 8-May-2022 @@ -337,7 +337,8 @@ _change_log = """ popup_get_date - exposed the fonts as parameters so that the user code and modify them (specifically to get around a Mac font bug) 4.60.4.135 Renamed QuickMeter to _QuickMeter so that it's clear that it's not an object meant to be used by users - + 4.60.4.136 + Tree element - if headings is set to None, no headings area is shown """ __version__ = version.split()[0] # For PEP 396 and PEP 345 @@ -17504,7 +17505,8 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form): column_headings = element.ColumnHeadings # ------------- GET THE TREEVIEW WIDGET ------------- element.TKTreeview = element.Widget = ttk.Treeview(element_frame, columns=column_headings, - displaycolumns=displaycolumns, show='tree headings', + displaycolumns=displaycolumns, + show='tree headings' if column_headings is not None else 'tree', height=height, selectmode=element.SelectMode) treeview = element.TKTreeview @@ -17515,19 +17517,19 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form): if len(str(value)) > max_width: max_widths[i] = len(str(value)) - - for i, heading in enumerate(element.ColumnHeadings): # Configure cols + headings - treeview.heading(heading, text=heading) - if element.AutoSizeColumns: - max_width = max_widths.get(i, 0) - max_width = max(max_width, len(heading)) - width = min(element.MaxColumnWidth, max_width+1) - else: - try: - width = element.ColumnWidths[i] - except: - width = element.DefaultColumnWidth - treeview.column(heading, width=width * _char_width_in_pixels(font) + 10, anchor=anchor) + if element.ColumnHeadings is not None: + for i, heading in enumerate(element.ColumnHeadings): # Configure cols + headings + treeview.heading(heading, text=heading) + if element.AutoSizeColumns: + max_width = max_widths.get(i, 0) + max_width = max(max_width, len(heading)) + width = min(element.MaxColumnWidth, max_width+1) + else: + try: + width = element.ColumnWidths[i] + except: + width = element.DefaultColumnWidth + treeview.column(heading, width=width * _char_width_in_pixels(font) + 10, anchor=anchor) def add_treeview_data(node): """ @@ -26233,4 +26235,4 @@ if __name__ == '__main__': exit(0) main() exit(0) -#2d2045fc87ee17cd939d4e616b04275ddcce76fd8db3487270058eb7ccb30c1dbab79d6c7956da4eefa99fedf57f849d7106d75dbf09aaa1e372ccc051d85418f14c6b9252fa3870cb5d88023398f9d503145049ec9f9f148650f10040ae8ff41a79915066663d75df7bc63827711503d6e0a2f6b5f1f15ad8d8517f7a5cfa04bb7614ca65fa6ef8a3a0f4d5f8a0b432bb60f20dc1b3cd68dd047e5c00a93930732be95921a4ae79f4dbb1ccb9c34de276e7e704a7f179a72be7e14a4d537463807e0b73ab8a040e33918e596374af841c5e9a6b9cd350280e3d3ab577f247bdafdccf659b26b231322973c78fdb0464d5b93ffac5e0a177dce4291d73ea535c01b579812d7929f0e8b3a3ace84524d2e55ee617171782de6866bb7e219d5f46ee3ecd4821207a224880c0826e70fd2e00292bcb034a8b61cc8782ea035c4e566337b4ba7e5ebf018450042966f99c68a1fd4cfa1649042ef3ccaac8a0c472d0d81da274d4028246660ad6b16334ff3b8d77096dbb7640a92a7127713443e7a1c184542f8069c04f4e6528b19766f26f3eac9743f3d16558789d1579ecfc955e4d7ff7ed78aa1f2e33b25e73c7751bd267947bc4643992e030523cab2d8c025f38bec65c270a036d4fe76f6a19d729f9b544f155d3a775c944615ed0bf87cf04515bfe51fe5d1ec4ffe39c0c04ea0861fe91d385aa42fa97bb7f2d898e186ae0 \ No newline at end of file +#15b898227394d50e7b41524f11f1fe498d2c6c114f5c1bf5278bb9b486181938a3ac012b4a6e144fad3d0b23748d9012d3bb7ce016e5c946332dac672c965e04829e7c484ba4f06bb1a98b86ed382d27f5a5124a1451cafb3e700cfc90cdf212ce393aa01b64dee02bc42b90328f6b05e935d2b1725d8c596392cd37740ca969aab3165a6aa808a6d318f161d7ee826c536e4d5cc5a45ce948c139c3008b9edad36fc981fc6028e42b7aec5cd5d14e9b440fbb48ac29240371e40a28fbb1ed000bd1fc48df381d44efaa48e54bbdd280c07e7889c67bef7281e5e64987a4be969511e6db440ea0811c4b6e17489b138485022217e8f3f923bf4a70bab8263b3298cbd388aa4c0f9355917e114b3b1bc536e7e066f9f0e6d52e06e89dd165d46b9106a1f18313359fc90d7ec4d5ac149eb1d4ca729c634e20f3b2f42a1c20da96addfcc42f55479ebdbf2dfbf98deac050ef93196fa7b6a14b39bb81bafeedf4cb3ea4b38a51ce0df2f4ae3b5400e5c375c3897e3a2498ebe9530bc3502d471da0fbb11762a8d2505b0a2866d0fc0972ed29a9cfa4aaa5012cf618e77bc139d01e13a5239d85a78f8be1f3194166cfac6dafbc4a154f42b4b19a8bd9f923ced14409024fff87f90db4f35b317ce4e6679f08151dedeef6f81c37f26e2532a57cf056b765c2ea0a6970e66c27de68306a97614517ec0f1b1d2ea8e81f631ab9f9c \ No newline at end of file From b216a254809d35764caeb25418dd952dddd4b599 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Thu, 12 Jan 2023 06:23:28 -0500 Subject: [PATCH 009/145] Disables "Take me to error" button if no editor is configured --- PySimpleGUI.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index 35ea4f2b..f71df6f1 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -version = __version__ = "4.60.4.136 Unreleased" +version = __version__ = "4.60.4.137 Unreleased" _change_log = """ Changelog since 4.60.0 released to PyPI on 8-May-2022 @@ -339,6 +339,9 @@ _change_log = """ Renamed QuickMeter to _QuickMeter so that it's clear that it's not an object meant to be used by users 4.60.4.136 Tree element - if headings is set to None, no headings area is shown + 4.60.4.137 + "Take me to error" button is disabled in error traceback popup if not editor is configured. Also adds instructions if no editor. + """ __version__ = version.split()[0] # For PEP 396 and PEP 345 @@ -22202,6 +22205,7 @@ def _error_popup_with_code(title, filename, line_num, *args, emoji=None): :param emoji: An optional BASE64 Encoded image to shows in the error window :type emoji: bytes """ + editor_filename = _get_editor() emoji_data = emoji if emoji is not None else _random_error_emoji() layout = [[Text('ERROR'), Text(title)], [Image(data=emoji_data)]] @@ -22219,8 +22223,9 @@ def _error_popup_with_code(title, filename, line_num, *args, emoji=None): layout += [[Text(''.join(line), size=(min(max_line_len, 90), None))] for line in lines] - layout += [[Button('Close'), Button('Take me to error'), Button('Kill Application', button_color='white on red')]] - + layout += [[Button('Close'), Button('Take me to error', disabled=True if not editor_filename else False), Button('Kill Application', button_color='white on red')]] + if not editor_filename: + layout += [[Text('Configure editor in the Global settings to enable "Take me to error" feature')]] window = Window(title, layout, keep_on_top=True) while True: @@ -26235,4 +26240,4 @@ if __name__ == '__main__': exit(0) main() exit(0) -#15b898227394d50e7b41524f11f1fe498d2c6c114f5c1bf5278bb9b486181938a3ac012b4a6e144fad3d0b23748d9012d3bb7ce016e5c946332dac672c965e04829e7c484ba4f06bb1a98b86ed382d27f5a5124a1451cafb3e700cfc90cdf212ce393aa01b64dee02bc42b90328f6b05e935d2b1725d8c596392cd37740ca969aab3165a6aa808a6d318f161d7ee826c536e4d5cc5a45ce948c139c3008b9edad36fc981fc6028e42b7aec5cd5d14e9b440fbb48ac29240371e40a28fbb1ed000bd1fc48df381d44efaa48e54bbdd280c07e7889c67bef7281e5e64987a4be969511e6db440ea0811c4b6e17489b138485022217e8f3f923bf4a70bab8263b3298cbd388aa4c0f9355917e114b3b1bc536e7e066f9f0e6d52e06e89dd165d46b9106a1f18313359fc90d7ec4d5ac149eb1d4ca729c634e20f3b2f42a1c20da96addfcc42f55479ebdbf2dfbf98deac050ef93196fa7b6a14b39bb81bafeedf4cb3ea4b38a51ce0df2f4ae3b5400e5c375c3897e3a2498ebe9530bc3502d471da0fbb11762a8d2505b0a2866d0fc0972ed29a9cfa4aaa5012cf618e77bc139d01e13a5239d85a78f8be1f3194166cfac6dafbc4a154f42b4b19a8bd9f923ced14409024fff87f90db4f35b317ce4e6679f08151dedeef6f81c37f26e2532a57cf056b765c2ea0a6970e66c27de68306a97614517ec0f1b1d2ea8e81f631ab9f9c \ No newline at end of file +#0fc8e76e80cf311966aea1caad0abf27e052e259fa5cdd101f47301d25ced192cf52177eb64ac7554f7e4546cbb3dcaf5210b2d4c9116958f54fcb1f1f4882a3e553b4c9ef77a1eaee3fcabb8abd047107bcdc891f60ea96cbe345316d48f261a000f8434b9337a4e57ba9caf783f85038d9759872d9ad9613433e07207db1e94bc416b87ddff2c4836da4a98a405c6b28482cca84f60cf1c1924099668b71a33701b35e978924f9abcc904e88f3830acea23b69eacc81bbdbf07eb53438060630badfb914f1ea7d00c3d717da8f6199719476d93dcdf37aebd148e1a4641deb6955140aac1f9bf91244ac1a7b9439b45011aca3d4d02adce54efc6b9c20c0892485de5b343909ce6c89e0921adc7a35d9b9fb03e544d022b1549b0c016b72a70b7ffdb5aa92b3e2a49d52de9196008944b4455c3c8df4e9f9bfc6a8d6369081b19ca0b21b7b2333a0fea526f3935c21d40d3c2b74e10b3c0ec6166e0592fe85086d4ad3fb52d1080e921d37ead81fd2a5b1e4ac91dbd90f611a5373ec04ec735198454f52caad2bb3439790194ee4f546e23bcd84b9b54ac372ac5e5855dd97a02c06e6b3d5a285a3b482ecd90f7b89f819feece3e75154cd423d08c30c1f20872be13b0201c83720e0398e3ab9adcbd7b3718838bdd6073239d326bf7b2f54caee78b0f01eac621f379b25af78d7625f1797c6b87e6cf7f43a089980c07ace \ No newline at end of file From 81c16c6b5fc5559a79b037ef7c2e947c0c54d85f Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Thu, 12 Jan 2023 13:37:32 -0500 Subject: [PATCH 010/145] Added begin_at_sunday_plus to the docstring for CalendarButton --- PySimpleGUI.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index f71df6f1..8c63093e 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -version = __version__ = "4.60.4.137 Unreleased" +version = __version__ = "4.60.4.138 Unreleased" _change_log = """ Changelog since 4.60.0 released to PyPI on 8-May-2022 @@ -341,6 +341,8 @@ _change_log = """ Tree element - if headings is set to None, no headings area is shown 4.60.4.137 "Take me to error" button is disabled in error traceback popup if not editor is configured. Also adds instructions if no editor. + 4.60.4.138 + Added begin_at_sunday_plus to the CalendarButton docstring """ @@ -14661,6 +14663,8 @@ def CalendarButton(button_text, target=(ThisRow, -1), close_when_date_chosen=Tru :type locale: str :param format: formats result using this strftime format :type format: str + :param begin_at_sunday_plus: Determines the left-most day in the display. 0=sunday, 1=monday, etc + :type begin_at_sunday_plus: (int) :param month_names: optional list of month names to use (should be 12 items) :type month_names: List[str] :param day_abbreviations: optional list of abbreviations to display as the day of week @@ -26240,4 +26244,4 @@ if __name__ == '__main__': exit(0) main() exit(0) -#0fc8e76e80cf311966aea1caad0abf27e052e259fa5cdd101f47301d25ced192cf52177eb64ac7554f7e4546cbb3dcaf5210b2d4c9116958f54fcb1f1f4882a3e553b4c9ef77a1eaee3fcabb8abd047107bcdc891f60ea96cbe345316d48f261a000f8434b9337a4e57ba9caf783f85038d9759872d9ad9613433e07207db1e94bc416b87ddff2c4836da4a98a405c6b28482cca84f60cf1c1924099668b71a33701b35e978924f9abcc904e88f3830acea23b69eacc81bbdbf07eb53438060630badfb914f1ea7d00c3d717da8f6199719476d93dcdf37aebd148e1a4641deb6955140aac1f9bf91244ac1a7b9439b45011aca3d4d02adce54efc6b9c20c0892485de5b343909ce6c89e0921adc7a35d9b9fb03e544d022b1549b0c016b72a70b7ffdb5aa92b3e2a49d52de9196008944b4455c3c8df4e9f9bfc6a8d6369081b19ca0b21b7b2333a0fea526f3935c21d40d3c2b74e10b3c0ec6166e0592fe85086d4ad3fb52d1080e921d37ead81fd2a5b1e4ac91dbd90f611a5373ec04ec735198454f52caad2bb3439790194ee4f546e23bcd84b9b54ac372ac5e5855dd97a02c06e6b3d5a285a3b482ecd90f7b89f819feece3e75154cd423d08c30c1f20872be13b0201c83720e0398e3ab9adcbd7b3718838bdd6073239d326bf7b2f54caee78b0f01eac621f379b25af78d7625f1797c6b87e6cf7f43a089980c07ace \ No newline at end of file +#72a37da2ed2698572ff1dd1ff7c3117548c6d90f24a80357f9ab68bf2ce2631e77578781d2a862823b929a07256888312fd4d577981e55c841544ea2aa0705867d41371f9b5ebf3e779fa0af4dee1bbacc65e6c4c8f8524a881eebb41121b3664966154f6346594dd364552465cd951eae92dfd878fb092ebc3885e4186537addeca75a45074d7027d7c91c0a9f294770d35757a46164a5d33e16f18eac7ca661fc184cc68d2d9204e34b01ad877ac4aadb020bf86e36decdeb51417866aa9e03a9ee34902c9ed84f604f15267cdfd6d4dc75bb0cd7b989c4552941a91ec3fecfa7abc13c179cfcbc943ca197f42d602c22966e40eb4230381a12da8d5a8c9c1ba31c8a857cbb3376a7d046b5e27567680abc2c10f4fde972371fd8b3005fc536f998834139061bfe8291aa641c767cd6996d7684d36bf388da4ea8ff26685625f4c757520df5772af2d2e1029009562628aad1acdc91d924269eb44d6e1427ffda09c46e44dcfac8bf46d3cd8139c20109e61966695176386ff8fd289ef9d62419824283ba656b9e744ad49eb0345375e1d3cefbc11c2a09f4309d9b33edf38de9dbbf2656198459b5bd051b18b1dc8ccd5edc87fe45b85e6b083b52c1748e16f4952609278705daa1475b83669922dd1168db67b4ea7dbfa1526e9bd89f3c30a4334fd198ce05f3dfcc4358cd1682428890d795541fea9b405447ee485d0ff \ No newline at end of file From 529c285489e51f7c2e96a7264d21fcf82ac8e896 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Thu, 12 Jan 2023 21:06:16 -0500 Subject: [PATCH 011/145] Moved debugger constants to sinde of the debugger class. Simplified the locals and globals popups. --- PySimpleGUI.py | 104 ++++++++++++++++++++++++++----------------------- 1 file changed, 55 insertions(+), 49 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index 8c63093e..294d80bb 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -version = __version__ = "4.60.4.138 Unreleased" +version = __version__ = "4.60.4.139 Unreleased" _change_log = """ Changelog since 4.60.0 released to PyPI on 8-May-2022 @@ -343,6 +343,8 @@ _change_log = """ "Take me to error" button is disabled in error traceback popup if not editor is configured. Also adds instructions if no editor. 4.60.4.138 Added begin_at_sunday_plus to the CalendarButton docstring + 4.60.4.139 + Moved debugger constants to sinde of the debugger class. Simplified the locals and globals popups. """ @@ -23654,26 +23656,28 @@ def main_mac_feature_control(): red_x = b"R0lGODlhEAAQAPeQAIsAAI0AAI4AAI8AAJIAAJUAAJQCApkAAJoAAJ4AAJkJCaAAAKYAAKcAAKcCAKcDA6cGAKgAAKsAAKsCAKwAAK0AAK8AAK4CAK8DAqUJAKULAKwLALAAALEAALIAALMAALMDALQAALUAALYAALcEALoAALsAALsCALwAAL8AALkJAL4NAL8NAKoTAKwbAbEQALMVAL0QAL0RAKsREaodHbkQELMsALg2ALk3ALs+ALE2FbgpKbA1Nbc1Nb44N8AAAMIWAMsvAMUgDMcxAKVABb9NBbVJErFYEq1iMrtoMr5kP8BKAMFLAMxKANBBANFCANJFANFEB9JKAMFcANFZANZcANpfAMJUEMZVEc5hAM5pAMluBdRsANR8AM9YOrdERMpIQs1UVMR5WNt8X8VgYMdlZcxtYtx4YNF/btp9eraNf9qXXNCCZsyLeNSLd8SSecySf82kd9qqc9uBgdyBgd+EhN6JgtSIiNuJieGHhOGLg+GKhOKamty1ste4sNO+ueenp+inp+HHrebGrefKuOPTzejWzera1O7b1vLb2/bl4vTu7fbw7ffx7vnz8f///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAJAALAAAAAAQABAAAAjUACEJHEiwYEEABniQKfNFgQCDkATQwAMokEU+PQgUFDAjjR09e/LUmUNnh8aBCcCgUeRmzBkzie6EeQBAoAAMXuA8ciRGCaJHfXzUMCAQgYooWN48anTokR8dQk4sELggBhQrU9Q8evSHiJQgLCIIfMDCSZUjhbYuQkLFCRAMAiOQGGLE0CNBcZYmaRIDLqQFGF60eTRoSxc5jwjhACFWIAgMLtgUocJFy5orL0IQRHAiQgsbRZYswbEhBIiCCH6EiJAhAwQMKU5DjHCi9gnZEHMTDAgAOw==" -COLOR_SCHEME = 'dark grey 13' -DEBUGGER_POPOUT_THEME = 'dark grey 13' -WIDTH_VARIABLES = 23 -WIDTH_RESULTS = 46 -WIDTH_WATCHER_VARIABLES = 20 -WIDTH_WATCHER_RESULTS = 60 - -WIDTH_LOCALS = 80 -NUM_AUTO_WATCH = 9 - -MAX_LINES_PER_RESULT_FLOATING = 4 -MAX_LINES_PER_RESULT_MAIN = 3 - -POPOUT_WINDOW_FONT = 'Sans 8' -DEBUGGER_VARIABLE_DETAILS_FONT = 'Courier 10' class _Debugger: debugger = None + DEBUGGER_MAIN_WINDOW_THEME = 'dark grey 13' + DEBUGGER_POPOUT_THEME = 'dark grey 13' + WIDTH_VARIABLES = 23 + WIDTH_RESULTS = 46 + + WIDTH_WATCHER_VARIABLES = 20 + WIDTH_WATCHER_RESULTS = 60 + + WIDTH_LOCALS = 80 + NUM_AUTO_WATCH = 9 + + MAX_LINES_PER_RESULT_FLOATING = 4 + MAX_LINES_PER_RESULT_MAIN = 3 + + DEBUGGER_POPOUT_WINDOW_FONT = 'Sans 8' + DEBUGGER_VARIABLE_DETAILS_FONT = 'Courier 10' + ''' # # ###### ## ## ## # # # # # ###### ##### # # #### #### ###### ##### @@ -23696,12 +23700,12 @@ class _Debugger: # Includes the DUAL PANE (now 2 tabs)! Don't forget REPL is there too! def _build_main_debugger_window(self, location=(None, None)): old_theme = theme() - theme(COLOR_SCHEME) + theme(_Debugger.DEBUGGER_MAIN_WINDOW_THEME) def InVar(key1): row1 = [T(' '), - I(key=key1, size=(WIDTH_VARIABLES, 1)), - T('', key=key1 + 'CHANGED_', size=(WIDTH_RESULTS, 1)), B('Detail', key=key1 + 'DETAIL_'), + I(key=key1, size=(_Debugger.WIDTH_VARIABLES, 1)), + T('', key=key1 + 'CHANGED_', size=(_Debugger.WIDTH_RESULTS, 1)), B('Detail', key=key1 + 'DETAIL_'), B('Obj', key=key1 + 'OBJ_'), ] return row1 @@ -23722,10 +23726,9 @@ class _Debugger: Button('Popout', key='-POPOUT-')]] var_layout = [] - for i in range(NUM_AUTO_WATCH): - var_layout.append([T('', size=(WIDTH_WATCHER_VARIABLES, 1), key='_WATCH%s_' % i), - T('', size=(WIDTH_WATCHER_RESULTS, MAX_LINES_PER_RESULT_MAIN), key='_WATCH%s_RESULT_' % i, - )]) + for i in range(_Debugger.NUM_AUTO_WATCH): + var_layout.append([T('', size=(_Debugger.WIDTH_WATCHER_VARIABLES, 1), key='_WATCH%s_' % i), + T('', size=(_Debugger.WIDTH_WATCHER_RESULTS, _Debugger.MAX_LINES_PER_RESULT_MAIN), key='_WATCH%s_RESULT_' % i,)]) col1 = [ # [Frame('Auto Watches', autowatch_frame+variable_values, title_color='blue')] @@ -23742,8 +23745,7 @@ class _Debugger: [TabGroup([[Tab('Variables', col1), Tab('REPL & Watches', col2)]])]] # ------------------------------- Create main window ------------------------------- - window = Window("PySimpleGUI Debugger", layout, icon=PSG_DEBUGGER_LOGO, margins=(0, 0), location=location, keep_on_top=True, - right_click_menu=[[''], ['Exit', ]]) + window = Window("PySimpleGUI Debugger", layout, icon=PSG_DEBUGGER_LOGO, margins=(0, 0), location=location, keep_on_top=True, right_click_menu=[[''], ['Exit', ]]) Window._read_call_from_debugger = True window.finalize() @@ -23801,7 +23803,7 @@ class _Debugger: result = str(eval(str(var), myglobals, mylocals)) except: result = '' - popup_scrolled(str(values['_VAR{}_'.format(event[4])]) + '\n' + result, title=var, non_blocking=True, font=DEBUGGER_VARIABLE_DETAILS_FONT) + popup_scrolled(str(values['_VAR{}_'.format(event[4])]) + '\n' + result, title=var, non_blocking=True, font=_Debugger.DEBUGGER_VARIABLE_DETAILS_FONT) # BUTTON - OBJ elif event.endswith('_OBJ_'): # OBJECT BUTTON var = values['_VAR{}_'.format(event[4])] @@ -23813,17 +23815,17 @@ class _Debugger: result = ObjToStringSingleObj(result) except Exception as e: result = '{}\nError showing object {}'.format(e, var) - popup_scrolled(str(var) + '\n' + str(result), title=var, non_blocking=True, font=DEBUGGER_VARIABLE_DETAILS_FONT) + popup_scrolled(str(var) + '\n' + str(result), title=var, non_blocking=True, font=Debugger.DEBUGGER_VARIABLE_DETAILS_FONT) # ------------------------------- Process Watch Tab ------------------------------- # BUTTON - Choose Locals to see elif event == '-LOCALS-': # Show all locals BUTTON self._choose_auto_watches(mylocals) # BUTTON - Locals (quick popup) elif event == '-ALL_LOCALS-': - self._display_all_vars(mylocals) + self._display_all_vars('All Locals', mylocals) # BUTTON - Globals (quick popup) elif event == '-GLOBALS-': - self._display_all_vars(myglobals) + self._display_all_vars('All Globals', myglobals) # BUTTON - clear all elif event == 'Clear All Auto Watches': if popup_yes_no('Do you really want to clear all Auto-Watches?', 'Really Clear??') == 'Yes': @@ -23866,7 +23868,7 @@ class _Debugger: self.watcher_window.Element('_WATCH{}_RESULT_'.format(slot)).Update('') slot += 1 - if slot + int(not self.custom_watch in (None, '')) >= NUM_AUTO_WATCH: + if slot + int(not self.custom_watch in (None, '')) >= _Debugger.NUM_AUTO_WATCH: break # If a custom watch was set, display that value in the window if self.custom_watch: @@ -23878,7 +23880,7 @@ class _Debugger: self.watcher_window.Element('_WATCH{}_RESULT_'.format(slot)).Update(self.myrc) slot += 1 # blank out all of the slots not used (blank) - for i in range(slot, NUM_AUTO_WATCH): + for i in range(slot, _Debugger.NUM_AUTO_WATCH): self.watcher_window.Element('_WATCH{}_'.format(i)).Update('') self.watcher_window.Element('_WATCH{}_RESULT_'.format(i)).Update('') @@ -23927,12 +23929,12 @@ class _Debugger: ''' # displays them into a single text box - def _display_all_vars(self, dict): + def _display_all_vars(self, title, dict): num_cols = 3 output_text = '' num_lines = 2 cur_col = 0 - out_text = 'All of your Vars' + out_text = title + '\n' longest_line = max([len(key) for key in dict]) line = [] sorted_dict = {} @@ -23940,15 +23942,19 @@ class _Debugger: sorted_dict[key] = dict[key] for key in sorted_dict: value = dict[key] - wrapped_list = textwrap.wrap(str(value), 60) - wrapped_text = '\n'.join(wrapped_list) + # wrapped_list = textwrap.wrap(str(value), 60) + # wrapped_text = '\n'.join(wrapped_list) + wrapped_text = str(value) out_text += '{} - {}\n'.format(key, wrapped_text) - if cur_col + 1 == num_cols: - cur_col = 0 - num_lines += len(wrapped_list) - else: - cur_col += 1 - popup_scrolled(out_text, non_blocking=True) + # if cur_col + 1 == num_cols: + # cur_col = 0 + # num_lines += len(wrapped_list) + # else: + # cur_col += 1 + old_theme = theme() + theme(_Debugger.DEBUGGER_MAIN_WINDOW_THEME) + popup_scrolled(out_text, title=title, non_blocking=True, font=_Debugger.DEBUGGER_VARIABLE_DETAILS_FONT, keep_on_top=True, icon=PSG_DEBUGGER_LOGO) + theme(old_theme) ''' ##### # # @@ -23970,7 +23976,7 @@ class _Debugger: def _choose_auto_watches(self, my_locals): old_theme = theme() - theme(COLOR_SCHEME) + theme(_Debugger.DEBUGGER_MAIN_WINDOW_THEME) num_cols = 3 output_text = '' num_lines = 2 @@ -23998,7 +24004,7 @@ class _Debugger: layout += [ [Ok(), Cancel(), Button('Clear All'), Button('Select [almost] All', key='-AUTO_SELECT-')]] - window = Window('All Locals', layout, icon=PSG_DEBUGGER_LOGO, finalize=True) + window = Window('Choose Watches', layout, icon=PSG_DEBUGGER_LOGO, finalize=True, keep_on_top=True) while True: # event loop event, values = window.read() @@ -24053,7 +24059,7 @@ class _Debugger: if self.popout_window: # if floating window already exists, close it first self.popout_window.Close() old_theme = theme() - theme(DEBUGGER_POPOUT_THEME) + theme(_Debugger.DEBUGGER_POPOUT_THEME) num_cols = 2 width_var = 15 width_value = 30 @@ -24070,10 +24076,10 @@ class _Debugger: for key in self.popout_choices: if self.popout_choices[key] is True: value = str(self.locals.get(key)) - h = min(len(value) // width_value + 1, MAX_LINES_PER_RESULT_FLOATING) - line += [Text('{}'.format(key), size=(width_var, 1), font=POPOUT_WINDOW_FONT), - Text(' = ', font=POPOUT_WINDOW_FONT), - Text(value, key=key, size=(width_value, h), font=POPOUT_WINDOW_FONT)] + h = min(len(value) // width_value + 1, _Debugger.MAX_LINES_PER_RESULT_FLOATING) + line += [Text('{}'.format(key), size=(width_var, 1), font=_Debugger.DEBUGGER_POPOUT_WINDOW_FONT), + Text(' = ', font=_Debugger.DEBUGGER_POPOUT_WINDOW_FONT), + Text(value, key=key, size=(width_value, h), font=_Debugger.DEBUGGER_POPOUT_WINDOW_FONT)] if col + 1 < num_cols: line += [VerticalSeparator(), T(' ')] col += 1 @@ -26244,4 +26250,4 @@ if __name__ == '__main__': exit(0) main() exit(0) -#72a37da2ed2698572ff1dd1ff7c3117548c6d90f24a80357f9ab68bf2ce2631e77578781d2a862823b929a07256888312fd4d577981e55c841544ea2aa0705867d41371f9b5ebf3e779fa0af4dee1bbacc65e6c4c8f8524a881eebb41121b3664966154f6346594dd364552465cd951eae92dfd878fb092ebc3885e4186537addeca75a45074d7027d7c91c0a9f294770d35757a46164a5d33e16f18eac7ca661fc184cc68d2d9204e34b01ad877ac4aadb020bf86e36decdeb51417866aa9e03a9ee34902c9ed84f604f15267cdfd6d4dc75bb0cd7b989c4552941a91ec3fecfa7abc13c179cfcbc943ca197f42d602c22966e40eb4230381a12da8d5a8c9c1ba31c8a857cbb3376a7d046b5e27567680abc2c10f4fde972371fd8b3005fc536f998834139061bfe8291aa641c767cd6996d7684d36bf388da4ea8ff26685625f4c757520df5772af2d2e1029009562628aad1acdc91d924269eb44d6e1427ffda09c46e44dcfac8bf46d3cd8139c20109e61966695176386ff8fd289ef9d62419824283ba656b9e744ad49eb0345375e1d3cefbc11c2a09f4309d9b33edf38de9dbbf2656198459b5bd051b18b1dc8ccd5edc87fe45b85e6b083b52c1748e16f4952609278705daa1475b83669922dd1168db67b4ea7dbfa1526e9bd89f3c30a4334fd198ce05f3dfcc4358cd1682428890d795541fea9b405447ee485d0ff \ No newline at end of file +#33fbe913c63f0fa0f0893ef55e3f6af4895e599092b2f002692e055f221a53df9b32f5642ce0d85df2d6f7a8eb74aaea23ff3e3b7b60db9bb7746ea8383c9a3c9950c8a1eef3573bd88760d605dd513dee435968c36503c87cc5ae59e2bc32406922fc801a2ce114f12134c6fdc40207a08a93164c44591824222cd0fd6eb7e13255257ba3359d2d2026c8404e351949788c32d159018219ac53b5ca362e86c0c8d6e44158ee39d142f6b2326d16c1616ca86e2f17299d2df53dedd7af1a7f7ff5ed61aa78881f3f4ecf612ca5b170c780122bb4c7cd53dfe3cb421bd78b1748f611b3de86357a98e0258e08480b8d0e3a81978565a11db28a2ba288e6f1271b01b93561e35e7aa1107801896afd249b9ba60c5557bf1040656c6e6d790a72f6dfeedf5cf4b7270e90a897e5b86964bf1c87f6c3c49f2df6e6474f2b4397c2804d16b69d289440e8763373ed5fd73f967203e65b0aec8ef83add0a286c41c4d324faa94b0dd1fd6b0f49ab61755317a954dada3b2661e24afef5cc9721f6ac9a8468b0b051c98993202e4dabb0607dc98720712adc9f567613d3237491a7933881a7efa57f2ff6776b6d49674c24e334ce3d6a006d2b5e7e0d9c6b5253688bd86ba462bd2df37b5ece8a1050b9379f9da0e0fea97868eaaff566d2f5ad34f71456495138244bf983be36be53a90ecc1c2b712bdb123391296a7c770bfff48590 \ No newline at end of file From 6a64f8cfd22699924a234954a8e7378e6a6785a0 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Fri, 13 Jan 2023 12:01:52 -0500 Subject: [PATCH 012/145] Experimental change to Table.get. Using the tkinter widget's selection method. Looks like it could work. --- PySimpleGUI.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index 294d80bb..158de052 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -version = __version__ = "4.60.4.139 Unreleased" +version = __version__ = "4.60.4.140 Unreleased" _change_log = """ Changelog since 4.60.0 released to PyPI on 8-May-2022 @@ -344,7 +344,9 @@ _change_log = """ 4.60.4.138 Added begin_at_sunday_plus to the CalendarButton docstring 4.60.4.139 - Moved debugger constants to sinde of the debugger class. Simplified the locals and globals popups. + Moved debugger constants to inside of the debugger class. Simplified the locals and globals popups. + 4.60.4.140 + Experimental change.... Table.get now returns the values from the widget's selection method """ @@ -9284,15 +9286,14 @@ class Table(Element): def get(self): """ - Dummy function for tkinter port. In the Qt port you can read back the values in the table in case they were - edited. Don't know yet how to enable editing of a Tree in tkinter so just returning the values provided by - user when Table was created or Updated. + Get the selected rows using tktiner's selection method. Experimenting with this change.... - :return: the current table values (for now what was originally provided up updated) + :return: the current table values :rtype: List[List[Any]] """ - return self.Values - + selections = self.TKTreeview.selection() + selected_rows = [int(x) - 1 for x in selections] + return selected_rows def get_last_clicked_position(self): """ @@ -26250,4 +26251,4 @@ if __name__ == '__main__': exit(0) main() exit(0) -#33fbe913c63f0fa0f0893ef55e3f6af4895e599092b2f002692e055f221a53df9b32f5642ce0d85df2d6f7a8eb74aaea23ff3e3b7b60db9bb7746ea8383c9a3c9950c8a1eef3573bd88760d605dd513dee435968c36503c87cc5ae59e2bc32406922fc801a2ce114f12134c6fdc40207a08a93164c44591824222cd0fd6eb7e13255257ba3359d2d2026c8404e351949788c32d159018219ac53b5ca362e86c0c8d6e44158ee39d142f6b2326d16c1616ca86e2f17299d2df53dedd7af1a7f7ff5ed61aa78881f3f4ecf612ca5b170c780122bb4c7cd53dfe3cb421bd78b1748f611b3de86357a98e0258e08480b8d0e3a81978565a11db28a2ba288e6f1271b01b93561e35e7aa1107801896afd249b9ba60c5557bf1040656c6e6d790a72f6dfeedf5cf4b7270e90a897e5b86964bf1c87f6c3c49f2df6e6474f2b4397c2804d16b69d289440e8763373ed5fd73f967203e65b0aec8ef83add0a286c41c4d324faa94b0dd1fd6b0f49ab61755317a954dada3b2661e24afef5cc9721f6ac9a8468b0b051c98993202e4dabb0607dc98720712adc9f567613d3237491a7933881a7efa57f2ff6776b6d49674c24e334ce3d6a006d2b5e7e0d9c6b5253688bd86ba462bd2df37b5ece8a1050b9379f9da0e0fea97868eaaff566d2f5ad34f71456495138244bf983be36be53a90ecc1c2b712bdb123391296a7c770bfff48590 \ No newline at end of file +#54251a437ae53503c980748d9b49f5e541745a71f9633a639b5d1df4f2ce9722d3521a73a57c87dcf17e57225f46f455ccf04dbe5066e1c09e19830a9ab3866b40f91f8af4093c954e5c608f8eb49d7e1d82b9db4b9a680fde861b4c55b5ccb68e918710b9df3395fc5f156c88ab737739dde188ca4ae0e7559179b06d9573e18eb597cee9a8dc7363380e5bbeee99aef17f5b81ed8d06e533b4a38e1b1ed79a2fc4ad4e9a19f93042ac1f5eb637b2875694b65908f35888aa27fbb2361599332411117fa5a6090eace1b0d3f749a6ccbbf52f80b39cf04fd7dacaeb79893792017f79da8749338b4dbb4e9203f17a1728248a323d6f67c09a1052e44f2ccb821b0c7b6c41ce2d52fec97ffcd02e3257853d3691e5c6bc6ed9ada4eef49174560dad6e7d25c8346c1f634e759dd4d07e71363809c39d54ecacfaf662231a43e76d253d332a2eccde36823ea99d14bf6c62ace0cedcf815045deb9839efa7b5407fed7ce368059a19a50692b16c429cecebdbb62bcf46d4f66fa43647c4a03453fabc56f18a4ac92a8225bdb6fbb6d968fd189889392c0377d4b2ca34b45683a3ae5efdb959a06dd3e61ddf3d2a7dd3f4da60aecb3912277dc53534c74a2f768563ad77819269d9c39ed11194666e6a0f0c9581bcfb7cbb0afa19731500e1e4f9d92de8bc2ab3fa835dfe454b6dffb6e215a94c2ae5b03b1c7a75876880494dcc \ No newline at end of file From 805727fed9b28998564a641c5d5258443e999d50 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Fri, 13 Jan 2023 14:30:33 -0500 Subject: [PATCH 013/145] Get the latest docstrings from PySimpleGUI on github so that the SDK docs online match. --- docs/call reference.md | 35 ++++++++++++++----------- docs/index.md | 8 +++--- readme_creator/output/call reference.md | 35 ++++++++++++++----------- readme_creator/output/index.md | 8 +++--- 4 files changed, 46 insertions(+), 40 deletions(-) diff --git a/docs/call reference.md b/docs/call reference.md index b2037bda..ad33251c 100644 --- a/docs/call reference.md +++ b/docs/call reference.md @@ -11420,15 +11420,13 @@ Parameter Descriptions: ### get -Dummy function for tkinter port. In the Qt port you can read back the values in the table in case they were -edited. Don't know yet how to enable editing of a Tree in tkinter so just returning the values provided by -user when Table was created or Updated. +Get the selected rows using tktiner's selection method. Experimenting with this change.... `get()` |Type|Name|Meaning| |---|---|---| -|List[List[Any]]| **return** | the current table values (for now what was originally provided up updated) | +|List[List[Any]]| **return** | the current table values | ### get_next_focus @@ -11652,15 +11650,13 @@ The following methods are here for backwards compatibility reference. You will ### Get -Dummy function for tkinter port. In the Qt port you can read back the values in the table in case they were -edited. Don't know yet how to enable editing of a Tree in tkinter so just returning the values provided by -user when Table was created or Updated. +Get the selected rows using tktiner's selection method. Experimenting with this change.... `Get()` |Type|Name|Meaning| |---|---|---| -|List[List[Any]]| **return** | the current table values (for now what was originally provided up updated) | +|List[List[Any]]| **return** | the current table values | ### SetFocus @@ -14919,6 +14915,7 @@ Parameter Descriptions: | str or int or tuple or object | k | Same as the Key. You can use either k or key. Which ever is set will be used. | | str | locale | defines the locale used to get day names | | str | format | formats result using this strftime format | +| int | begin_at_sunday_plus | Determines the left-most day in the display. 0=sunday, 1=monday, etc | | List[str] | month_names | optional list of month names to use (should be 12 items) | | List[str] | day_abbreviations | optional list of abbreviations to display as the day of week | | str | title | Title shown on the date chooser window | @@ -16571,11 +16568,11 @@ Parameter Descriptions: |Type|Name|Meaning| |--|--|--| -| str | title | text to display in eleemnt | +| str | title | text to display in titlebar of window | | int | current_value | current value | -| int | max_value | max value of QuickMeter | -| Any | *args | stuff to output | -| str or int or tuple or object | key | Used to differentiate between mutliple meters. Used to cancel meter early. Now optional as there is a default value for single meters | +| int | max_value | max value of progress meter | +| Any | *args | stuff to output as text in the window along with the meter | +| str or int or tuple or object | key | Used to differentiate between multiple meters. Used to cancel meter early. Now optional as there is a default value for single meters | | str | orientation | 'horizontal' or 'vertical' ('h' or 'v' work) (Default value = 'vertical' / 'v') | | (str, str) or str | bar_color | The 2 colors that make up a progress bar. Either a tuple of 2 strings or a string. Tuple - (bar, background). A string with 1 color changes the background of the bar only. A string with 2 colors separated by "on" like "red on blue" specifies a red bar on a blue background. | | (str, str) or str | button_color | button color (foreground, background) | @@ -16625,11 +16622,11 @@ Parameter Descriptions: |Type|Name|Meaning| |--|--|--| -| str | title | text to display in eleemnt | +| str | title | text to display in titlebar of window | | int | current_value | current value | -| int | max_value | max value of QuickMeter | -| Any | *args | stuff to output | -| str or int or tuple or object | key | Used to differentiate between mutliple meters. Used to cancel meter early. Now optional as there is a default value for single meters | +| int | max_value | max value of progress meter | +| Any | *args | stuff to output as text in the window along with the meter | +| str or int or tuple or object | key | Used to differentiate between multiple meters. Used to cancel meter early. Now optional as there is a default value for single meters | | str | orientation | 'horizontal' or 'vertical' ('h' or 'v' work) (Default value = 'vertical' / 'v') | | (str, str) or str | bar_color | The 2 colors that make up a progress bar. Either a tuple of 2 strings or a string. Tuple - (bar, background). A string with 1 color changes the background of the bar only. A string with 2 colors separated by "on" like "red on blue" specifies a red bar on a blue background. | | (str, str) or str | button_color | button color (foreground, background) | @@ -16942,6 +16939,9 @@ popup_get_date(start_mon = None, locale = None, month_names = None, day_abbreviations = None, + day_font = "TkFixedFont 9", + mon_year_font = "TkFixedFont 10", + arrow_font = "TkFixedFont 7", modal = True) ``` @@ -16963,6 +16963,9 @@ Parameter Descriptions: | bool | keep_on_top | If True the window will remain above all current windows | | List[str] | month_names | optional list of month names to use (should be 12 items) | | List[str] | day_abbreviations | optional list of abbreviations to display as the day of week | +| str or tuple | day_font | Font and size to use for the calendar | +| str or tuple | mon_year_font | Font and size to use for the month and year at the top | +| str or tuple | arrow_font | Font and size to use for the arrow buttons | | bool | modal | If True then makes the popup will behave like a Modal window... all other windows are non-operational until this one is closed. Default = True | | None or (int, int, int) | **RETURN** | Tuple containing (month, day, year) of chosen date or None if was cancelled diff --git a/docs/index.md b/docs/index.md index 52331638..b851cf66 100644 --- a/docs/index.md +++ b/docs/index.md @@ -2078,11 +2078,11 @@ Parameter Descriptions: |Type|Name|Meaning| |--|--|--| -| str | title | text to display in eleemnt | +| str | title | text to display in titlebar of window | | int | current_value | current value | -| int | max_value | max value of QuickMeter | -| Any | *args | stuff to output | -| str or int or tuple or object | key | Used to differentiate between mutliple meters. Used to cancel meter early. Now optional as there is a default value for single meters | +| int | max_value | max value of progress meter | +| Any | *args | stuff to output as text in the window along with the meter | +| str or int or tuple or object | key | Used to differentiate between multiple meters. Used to cancel meter early. Now optional as there is a default value for single meters | | str | orientation | 'horizontal' or 'vertical' ('h' or 'v' work) (Default value = 'vertical' / 'v') | | (str, str) or str | bar_color | The 2 colors that make up a progress bar. Either a tuple of 2 strings or a string. Tuple - (bar, background). A string with 1 color changes the background of the bar only. A string with 2 colors separated by "on" like "red on blue" specifies a red bar on a blue background. | | (str, str) or str | button_color | button color (foreground, background) | diff --git a/readme_creator/output/call reference.md b/readme_creator/output/call reference.md index b2037bda..ad33251c 100644 --- a/readme_creator/output/call reference.md +++ b/readme_creator/output/call reference.md @@ -11420,15 +11420,13 @@ Parameter Descriptions: ### get -Dummy function for tkinter port. In the Qt port you can read back the values in the table in case they were -edited. Don't know yet how to enable editing of a Tree in tkinter so just returning the values provided by -user when Table was created or Updated. +Get the selected rows using tktiner's selection method. Experimenting with this change.... `get()` |Type|Name|Meaning| |---|---|---| -|List[List[Any]]| **return** | the current table values (for now what was originally provided up updated) | +|List[List[Any]]| **return** | the current table values | ### get_next_focus @@ -11652,15 +11650,13 @@ The following methods are here for backwards compatibility reference. You will ### Get -Dummy function for tkinter port. In the Qt port you can read back the values in the table in case they were -edited. Don't know yet how to enable editing of a Tree in tkinter so just returning the values provided by -user when Table was created or Updated. +Get the selected rows using tktiner's selection method. Experimenting with this change.... `Get()` |Type|Name|Meaning| |---|---|---| -|List[List[Any]]| **return** | the current table values (for now what was originally provided up updated) | +|List[List[Any]]| **return** | the current table values | ### SetFocus @@ -14919,6 +14915,7 @@ Parameter Descriptions: | str or int or tuple or object | k | Same as the Key. You can use either k or key. Which ever is set will be used. | | str | locale | defines the locale used to get day names | | str | format | formats result using this strftime format | +| int | begin_at_sunday_plus | Determines the left-most day in the display. 0=sunday, 1=monday, etc | | List[str] | month_names | optional list of month names to use (should be 12 items) | | List[str] | day_abbreviations | optional list of abbreviations to display as the day of week | | str | title | Title shown on the date chooser window | @@ -16571,11 +16568,11 @@ Parameter Descriptions: |Type|Name|Meaning| |--|--|--| -| str | title | text to display in eleemnt | +| str | title | text to display in titlebar of window | | int | current_value | current value | -| int | max_value | max value of QuickMeter | -| Any | *args | stuff to output | -| str or int or tuple or object | key | Used to differentiate between mutliple meters. Used to cancel meter early. Now optional as there is a default value for single meters | +| int | max_value | max value of progress meter | +| Any | *args | stuff to output as text in the window along with the meter | +| str or int or tuple or object | key | Used to differentiate between multiple meters. Used to cancel meter early. Now optional as there is a default value for single meters | | str | orientation | 'horizontal' or 'vertical' ('h' or 'v' work) (Default value = 'vertical' / 'v') | | (str, str) or str | bar_color | The 2 colors that make up a progress bar. Either a tuple of 2 strings or a string. Tuple - (bar, background). A string with 1 color changes the background of the bar only. A string with 2 colors separated by "on" like "red on blue" specifies a red bar on a blue background. | | (str, str) or str | button_color | button color (foreground, background) | @@ -16625,11 +16622,11 @@ Parameter Descriptions: |Type|Name|Meaning| |--|--|--| -| str | title | text to display in eleemnt | +| str | title | text to display in titlebar of window | | int | current_value | current value | -| int | max_value | max value of QuickMeter | -| Any | *args | stuff to output | -| str or int or tuple or object | key | Used to differentiate between mutliple meters. Used to cancel meter early. Now optional as there is a default value for single meters | +| int | max_value | max value of progress meter | +| Any | *args | stuff to output as text in the window along with the meter | +| str or int or tuple or object | key | Used to differentiate between multiple meters. Used to cancel meter early. Now optional as there is a default value for single meters | | str | orientation | 'horizontal' or 'vertical' ('h' or 'v' work) (Default value = 'vertical' / 'v') | | (str, str) or str | bar_color | The 2 colors that make up a progress bar. Either a tuple of 2 strings or a string. Tuple - (bar, background). A string with 1 color changes the background of the bar only. A string with 2 colors separated by "on" like "red on blue" specifies a red bar on a blue background. | | (str, str) or str | button_color | button color (foreground, background) | @@ -16942,6 +16939,9 @@ popup_get_date(start_mon = None, locale = None, month_names = None, day_abbreviations = None, + day_font = "TkFixedFont 9", + mon_year_font = "TkFixedFont 10", + arrow_font = "TkFixedFont 7", modal = True) ``` @@ -16963,6 +16963,9 @@ Parameter Descriptions: | bool | keep_on_top | If True the window will remain above all current windows | | List[str] | month_names | optional list of month names to use (should be 12 items) | | List[str] | day_abbreviations | optional list of abbreviations to display as the day of week | +| str or tuple | day_font | Font and size to use for the calendar | +| str or tuple | mon_year_font | Font and size to use for the month and year at the top | +| str or tuple | arrow_font | Font and size to use for the arrow buttons | | bool | modal | If True then makes the popup will behave like a Modal window... all other windows are non-operational until this one is closed. Default = True | | None or (int, int, int) | **RETURN** | Tuple containing (month, day, year) of chosen date or None if was cancelled diff --git a/readme_creator/output/index.md b/readme_creator/output/index.md index 52331638..b851cf66 100644 --- a/readme_creator/output/index.md +++ b/readme_creator/output/index.md @@ -2078,11 +2078,11 @@ Parameter Descriptions: |Type|Name|Meaning| |--|--|--| -| str | title | text to display in eleemnt | +| str | title | text to display in titlebar of window | | int | current_value | current value | -| int | max_value | max value of QuickMeter | -| Any | *args | stuff to output | -| str or int or tuple or object | key | Used to differentiate between mutliple meters. Used to cancel meter early. Now optional as there is a default value for single meters | +| int | max_value | max value of progress meter | +| Any | *args | stuff to output as text in the window along with the meter | +| str or int or tuple or object | key | Used to differentiate between multiple meters. Used to cancel meter early. Now optional as there is a default value for single meters | | str | orientation | 'horizontal' or 'vertical' ('h' or 'v' work) (Default value = 'vertical' / 'v') | | (str, str) or str | bar_color | The 2 colors that make up a progress bar. Either a tuple of 2 strings or a string. Tuple - (bar, background). A string with 1 color changes the background of the bar only. A string with 2 colors separated by "on" like "red on blue" specifies a red bar on a blue background. | | (str, str) or str | button_color | button color (foreground, background) | From 4ca5cf084a1e7ca993a0250d4e6fbb3d8a4e0996 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Sun, 15 Jan 2023 10:39:30 -0500 Subject: [PATCH 014/145] 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. --- PySimpleGUI.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index 158de052..69618f3a 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -version = __version__ = "4.60.4.140 Unreleased" +version = __version__ = "4.60.4.141 Unreleased" _change_log = """ Changelog since 4.60.0 released to PyPI on 8-May-2022 @@ -347,6 +347,8 @@ _change_log = """ Moved debugger constants to inside of the debugger class. Simplified the locals and globals popups. 4.60.4.140 Experimental change.... Table.get now returns the values from the widget's selection method + 4.60.4.141 + Made the Debugger's use of popups change the theme to the same dark gray theme used in the rest of the debugger windows. """ @@ -23804,7 +23806,10 @@ class _Debugger: result = str(eval(str(var), myglobals, mylocals)) except: result = '' + old_theme = theme() + theme(_Debugger.DEBUGGER_MAIN_WINDOW_THEME) popup_scrolled(str(values['_VAR{}_'.format(event[4])]) + '\n' + result, title=var, non_blocking=True, font=_Debugger.DEBUGGER_VARIABLE_DETAILS_FONT) + theme(old_theme) # BUTTON - OBJ elif event.endswith('_OBJ_'): # OBJECT BUTTON var = values['_VAR{}_'.format(event[4])] @@ -23816,7 +23821,10 @@ class _Debugger: result = ObjToStringSingleObj(result) except Exception as e: result = '{}\nError showing object {}'.format(e, var) - popup_scrolled(str(var) + '\n' + str(result), title=var, non_blocking=True, font=Debugger.DEBUGGER_VARIABLE_DETAILS_FONT) + old_theme = theme() + theme(_Debugger.DEBUGGER_MAIN_WINDOW_THEME) + popup_scrolled(str(var) + '\n' + str(result), title=var, non_blocking=True, font=_Debugger.DEBUGGER_VARIABLE_DETAILS_FONT) + theme(old_theme) # ------------------------------- Process Watch Tab ------------------------------- # BUTTON - Choose Locals to see elif event == '-LOCALS-': # Show all locals BUTTON @@ -26251,4 +26259,4 @@ if __name__ == '__main__': exit(0) main() exit(0) -#54251a437ae53503c980748d9b49f5e541745a71f9633a639b5d1df4f2ce9722d3521a73a57c87dcf17e57225f46f455ccf04dbe5066e1c09e19830a9ab3866b40f91f8af4093c954e5c608f8eb49d7e1d82b9db4b9a680fde861b4c55b5ccb68e918710b9df3395fc5f156c88ab737739dde188ca4ae0e7559179b06d9573e18eb597cee9a8dc7363380e5bbeee99aef17f5b81ed8d06e533b4a38e1b1ed79a2fc4ad4e9a19f93042ac1f5eb637b2875694b65908f35888aa27fbb2361599332411117fa5a6090eace1b0d3f749a6ccbbf52f80b39cf04fd7dacaeb79893792017f79da8749338b4dbb4e9203f17a1728248a323d6f67c09a1052e44f2ccb821b0c7b6c41ce2d52fec97ffcd02e3257853d3691e5c6bc6ed9ada4eef49174560dad6e7d25c8346c1f634e759dd4d07e71363809c39d54ecacfaf662231a43e76d253d332a2eccde36823ea99d14bf6c62ace0cedcf815045deb9839efa7b5407fed7ce368059a19a50692b16c429cecebdbb62bcf46d4f66fa43647c4a03453fabc56f18a4ac92a8225bdb6fbb6d968fd189889392c0377d4b2ca34b45683a3ae5efdb959a06dd3e61ddf3d2a7dd3f4da60aecb3912277dc53534c74a2f768563ad77819269d9c39ed11194666e6a0f0c9581bcfb7cbb0afa19731500e1e4f9d92de8bc2ab3fa835dfe454b6dffb6e215a94c2ae5b03b1c7a75876880494dcc \ No newline at end of file +#4db6b98b71ad586548e87cc9e4d297e44fcf6242b3833a738c844f448f1e5c7ddc085afd61eabde9bb8750619f12db065e69640cebf5edf9f4b745c4a3caf5e1670d2d8ad3a7e8090bdca1322ccad1c69967e866aef3c1bd5e118d3de7cba9e6f8b96b334ba3add026cddd8ce35be473577d5be009100e3ffb4ec78807b3916a8e40f292032ef67ba342ab9a971f3aac089684e21da209b728eaf8b9f0a7158b9aae4139f0212e1909a961c60951b56ffe832778b6537f85e29d5a77b4444fcf680a48a4340a4be5d910b11ce0e5675ac40a7f556ba062602c1cf2e19138782546118b343fae8c7bcd9765318996f5c7ebd1f7a7d079839d9456320d14cd2e62a14be59f40d25b11d1cfe1b902304f87bb27bbbc58bff1d1c333bb184b9d3033ee9c60b2bd72d69363708ab0280104c481453b0aee209f4e0c3af21dcbb8e64c165b1284d82a4a9b2ecd89522cb89807f297c5a41ee98a98a3aaf498e65eea040a309f41732f3105858d08266bcf0781fa7cd1ce218968b3e5ac8a660c1335aee944c0cbb17ea4766f603b2fbc10e28da3981d2160e256183e9d52355efe2a22e4c1369fd4e3838923b27e6db641955310a4c3c95cce90a6371d52ef3e7ca8104e0b88ebf340ddc7c133c1b696d5b34d796ebbdeac5e3b419b425b72a0bc0db3d6d572dadaf20abad3e81e7a64e7432af588b3f635202b4cfa6025bd4ca3812f \ No newline at end of file From 59cbf6311611212efdde8d78b5d25c5a3ed8ee81 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Wed, 18 Jan 2023 14:13:43 -0500 Subject: [PATCH 015/145] Added selected_text_color & selected_background_color to Input element as an experiment --- PySimpleGUI.py | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index 69618f3a..2883f756 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -version = __version__ = "4.60.4.141 Unreleased" +version = __version__ = "4.60.4.142 Unreleased" _change_log = """ Changelog since 4.60.0 released to PyPI on 8-May-2022 @@ -349,6 +349,8 @@ _change_log = """ Experimental change.... Table.get now returns the values from the widget's selection method 4.60.4.141 Made the Debugger's use of popups change the theme to the same dark gray theme used in the rest of the debugger windows. + 4.60.4.142 + Added selected_text_color & selected_background_color to Input element. Will override the default values """ @@ -2287,7 +2289,7 @@ class Input(Element): def __init__(self, default_text='', size=(None, None), s=(None, None), disabled=False, password_char='', justification=None, background_color=None, text_color=None, font=None, tooltip=None, border_width=None, change_submits=False, enable_events=False, do_not_clear=True, key=None, k=None, focus=False, pad=None, p=None, - use_readonly_for_disable=True, readonly=False, disabled_readonly_background_color=None, disabled_readonly_text_color=None, expand_x=False, expand_y=False, + use_readonly_for_disable=True, readonly=False, disabled_readonly_background_color=None, disabled_readonly_text_color=None, selected_text_color=None, selected_background_color=None, expand_x=False, expand_y=False, right_click_menu=None, visible=True, metadata=None): """ :param default_text: Text initially shown in the input box as a default value(Default value = ''). Will automatically be converted to string @@ -2336,6 +2338,10 @@ class Input(Element): :type disabled_readonly_background_color: (str) :param disabled_readonly_text_color: If state is set to readonly or disabled, the color to use for the text :type disabled_readonly_text_color: (str) + :param selected_text_color: Color of text when it is selected (using mouse or control+A, etc) + :type selected_text_color: (str) + :param selected_background_color: Color of background when it is selected (using mouse or control+A, etc) + :type selected_background_color: (str) :param expand_x: If True the element will automatically expand in the X direction to fill available space :type expand_x: (bool) :param expand_y: If True the element will automatically expand in the Y direction to fill available space @@ -2353,6 +2359,8 @@ class Input(Element): self.PasswordCharacter = password_char bg = background_color if background_color is not None else DEFAULT_INPUT_ELEMENTS_COLOR fg = text_color if text_color is not None else DEFAULT_INPUT_TEXT_COLOR + self.seclected_text_color = selected_text_color + self.selected_background_color = selected_background_color self.Focus = focus self.do_not_clear = do_not_clear self.Justification = justification @@ -16425,11 +16433,15 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form): element.TKEntry.bind('', element._KeyboardHandler) element.TKEntry.bind('', element._ReturnKeyHandler) + if element.BackgroundColor not in (None, COLOR_SYSTEM_DEFAULT): element.TKEntry.configure(background=element.BackgroundColor, selectforeground=element.BackgroundColor) if text_color not in (None, COLOR_SYSTEM_DEFAULT): element.TKEntry.configure(fg=text_color, selectbackground=text_color) - + if element.selected_background_color not in (None, COLOR_SYSTEM_DEFAULT): + element.TKEntry.configure(selectbackground=element.selected_background_color) + if element.seclected_text_color not in (None, COLOR_SYSTEM_DEFAULT): + element.TKEntry.configure(selectforeground=element.seclected_text_color) if element.disabled_readonly_background_color not in (None, COLOR_SYSTEM_DEFAULT): element.TKEntry.config(readonlybackground=element.disabled_readonly_background_color) if element.disabled_readonly_text_color not in (None, COLOR_SYSTEM_DEFAULT): @@ -26259,4 +26271,4 @@ if __name__ == '__main__': exit(0) main() exit(0) -#4db6b98b71ad586548e87cc9e4d297e44fcf6242b3833a738c844f448f1e5c7ddc085afd61eabde9bb8750619f12db065e69640cebf5edf9f4b745c4a3caf5e1670d2d8ad3a7e8090bdca1322ccad1c69967e866aef3c1bd5e118d3de7cba9e6f8b96b334ba3add026cddd8ce35be473577d5be009100e3ffb4ec78807b3916a8e40f292032ef67ba342ab9a971f3aac089684e21da209b728eaf8b9f0a7158b9aae4139f0212e1909a961c60951b56ffe832778b6537f85e29d5a77b4444fcf680a48a4340a4be5d910b11ce0e5675ac40a7f556ba062602c1cf2e19138782546118b343fae8c7bcd9765318996f5c7ebd1f7a7d079839d9456320d14cd2e62a14be59f40d25b11d1cfe1b902304f87bb27bbbc58bff1d1c333bb184b9d3033ee9c60b2bd72d69363708ab0280104c481453b0aee209f4e0c3af21dcbb8e64c165b1284d82a4a9b2ecd89522cb89807f297c5a41ee98a98a3aaf498e65eea040a309f41732f3105858d08266bcf0781fa7cd1ce218968b3e5ac8a660c1335aee944c0cbb17ea4766f603b2fbc10e28da3981d2160e256183e9d52355efe2a22e4c1369fd4e3838923b27e6db641955310a4c3c95cce90a6371d52ef3e7ca8104e0b88ebf340ddc7c133c1b696d5b34d796ebbdeac5e3b419b425b72a0bc0db3d6d572dadaf20abad3e81e7a64e7432af588b3f635202b4cfa6025bd4ca3812f \ No newline at end of file +#1a3a9f560ea0d7827ea35a6f671e4232f531fe8510b4d98dd30dcea7e27ea5d820cc220d0146cdb57452d1e869e91c6b5660834e98a0a65495ca9060ac4b84f4398cee2fe2b7e6fd3654ac4f4ce0661a19e370c66aeef8f724677db6b0b8a0b005b2728f6f72079747a33515c3716868d94c2c31e0feec3f8da32947c651b399775130dfaa2bca1ce71f4a65ca4dcde455d0ca46f00863de191f80cf4e894e38c0ec483edc586496c062e51844a7fc77bb68963096c1ecac54ac0073c5d42ada0ef747f26f3752d70de1f8ba55fd66f88751aec8281ca3312b84f7fc11523117118b56f6c153cce8a2d8dde522388e82b633644d8a11da3f8a08eea66c9b56a519c831d11ad717a585f72e933a5cfb77f03c61fd58e978e5e1fc1deb3a6e187b29ce1ade80b3214f78e2fde39106c7c95537a4251d02c55ce773e02c36ced132ba5187c69de894dea2be52ce34fef51286e291a72a7684e5ff5bce381d05af0b70c67c0deb0681f9291d2da87b8523f66b0b1ce1afc248a17aa6c8726f33f440c4ff2de4f07e8ac7b8f05f3a4fa14b502425c465c838d9d7e1fe41d197be17655d37aa399178363147fe9654c495a25abe3f4a4ed4b0ddff35995d26fede35dba2a2358c46b6de8b90e0922402e4a326f74f2d8221f6aaed051881a55e31e8dbe26235f00ef0a624afa171144d6bc0d9df19c41fa5bc2624134809861a76cf62 \ No newline at end of file From 7e88e04ceeac746ab2c77bb7331a72ddf7ef4cd1 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Fri, 20 Jan 2023 17:54:50 -0500 Subject: [PATCH 016/145] Fixed bug in Combo.update - width wasn't getting updated to match new values --- PySimpleGUI.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index 2883f756..2df041d5 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -version = __version__ = "4.60.4.142 Unreleased" +version = __version__ = "4.60.4.143 Unreleased" _change_log = """ Changelog since 4.60.0 released to PyPI on 8-May-2022 @@ -351,6 +351,8 @@ _change_log = """ Made the Debugger's use of popups change the theme to the same dark gray theme used in the rest of the debugger windows. 4.60.4.142 Added selected_text_color & selected_background_color to Input element. Will override the default values + 4.60.4.143 + Fixed bug in Combo.update - the width of the element wasn't getting updated to match new values """ @@ -2648,7 +2650,7 @@ class Combo(Element): width = self.Size[0] else: width = max_line_len + 1 - # self.TKCombo.configure(width=width) + self.TKCombo.configure(width=width) else: self.TKCombo.configure(height=size[1]) self.TKCombo.configure(width=size[0]) @@ -26271,4 +26273,4 @@ if __name__ == '__main__': exit(0) main() exit(0) -#1a3a9f560ea0d7827ea35a6f671e4232f531fe8510b4d98dd30dcea7e27ea5d820cc220d0146cdb57452d1e869e91c6b5660834e98a0a65495ca9060ac4b84f4398cee2fe2b7e6fd3654ac4f4ce0661a19e370c66aeef8f724677db6b0b8a0b005b2728f6f72079747a33515c3716868d94c2c31e0feec3f8da32947c651b399775130dfaa2bca1ce71f4a65ca4dcde455d0ca46f00863de191f80cf4e894e38c0ec483edc586496c062e51844a7fc77bb68963096c1ecac54ac0073c5d42ada0ef747f26f3752d70de1f8ba55fd66f88751aec8281ca3312b84f7fc11523117118b56f6c153cce8a2d8dde522388e82b633644d8a11da3f8a08eea66c9b56a519c831d11ad717a585f72e933a5cfb77f03c61fd58e978e5e1fc1deb3a6e187b29ce1ade80b3214f78e2fde39106c7c95537a4251d02c55ce773e02c36ced132ba5187c69de894dea2be52ce34fef51286e291a72a7684e5ff5bce381d05af0b70c67c0deb0681f9291d2da87b8523f66b0b1ce1afc248a17aa6c8726f33f440c4ff2de4f07e8ac7b8f05f3a4fa14b502425c465c838d9d7e1fe41d197be17655d37aa399178363147fe9654c495a25abe3f4a4ed4b0ddff35995d26fede35dba2a2358c46b6de8b90e0922402e4a326f74f2d8221f6aaed051881a55e31e8dbe26235f00ef0a624afa171144d6bc0d9df19c41fa5bc2624134809861a76cf62 \ No newline at end of file +#05575c0321f1544102608baf59fa822078b0f49b10c74497210f0b121630604b4e499d86b8da16c35e5055a1f4b2439e4d517292dcc71d28ffa0ddd88356b4c858f039198e04890a2545f5c0c202aa4d3dbb213c9fd0582922f29a5b669f16c380fc4b34d78b3af787347e3bf2b6b8b8632bb666239749709ae4f0dd35591964d841408ba1a71dac773e09a71356bb280f6c80d4ff30cb1385b4bd4cc6c930fc79f4b28418e40a30723f26fe5ad64c772e542949029265b1cd66d12b2593f95b48982777759ee64920b9f33a22e3f3aa7dfae01a6eb55782832496ef299a33174991261aa2e8dc76b2d273e8a0c56ac69fdfea2460c7a6299c41182faa0a7bd3d4f85fbef8ba36de2d70381244510ad153df900e371cf4d1b3d2e9c09b00a54503e4504dcbc5ad9b5c50aa0c2fa10d5b0bf94a707fdd594bd92c00e8f675fce40cef403187639ba2ac30c685e7e838faa5d208c47fe18fb31f590dd2ff8a9055894f73fd026d5ef2f8580b6a1a1ea4e7072a2ba64d3185e399fc487a1b828ac8a4802f757d498bfaf7a54e18cb9ae1e4d38e911c4ece4e9cd3ca735f1605b3fec2b5ab52c63791be5a1766169f575e2eb3a63f7185b24864e27019c32aa9470b74d507be1f90b6a05e385d4d8ad22e390a34913b28c265a0b45ed9da45dcad2c7ede9162740333735ed2b686524453e1e8321515c7f08f31e1ee8d9ce74f476b \ No newline at end of file From 2492b2353d7e94be2d55fb02b2e0988b1c0d8203 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Sat, 21 Jan 2023 15:08:45 -0500 Subject: [PATCH 017/145] Added selected_text_color and selected_background_color to Multline element --- PySimpleGUI.py | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index 2df041d5..c6940b5c 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -version = __version__ = "4.60.4.143 Unreleased" +version = __version__ = "4.60.4.144 Unreleased" _change_log = """ Changelog since 4.60.0 released to PyPI on 8-May-2022 @@ -353,7 +353,9 @@ _change_log = """ Added selected_text_color & selected_background_color to Input element. Will override the default values 4.60.4.143 Fixed bug in Combo.update - the width of the element wasn't getting updated to match new values - + 4.60.4.144 + Added selected_text_color & selected_background_color to Multiline element. Will override the default values + """ __version__ = version.split()[0] # For PEP 396 and PEP 345 @@ -2361,7 +2363,7 @@ class Input(Element): self.PasswordCharacter = password_char bg = background_color if background_color is not None else DEFAULT_INPUT_ELEMENTS_COLOR fg = text_color if text_color is not None else DEFAULT_INPUT_TEXT_COLOR - self.seclected_text_color = selected_text_color + self.selected_text_color = selected_text_color self.selected_background_color = selected_background_color self.Focus = focus self.do_not_clear = do_not_clear @@ -3735,7 +3737,7 @@ class Multiline(Element): """ def __init__(self, default_text='', enter_submits=False, disabled=False, autoscroll=False, border_width=None, - size=(None, None), s=(None, None), auto_size_text=None, background_color=None, text_color=None, horizontal_scroll=False, change_submits=False, + size=(None, None), s=(None, None), auto_size_text=None, background_color=None, text_color=None, selected_text_color=None, selected_background_color=None, horizontal_scroll=False, change_submits=False, enable_events=False, do_not_clear=True, key=None, k=None, write_only=False, auto_refresh=False, reroute_stdout=False, reroute_stderr=False, reroute_cprint=False, echo_stdout_stderr=False, focus=False, font=None, pad=None, p=None, tooltip=None, justification=None, no_scrollbar=False, wrap_lines=None, sbar_trough_color=None, sbar_background_color=None, sbar_arrow_color=None, sbar_width=None, sbar_arrow_width=None, sbar_frame_color=None, sbar_relief=None, expand_x=False, expand_y=False, rstrip=True, right_click_menu=None, visible=True, metadata=None): @@ -3760,6 +3762,10 @@ class Multiline(Element): :type background_color: (str) :param text_color: color of the text :type text_color: (str) + :param selected_text_color: Color of text when it is selected (using mouse or control+A, etc) + :type selected_text_color: (str) + :param selected_background_color: Color of background when it is selected (using mouse or control+A, etc) + :type selected_background_color: (str) :param horizontal_scroll: Controls if a horizontal scrollbar should be shown. If True a horizontal scrollbar will be shown in addition to vertical :type horizontal_scroll: (bool) :param change_submits: DO NOT USE. Only listed for backwards compat - Use enable_events instead @@ -3835,6 +3841,9 @@ class Multiline(Element): self.Focus = focus self.do_not_clear = do_not_clear fg = text_color if text_color is not None else DEFAULT_INPUT_TEXT_COLOR + fg = text_color if text_color is not None else DEFAULT_INPUT_TEXT_COLOR + self.selected_text_color = selected_text_color + self.selected_background_color = selected_background_color self.Autoscroll = autoscroll self.Disabled = disabled self.ChangeSubmits = change_submits or enable_events @@ -16442,8 +16451,8 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form): element.TKEntry.configure(fg=text_color, selectbackground=text_color) if element.selected_background_color not in (None, COLOR_SYSTEM_DEFAULT): element.TKEntry.configure(selectbackground=element.selected_background_color) - if element.seclected_text_color not in (None, COLOR_SYSTEM_DEFAULT): - element.TKEntry.configure(selectforeground=element.seclected_text_color) + if element.selected_text_color not in (None, COLOR_SYSTEM_DEFAULT): + element.TKEntry.configure(selectforeground=element.selected_text_color) if element.disabled_readonly_background_color not in (None, COLOR_SYSTEM_DEFAULT): element.TKEntry.config(readonlybackground=element.disabled_readonly_background_color) if element.disabled_readonly_text_color not in (None, COLOR_SYSTEM_DEFAULT): @@ -16744,9 +16753,14 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form): if element.DefaultText: element.TKText.insert(1.0, element.DefaultText) # set the default text element.TKText.config(highlightthickness=0) + if text_color is not None and text_color != COLOR_SYSTEM_DEFAULT: + element.TKText.configure(fg=text_color, selectbackground=text_color) if element.BackgroundColor is not None and element.BackgroundColor != COLOR_SYSTEM_DEFAULT: element.TKText.configure(background=element.BackgroundColor, selectforeground=element.BackgroundColor) - + if element.selected_background_color not in (None, COLOR_SYSTEM_DEFAULT): + element.TKText.configure(selectbackground=element.selected_background_color) + if element.selected_text_color not in (None, COLOR_SYSTEM_DEFAULT): + element.TKText.configure(selectforeground=element.selected_text_color) element.TKText.tag_configure("center", justify='center') element.TKText.tag_configure("left", justify='left') element.TKText.tag_configure("right", justify='right') @@ -16781,8 +16795,7 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form): if element.Focus is True or (toplevel_form.UseDefaultFocus and not toplevel_form.FocusSet): toplevel_form.FocusSet = True element.TKText.focus_set() - if text_color is not None and text_color != COLOR_SYSTEM_DEFAULT: - element.TKText.configure(fg=text_color, selectbackground=text_color) + if element.Disabled is True: @@ -26273,4 +26286,4 @@ if __name__ == '__main__': exit(0) main() exit(0) -#05575c0321f1544102608baf59fa822078b0f49b10c74497210f0b121630604b4e499d86b8da16c35e5055a1f4b2439e4d517292dcc71d28ffa0ddd88356b4c858f039198e04890a2545f5c0c202aa4d3dbb213c9fd0582922f29a5b669f16c380fc4b34d78b3af787347e3bf2b6b8b8632bb666239749709ae4f0dd35591964d841408ba1a71dac773e09a71356bb280f6c80d4ff30cb1385b4bd4cc6c930fc79f4b28418e40a30723f26fe5ad64c772e542949029265b1cd66d12b2593f95b48982777759ee64920b9f33a22e3f3aa7dfae01a6eb55782832496ef299a33174991261aa2e8dc76b2d273e8a0c56ac69fdfea2460c7a6299c41182faa0a7bd3d4f85fbef8ba36de2d70381244510ad153df900e371cf4d1b3d2e9c09b00a54503e4504dcbc5ad9b5c50aa0c2fa10d5b0bf94a707fdd594bd92c00e8f675fce40cef403187639ba2ac30c685e7e838faa5d208c47fe18fb31f590dd2ff8a9055894f73fd026d5ef2f8580b6a1a1ea4e7072a2ba64d3185e399fc487a1b828ac8a4802f757d498bfaf7a54e18cb9ae1e4d38e911c4ece4e9cd3ca735f1605b3fec2b5ab52c63791be5a1766169f575e2eb3a63f7185b24864e27019c32aa9470b74d507be1f90b6a05e385d4d8ad22e390a34913b28c265a0b45ed9da45dcad2c7ede9162740333735ed2b686524453e1e8321515c7f08f31e1ee8d9ce74f476b \ No newline at end of file +#4e3d3948980125933466017e428c1dc993601ea86dfe8356c300cf2b0cfcb6441b6bdd5efcd5787f432fa4ba558cfa0243d09ec1ed5d78c5d2b25639ac4a7ec9bbddea5d00379aab0d46996b8dab188d0d361470abe50841d6e7bfa102c8cbacb60734b261f7bd81fbd66498e0b1890822902dc4c16a29914c39d78c10ae462b4e00093bd28fe7fb1ca8a1a43ec4e56b29fa1a6d38feff72885e38ba37f727ec7b0eaece73e8c49e7b2fa3563f06fa9e3e9575596d5824a490510b412fc67f40c4713d27d74d7e0065741b7f05dd9b00715fde6f877867e828f51c34b31091e72b47a7afa600d4eb27d4b9f1971ef181b0f44ff0d0e2a355aca1bf98da4660d2f58a7b65b680e51f16d65ffe2f5e4151434dd2bf3c726e65bc1e863e080b61a4241b2e5e59558eb637a34b557b1ae44fcaf75aa25db7d4dc782d4d9c8e190e9b6093a69706ae98937ee96c5cd98242378e58159f65b90042077d26ccc62e4425c80abefc0d5e44dd757255be58bf8c8831d2ccab684fdd0950db23deaea9d3bbb96fe87c4b361c2ee7e072422718bfdf1fe7b082856a264d3148a11ffc2a2a5b64898133a6275b774b32114415daf11bd17ee3c3c6f9cc42d47bdc12cb6f418db25215be6341ade53528529e907d5d18adf34b4c2990425b3739556cf652ad08b64d1b2ed93dbc1b4c0991ea95efce22b0ab1f1476827ce51c56b972b1286176 \ No newline at end of file From de3beca51a853558b9f309222d5a78d1ff402eb8 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Sun, 22 Jan 2023 10:11:51 -0500 Subject: [PATCH 018/145] Fixed bind_return_key docstrings in the pre-defined buttons. Made the Button bind_return_key docstring more descriptive --- PySimpleGUI.py | 50 ++++++++++++++++++++++++++------------------------ 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index c6940b5c..43ddf381 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -version = __version__ = "4.60.4.144 Unreleased" +version = __version__ = "4.60.4.145 Unreleased" _change_log = """ Changelog since 4.60.0 released to PyPI on 8-May-2022 @@ -355,6 +355,8 @@ _change_log = """ Fixed bug in Combo.update - the width of the element wasn't getting updated to match new values 4.60.4.144 Added selected_text_color & selected_background_color to Multiline element. Will override the default values + 4.60.4.145 + Fixed bind_return_key docstrings in the pre-defined buttons. Made the Button bind_return_key docstring more descriptive """ @@ -2529,7 +2531,7 @@ class Combo(Element): :type button_background_color: (str) :param button_arrow_color: The color of the arrow on the button on the combo box :type button_arrow_color: (str) - :param bind_return_key: If True, then the return key will cause a the Combo to generate an event + :param bind_return_key: If True, then the return key will cause a the Combo to generate an event when return key is pressed :type bind_return_key: (bool) :param change_submits: DEPRICATED DO NOT USE. Use `enable_events` instead :type change_submits: (bool) @@ -2896,7 +2898,7 @@ class Listbox(Element): :type change_submits: (bool) :param enable_events: Turns on the element specific events. Listbox generates events when an item is clicked :type enable_events: (bool) - :param bind_return_key: If True, then the return key will cause a the Listbox to generate an event + :param bind_return_key: If True, then the return key will cause a the Listbox to generate an event when return key is pressed :type bind_return_key: (bool) :param size: w=characters-wide, h=rows-high. If an int instead of a tuple is supplied, then height is auto-set to 1 :type size: (int, int) | (int, None) | int @@ -3562,7 +3564,7 @@ class Spin(Element): :type s: (int, int) | (None, None) | int :param auto_size_text: if True will size the element to match the length of the text :type auto_size_text: (bool) - :param bind_return_key: If True, then the return key will cause a the element to generate an event + :param bind_return_key: If True, then the return key will cause a the element to generate an event when return key is pressed :type bind_return_key: (bool) :param font: specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike :type font: (str or (str, int[, str]) or None) @@ -4881,7 +4883,7 @@ class Button(Element): :type use_ttk_buttons: (bool) :param font: specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike :type font: (str or (str, int[, str]) or None) - :param bind_return_key: If True the return key will cause this button to be pressed + :param bind_return_key: If True then pressing the return key in an Input or Multiline Element will cause this button to appear to be clicked (generates event with this button's key :type bind_return_key: (bool) :param focus: if True, initial focus will be put on this button :type focus: (bool) @@ -13726,7 +13728,7 @@ def Save(button_text='Save', size=(None, None), s=(None, None), auto_size_button :type auto_size_button: (bool) :param button_color: button color (foreground, background) :type button_color: (str, str) | str - :param bind_return_key: (Default = True) If True, then the return key will cause a the Listbox to generate an event + :param bind_return_key: (Default = True) If True, this button will appear to be clicked when return key is pressed in other elements such as Input and elements with return key options :type bind_return_key: (bool) :param disabled: set disable state for element (Default = False) :type disabled: (bool) @@ -13777,7 +13779,7 @@ def Submit(button_text='Submit', size=(None, None), s=(None, None), auto_size_bu :type button_color: (str, str) | str :param disabled: set disable state for element (Default = False) :type disabled: (bool) - :param bind_return_key: (Default = True) If True, then the return key will cause a the Listbox to generate an event + :param bind_return_key: (Default = True) If True, this button will appear to be clicked when return key is pressed in other elements such as Input and elements with return key options :type bind_return_key: (bool) :param tooltip: text, that will appear when mouse hovers over the element :type tooltip: (str) @@ -13827,7 +13829,7 @@ def Open(button_text='Open', size=(None, None), s=(None, None), auto_size_button :type button_color: (str, str) | str :param disabled: set disable state for element (Default = False) :type disabled: (bool) - :param bind_return_key: (Default = True) If True, then the return key will cause a the Listbox to generate an event + :param bind_return_key: (Default = True) If True, this button will appear to be clicked when return key is pressed in other elements such as Input and elements with return key options :type bind_return_key: (bool) :param tooltip: text, that will appear when mouse hovers over the element :type tooltip: (str) @@ -13876,7 +13878,7 @@ def OK(button_text='OK', size=(None, None), s=(None, None), auto_size_button=Non :type button_color: (str, str) | str :param disabled: set disable state for element (Default = False) :type disabled: (bool) - :param bind_return_key: (Default = True) If True, then the return key will cause a the Listbox to generate an event + :param bind_return_key: (Default = True) If True, this button will appear to be clicked when return key is pressed in other elements such as Input and elements with return key options :type bind_return_key: (bool) :param tooltip: text, that will appear when mouse hovers over the element :type tooltip: (str) @@ -13925,7 +13927,7 @@ def Ok(button_text='Ok', size=(None, None), s=(None, None), auto_size_button=Non :type button_color: (str, str) | str :param disabled: set disable state for element (Default = False) :type disabled: (bool) - :param bind_return_key: (Default = True) If True, then the return key will cause a the Listbox to generate an event + :param bind_return_key: (Default = True) If True, this button will appear to be clicked when return key is pressed in other elements such as Input and elements with return key options :type bind_return_key: (bool) :param tooltip: text, that will appear when mouse hovers over the element :type tooltip: (str) @@ -13978,7 +13980,7 @@ def Cancel(button_text='Cancel', size=(None, None), s=(None, None), auto_size_bu :type tooltip: (str) :param font: specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike :type font: (str or (str, int[, str]) or None) - :param bind_return_key: (Default = False) If True, then the return key will cause a the Listbox to generate an event + :param bind_return_key: (Default = False) If True, this button will appear to be clicked when return key is pressed in other elements such as Input and elements with return key options :type bind_return_key: (bool) :param focus: if focus should be set to this :type focus: @@ -14027,7 +14029,7 @@ def Quit(button_text='Quit', size=(None, None), s=(None, None), auto_size_button :type tooltip: (str) :param font: specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike :type font: (str or (str, int[, str]) or None) - :param bind_return_key: (Default = False) If True, then the return key will cause a the Listbox to generate an event + :param bind_return_key: (Default = False) If True, this button will appear to be clicked when return key is pressed in other elements such as Input and elements with return key options :type bind_return_key: (bool) :param focus: if focus should be set to this :type focus: (bool) @@ -14076,7 +14078,7 @@ def Exit(button_text='Exit', size=(None, None), s=(None, None), auto_size_button :type tooltip: (str) :param font: specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike :type font: (str or (str, int[, str]) or None) - :param bind_return_key: (Default = False) If True, then the return key will cause a the Listbox to generate an event + :param bind_return_key: (Default = False) If True, this button will appear to be clicked when return key is pressed in other elements such as Input and elements with return key options :type bind_return_key: (bool) :param focus: if focus should be set to this :type focus: @@ -14125,7 +14127,7 @@ def Yes(button_text='Yes', size=(None, None), s=(None, None), auto_size_button=N :type tooltip: (str) :param font: specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike :type font: (str or (str, int[, str]) or None) - :param bind_return_key: (Default = True) If True, then the return key will cause a the Listbox to generate an event + :param bind_return_key: (Default = True) If True, this button will appear to be clicked when return key is pressed in other elements such as Input and elements with return key options :type bind_return_key: (bool) :param focus: if focus should be set to this :type focus: @@ -14223,7 +14225,7 @@ def Help(button_text='Help', size=(None, None), s=(None, None), auto_size_button :type font: (str or (str, int[, str]) or None) :param tooltip: text, that will appear when mouse hovers over the element :type tooltip: (str) - :param bind_return_key: (Default = False) If True, then the return key will cause a the Listbox to generate an event + :param bind_return_key: (Default = False) If True, this button will appear to be clicked when return key is pressed in other elements such as Input and elements with return key options :type bind_return_key: (bool) :param focus: if focus should be set to this :type focus: @@ -14275,7 +14277,7 @@ def Debug(button_text='', size=(None, None), s=(None, None), auto_size_button=No :type font: (str or (str, int[, str]) or None) :param tooltip: text, that will appear when mouse hovers over the element :type tooltip: (str) - :param bind_return_key: (Default = False) If True, then the return key will cause a the Listbox to generate an event + :param bind_return_key: (Default = False) If True, this button will appear to be clicked when return key is pressed in other elements such as Input and elements with return key options :type bind_return_key: (bool) :param focus: if focus should be set to this :type focus: @@ -14339,7 +14341,7 @@ def SimpleButton(button_text, image_filename=None, image_data=None, image_size=( :type button_color: (str, str) | str :param font: specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike :type font: (str or (str, int[, str]) or None) - :param bind_return_key: (Default = False) If True, then the return key will cause a the Listbox to generate an event + :param bind_return_key: (Default = False) If True, this button will appear to be clicked when return key is pressed in other elements such as Input and elements with return key options :type bind_return_key: (bool) :param disabled: set disable state for element (Default = False) :type disabled: (bool) @@ -14401,7 +14403,7 @@ def CloseButton(button_text, image_filename=None, image_data=None, image_size=(N :type button_color: (str, str) | str :param font: specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike :type font: (str or (str, int[, str]) or None) - :param bind_return_key: (Default = False) If True, then the return key will cause a the Listbox to generate an event + :param bind_return_key: (Default = False) If True, this button will appear to be clicked when return key is pressed in other elements such as Input and elements with return key options :type bind_return_key: (bool) :param disabled: set disable state for element (Default = False) :type disabled: (bool) @@ -14461,7 +14463,7 @@ def ReadButton(button_text, image_filename=None, image_data=None, image_size=(No :type button_color: (str, str) | str :param font: specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike :type font: (str or (str, int[, str]) or None) - :param bind_return_key: (Default = False) If True, then the return key will cause a the Listbox to generate an event + :param bind_return_key: (Default = False) If True, this button will appear to be clicked when return key is pressed in other elements such as Input and elements with return key options :type bind_return_key: (bool) :param disabled: set disable state for element (Default = False) :type disabled: (bool) @@ -14530,7 +14532,7 @@ def RealtimeButton(button_text, image_filename=None, image_data=None, image_size :type font: (str or (str, int[, str]) or None) :param disabled: set disable state for element (Default = False) :type disabled: (bool) - :param bind_return_key: (Default = False) If True, then the return key will cause a the Listbox to generate an event + :param bind_return_key: (Default = False) If True, this button will appear to be clicked when return key is pressed in other elements such as Input and elements with return key options :type bind_return_key: (bool) :param focus: if focus should be set to this :type focus: (bool) @@ -14598,7 +14600,7 @@ def DummyButton(button_text, image_filename=None, image_data=None, image_size=(N :type font: (str or (str, int[, str]) or None) :param disabled: set disable state for element (Default = False) :type disabled: (bool) - :param bind_return_key: (Default = False) If True, then the return key will cause a the Listbox to generate an event + :param bind_return_key: (Default = False) If True, this button will appear to be clicked when return key is pressed in other elements such as Input and elements with return key options :type bind_return_key: (bool) :param focus: if focus should be set to this :type focus: (bool) @@ -14671,7 +14673,7 @@ def CalendarButton(button_text, target=(ThisRow, -1), close_when_date_chosen=Tru :type disabled: (bool) :param font: specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike :type font: (str or (str, int[, str]) or None) - :param bind_return_key: (Default = False) If True, then the return key will cause a the Listbox to generate an event + :param bind_return_key: (Default = False) If True, this button will appear to be clicked when return key is pressed in other elements such as Input and elements with return key options :type bind_return_key: bool :param focus: if focus should be set to this :type focus: bool @@ -14765,7 +14767,7 @@ def ColorChooserButton(button_text, target=(ThisRow, -1), image_filename=None, i :type disabled: (bool) :param font: specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike :type font: (str or (str, int[, str]) or None) - :param bind_return_key: If True, then the return key will cause a the Listbox to generate an event + :param bind_return_key: (Default = False) If True, this button will appear to be clicked when return key is pressed in other elements such as Input and elements with return key options :type bind_return_key: (bool) :param focus: Determines if initial focus should go to this element. :type focus: (bool) @@ -26286,4 +26288,4 @@ if __name__ == '__main__': exit(0) main() exit(0) -#4e3d3948980125933466017e428c1dc993601ea86dfe8356c300cf2b0cfcb6441b6bdd5efcd5787f432fa4ba558cfa0243d09ec1ed5d78c5d2b25639ac4a7ec9bbddea5d00379aab0d46996b8dab188d0d361470abe50841d6e7bfa102c8cbacb60734b261f7bd81fbd66498e0b1890822902dc4c16a29914c39d78c10ae462b4e00093bd28fe7fb1ca8a1a43ec4e56b29fa1a6d38feff72885e38ba37f727ec7b0eaece73e8c49e7b2fa3563f06fa9e3e9575596d5824a490510b412fc67f40c4713d27d74d7e0065741b7f05dd9b00715fde6f877867e828f51c34b31091e72b47a7afa600d4eb27d4b9f1971ef181b0f44ff0d0e2a355aca1bf98da4660d2f58a7b65b680e51f16d65ffe2f5e4151434dd2bf3c726e65bc1e863e080b61a4241b2e5e59558eb637a34b557b1ae44fcaf75aa25db7d4dc782d4d9c8e190e9b6093a69706ae98937ee96c5cd98242378e58159f65b90042077d26ccc62e4425c80abefc0d5e44dd757255be58bf8c8831d2ccab684fdd0950db23deaea9d3bbb96fe87c4b361c2ee7e072422718bfdf1fe7b082856a264d3148a11ffc2a2a5b64898133a6275b774b32114415daf11bd17ee3c3c6f9cc42d47bdc12cb6f418db25215be6341ade53528529e907d5d18adf34b4c2990425b3739556cf652ad08b64d1b2ed93dbc1b4c0991ea95efce22b0ab1f1476827ce51c56b972b1286176 \ No newline at end of file +#40e80a71aea2a1b41dfdcba9263cffd1ea8d8dba433feb55ec28f46041ead94584c0357919f99c17c0f55cc1270b5f742f90a6cb967060d420598da884b48952987be0aa687b06556ac829c34bf84d705ef76b6a11eefc2fd3bc808e968f6fe4aca40d643643ec2906f4a8420af6d4fce3ca585591591cce1bf067c77edd7a555f5977205bd8ed1ea55ce615dd47e1f138c54f6fe23dc14764563c00d158164c9b7daab5c5b772c90ad040133a441a45e39b66567f4b957b5db188a8155e2fe72d0c06ba927c55260d1c2e4199a86d69765872b059f5b167202fcebed340c6fd91da8d7831f7ced36886e0a5a51947aeba24f62e8a5675ec01ee0e122983bc8cc9d9c7dfc77d78708f8e889ba91676b3b183aaf8cae3ed0cf79051561a2cd692f933b5f40a17b987644978c59962ead7011f369580e30d665fd5f4860411df8fea4d1027e653da3b2e7baff69c5035a311143efba8609383af517ed23e363af68fa1a1f95a1ef3c7991b79f55634787e14e32a0c32442feaf4df13a0212754c207cb27a129fc702d206d50d90bfbd4d10d10ede5fba0dedf3ec2c0d66e4741c30033356bc5911de8395977214646517e6e94e8130b32330d0e63fb13ec8eeaee673a68e94151ed9ecb92a506e184df9c53b798277c5cb10acec0e3f2a1dafba2510687d9eaad97a79d729ce2a33b2e9229f03289c111f8f3774e89e329e76c4e \ No newline at end of file From cef6e8e0cdbacd2dd0fbdf578e8cc32b8009566c Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Sun, 22 Jan 2023 10:23:55 -0500 Subject: [PATCH 019/145] Get the latest doctrings and post to the online documentation in the call reference --- docs/call reference.md | 140 +++++++++++++----------- readme_creator/output/call reference.md | 140 +++++++++++++----------- 2 files changed, 148 insertions(+), 132 deletions(-) diff --git a/docs/call reference.md b/docs/call reference.md index ad33251c..77b324bb 100644 --- a/docs/call reference.md +++ b/docs/call reference.md @@ -126,7 +126,7 @@ Parameter Descriptions: | (str, str) or str | mouseover_colors | Important difference between Linux & Windows! Linux - Colors when mouse moved over button. Windows - colors when button is pressed. The default is to switch the text and background colors (an inverse effect) | | bool | use_ttk_buttons | True = use ttk buttons. False = do not use ttk buttons. None (Default) = use ttk buttons only if on a Mac and not with button images | | (str or (str, int[, str]) or None) | font | specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike | -| bool | bind_return_key | If True the return key will cause this button to be pressed | +| bool | bind_return_key | If True then pressing the return key in an Input or Multiline Element will cause this button to appear to be clicked (generates event with this button's key | | bool | focus | if True, initial focus will be put on this button | | (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | pad | Amount of padding to put around element in pixels (left/right, top/bottom) or ((left, right), (top, bottom)) or an int. If an int, then it's converted into a tuple (int, int) | | (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | p | Same as pad parameter. It's an alias. If EITHER of them are set, then the one that's set will be used. If BOTH are set, pad will be used | @@ -2214,7 +2214,7 @@ Parameter Descriptions: | str | text_color | color of the text | | str | button_background_color | The color of the background of the button on the combo box | | str | button_arrow_color | The color of the arrow on the button on the combo box | -| bool | bind_return_key | If True, then the return key will cause a the Combo to generate an event | +| bool | bind_return_key | If True, then the return key will cause a the Combo to generate an event when return key is pressed | | bool | change_submits | DEPRICATED DO NOT USE. Use `enable_events` instead | | bool | enable_events | Turns on the element specific events. Combo event is when a choice is made | | bool | enable_per_char_events | Enables generation of events for every character that's input. This is like the Input element's events | @@ -4881,6 +4881,8 @@ Input(default_text = "", readonly = False, disabled_readonly_background_color = None, disabled_readonly_text_color = None, + selected_text_color = None, + selected_background_color = None, expand_x = False, expand_y = False, right_click_menu = None, @@ -4915,6 +4917,8 @@ Parameter Descriptions: | bool | readonly | If True tkinter state set to 'readonly'. Use this in place of use_readonly_for_disable as another way of achieving readonly. Note cannot set BOTH readonly and disabled as tkinter only supplies a single flag | | str | disabled_readonly_background_color | If state is set to readonly or disabled, the color to use for the background | | str | disabled_readonly_text_color | If state is set to readonly or disabled, the color to use for the text | +| str | selected_text_color | Color of text when it is selected (using mouse or control+A, etc) | +| str | selected_background_color | Color of background when it is selected (using mouse or control+A, etc) | | bool | expand_x | If True the element will automatically expand in the X direction to fill available space | | bool | expand_y | If True the element will automatically expand in the Y direction to fill available space | | List[List[ List[str] or str ]] | right_click_menu | A list of lists of Menu items to show when this element is right clicked. See user docs for exact format. | @@ -5359,7 +5363,7 @@ Parameter Descriptions: | [enum] | select_mode | Select modes are used to determine if only 1 item can be selected or multiple and how they can be selected. Valid choices begin with "LISTBOX_SELECT_MODE_" and include: LISTBOX_SELECT_MODE_SINGLE LISTBOX_SELECT_MODE_MULTIPLE LISTBOX_SELECT_MODE_BROWSE LISTBOX_SELECT_MODE_EXTENDED | | bool | change_submits | DO NOT USE. Only listed for backwards compat - Use enable_events instead | | bool | enable_events | Turns on the element specific events. Listbox generates events when an item is clicked | -| bool | bind_return_key | If True, then the return key will cause a the Listbox to generate an event | +| bool | bind_return_key | If True, then the return key will cause a the Listbox to generate an event when return key is pressed | | (int, int) or (int, None) or int | size | w=characters-wide, h=rows-high. If an int instead of a tuple is supplied, then height is auto-set to 1 | | (int, int) or (None, None) or int | s | Same as size parameter. It's an alias. If EITHER of them are set, then the one that's set will be used. If BOTH are set, size will be used | | bool | disabled | set disable state for element | @@ -6250,6 +6254,8 @@ Multiline(default_text = "", auto_size_text = None, background_color = None, text_color = None, + selected_text_color = None, + selected_background_color = None, horizontal_scroll = False, change_submits = False, enable_events = False, @@ -6289,49 +6295,51 @@ Parameter Descriptions: |Type|Name|Meaning| |--|--|--| -| Any | default_text | Initial text to show | -| bool | enter_submits | if True, the Window.read call will return is enter key is pressed in this element | -| bool | disabled | set disable state | -| bool | autoscroll | If True the contents of the element will automatically scroll as more data added to the end | -| int | border_width | width of border around element in pixels | -| (int, int) or (None, None) or int | size | (w, h) w=characters-wide, h=rows-high. If an int instead of a tuple is supplied, then height is auto-set to 1 | -| (int, int) or (None, None) or int | s | Same as size parameter. It's an alias. If EITHER of them are set, then the one that's set will be used. If BOTH are set, size will be used | -| bool | auto_size_text | if True will size the element to match the length of the text | -| str | background_color | color of background | -| str | text_color | color of the text | -| bool | horizontal_scroll | Controls if a horizontal scrollbar should be shown. If True a horizontal scrollbar will be shown in addition to vertical | -| bool | change_submits | DO NOT USE. Only listed for backwards compat - Use enable_events instead | -| bool | enable_events | If True then any key press that happens when the element has focus will generate an event. | -| bool | do_not_clear | if False the element will be cleared any time the Window.read call returns | -| str or int or tuple or object | key | Used with window.find_element and with return values to uniquely identify this element to uniquely identify this element | -| str or int or tuple or object | k | Same as the Key. You can use either k or key. Which ever is set will be used. | -| bool | write_only | If True then no entry will be added to the values dictionary when the window is read | -| bool | auto_refresh | If True then anytime the element is updated, the window will be refreshed so that the change is immediately displayed | -| bool | reroute_stdout | If True then all output to stdout will be output to this element | -| bool | reroute_stderr | If True then all output to stderr will be output to this element | -| bool | reroute_cprint | If True your cprint calls will output to this element. It's the same as you calling cprint_set_output_destination | -| bool | echo_stdout_stderr | If True then output to stdout and stderr will be output to this element AND also to the normal console location | -| bool | focus | if True initial focus will go to this element | -| (str or (str, int[, str]) or None) | font | specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike | -| (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | pad | Amount of padding to put around element in pixels (left/right, top/bottom) or ((left, right), (top, bottom)) or an int. If an int, then it's converted into a tuple (int, int) | -| (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | p | Same as pad parameter. It's an alias. If EITHER of them are set, then the one that's set will be used. If BOTH are set, pad will be used | -| str | tooltip | text, that will appear when mouse hovers over the element | -| str | justification | text justification. left, right, center. Can use single characters l, r, c. | -| bool | no_scrollbar | If False then a vertical scrollbar will be shown (the default) | -| bool | wrap_lines | If True, the lines will be wrapped automatically. Other parms affect this setting, but this one will override them all. Default is it does nothing and uses previous settings for wrapping. | -| str | sbar_trough_color | Scrollbar color of the trough | -| str | sbar_background_color | Scrollbar color of the background of the arrow buttons at the ends AND the color of the "thumb" (the thing you grab and slide). Switches to arrow color when mouse is over | -| str | sbar_arrow_color | Scrollbar color of the arrow at the ends of the scrollbar (it looks like a button). Switches to background color when mouse is over | -| int | sbar_width | Scrollbar width in pixels | -| int | sbar_arrow_width | Scrollbar width of the arrow on the scrollbar. It will potentially impact the overall width of the scrollbar | -| str | sbar_frame_color | Scrollbar Color of frame around scrollbar (available only on some ttk themes) | -| str | sbar_relief | Scrollbar relief that will be used for the "thumb" of the scrollbar (the thing you grab that slides). Should be a constant that is defined at starting with "RELIEF_" - RELIEF_RAISED, RELIEF_SUNKEN, RELIEF_FLAT, RELIEF_RIDGE, RELIEF_GROOVE, RELIEF_SOLID | -| bool | expand_x | If True the element will automatically expand in the X direction to fill available space | -| bool | expand_y | If True the element will automatically expand in the Y direction to fill available space | -| bool | rstrip | If True the value returned in will have whitespace stripped from the right side | -| List[List[ List[str] or str ]] | right_click_menu | A list of lists of Menu items to show when this element is right clicked. See user docs for exact format. | -| bool | visible | set visibility state of the element | -| Any | metadata | User metadata that can be set to ANYTHING | +| Any | default_text | Initial text to show | +| bool | enter_submits | if True, the Window.read call will return is enter key is pressed in this element | +| bool | disabled | set disable state | +| bool | autoscroll | If True the contents of the element will automatically scroll as more data added to the end | +| int | border_width | width of border around element in pixels | +| (int, int) or (None, None) or int | size | (w, h) w=characters-wide, h=rows-high. If an int instead of a tuple is supplied, then height is auto-set to 1 | +| (int, int) or (None, None) or int | s | Same as size parameter. It's an alias. If EITHER of them are set, then the one that's set will be used. If BOTH are set, size will be used | +| bool | auto_size_text | if True will size the element to match the length of the text | +| str | background_color | color of background | +| str | text_color | color of the text | +| str | selected_text_color | Color of text when it is selected (using mouse or control+A, etc) | +| str | selected_background_color | Color of background when it is selected (using mouse or control+A, etc) | +| bool | horizontal_scroll | Controls if a horizontal scrollbar should be shown. If True a horizontal scrollbar will be shown in addition to vertical | +| bool | change_submits | DO NOT USE. Only listed for backwards compat - Use enable_events instead | +| bool | enable_events | If True then any key press that happens when the element has focus will generate an event. | +| bool | do_not_clear | if False the element will be cleared any time the Window.read call returns | +| str or int or tuple or object | key | Used with window.find_element and with return values to uniquely identify this element to uniquely identify this element | +| str or int or tuple or object | k | Same as the Key. You can use either k or key. Which ever is set will be used. | +| bool | write_only | If True then no entry will be added to the values dictionary when the window is read | +| bool | auto_refresh | If True then anytime the element is updated, the window will be refreshed so that the change is immediately displayed | +| bool | reroute_stdout | If True then all output to stdout will be output to this element | +| bool | reroute_stderr | If True then all output to stderr will be output to this element | +| bool | reroute_cprint | If True your cprint calls will output to this element. It's the same as you calling cprint_set_output_destination | +| bool | echo_stdout_stderr | If True then output to stdout and stderr will be output to this element AND also to the normal console location | +| bool | focus | if True initial focus will go to this element | +| (str or (str, int[, str]) or None) | font | specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike | +| (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | pad | Amount of padding to put around element in pixels (left/right, top/bottom) or ((left, right), (top, bottom)) or an int. If an int, then it's converted into a tuple (int, int) | +| (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | p | Same as pad parameter. It's an alias. If EITHER of them are set, then the one that's set will be used. If BOTH are set, pad will be used | +| str | tooltip | text, that will appear when mouse hovers over the element | +| str | justification | text justification. left, right, center. Can use single characters l, r, c. | +| bool | no_scrollbar | If False then a vertical scrollbar will be shown (the default) | +| bool | wrap_lines | If True, the lines will be wrapped automatically. Other parms affect this setting, but this one will override them all. Default is it does nothing and uses previous settings for wrapping. | +| str | sbar_trough_color | Scrollbar color of the trough | +| str | sbar_background_color | Scrollbar color of the background of the arrow buttons at the ends AND the color of the "thumb" (the thing you grab and slide). Switches to arrow color when mouse is over | +| str | sbar_arrow_color | Scrollbar color of the arrow at the ends of the scrollbar (it looks like a button). Switches to background color when mouse is over | +| int | sbar_width | Scrollbar width in pixels | +| int | sbar_arrow_width | Scrollbar width of the arrow on the scrollbar. It will potentially impact the overall width of the scrollbar | +| str | sbar_frame_color | Scrollbar Color of frame around scrollbar (available only on some ttk themes) | +| str | sbar_relief | Scrollbar relief that will be used for the "thumb" of the scrollbar (the thing you grab that slides). Should be a constant that is defined at starting with "RELIEF_" - RELIEF_RAISED, RELIEF_SUNKEN, RELIEF_FLAT, RELIEF_RIDGE, RELIEF_GROOVE, RELIEF_SOLID | +| bool | expand_x | If True the element will automatically expand in the X direction to fill available space | +| bool | expand_y | If True the element will automatically expand in the Y direction to fill available space | +| bool | rstrip | If True the value returned in will have whitespace stripped from the right side | +| List[List[ List[str] or str ]] | right_click_menu | A list of lists of Menu items to show when this element is right clicked. See user docs for exact format. | +| bool | visible | set visibility state of the element | +| Any | metadata | User metadata that can be set to ANYTHING | ### bind @@ -9616,7 +9624,7 @@ Parameter Descriptions: | (int, int) or (None, None) or int | size | (w, h) w=characters-wide, h=rows-high. If an int instead of a tuple is supplied, then height is auto-set to 1 | | (int, int) or (None, None) or int | s | Same as size parameter. It's an alias. If EITHER of them are set, then the one that's set will be used. If BOTH are set, size will be used | | bool | auto_size_text | if True will size the element to match the length of the text | -| bool | bind_return_key | If True, then the return key will cause a the element to generate an event | +| bool | bind_return_key | If True, then the return key will cause a the element to generate an event when return key is pressed | | (str or (str, int[, str]) or None) | font | specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike | | str | background_color | color of background | | str | text_color | color of the text | @@ -14907,7 +14915,7 @@ Parameter Descriptions: | (str, str) or str | button_color | button color (foreground, background) | | bool | disabled | set disable state for element (Default = False) | | (str or (str, int[, str]) or None) | font | specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike | -| bool | bind_return_key | (Default = False) If True, then the return key will cause a the Listbox to generate an event | +| bool | bind_return_key | (Default = False) If True, this button will appear to be clicked when return key is pressed in other elements such as Input and elements with return key options | | bool | focus | if focus should be set to this | | (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | pad | Amount of padding to put around element in pixels (left/right, top/bottom) or ((left, right), (top, bottom)) or an int. If an int, then it's converted into a tuple (int, int) | | (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | p | Same as pad parameter. It's an alias. If EITHER of them are set, then the one that's set will be used. If BOTH are set, pad will be used | @@ -14960,7 +14968,7 @@ Parameter Descriptions: | bool | disabled | set disable state for element (Default = False) | | str | tooltip | text, that will appear when mouse hovers over the element | | (str or (str, int[, str]) or None) | font | specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike | -| bool | bind_return_key | (Default = False) If True, then the return key will cause a the Listbox to generate an event | +| bool | bind_return_key | (Default = False) If True, this button will appear to be clicked when return key is pressed in other elements such as Input and elements with return key options | | | focus | if focus should be set to this | | (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | pad | Amount of padding to put around element in pixels (left/right, top/bottom) or ((left, right), (top, bottom)) or an int. If an int, then it's converted into a tuple (int, int) | | (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | p | Same as pad parameter. It's an alias. If EITHER of them are set, then the one that's set will be used. If BOTH are set, pad will be used | @@ -15018,7 +15026,7 @@ Parameter Descriptions: | (str, str) or str | button_color | button color (foreground, background) | | bool | disabled | set disable state for element (Default = False) | | (str or (str, int[, str]) or None) | font | specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike | -| bool | bind_return_key | If True, then the return key will cause a the Listbox to generate an event | +| bool | bind_return_key | (Default = False) If True, this button will appear to be clicked when return key is pressed in other elements such as Input and elements with return key options | | bool | focus | Determines if initial focus should go to this element. | | (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | pad | Amount of padding to put around element in pixels (left/right, top/bottom) or ((left, right), (top, bottom)) or an int. If an int, then it's converted into a tuple (int, int) | | (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | p | Same as pad parameter. It's an alias. If EITHER of them are set, then the one that's set will be used. If BOTH are set, pad will be used | @@ -15069,7 +15077,7 @@ Parameter Descriptions: | bool | disabled | set disable state for element (Default = False) | | (str or (str, int[, str]) or None) | font | specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike | | str | tooltip | text, that will appear when mouse hovers over the element | -| bool | bind_return_key | (Default = False) If True, then the return key will cause a the Listbox to generate an event | +| bool | bind_return_key | (Default = False) If True, this button will appear to be clicked when return key is pressed in other elements such as Input and elements with return key options | | | focus | if focus should be set to this | | (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | pad | Amount of padding to put around element in pixels (left/right, top/bottom) or ((left, right), (top, bottom)) or an int. If an int, then it's converted into a tuple (int, int) | | (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | p | Same as pad parameter. It's an alias. If EITHER of them are set, then the one that's set will be used. If BOTH are set, pad will be used | @@ -15131,7 +15139,7 @@ Parameter Descriptions: | (str, str) or str | button_color | button color (foreground, background) | | (str or (str, int[, str]) or None) | font | specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike | | bool | disabled | set disable state for element (Default = False) | -| bool | bind_return_key | (Default = False) If True, then the return key will cause a the Listbox to generate an event | +| bool | bind_return_key | (Default = False) If True, this button will appear to be clicked when return key is pressed in other elements such as Input and elements with return key options | | bool | focus | if focus should be set to this | | (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | pad | Amount of padding to put around element in pixels (left/right, top/bottom) or ((left, right), (top, bottom)) or an int. If an int, then it's converted into a tuple (int, int) | | (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | p | Same as pad parameter. It's an alias. If EITHER of them are set, then the one that's set will be used. If BOTH are set, pad will be used | @@ -15176,7 +15184,7 @@ Parameter Descriptions: | bool | disabled | set disable state for element (Default = False) | | str | tooltip | text, that will appear when mouse hovers over the element | | (str or (str, int[, str]) or None) | font | specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike | -| bool | bind_return_key | (Default = False) If True, then the return key will cause a the Listbox to generate an event | +| bool | bind_return_key | (Default = False) If True, this button will appear to be clicked when return key is pressed in other elements such as Input and elements with return key options | | | focus | if focus should be set to this | | (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | pad | Amount of padding to put around element in pixels (left/right, top/bottom) or ((left, right), (top, bottom)) or an int. If an int, then it's converted into a tuple (int, int) | | (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | p | Same as pad parameter. It's an alias. If EITHER of them are set, then the one that's set will be used. If BOTH are set, pad will be used | @@ -15429,7 +15437,7 @@ Parameter Descriptions: | bool | disabled | set disable state for element (Default = False) | | (str or (str, int[, str]) or None) | font | specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike | | str | tooltip | text, that will appear when mouse hovers over the element | -| bool | bind_return_key | (Default = False) If True, then the return key will cause a the Listbox to generate an event | +| bool | bind_return_key | (Default = False) If True, this button will appear to be clicked when return key is pressed in other elements such as Input and elements with return key options | | | focus | if focus should be set to this | | (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | pad | Amount of padding to put around element in pixels (left/right, top/bottom) or ((left, right), (top, bottom)) or an int. If an int, then it's converted into a tuple (int, int) | | (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | p | Same as pad parameter. It's an alias. If EITHER of them are set, then the one that's set will be used. If BOTH are set, pad will be used | @@ -15517,7 +15525,7 @@ Parameter Descriptions: | bool | auto_size_button | True if button size is determined by button text | | (str, str) or str | button_color | button color (foreground, background) | | bool | disabled | set disable state for element (Default = False) | -| bool | bind_return_key | (Default = True) If True, then the return key will cause a the Listbox to generate an event | +| bool | bind_return_key | (Default = True) If True, this button will appear to be clicked when return key is pressed in other elements such as Input and elements with return key options | | str | tooltip | text, that will appear when mouse hovers over the element | | (str or (str, int[, str]) or None) | font | specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike | | idk_yetReally | focus | if focus should be set to this | @@ -15562,7 +15570,7 @@ Parameter Descriptions: | bool | auto_size_button | True if button size is determined by button text | | (str, str) or str | button_color | button color (foreground, background) | | bool | disabled | set disable state for element (Default = False) | -| bool | bind_return_key | (Default = True) If True, then the return key will cause a the Listbox to generate an event | +| bool | bind_return_key | (Default = True) If True, this button will appear to be clicked when return key is pressed in other elements such as Input and elements with return key options | | str | tooltip | text, that will appear when mouse hovers over the element | | (str or (str, int[, str]) or None) | font | specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike | | idk_yetReally | focus | if focus should be set to this | @@ -15607,7 +15615,7 @@ Parameter Descriptions: | bool | auto_size_button | True if button size is determined by button text | | (str, str) or str | button_color | button color (foreground, background) | | bool | disabled | set disable state for element (Default = False) | -| bool | bind_return_key | (Default = True) If True, then the return key will cause a the Listbox to generate an event | +| bool | bind_return_key | (Default = True) If True, this button will appear to be clicked when return key is pressed in other elements such as Input and elements with return key options | | str | tooltip | text, that will appear when mouse hovers over the element | | (str or (str, int[, str]) or None) | font | specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike | | idk_yetReally | focus | if focus should be set to this | @@ -15654,7 +15662,7 @@ Parameter Descriptions: | bool | disabled | set disable state for element (Default = False) | | str | tooltip | text, that will appear when mouse hovers over the element | | (str or (str, int[, str]) or None) | font | specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike | -| bool | bind_return_key | (Default = False) If True, then the return key will cause a the Listbox to generate an event | +| bool | bind_return_key | (Default = False) If True, this button will appear to be clicked when return key is pressed in other elements such as Input and elements with return key options | | bool | focus | if focus should be set to this | | (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | pad | Amount of padding to put around element in pixels (left/right, top/bottom) or ((left, right), (top, bottom)) or an int. If an int, then it's converted into a tuple (int, int) | | (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | p | Same as pad parameter. It's an alias. If EITHER of them are set, then the one that's set will be used. If BOTH are set, pad will be used | @@ -15709,7 +15717,7 @@ Parameter Descriptions: | (str, str) or str | button_color | button color (foreground, background) | | (str or (str, int[, str]) or None) | font | specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike | | bool | disabled | set disable state for element (Default = False) | -| bool | bind_return_key | (Default = False) If True, then the return key will cause a the Listbox to generate an event | +| bool | bind_return_key | (Default = False) If True, this button will appear to be clicked when return key is pressed in other elements such as Input and elements with return key options | | bool | focus | if focus should be set to this | | (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | pad | Amount of padding to put around element in pixels (left/right, top/bottom) or ((left, right), (top, bottom)) or an int. If an int, then it's converted into a tuple (int, int) | | (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | p | Same as pad parameter. It's an alias. If EITHER of them are set, then the one that's set will be used. If BOTH are set, pad will be used | @@ -15751,7 +15759,7 @@ Parameter Descriptions: | (int, int) or (None, None) or int | s | Same as size parameter. It's an alias. If EITHER of them are set, then the one that's set will be used. If BOTH are set, size will be used | | bool | auto_size_button | True if button size is determined by button text | | (str, str) or str | button_color | button color (foreground, background) | -| bool | bind_return_key | (Default = True) If True, then the return key will cause a the Listbox to generate an event | +| bool | bind_return_key | (Default = True) If True, this button will appear to be clicked when return key is pressed in other elements such as Input and elements with return key options | | bool | disabled | set disable state for element (Default = False) | | str | tooltip | text, that will appear when mouse hovers over the element | | (str or (str, int[, str]) or None) | font | specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike | @@ -15849,7 +15857,7 @@ Parameter Descriptions: | bool | auto_size_button | True if button size is determined by button text | | (str, str) or str | button_color | button color (foreground, background) | | bool | disabled | set disable state for element (Default = False) | -| bool | bind_return_key | (Default = True) If True, then the return key will cause a the Listbox to generate an event | +| bool | bind_return_key | (Default = True) If True, this button will appear to be clicked when return key is pressed in other elements such as Input and elements with return key options | | str | tooltip | text, that will appear when mouse hovers over the element | | (str or (str, int[, str]) or None) | font | specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike | | idk_yetReally | focus | if focus should be set to this | @@ -15896,7 +15904,7 @@ Parameter Descriptions: | bool | disabled | set disable state for element (Default = False) | | str | tooltip | text, that will appear when mouse hovers over the element | | (str or (str, int[, str]) or None) | font | specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike | -| bool | bind_return_key | (Default = True) If True, then the return key will cause a the Listbox to generate an event | +| bool | bind_return_key | (Default = True) If True, this button will appear to be clicked when return key is pressed in other elements such as Input and elements with return key options | | | focus | if focus should be set to this | | (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | pad | Amount of padding to put around element in pixels (left/right, top/bottom) or ((left, right), (top, bottom)) or an int. If an int, then it's converted into a tuple (int, int) | | (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | p | Same as pad parameter. It's an alias. If EITHER of them are set, then the one that's set will be used. If BOTH are set, pad will be used | @@ -15953,7 +15961,7 @@ Parameter Descriptions: | bool | auto_size_button | True if button size is determined by button text | | (str, str) or str | button_color | button color (foreground, background) | | (str or (str, int[, str]) or None) | font | specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike | -| bool | bind_return_key | (Default = False) If True, then the return key will cause a the Listbox to generate an event | +| bool | bind_return_key | (Default = False) If True, this button will appear to be clicked when return key is pressed in other elements such as Input and elements with return key options | | bool | disabled | set disable state for element (Default = False) | | idk_yetReally | focus | if focus should be set to this | | (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | pad | Amount of padding to put around element in pixels (left/right, top/bottom) or ((left, right), (top, bottom)) or an int. If an int, then it's converted into a tuple (int, int) | @@ -16006,7 +16014,7 @@ Parameter Descriptions: | bool | auto_size_button | True if button size is determined by button text | | (str, str) or str | button_color | button color (foreground, background) | | (str or (str, int[, str]) or None) | font | specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike | -| bool | bind_return_key | (Default = False) If True, then the return key will cause a the Listbox to generate an event | +| bool | bind_return_key | (Default = False) If True, this button will appear to be clicked when return key is pressed in other elements such as Input and elements with return key options | | bool | disabled | set disable state for element (Default = False) | | idk_yetReally | focus | if focus should be set to this | | (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | pad | Amount of padding to put around element in pixels (left/right, top/bottom) or ((left, right), (top, bottom)) or an int. If an int, then it's converted into a tuple (int, int) | @@ -16064,7 +16072,7 @@ Parameter Descriptions: | bool | auto_size_button | True if button size is determined by button text | | (str, str) or str | button_color | button color (foreground, background) | | (str or (str, int[, str]) or None) | font | specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike | -| bool | bind_return_key | (Default = False) If True, then the return key will cause a the Listbox to generate an event | +| bool | bind_return_key | (Default = False) If True, this button will appear to be clicked when return key is pressed in other elements such as Input and elements with return key options | | bool | disabled | set disable state for element (Default = False) | | idk_yetReally | focus | if focus should be set to this | | (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | pad | Amount of padding to put around element in pixels (left/right, top/bottom) or ((left, right), (top, bottom)) or an int. If an int, then it's converted into a tuple (int, int) | @@ -16121,7 +16129,7 @@ Parameter Descriptions: | bool | auto_size_button | True if button size is determined by button text | | (str, str) or str | button_color | button color (foreground, background) | | (str or (str, int[, str]) or None) | font | specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike | -| bool | bind_return_key | (Default = False) If True, then the return key will cause a the Listbox to generate an event | +| bool | bind_return_key | (Default = False) If True, this button will appear to be clicked when return key is pressed in other elements such as Input and elements with return key options | | bool | disabled | set disable state for element (Default = False) | | idk_yetReally | focus | if focus should be set to this | | (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | pad | Amount of padding to put around element in pixels (left/right, top/bottom) or ((left, right), (top, bottom)) or an int. If an int, then it's converted into a tuple (int, int) | diff --git a/readme_creator/output/call reference.md b/readme_creator/output/call reference.md index ad33251c..77b324bb 100644 --- a/readme_creator/output/call reference.md +++ b/readme_creator/output/call reference.md @@ -126,7 +126,7 @@ Parameter Descriptions: | (str, str) or str | mouseover_colors | Important difference between Linux & Windows! Linux - Colors when mouse moved over button. Windows - colors when button is pressed. The default is to switch the text and background colors (an inverse effect) | | bool | use_ttk_buttons | True = use ttk buttons. False = do not use ttk buttons. None (Default) = use ttk buttons only if on a Mac and not with button images | | (str or (str, int[, str]) or None) | font | specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike | -| bool | bind_return_key | If True the return key will cause this button to be pressed | +| bool | bind_return_key | If True then pressing the return key in an Input or Multiline Element will cause this button to appear to be clicked (generates event with this button's key | | bool | focus | if True, initial focus will be put on this button | | (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | pad | Amount of padding to put around element in pixels (left/right, top/bottom) or ((left, right), (top, bottom)) or an int. If an int, then it's converted into a tuple (int, int) | | (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | p | Same as pad parameter. It's an alias. If EITHER of them are set, then the one that's set will be used. If BOTH are set, pad will be used | @@ -2214,7 +2214,7 @@ Parameter Descriptions: | str | text_color | color of the text | | str | button_background_color | The color of the background of the button on the combo box | | str | button_arrow_color | The color of the arrow on the button on the combo box | -| bool | bind_return_key | If True, then the return key will cause a the Combo to generate an event | +| bool | bind_return_key | If True, then the return key will cause a the Combo to generate an event when return key is pressed | | bool | change_submits | DEPRICATED DO NOT USE. Use `enable_events` instead | | bool | enable_events | Turns on the element specific events. Combo event is when a choice is made | | bool | enable_per_char_events | Enables generation of events for every character that's input. This is like the Input element's events | @@ -4881,6 +4881,8 @@ Input(default_text = "", readonly = False, disabled_readonly_background_color = None, disabled_readonly_text_color = None, + selected_text_color = None, + selected_background_color = None, expand_x = False, expand_y = False, right_click_menu = None, @@ -4915,6 +4917,8 @@ Parameter Descriptions: | bool | readonly | If True tkinter state set to 'readonly'. Use this in place of use_readonly_for_disable as another way of achieving readonly. Note cannot set BOTH readonly and disabled as tkinter only supplies a single flag | | str | disabled_readonly_background_color | If state is set to readonly or disabled, the color to use for the background | | str | disabled_readonly_text_color | If state is set to readonly or disabled, the color to use for the text | +| str | selected_text_color | Color of text when it is selected (using mouse or control+A, etc) | +| str | selected_background_color | Color of background when it is selected (using mouse or control+A, etc) | | bool | expand_x | If True the element will automatically expand in the X direction to fill available space | | bool | expand_y | If True the element will automatically expand in the Y direction to fill available space | | List[List[ List[str] or str ]] | right_click_menu | A list of lists of Menu items to show when this element is right clicked. See user docs for exact format. | @@ -5359,7 +5363,7 @@ Parameter Descriptions: | [enum] | select_mode | Select modes are used to determine if only 1 item can be selected or multiple and how they can be selected. Valid choices begin with "LISTBOX_SELECT_MODE_" and include: LISTBOX_SELECT_MODE_SINGLE LISTBOX_SELECT_MODE_MULTIPLE LISTBOX_SELECT_MODE_BROWSE LISTBOX_SELECT_MODE_EXTENDED | | bool | change_submits | DO NOT USE. Only listed for backwards compat - Use enable_events instead | | bool | enable_events | Turns on the element specific events. Listbox generates events when an item is clicked | -| bool | bind_return_key | If True, then the return key will cause a the Listbox to generate an event | +| bool | bind_return_key | If True, then the return key will cause a the Listbox to generate an event when return key is pressed | | (int, int) or (int, None) or int | size | w=characters-wide, h=rows-high. If an int instead of a tuple is supplied, then height is auto-set to 1 | | (int, int) or (None, None) or int | s | Same as size parameter. It's an alias. If EITHER of them are set, then the one that's set will be used. If BOTH are set, size will be used | | bool | disabled | set disable state for element | @@ -6250,6 +6254,8 @@ Multiline(default_text = "", auto_size_text = None, background_color = None, text_color = None, + selected_text_color = None, + selected_background_color = None, horizontal_scroll = False, change_submits = False, enable_events = False, @@ -6289,49 +6295,51 @@ Parameter Descriptions: |Type|Name|Meaning| |--|--|--| -| Any | default_text | Initial text to show | -| bool | enter_submits | if True, the Window.read call will return is enter key is pressed in this element | -| bool | disabled | set disable state | -| bool | autoscroll | If True the contents of the element will automatically scroll as more data added to the end | -| int | border_width | width of border around element in pixels | -| (int, int) or (None, None) or int | size | (w, h) w=characters-wide, h=rows-high. If an int instead of a tuple is supplied, then height is auto-set to 1 | -| (int, int) or (None, None) or int | s | Same as size parameter. It's an alias. If EITHER of them are set, then the one that's set will be used. If BOTH are set, size will be used | -| bool | auto_size_text | if True will size the element to match the length of the text | -| str | background_color | color of background | -| str | text_color | color of the text | -| bool | horizontal_scroll | Controls if a horizontal scrollbar should be shown. If True a horizontal scrollbar will be shown in addition to vertical | -| bool | change_submits | DO NOT USE. Only listed for backwards compat - Use enable_events instead | -| bool | enable_events | If True then any key press that happens when the element has focus will generate an event. | -| bool | do_not_clear | if False the element will be cleared any time the Window.read call returns | -| str or int or tuple or object | key | Used with window.find_element and with return values to uniquely identify this element to uniquely identify this element | -| str or int or tuple or object | k | Same as the Key. You can use either k or key. Which ever is set will be used. | -| bool | write_only | If True then no entry will be added to the values dictionary when the window is read | -| bool | auto_refresh | If True then anytime the element is updated, the window will be refreshed so that the change is immediately displayed | -| bool | reroute_stdout | If True then all output to stdout will be output to this element | -| bool | reroute_stderr | If True then all output to stderr will be output to this element | -| bool | reroute_cprint | If True your cprint calls will output to this element. It's the same as you calling cprint_set_output_destination | -| bool | echo_stdout_stderr | If True then output to stdout and stderr will be output to this element AND also to the normal console location | -| bool | focus | if True initial focus will go to this element | -| (str or (str, int[, str]) or None) | font | specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike | -| (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | pad | Amount of padding to put around element in pixels (left/right, top/bottom) or ((left, right), (top, bottom)) or an int. If an int, then it's converted into a tuple (int, int) | -| (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | p | Same as pad parameter. It's an alias. If EITHER of them are set, then the one that's set will be used. If BOTH are set, pad will be used | -| str | tooltip | text, that will appear when mouse hovers over the element | -| str | justification | text justification. left, right, center. Can use single characters l, r, c. | -| bool | no_scrollbar | If False then a vertical scrollbar will be shown (the default) | -| bool | wrap_lines | If True, the lines will be wrapped automatically. Other parms affect this setting, but this one will override them all. Default is it does nothing and uses previous settings for wrapping. | -| str | sbar_trough_color | Scrollbar color of the trough | -| str | sbar_background_color | Scrollbar color of the background of the arrow buttons at the ends AND the color of the "thumb" (the thing you grab and slide). Switches to arrow color when mouse is over | -| str | sbar_arrow_color | Scrollbar color of the arrow at the ends of the scrollbar (it looks like a button). Switches to background color when mouse is over | -| int | sbar_width | Scrollbar width in pixels | -| int | sbar_arrow_width | Scrollbar width of the arrow on the scrollbar. It will potentially impact the overall width of the scrollbar | -| str | sbar_frame_color | Scrollbar Color of frame around scrollbar (available only on some ttk themes) | -| str | sbar_relief | Scrollbar relief that will be used for the "thumb" of the scrollbar (the thing you grab that slides). Should be a constant that is defined at starting with "RELIEF_" - RELIEF_RAISED, RELIEF_SUNKEN, RELIEF_FLAT, RELIEF_RIDGE, RELIEF_GROOVE, RELIEF_SOLID | -| bool | expand_x | If True the element will automatically expand in the X direction to fill available space | -| bool | expand_y | If True the element will automatically expand in the Y direction to fill available space | -| bool | rstrip | If True the value returned in will have whitespace stripped from the right side | -| List[List[ List[str] or str ]] | right_click_menu | A list of lists of Menu items to show when this element is right clicked. See user docs for exact format. | -| bool | visible | set visibility state of the element | -| Any | metadata | User metadata that can be set to ANYTHING | +| Any | default_text | Initial text to show | +| bool | enter_submits | if True, the Window.read call will return is enter key is pressed in this element | +| bool | disabled | set disable state | +| bool | autoscroll | If True the contents of the element will automatically scroll as more data added to the end | +| int | border_width | width of border around element in pixels | +| (int, int) or (None, None) or int | size | (w, h) w=characters-wide, h=rows-high. If an int instead of a tuple is supplied, then height is auto-set to 1 | +| (int, int) or (None, None) or int | s | Same as size parameter. It's an alias. If EITHER of them are set, then the one that's set will be used. If BOTH are set, size will be used | +| bool | auto_size_text | if True will size the element to match the length of the text | +| str | background_color | color of background | +| str | text_color | color of the text | +| str | selected_text_color | Color of text when it is selected (using mouse or control+A, etc) | +| str | selected_background_color | Color of background when it is selected (using mouse or control+A, etc) | +| bool | horizontal_scroll | Controls if a horizontal scrollbar should be shown. If True a horizontal scrollbar will be shown in addition to vertical | +| bool | change_submits | DO NOT USE. Only listed for backwards compat - Use enable_events instead | +| bool | enable_events | If True then any key press that happens when the element has focus will generate an event. | +| bool | do_not_clear | if False the element will be cleared any time the Window.read call returns | +| str or int or tuple or object | key | Used with window.find_element and with return values to uniquely identify this element to uniquely identify this element | +| str or int or tuple or object | k | Same as the Key. You can use either k or key. Which ever is set will be used. | +| bool | write_only | If True then no entry will be added to the values dictionary when the window is read | +| bool | auto_refresh | If True then anytime the element is updated, the window will be refreshed so that the change is immediately displayed | +| bool | reroute_stdout | If True then all output to stdout will be output to this element | +| bool | reroute_stderr | If True then all output to stderr will be output to this element | +| bool | reroute_cprint | If True your cprint calls will output to this element. It's the same as you calling cprint_set_output_destination | +| bool | echo_stdout_stderr | If True then output to stdout and stderr will be output to this element AND also to the normal console location | +| bool | focus | if True initial focus will go to this element | +| (str or (str, int[, str]) or None) | font | specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike | +| (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | pad | Amount of padding to put around element in pixels (left/right, top/bottom) or ((left, right), (top, bottom)) or an int. If an int, then it's converted into a tuple (int, int) | +| (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | p | Same as pad parameter. It's an alias. If EITHER of them are set, then the one that's set will be used. If BOTH are set, pad will be used | +| str | tooltip | text, that will appear when mouse hovers over the element | +| str | justification | text justification. left, right, center. Can use single characters l, r, c. | +| bool | no_scrollbar | If False then a vertical scrollbar will be shown (the default) | +| bool | wrap_lines | If True, the lines will be wrapped automatically. Other parms affect this setting, but this one will override them all. Default is it does nothing and uses previous settings for wrapping. | +| str | sbar_trough_color | Scrollbar color of the trough | +| str | sbar_background_color | Scrollbar color of the background of the arrow buttons at the ends AND the color of the "thumb" (the thing you grab and slide). Switches to arrow color when mouse is over | +| str | sbar_arrow_color | Scrollbar color of the arrow at the ends of the scrollbar (it looks like a button). Switches to background color when mouse is over | +| int | sbar_width | Scrollbar width in pixels | +| int | sbar_arrow_width | Scrollbar width of the arrow on the scrollbar. It will potentially impact the overall width of the scrollbar | +| str | sbar_frame_color | Scrollbar Color of frame around scrollbar (available only on some ttk themes) | +| str | sbar_relief | Scrollbar relief that will be used for the "thumb" of the scrollbar (the thing you grab that slides). Should be a constant that is defined at starting with "RELIEF_" - RELIEF_RAISED, RELIEF_SUNKEN, RELIEF_FLAT, RELIEF_RIDGE, RELIEF_GROOVE, RELIEF_SOLID | +| bool | expand_x | If True the element will automatically expand in the X direction to fill available space | +| bool | expand_y | If True the element will automatically expand in the Y direction to fill available space | +| bool | rstrip | If True the value returned in will have whitespace stripped from the right side | +| List[List[ List[str] or str ]] | right_click_menu | A list of lists of Menu items to show when this element is right clicked. See user docs for exact format. | +| bool | visible | set visibility state of the element | +| Any | metadata | User metadata that can be set to ANYTHING | ### bind @@ -9616,7 +9624,7 @@ Parameter Descriptions: | (int, int) or (None, None) or int | size | (w, h) w=characters-wide, h=rows-high. If an int instead of a tuple is supplied, then height is auto-set to 1 | | (int, int) or (None, None) or int | s | Same as size parameter. It's an alias. If EITHER of them are set, then the one that's set will be used. If BOTH are set, size will be used | | bool | auto_size_text | if True will size the element to match the length of the text | -| bool | bind_return_key | If True, then the return key will cause a the element to generate an event | +| bool | bind_return_key | If True, then the return key will cause a the element to generate an event when return key is pressed | | (str or (str, int[, str]) or None) | font | specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike | | str | background_color | color of background | | str | text_color | color of the text | @@ -14907,7 +14915,7 @@ Parameter Descriptions: | (str, str) or str | button_color | button color (foreground, background) | | bool | disabled | set disable state for element (Default = False) | | (str or (str, int[, str]) or None) | font | specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike | -| bool | bind_return_key | (Default = False) If True, then the return key will cause a the Listbox to generate an event | +| bool | bind_return_key | (Default = False) If True, this button will appear to be clicked when return key is pressed in other elements such as Input and elements with return key options | | bool | focus | if focus should be set to this | | (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | pad | Amount of padding to put around element in pixels (left/right, top/bottom) or ((left, right), (top, bottom)) or an int. If an int, then it's converted into a tuple (int, int) | | (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | p | Same as pad parameter. It's an alias. If EITHER of them are set, then the one that's set will be used. If BOTH are set, pad will be used | @@ -14960,7 +14968,7 @@ Parameter Descriptions: | bool | disabled | set disable state for element (Default = False) | | str | tooltip | text, that will appear when mouse hovers over the element | | (str or (str, int[, str]) or None) | font | specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike | -| bool | bind_return_key | (Default = False) If True, then the return key will cause a the Listbox to generate an event | +| bool | bind_return_key | (Default = False) If True, this button will appear to be clicked when return key is pressed in other elements such as Input and elements with return key options | | | focus | if focus should be set to this | | (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | pad | Amount of padding to put around element in pixels (left/right, top/bottom) or ((left, right), (top, bottom)) or an int. If an int, then it's converted into a tuple (int, int) | | (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | p | Same as pad parameter. It's an alias. If EITHER of them are set, then the one that's set will be used. If BOTH are set, pad will be used | @@ -15018,7 +15026,7 @@ Parameter Descriptions: | (str, str) or str | button_color | button color (foreground, background) | | bool | disabled | set disable state for element (Default = False) | | (str or (str, int[, str]) or None) | font | specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike | -| bool | bind_return_key | If True, then the return key will cause a the Listbox to generate an event | +| bool | bind_return_key | (Default = False) If True, this button will appear to be clicked when return key is pressed in other elements such as Input and elements with return key options | | bool | focus | Determines if initial focus should go to this element. | | (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | pad | Amount of padding to put around element in pixels (left/right, top/bottom) or ((left, right), (top, bottom)) or an int. If an int, then it's converted into a tuple (int, int) | | (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | p | Same as pad parameter. It's an alias. If EITHER of them are set, then the one that's set will be used. If BOTH are set, pad will be used | @@ -15069,7 +15077,7 @@ Parameter Descriptions: | bool | disabled | set disable state for element (Default = False) | | (str or (str, int[, str]) or None) | font | specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike | | str | tooltip | text, that will appear when mouse hovers over the element | -| bool | bind_return_key | (Default = False) If True, then the return key will cause a the Listbox to generate an event | +| bool | bind_return_key | (Default = False) If True, this button will appear to be clicked when return key is pressed in other elements such as Input and elements with return key options | | | focus | if focus should be set to this | | (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | pad | Amount of padding to put around element in pixels (left/right, top/bottom) or ((left, right), (top, bottom)) or an int. If an int, then it's converted into a tuple (int, int) | | (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | p | Same as pad parameter. It's an alias. If EITHER of them are set, then the one that's set will be used. If BOTH are set, pad will be used | @@ -15131,7 +15139,7 @@ Parameter Descriptions: | (str, str) or str | button_color | button color (foreground, background) | | (str or (str, int[, str]) or None) | font | specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike | | bool | disabled | set disable state for element (Default = False) | -| bool | bind_return_key | (Default = False) If True, then the return key will cause a the Listbox to generate an event | +| bool | bind_return_key | (Default = False) If True, this button will appear to be clicked when return key is pressed in other elements such as Input and elements with return key options | | bool | focus | if focus should be set to this | | (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | pad | Amount of padding to put around element in pixels (left/right, top/bottom) or ((left, right), (top, bottom)) or an int. If an int, then it's converted into a tuple (int, int) | | (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | p | Same as pad parameter. It's an alias. If EITHER of them are set, then the one that's set will be used. If BOTH are set, pad will be used | @@ -15176,7 +15184,7 @@ Parameter Descriptions: | bool | disabled | set disable state for element (Default = False) | | str | tooltip | text, that will appear when mouse hovers over the element | | (str or (str, int[, str]) or None) | font | specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike | -| bool | bind_return_key | (Default = False) If True, then the return key will cause a the Listbox to generate an event | +| bool | bind_return_key | (Default = False) If True, this button will appear to be clicked when return key is pressed in other elements such as Input and elements with return key options | | | focus | if focus should be set to this | | (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | pad | Amount of padding to put around element in pixels (left/right, top/bottom) or ((left, right), (top, bottom)) or an int. If an int, then it's converted into a tuple (int, int) | | (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | p | Same as pad parameter. It's an alias. If EITHER of them are set, then the one that's set will be used. If BOTH are set, pad will be used | @@ -15429,7 +15437,7 @@ Parameter Descriptions: | bool | disabled | set disable state for element (Default = False) | | (str or (str, int[, str]) or None) | font | specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike | | str | tooltip | text, that will appear when mouse hovers over the element | -| bool | bind_return_key | (Default = False) If True, then the return key will cause a the Listbox to generate an event | +| bool | bind_return_key | (Default = False) If True, this button will appear to be clicked when return key is pressed in other elements such as Input and elements with return key options | | | focus | if focus should be set to this | | (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | pad | Amount of padding to put around element in pixels (left/right, top/bottom) or ((left, right), (top, bottom)) or an int. If an int, then it's converted into a tuple (int, int) | | (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | p | Same as pad parameter. It's an alias. If EITHER of them are set, then the one that's set will be used. If BOTH are set, pad will be used | @@ -15517,7 +15525,7 @@ Parameter Descriptions: | bool | auto_size_button | True if button size is determined by button text | | (str, str) or str | button_color | button color (foreground, background) | | bool | disabled | set disable state for element (Default = False) | -| bool | bind_return_key | (Default = True) If True, then the return key will cause a the Listbox to generate an event | +| bool | bind_return_key | (Default = True) If True, this button will appear to be clicked when return key is pressed in other elements such as Input and elements with return key options | | str | tooltip | text, that will appear when mouse hovers over the element | | (str or (str, int[, str]) or None) | font | specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike | | idk_yetReally | focus | if focus should be set to this | @@ -15562,7 +15570,7 @@ Parameter Descriptions: | bool | auto_size_button | True if button size is determined by button text | | (str, str) or str | button_color | button color (foreground, background) | | bool | disabled | set disable state for element (Default = False) | -| bool | bind_return_key | (Default = True) If True, then the return key will cause a the Listbox to generate an event | +| bool | bind_return_key | (Default = True) If True, this button will appear to be clicked when return key is pressed in other elements such as Input and elements with return key options | | str | tooltip | text, that will appear when mouse hovers over the element | | (str or (str, int[, str]) or None) | font | specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike | | idk_yetReally | focus | if focus should be set to this | @@ -15607,7 +15615,7 @@ Parameter Descriptions: | bool | auto_size_button | True if button size is determined by button text | | (str, str) or str | button_color | button color (foreground, background) | | bool | disabled | set disable state for element (Default = False) | -| bool | bind_return_key | (Default = True) If True, then the return key will cause a the Listbox to generate an event | +| bool | bind_return_key | (Default = True) If True, this button will appear to be clicked when return key is pressed in other elements such as Input and elements with return key options | | str | tooltip | text, that will appear when mouse hovers over the element | | (str or (str, int[, str]) or None) | font | specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike | | idk_yetReally | focus | if focus should be set to this | @@ -15654,7 +15662,7 @@ Parameter Descriptions: | bool | disabled | set disable state for element (Default = False) | | str | tooltip | text, that will appear when mouse hovers over the element | | (str or (str, int[, str]) or None) | font | specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike | -| bool | bind_return_key | (Default = False) If True, then the return key will cause a the Listbox to generate an event | +| bool | bind_return_key | (Default = False) If True, this button will appear to be clicked when return key is pressed in other elements such as Input and elements with return key options | | bool | focus | if focus should be set to this | | (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | pad | Amount of padding to put around element in pixels (left/right, top/bottom) or ((left, right), (top, bottom)) or an int. If an int, then it's converted into a tuple (int, int) | | (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | p | Same as pad parameter. It's an alias. If EITHER of them are set, then the one that's set will be used. If BOTH are set, pad will be used | @@ -15709,7 +15717,7 @@ Parameter Descriptions: | (str, str) or str | button_color | button color (foreground, background) | | (str or (str, int[, str]) or None) | font | specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike | | bool | disabled | set disable state for element (Default = False) | -| bool | bind_return_key | (Default = False) If True, then the return key will cause a the Listbox to generate an event | +| bool | bind_return_key | (Default = False) If True, this button will appear to be clicked when return key is pressed in other elements such as Input and elements with return key options | | bool | focus | if focus should be set to this | | (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | pad | Amount of padding to put around element in pixels (left/right, top/bottom) or ((left, right), (top, bottom)) or an int. If an int, then it's converted into a tuple (int, int) | | (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | p | Same as pad parameter. It's an alias. If EITHER of them are set, then the one that's set will be used. If BOTH are set, pad will be used | @@ -15751,7 +15759,7 @@ Parameter Descriptions: | (int, int) or (None, None) or int | s | Same as size parameter. It's an alias. If EITHER of them are set, then the one that's set will be used. If BOTH are set, size will be used | | bool | auto_size_button | True if button size is determined by button text | | (str, str) or str | button_color | button color (foreground, background) | -| bool | bind_return_key | (Default = True) If True, then the return key will cause a the Listbox to generate an event | +| bool | bind_return_key | (Default = True) If True, this button will appear to be clicked when return key is pressed in other elements such as Input and elements with return key options | | bool | disabled | set disable state for element (Default = False) | | str | tooltip | text, that will appear when mouse hovers over the element | | (str or (str, int[, str]) or None) | font | specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike | @@ -15849,7 +15857,7 @@ Parameter Descriptions: | bool | auto_size_button | True if button size is determined by button text | | (str, str) or str | button_color | button color (foreground, background) | | bool | disabled | set disable state for element (Default = False) | -| bool | bind_return_key | (Default = True) If True, then the return key will cause a the Listbox to generate an event | +| bool | bind_return_key | (Default = True) If True, this button will appear to be clicked when return key is pressed in other elements such as Input and elements with return key options | | str | tooltip | text, that will appear when mouse hovers over the element | | (str or (str, int[, str]) or None) | font | specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike | | idk_yetReally | focus | if focus should be set to this | @@ -15896,7 +15904,7 @@ Parameter Descriptions: | bool | disabled | set disable state for element (Default = False) | | str | tooltip | text, that will appear when mouse hovers over the element | | (str or (str, int[, str]) or None) | font | specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike | -| bool | bind_return_key | (Default = True) If True, then the return key will cause a the Listbox to generate an event | +| bool | bind_return_key | (Default = True) If True, this button will appear to be clicked when return key is pressed in other elements such as Input and elements with return key options | | | focus | if focus should be set to this | | (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | pad | Amount of padding to put around element in pixels (left/right, top/bottom) or ((left, right), (top, bottom)) or an int. If an int, then it's converted into a tuple (int, int) | | (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | p | Same as pad parameter. It's an alias. If EITHER of them are set, then the one that's set will be used. If BOTH are set, pad will be used | @@ -15953,7 +15961,7 @@ Parameter Descriptions: | bool | auto_size_button | True if button size is determined by button text | | (str, str) or str | button_color | button color (foreground, background) | | (str or (str, int[, str]) or None) | font | specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike | -| bool | bind_return_key | (Default = False) If True, then the return key will cause a the Listbox to generate an event | +| bool | bind_return_key | (Default = False) If True, this button will appear to be clicked when return key is pressed in other elements such as Input and elements with return key options | | bool | disabled | set disable state for element (Default = False) | | idk_yetReally | focus | if focus should be set to this | | (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | pad | Amount of padding to put around element in pixels (left/right, top/bottom) or ((left, right), (top, bottom)) or an int. If an int, then it's converted into a tuple (int, int) | @@ -16006,7 +16014,7 @@ Parameter Descriptions: | bool | auto_size_button | True if button size is determined by button text | | (str, str) or str | button_color | button color (foreground, background) | | (str or (str, int[, str]) or None) | font | specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike | -| bool | bind_return_key | (Default = False) If True, then the return key will cause a the Listbox to generate an event | +| bool | bind_return_key | (Default = False) If True, this button will appear to be clicked when return key is pressed in other elements such as Input and elements with return key options | | bool | disabled | set disable state for element (Default = False) | | idk_yetReally | focus | if focus should be set to this | | (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | pad | Amount of padding to put around element in pixels (left/right, top/bottom) or ((left, right), (top, bottom)) or an int. If an int, then it's converted into a tuple (int, int) | @@ -16064,7 +16072,7 @@ Parameter Descriptions: | bool | auto_size_button | True if button size is determined by button text | | (str, str) or str | button_color | button color (foreground, background) | | (str or (str, int[, str]) or None) | font | specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike | -| bool | bind_return_key | (Default = False) If True, then the return key will cause a the Listbox to generate an event | +| bool | bind_return_key | (Default = False) If True, this button will appear to be clicked when return key is pressed in other elements such as Input and elements with return key options | | bool | disabled | set disable state for element (Default = False) | | idk_yetReally | focus | if focus should be set to this | | (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | pad | Amount of padding to put around element in pixels (left/right, top/bottom) or ((left, right), (top, bottom)) or an int. If an int, then it's converted into a tuple (int, int) | @@ -16121,7 +16129,7 @@ Parameter Descriptions: | bool | auto_size_button | True if button size is determined by button text | | (str, str) or str | button_color | button color (foreground, background) | | (str or (str, int[, str]) or None) | font | specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike | -| bool | bind_return_key | (Default = False) If True, then the return key will cause a the Listbox to generate an event | +| bool | bind_return_key | (Default = False) If True, this button will appear to be clicked when return key is pressed in other elements such as Input and elements with return key options | | bool | disabled | set disable state for element (Default = False) | | idk_yetReally | focus | if focus should be set to this | | (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | pad | Amount of padding to put around element in pixels (left/right, top/bottom) or ((left, right), (top, bottom)) or an int. If an int, then it's converted into a tuple (int, int) | From de383504e0e1d3b0b42d87fc1b647f2a42b988c2 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Wed, 25 Jan 2023 07:57:50 -0500 Subject: [PATCH 020/145] Error handling for when no editor has been configured --- ...rowser_START_HERE_Demo_Programs_Browser.py | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/DemoPrograms/Browser_START_HERE_Demo_Programs_Browser.py b/DemoPrograms/Browser_START_HERE_Demo_Programs_Browser.py index 60150ca8..f7c4a84d 100644 --- a/DemoPrograms/Browser_START_HERE_Demo_Programs_Browser.py +++ b/DemoPrograms/Browser_START_HERE_Demo_Programs_Browser.py @@ -5,7 +5,7 @@ import warnings import PySimpleGUI as sg -__version__ = '1.12.0' +__version__ = '1.12.2' """ PySimpleGUI Demo Program Browser @@ -36,7 +36,7 @@ __version__ = '1.12.0' 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 """ @@ -577,16 +577,16 @@ def main(): sg.cprint(f'Editing using {editor_program}', c='white on red', end='') sg.cprint('') sg.cprint(f'{full_filename}', c='white on purple') - # if line != 1: - if using_local_editor(): - sg.execute_command_subprocess(editor_program, f'"{full_filename}"') + if not get_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') else: - try: - sg.execute_editor(full_filename, line_number=int(line)) - except: + if using_local_editor(): sg.execute_command_subprocess(editor_program, f'"{full_filename}"') - # else: - # sg.execute_editor(full_filename) + else: + try: + sg.execute_editor(full_filename, line_number=int(line)) + except: + sg.execute_command_subprocess(editor_program, f'"{full_filename}"') else: sg.cprint('Editing canceled') elif event == 'Run': From 5b0f6950a32392b9f2db751abc085a709d3ccad9 Mon Sep 17 00:00:00 2001 From: PySimpleGUI <46163555+PySimpleGUI@users.noreply.github.com> Date: Sat, 28 Jan 2023 18:30:26 +0000 Subject: [PATCH 021/145] Automated Update! --- docs/Screens.md | 7 +++++++ docs/Screens2.md | 10 ++++++++++ 2 files changed, 17 insertions(+) diff --git a/docs/Screens.md b/docs/Screens.md index 04c74418..34cf4847 100644 --- a/docs/Screens.md +++ b/docs/Screens.md @@ -1,3 +1,10 @@ +[eagleEggs](https://github.com/eagleEggs) 2023-01-28T02:30:37Z + +![image](https://user-images.githubusercontent.com/29800532/215237562-60eb47d3-b5da-4880-8b38-53f33c185f74.png) +![image](https://user-images.githubusercontent.com/29800532/215237481-117ba32e-a94e-480b-9c89-8d66922b7bff.png) + +----------- + [hseera](https://github.com/hseera) 2023-01-04T23:30:35Z ![image](https://user-images.githubusercontent.com/59352356/210669262-7f74f961-5294-43b7-885e-d931d995569a.png) diff --git a/docs/Screens2.md b/docs/Screens2.md index cdef5da7..c78cf81c 100644 --- a/docs/Screens2.md +++ b/docs/Screens2.md @@ -1,3 +1,13 @@ +[eagleEggs](https://github.com/eagleEggs) 2023-01-28T02:30:37Z +PSG WOOOHOOOO. Super fast implementation of this thanks to PSG. We were able to jump straight into core code, and add new things on the fly in minutes. This is a vulnerability management / parser, scanner... and moreeeee. + +![image](https://user-images.githubusercontent.com/29800532/215237562-60eb47d3-b5da-4880-8b38-53f33c185f74.png) +![image](https://user-images.githubusercontent.com/29800532/215237481-117ba32e-a94e-480b-9c89-8d66922b7bff.png) + +Thanks again PSG <3 + +----------- + [hseera](https://github.com/hseera) 2023-01-04T23:30:35Z Using PySimpleGUI framework, I built an opernsource tool called "CloudWatch Dashboard Builder" for SRE, Performance Engineers and Operations teams, who work with AWS services. It gives them capability to build CloudWatch Dashboard from different Namespace templates. The tool lets you modify the template too. From 16aea9c37fe1ab6c2cc56e237bc51ebf24dc6b47 Mon Sep 17 00:00:00 2001 From: PySimpleGUI <46163555+PySimpleGUI@users.noreply.github.com> Date: Sun, 29 Jan 2023 18:30:26 +0000 Subject: [PATCH 022/145] Automated Update! --- docs/Screens.md | 7 +++++++ docs/Screens2.md | 14 ++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/docs/Screens.md b/docs/Screens.md index 34cf4847..86ba1e2e 100644 --- a/docs/Screens.md +++ b/docs/Screens.md @@ -1,3 +1,10 @@ +[PySimpleGUI](https://github.com/PySimpleGUI) 2023-01-29T15:31:26Z + +![image](https://user-images.githubusercontent.com/46163555/215336720-2cc04845-ecf1-4c80-8769-8d8d92026c93.png) +![image](https://user-images.githubusercontent.com/46163555/215336743-7519cbb7-d700-47b3-8c6f-b2abb29fdea2.png) + +----------- + [eagleEggs](https://github.com/eagleEggs) 2023-01-28T02:30:37Z ![image](https://user-images.githubusercontent.com/29800532/215237562-60eb47d3-b5da-4880-8b38-53f33c185f74.png) diff --git a/docs/Screens2.md b/docs/Screens2.md index c78cf81c..adb9f019 100644 --- a/docs/Screens2.md +++ b/docs/Screens2.md @@ -1,3 +1,17 @@ +[PySimpleGUI](https://github.com/PySimpleGUI) 2023-01-29T15:31:26Z +@eagleEggs I briefly saw a version of this GUI and then it disappeared. I'm THRILLED you've posted it. ![image](https://user-images.githubusercontent.com/46163555/215336720-2cc04845-ecf1-4c80-8769-8d8d92026c93.png) + +Thank you so very much for sharing your talent in using PySimpleGUI. You're such an expert now and I SO appreciate you being here since the early days. + +That's a beautiful window.... just plain beautiful! + +Your support and encouragement have been really appreciated. + +![image](https://user-images.githubusercontent.com/46163555/215336743-7519cbb7-d700-47b3-8c6f-b2abb29fdea2.png) + + +----------- + [eagleEggs](https://github.com/eagleEggs) 2023-01-28T02:30:37Z PSG WOOOHOOOO. Super fast implementation of this thanks to PSG. We were able to jump straight into core code, and add new things on the fly in minutes. This is a vulnerability management / parser, scanner... and moreeeee. From 2af2d59c4d3f04a4d3a745bf177e4d05a4e7bc08 Mon Sep 17 00:00:00 2001 From: PySimpleGUI <46163555+PySimpleGUI@users.noreply.github.com> Date: Mon, 30 Jan 2023 18:30:24 +0000 Subject: [PATCH 023/145] Automated Update! --- docs/Screens.md | 9 +++++++++ docs/Screens2.md | 21 +++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/docs/Screens.md b/docs/Screens.md index 86ba1e2e..73bcad6a 100644 --- a/docs/Screens.md +++ b/docs/Screens.md @@ -1,3 +1,12 @@ +[J-Josu](https://github.com/J-Josu) 2023-01-30T13:20:08Z + +![image](https://user-images.githubusercontent.com/92873227/215487552-cd9a9185-5ca1-4c63-8c4e-b084a1fce2e5.png) +![image](https://user-images.githubusercontent.com/92873227/215487639-4facc1ba-2c5f-430f-ac41-2cceb4f52708.png) +![image](https://user-images.githubusercontent.com/92873227/215487687-61a880c8-13f2-4641-80c9-455a8378a9a3.png) +![image](https://user-images.githubusercontent.com/92873227/215487759-278903f6-de06-4d47-b016-d0f5324ad6e2.png) + +----------- + [PySimpleGUI](https://github.com/PySimpleGUI) 2023-01-29T15:31:26Z ![image](https://user-images.githubusercontent.com/46163555/215336720-2cc04845-ecf1-4c80-8769-8d8d92026c93.png) diff --git a/docs/Screens2.md b/docs/Screens2.md index adb9f019..3d2651bb 100644 --- a/docs/Screens2.md +++ b/docs/Screens2.md @@ -1,3 +1,24 @@ +[J-Josu](https://github.com/J-Josu) 2023-01-30T13:20:08Z +Hi! I'm a stundent of Computer Science in Argentina and i`ve had to do a Final project for my Python Course. The project its about a card game where you can choose between availible themes to try to guess the correct option. The data is automtically loaded from cvs. + +Here are some screenshoots of the final result: + +![image](https://user-images.githubusercontent.com/92873227/215487552-cd9a9185-5ca1-4c63-8c4e-b084a1fce2e5.png) + +![image](https://user-images.githubusercontent.com/92873227/215487639-4facc1ba-2c5f-430f-ac41-2cceb4f52708.png) + +![image](https://user-images.githubusercontent.com/92873227/215487687-61a880c8-13f2-4641-80c9-455a8378a9a3.png) + +![image](https://user-images.githubusercontent.com/92873227/215487759-278903f6-de06-4d47-b016-d0f5324ad6e2.png) + +And other pages... + +All the ui its in spanish, but the code all written in english. +The project includes a mini-framework to build pages easly and some cli utilities. +Also the code have all the corresponding typing annotations and more interesting stuff. + +----------- + [PySimpleGUI](https://github.com/PySimpleGUI) 2023-01-29T15:31:26Z @eagleEggs I briefly saw a version of this GUI and then it disappeared. I'm THRILLED you've posted it. ![image](https://user-images.githubusercontent.com/46163555/215336720-2cc04845-ecf1-4c80-8769-8d8d92026c93.png) From e764cc07b8a609ce717b6da460e6dd6433f732d5 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Sat, 4 Feb 2023 17:45:33 -0500 Subject: [PATCH 024/145] New Demo Program - automatically save and load Input element values using User Settings API --- .../Demo_User_Settings_Auto_Load_and_Save.py | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 DemoPrograms/Demo_User_Settings_Auto_Load_and_Save.py diff --git a/DemoPrograms/Demo_User_Settings_Auto_Load_and_Save.py b/DemoPrograms/Demo_User_Settings_Auto_Load_and_Save.py new file mode 100644 index 00000000..d5e1ff32 --- /dev/null +++ b/DemoPrograms/Demo_User_Settings_Auto_Load_and_Save.py @@ -0,0 +1,55 @@ +import PySimpleGUI as sg + +""" + Demo - User Setting API to automatically save and load Input Elements + + This Demo Program shows an easy way to add saving and loading of Input elements. + + The variable keys_to_save is used to determine which elements will be saved to the user settings file. + + The function make_key returns a dictionary that's used as keyword parameters that are passed to the Input elements. Using this technique allows the Input elements in the layout to benefit from the docstrings provided by PySimpleGUI. Another approach could be to use a function that returns an Input element, but that limits the flexibility for configuring Input elements. + + Copyright 2023 PySimpleGUI +""" + +keys_to_save = ('-IN1-', '-IN2-', '-IN3-', '-IN4-') + +def make_key(key): + """ + Returns a dictionary that is used to pass parameters to an Input element. + Another approach could be to return an Input element. The downside to that approach is + the lack of parameters and associated docstrings when creating the layout. + + :param key: + :return: Dict( + """ + return {'default_text':sg.user_settings_get_entry(key, ''), 'key':key} + + +def main(): + layout = [ [sg.Text('Automatically Load and Save Of Inputs', font='_ 15')], + [sg.Text('Input 1'), sg.Input(**make_key('-IN1-'))], + [sg.Text('Input 2'), sg.Input(**make_key('-IN2-'), background_color='green')], + [sg.Text('Input 3'), sg.Input(**make_key('-IN3-'), text_color='blue')], + [sg.Text('Input 4'), sg.Input(**make_key('-IN4-'), size=5)], + [sg.Button('Exit (and save)', key='-EXIT SAVE-'), sg.Button('Exit without save')] ] + + window = sg.Window('Save / Load Inputs Using User Settings API', layout) + + while True: # Event Loop + event, values = window.read() + print(event, values) + if event == sg.WIN_CLOSED or event == 'Exit without save': + sg.popup_quick_message('Exiting without save', text_color='white', background_color='red', font='_ 20') + + break + elif event == '-EXIT SAVE-': + sg.popup_quick_message('Saving settings & Exiting', text_color='white', background_color='red', font='_ 20') + for key in keys_to_save: + sg.user_settings_set_entry(key, values[key]) + break + + window.close() + +if __name__ == '__main__': + main() From 078fc3b1d486c8d0b06fd4c7fdc04161c4e5ee95 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Sun, 5 Feb 2023 06:16:23 -0500 Subject: [PATCH 025/145] Hacked the version numbering (again... sorry!) to try to mediate the confusion about what's posted to PyPI. --- PySimpleGUI.py | 314 +++++++++++++++++++++++++------------------------ 1 file changed, 159 insertions(+), 155 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index 43ddf381..819751dd 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1,362 +1,364 @@ #!/usr/bin/python3 -version = __version__ = "4.60.4.145 Unreleased" +version = __version__ = "4.61.0.145 Unreleased" _change_log = """ Changelog since 4.60.0 released to PyPI on 8-May-2022 - 4.60.0.1 + 4.61.0.1 main_open_github_issue - prefill the "Details" using the platform module (thank you macdeport!) Fills Mac, Windows and Linux with details - 4.60.0.2 + 4.61.0.2 Fix for the "jumping window problem on Linux". Major credit to Chr0nic for his amazing "stick with it" work on this problem! - 4.60.0.3 + 4.61.0.3 Removed the previous fix attempt for jumping window on linux Added ability for Mac users to specify file_type in Browse and popup_get_file This feature must be ENABLED by the user in the Mac control panel that can be found in the PySimpleGUI Global Settings The default is this feature is OFF - 4.60.0.4 + 4.61.0.4 New location parameter option for Windows. Setting location=None tells PySimpleGUI to not set any location when window is created. It's up to the OS to decide. The docstring for Window has been changed, but not all the other places (like popup). Want to make sure this works before making all those changes. - 4.60.0.5 + 4.61.0.5 Added check for None invalid values parm when creating a Listbox element - 4.60.0.6 + 4.61.0.6 Column docstring changed to add reminder to call contents_changed if changing the contents of a scrollable column - 4.60.0.7 + 4.61.0.7 Fixed crash when horizontal_scroll=True for Listbox element - 4.60.0.8 + 4.61.0.8 Added readonly to Input.update - 4.60.0.9 + 4.61.0.9 Added Window.set_resizable - can change the X and Y axis resizing after window is created - 4.60.0.10 + 4.61.0.10 Added wrap parameter to Spin element - if True, wraps back to the first value when at the end Temp test code added for a new verification feature - 4.60.0.11 + 4.61.0.11 Fixed Spin Element docstring - readonly was not correct - 4.60.0.12 + 4.61.0.12 Output element - addition of wrap_lines and horizontal_scroll parameters Multiline element - addition of wrap_lines parameter - 4.60.0.13 + 4.61.0.13 Added Window.unbind - 4.60.0.14 + 4.61.0.14 Added (None, None) to the Window docstring - 4.60.0.15 + 4.61.0.15 Fix for continuous Graph element mouse up events when reading with a timeout=0. Big thank you to @davesmivers (THANKS DAVE!!) for finding and fixing - 4.60.0.16 + 4.61.0.16 Added platform (Windows, Mac, Linux) and platform version information to the get_versions function - 4.60.0.17 + 4.61.0.17 Added a fix for the file_types Mac problem that doesn't require the system settings to be used... let's give it a go! - 4.60.0.18 + 4.61.0.18 Added ubiquitious Edit Me to the right click menu - 4.60.0.19 + 4.61.0.19 PySimpleGUI Anniversary sale on Udemy course coupon - 4.60.0.20 + 4.61.0.20 Fix for bind_return_key - if a button has been disabled, then the event shouldn't be generated for the return key being pressed - 4.60.0.21 + 4.61.0.21 Added cols_justification for Table element - list or tuple of strings that indicates how each column should be justified - 4.60.0.22 + 4.61.0.22 Better error handling for table element's new justification list. If a bad value is found, will use the default value - 4.60.0.23 + 4.61.0.23 Additional mac filetype testing.... added more combinations that specify - 4.60.0.24 + 4.61.0.24 Added * *.* to the Mac filetypes to check for - 4.60.0.25 + 4.61.0.25 New logic for checking for the * case for Mac filetypes - 4.60.0.26 + 4.61.0.26 Docstring update - TabGroup visible parameter marked as deprecated . Use a Column element to make a TabGroup invisible - 4.60.0.27 + 4.61.0.27 Docstring update for the pin helper function that describes the shrinking of the container that it helps provide. Also added explanation that it's the elements you want to make visible/invisible that are what you want to pin - 4.60.0.28 + 4.61.0.28 Applied same Mac file_types fix to popup_get_file Removed filetypes setting from Mac Feature Control Panel - 4.60.0.29 + 4.61.0.29 Addition of enable_window_config_events to the Window object. This will cause a EVENT_WIMDOW_CONFIG event to be returned if the window is moved or resized. - 4.60.0.30 + 4.61.0.30 Made upgrade from GitHub window resizable so can screencapture the entire session - 4.60.0.31 + 4.61.0.31 Added new constant TKINTER_CURSORS which contains a list of the standard tkinter cursor names - 4.60.0.32 + 4.61.0.32 Added erase_all parameter to cprint (like the Debug Print already has) - 4.60.0.33 + 4.61.0.33 Fix popup_scrolled - was only adding the Sizegrip when there was no titlebar. It should be added to all windows unless the no_sizegrip parameter is set. popup_scrolled - added no_buttons option. If True then there will not be a row at the bottom where the buttons normally are. User will have to close the window with the "X" - 4.60.0.34 + 4.61.0.34 popup_scrolled - added button_justification parameter. Wanted to make scrolled popups consistent with other popups which have left justified buttons. But since they've been right justified in the past, want to give users the ability to retain that look. Since the Sizegrip works correctly now, it increases the changes of accidently clicking a button if it's right justified. - 4.60.0.35 + 4.61.0.35 Added default_color to ColorChooser button - 4.60.0.36 + 4.61.0.36 Added to Button element error message that images must be in PNG or GIF format - 4.60.0.37 + 4.61.0.37 Added exapnd_x and expand_y to all of the "lazy buttons" and Chooser buttons - 4.60.0.38 + 4.61.0.38 Column element - added horizontal_scroll_only parameter (fingers crossed on this one....) - 4.60.0.39 + 4.61.0.39 New signature testing - 4.60.0.40 + 4.61.0.40 Exposed the Table Element's ttk style using member variable TABLE.table_ttk_style_name - 4.60.0.41 + 4.61.0.41 New signature format - 4.60.0.42 - Backed out the changes from 4.60.0.38 (horizontal_scroll_only parameter). Those changes broke code in the scrollable columns. Need to make time to work on this feature more. - 4.60.0.43 + 4.61.0.42 + Backed out the changes from 4.61.0.38 (horizontal_scroll_only parameter). Those changes broke code in the scrollable columns. Need to make time to work on this feature more. + 4.61.0.43 Added a print if get an exception trying to set the alpha channel after a window is created (troubleshooting a Mac problem) - 4.60.0.44 + 4.61.0.44 Updated Menubar docstring to clarify the Menubar iself cannot have colors changed, only the submenus. Use MenubarCustom if you want full control Format of file-signature changed - 4.60.0.45 + 4.61.0.45 Further refinement of Menubar docstring - 4.60.0.46 + 4.61.0.46 Added suggestion of using the Demo Browser to the checklist item of "Look for Demo Programs similar to your problem" - 4.60.0.47 + 4.61.0.47 Testing some importing methods Delay rerouting stdout and stderr in Output and Multiline elements until window is being built instead of when element is initialized - 4.60.0.48 + 4.61.0.48 Additional window movement capability. If Control+Mouse movement feature is enabled, then Control+Arrow key will move the window 1 pixel in the indicated direction - 4.60.0.49 + 4.61.0.49 Added Window.set_size to match the other settings that are performed through method calls. There is also the Window.size property, but since PySimpleGUI rarely uses properties, it makes sense to include a method as well as a property - 4.60.0.50 + 4.61.0.50 Fix for ColorChooser button filling in a None value when cancel from color choise dialog box. Nothing will be filled in target if dialog cancelled - 4.60.0.51 + 4.61.0.51 vtop, vcenter, vbottom helper functions gets background_color parameter vcenter and vbottom - added USING the expand_x and expand_y parms that were already defined. (HOPE NOTHING BREAKS!) - 4.60.0.52 + 4.61.0.52 justification parameter added to Listbox (default is left.. can be right and center now too) - 4.60.0.53 + 4.61.0.53 Made settings dictionary multiline in test harness write-only. New coupon code - 4.60.0.54 + 4.61.0.54 alpha_channel added to set_options. This sets the default value for the alpha_channel for all windows both user generated and PySimpleGUI generated (such as popups). - 4.60.0.55 + 4.61.0.55 Allow Browse/Chooser buttons (that have a target) to indicate a target key that is a tuple. - 4.60.1.55 + 4.61.0.55 While not actually correct.... 4.60.1 was released in the middle of the development above... I'm changing the version to look as if this release is based on 4.60.1. This code DOES have the same code that's in 4.60.1 so it's more a matter of symantics. Hoping this clears up confusion. Sorry for the dot-release causing so much confusion. - 4.60.1.56 + 4.61.0.56 Fix for Window.extend_layout. Was not picking up the background color of the container that the rows were being added to. - 4.60.1.57 + 4.61.0.57 Fixed Text element's update method docstring to indicate that value can be "Any" type not just strings - 4.60.1.58 + 4.61.0.58 Addition of without_titlebar paramter to Window.current_location. Defaults to False. If True, then the location of the main portion of the window will be returned (i.e. will not have the titlebar) - 4.60.1.59 + 4.61.0.59 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 - 4.60.1.60 + 4.61.0.60 Addition of set_option parameter hide_window_when_creating. If set to False then window will not be hidden while creating and moving - 4.60.1.61 + 4.61.0.61 Changed the documentation location to PySimpleGUI.org (updated some comments as well as the SDK Reference Window's links) New coupon code. Make the Udemy button in the test harness now include the coupon code automatically - 4.60.1.62 + 4.61.0.62 Removed the "NOT avoilable on the MAC" from file_types parameter in the docstrings Use Withdraw to hide window during creation - 4.60.1.63 + 4.61.0.63 Addition of checklist item when logging new issue to GitHub - upgraded to latest version of PySimpleGUI on PyPI Listbox justification parameter found to not be implemented on some early verions of tkinter so had to protect this situation. This new feature crached on the Pi for example - 4.60.1.64 + 4.61.0.64 Allow set_options(window_location=None) to indicate the OS should provide the window location. This will stop the Alpha channel being set to 0 when the window is created - 4.60.1.65 + 4.61.0.65 Addition of new Mac Control Panel option and emergency patch for MacOS version 12.3+ If MacOS version 12.3 or greater than option is ON by default When ON, the default Alpha channel for all windows is set to 0.99. This can either be turned off, or can be overridden by calling set_options in your application - 4.60.2.65 + 4.61.0.65 Bumping version number to avoid confusion. An emergency 4.60.2 release was posted to PyPI. This change was added to this current GitHub version of PySimpleGUI. - 4.60.3.66 + 4.61.0.66 Fixed bug in checking Mac OS version number that is being released as 4.60.3 - 4.60.3.67 + 4.61.0.67 Correctly check for Mac 12.3+ AND 13+ this time. - 4.60.3.68 + 4.61.0.68 Roll in the changes being released to PyPI as 4.60.3 - 4.60.3.69 + 4.61.0.69 Test to see if the additional pack of Notebook in Tab code was causing expansion problems - 4.60.3.70 + 4.61.0.70 Debug Print - fix for bug caused by no_button being set with non_blocking... a lesson in thorough testing... assumption was either blocking OR no_button (or else app would close without seeing the output... unless something else blocked. (DOH) - 4.60.3.71 + 4.61.0.71 "Window closed" check added to update methods for elements. This will prevent a crash and instead show an error popup Will be helpful for users that forget to check for closed window event in their event loop and try to call update after window closed. - 4.60.3.72 + 4.61.0.72 Output element now automatically sets auto_refresh to True. Should this not be desired, switch to using the Multiline element. There will likely be no impact to this change as it seems like the windows are alredy refreshing OK, but adding it just to be sure. - 4.60.3.73 + 4.61.0.73 Addition of Window.key_is_good(key) method. Returns True if key is used in the window. Saves from having to understand the window's key dictionary. Makes for easier code completion versus writing "if key in window.key_dict" - 4.60.3.74 + 4.61.0.74 Combo - if readonly, then set the select colors to be "transparent" (text=text color, background=background color) - 4.60.3.75 + 4.61.0.75 Better description of bar_color parm for the ProgressMeter element and the one_line_progress_meter function Combo element - addition of select parameter to enable easier selection of the contents of clearing of the selection of the contents. - 4.60.3.76 + 4.61.0.76 Changed the _this_elements_window_closed to use a flag "quick_check" for cheking is the window is closed. Found that calling tkinter.update takes over 500ms sometimes! For appllications that call update frequently, this caused a catestrophic slowdown for complex windows. - 4.60.3.77 + 4.61.0.77 New Window method - get_scaling - gets the scaling value from tkinter. Returns DEFAULT_SCALING if error. - 4.60.3.78 + 4.61.0.78 Custom Titlebar - Support added to Window.minimize, Window.maximize, and Window.normal - 4.60.3.79 + 4.61.0.79 Fix for Mulitline showing constant error messages after a Window is closed. Fix for correctly restoring stdout, stderr after they've been rerouted. THIS CODE IS NOT YET COMPLETE! Shooting for this weekend to get it done! Image element - more speicific with tkinter when chaning to a new image so that pypy would stop crashing due to garbage collect not running. This change didn't fix the pypy problem but it also didn't hurt the code to have it - 4.60.3.80 + 4.61.0.80 Quick and dirty addition of Alt-shortcuts for Buttons (like exists for Menus) For backward compatablity, must be enabled using set_options with use_button_shortcuts=True Fixed docstring errors in set_options docstring - 4.60.3.81 + 4.61.0.81 Completed restoration of stdout & stderr If an Output Element is used or a Multline element to reroute stdout and/or stderr, then this hasn't worked quite right in the past Hopefuly now, it does. A LIFO list (stack) is used to keep track of the current output device and is scrubbed for closed windows and restored if one is closed - 4.60.3.82 + 4.61.0.82 Addition of Style Names for horizontaland vertical ttk scrollbars - hsb_style_name and vsb_style_name so that scrollbar colors can be changed in user code - 4.60.3.83 + 4.61.0.83 Output element - now automatically reroutes cprint to here as well. Assumption is that you want stuff to go here without needing to specify each thing. If want more control, then use the Multiline directly - 4.60.3.84 + 4.61.0.84 Output element - updated docstring - 4.60.3.85 + 4.61.0.85 Combo Element - new parameter enable_per_char_events. When True will get an event when individual characters are entered. - 4.60.3.86 + 4.61.0.86 Added path to the interpreter to the get_versions information for better debugging - 4.60.3.87 + 4.61.0.87 Dark Gray 16 theme added - 4.60.3.88 + 4.61.0.88 New batch of Emojis! - 4.60.3.89 + 4.61.0.89 Addition of TITLEBAR_TEXT_KEY to provide access to custom titlebar titles - 4.60.3.90 + 4.61.0.90 Implemented the visible parameter for TabGroup. Was not being honored when creating element. Added TabGroup.update so it can be made visible. - 4.60.3.91 + 4.61.0.91 Added support for Custom Titlebar to the Window.set_title method - 4.60.3.92 + 4.61.0.92 Addition of starting_row_number parameter to the Table element. Sets the value for the first row in the table. - 4.60.3.93 + 4.61.0.93 Added 2 parameters to popup - drop_whitespace is passed to the wraptext.fill method. right_justify_buttons will "push" buttons to the right side if set to True - 4.60.3.94 + 4.61.0.94 Added Element.save_element_screenshot_to_disk - uses the same PIL integration that the save window screenshot to disk uses but applied to a single element - 4.60.3.95 + 4.61.0.95 Changed popup again - replaced right_justify_buttons with button_justification. Also removed the extra padding that was being added to the buttons. This matches a changed made to popup_scrolled earlier - 4.60.3.96 + 4.61.0.96 More emojis? Yes... more emojis... - 4.60.3.97 + 4.61.0.97 The main test harness now shows the python interpreter used to launch the test harness to make clearer what's running - 4.60.3.98 + 4.61.0.98 Better alignment of text in test harness Fixed mispelling in SystemTray.show_message - crashed if an int was passed in as the time value - 4.60.3.99 + 4.61.0.99 popup_get_text - Addition of history feature to bring up to same level as other popup_get_ functions. - 4.60.3.100 + 4.61.0.100 Set the "Active" foreground and background colors for Menu and ButtonMenu items. Automatically uses the swapped foreground and background colors. This impacts both inside the menus themseleves as well as the ButtonMenus so that when they are used in a MenubarCustom they mouseover nicely now. - 4.60.3.101 + 4.61.0.101 Added Window.is_hidden method. Returns True if the window is currently hidden - 4.60.3.102 + 4.61.0.102 Fixed error in the main test harness "not modal" popup test. Was setting the "Force Modal" setting to true after the popup test. - 4.60.3.103 + 4.61.0.103 Trinket is detected using a new mechansim now. The previous one was waayyy too simnple and as a result has broken in the past week. - 4.60.4.104 + 4.61.0.104 Version bump to keep up with the PyPI emergency 4.60.4 release - 4.60.4.105 + 4.61.0.105 Added SYMBOL_BULLET character - 4.60.4.106 + 4.61.0.106 Neon Green, Blue, Yellow themes... was writing some tests using them and thought why not start a new theme color category... "neon" - 4.60.4.107 + 4.61.0.107 Fixed an unreported problem perhaps... Added saving new menu into the Menu.Widget memeber variable in the Menu.update method. - 4.60.4.108 + 4.61.0.108 Added drop_whitespace to the docstring for popup. Parm has been in the code for quite some time but forgot the docstring so it's not in the SDK reference. - 4.60.4.109 + 4.61.0.109 Changed error message in error window when an element reuse has been detected in a layout. Previous message wasn't clear why there was an error. - 4.60.4.110 + 4.61.0.110 Added very detailed information to popup_error_with_traceback if the Exception information is passed in as one of the arguments - 4.60.4.111 + 4.61.0.111 Menu Element - delete all items in existing Menu widget rather than making a new one when the Menu definition changes - 4.60.4.112 + 4.61.0.112 Input.update - added font parameter - 4.60.4.113 + 4.61.0.113 Dark Blue 18 theme, a materially kinda theme, added - tip - experiment like PySimpleGUI does when "computing" colors. Grab a color of a part of a theme and use it as a background or a secondary button color. In other words, mix and match since the colors should all work together by design. - 4.60.4.114 + 4.61.0.114 Added execute_py_get_running_interpreter to differentiate between the one in the settings file versus currently running interpreter - 4.60.4.115 + 4.61.0.115 Image Element... added Zooooooooommmmm parameter - 4.60.4.116 + 4.61.0.116 Proliferiation/infection of the zoom parameter to more elements with images - Button, ButtonMenu Note that zoom and subsample can BOTH be used. This enables fractional scaling. Want 2/3 the size of the image? subsample=3, zoom=2 Tab is the remaining element this is being added to The Buttons implemented as functions need this addition as well Addition of the image_source parameter to Button and Button.update. This way of specifying images is commonly used in other elements Fixed ButtonMenu bug - subsample was not being applied to initial image in the layout - 4.60.4.117 + 4.61.0.117 Fix for set_vscroll_position not working correctly for a scrollable Column - 4.60.4.118 + 4.61.0.118 Completed addition of zoom options for images by adding image_zoom parameter to Tab element - 4.60.4.119 + 4.61.0.119 Fixed Neon Yellow theme. Had an extra "#" in a color. - 4.60.4.120 + 4.61.0.120 New coupon code - 4.60.4.121 + 4.61.0.121 New Jedi emoji - 4.60.4.122 + 4.61.0.122 Swapped Push and Stretch, VPush and VStretch. Made Push and VPush the function and Stratch and VStresth the aliases. Did this because Push is used almost universally, not Stretch. - 4.60.4.123 + 4.61.0.123 Fix for incorrect values for Element.ttk_style and Element.ttk_style_name. Some elements had values overwritten if a scrollbar, etc, was used Changed a number of the ttk elements (Button for example) to use the base name as the parm to creating the custom style to achieve a more predictable naming style (relies on the formula used in the create style function rather than ad hoc adding "custom" onto name) - 4.60.4.124 + 4.61.0.124 Multiline Element docstring fixes - 4.60.4.125 + 4.61.0.125 Addition of 2 overrides to Window.find_element so that more control is available to applications wishing to perform special key lookups - 4.60.4.126 + 4.61.0.126 Made button_color parameter's docstring value consistent across all calls. Now set to - (str, str) | str - 4.60.4.127 + 4.61.0.127 User settings delete calls - aded silent_on_error option so deletes of non-existant entries can uappen silently if desired. popup_quick_message - now defaults to keep-on-top to True - 4.60.4.128 + 4.61.0.128 Cleaned up User Settings API code for porting - 4.60.4.129 + 4.61.0.129 button_color parm added to ButtonMenu.update - 4.60.4.130 + 4.61.0.130 New coupon - 4.60.4.131 + 4.61.0.131 Window timers feature added. Get a single or repeating timer events for your Window by calling window.timer_start - 4.60.4.132 + 4.61.0.132 Added the Window.stop_all method to stop all timers for a window - 4.60.4.133 + 4.61.0.133 Added Window.timer_get_active_timers to get a list of the active timers for the window - 4.60.4.134 + 4.61.0.134 popup_get_date - exposed the fonts as parameters so that the user code and modify them (specifically to get around a Mac font bug) - 4.60.4.135 + 4.61.0.135 Renamed QuickMeter to _QuickMeter so that it's clear that it's not an object meant to be used by users - 4.60.4.136 + 4.61.0.136 Tree element - if headings is set to None, no headings area is shown - 4.60.4.137 + 4.61.0.137 "Take me to error" button is disabled in error traceback popup if not editor is configured. Also adds instructions if no editor. - 4.60.4.138 + 4.61.0.138 Added begin_at_sunday_plus to the CalendarButton docstring - 4.60.4.139 + 4.61.0.139 Moved debugger constants to inside of the debugger class. Simplified the locals and globals popups. - 4.60.4.140 + 4.61.0.140 Experimental change.... Table.get now returns the values from the widget's selection method - 4.60.4.141 + 4.61.0.141 Made the Debugger's use of popups change the theme to the same dark gray theme used in the rest of the debugger windows. - 4.60.4.142 + 4.61.0.142 Added selected_text_color & selected_background_color to Input element. Will override the default values - 4.60.4.143 + 4.61.0.143 Fixed bug in Combo.update - the width of the element wasn't getting updated to match new values - 4.60.4.144 + 4.61.0.144 Added selected_text_color & selected_background_color to Multiline element. Will override the default values - 4.60.4.145 + 4.61.0.145 Fixed bind_return_key docstrings in the pre-defined buttons. Made the Button bind_return_key docstring more descriptive + 4.61.0.146 + Changed version numbers to 4.61.0 to try and fix the confusion about what's been released to PyPI. """ @@ -10836,8 +10838,11 @@ class Window: # self.TKroot.protocol("WM_DESTROY_WINDOW", self._OnClosingCallback) # self.TKroot.protocol("WM_DELETE_WINDOW", self._OnClosingCallback) Window._window_running_mainloop = self - Window._root_running_mainloop.mainloop() - + try: + Window._root_running_mainloop.mainloop() + except: + print('**** EXITING ****') + exit(-1) # print('Out main') self.CurrentlyRunningMainloop = False # if self.LastButtonClicked != TIMEOUT_KEY: @@ -22243,7 +22248,7 @@ def _error_popup_with_code(title, filename, line_num, *args, emoji=None): :param emoji: An optional BASE64 Encoded image to shows in the error window :type emoji: bytes """ - editor_filename = _get_editor() + editor_filename = execute_get_editor() emoji_data = emoji if emoji is not None else _random_error_emoji() layout = [[Text('ERROR'), Text(title)], [Image(data=emoji_data)]] @@ -22260,7 +22265,6 @@ def _error_popup_with_code(title, filename, line_num, *args, emoji=None): max_line_len = max(max_line_len, max([len(s) for s in line])) layout += [[Text(''.join(line), size=(min(max_line_len, 90), None))] for line in lines] - layout += [[Button('Close'), Button('Take me to error', disabled=True if not editor_filename else False), Button('Kill Application', button_color='white on red')]] if not editor_filename: layout += [[Text('Configure editor in the Global settings to enable "Take me to error" feature')]] @@ -23526,7 +23530,7 @@ def _create_full_editor_command(file_to_edit, line_number, edit_format_string): return command -def _get_editor(): +def execute_get_editor(): """ Get the path to the editor based on user settings or on PySimpleGUI's global settings @@ -26288,4 +26292,4 @@ if __name__ == '__main__': exit(0) main() exit(0) -#40e80a71aea2a1b41dfdcba9263cffd1ea8d8dba433feb55ec28f46041ead94584c0357919f99c17c0f55cc1270b5f742f90a6cb967060d420598da884b48952987be0aa687b06556ac829c34bf84d705ef76b6a11eefc2fd3bc808e968f6fe4aca40d643643ec2906f4a8420af6d4fce3ca585591591cce1bf067c77edd7a555f5977205bd8ed1ea55ce615dd47e1f138c54f6fe23dc14764563c00d158164c9b7daab5c5b772c90ad040133a441a45e39b66567f4b957b5db188a8155e2fe72d0c06ba927c55260d1c2e4199a86d69765872b059f5b167202fcebed340c6fd91da8d7831f7ced36886e0a5a51947aeba24f62e8a5675ec01ee0e122983bc8cc9d9c7dfc77d78708f8e889ba91676b3b183aaf8cae3ed0cf79051561a2cd692f933b5f40a17b987644978c59962ead7011f369580e30d665fd5f4860411df8fea4d1027e653da3b2e7baff69c5035a311143efba8609383af517ed23e363af68fa1a1f95a1ef3c7991b79f55634787e14e32a0c32442feaf4df13a0212754c207cb27a129fc702d206d50d90bfbd4d10d10ede5fba0dedf3ec2c0d66e4741c30033356bc5911de8395977214646517e6e94e8130b32330d0e63fb13ec8eeaee673a68e94151ed9ecb92a506e184df9c53b798277c5cb10acec0e3f2a1dafba2510687d9eaad97a79d729ce2a33b2e9229f03289c111f8f3774e89e329e76c4e \ No newline at end of file +#66c76f34d425350d8350621578fe72d8a9882f2a50c36658fd108cdaaf0c8e7d367bf50f46bb3ea2c68f490c918ad05501b46cec335066934ffdb1d97b2d5108bc8a4970ec8912c810315755aca1412410b93e98154544e374a7d72a5f71ab89eddea51281d7e8eccc02703de5632c084f77a0304cf69db30c16348524cd2d72555cba024011f8f1c0bed7a4301c53295d36cad6f49bcdc2fbaaad4f457d8e7eb9e8f7113a5424fdfe3fa4014deee5e44ad1a68916c710a21d270f8940b0d763927369c8a4b8b6f1495a884d8a1af05e4d74808e306e749279c4219b72820d9d6f87cb3065cc1a0b5e9668d776627179d3a75b9592327eaf14b31e457c5f37173a5b8a06dd9677011da86a5d40142f3249cc243e67a0060b1f0ab67128014c92d24e0798f5b90b734f325331d39c265136f8d7ae6de03a934b4e173551660415627651788b23a8784bf66264857ea27bd551950961c8a657d548324781820217e3e49f39b6177a29689d587cbda05a9a89dc1098427ec9862daafb2f5e64e16b5e6af0359c3a8f2044da1685529c271d9ffc84a8bb8fdba87557a3d4bdd1fe6855564a43d8e375e5d0b311d52fe40423bdcc466351af2b7efef19b32a17271132fbc6e565e7d3899a36dafda9cf6d81468df85af00e76f6cd73324eca2812009bc09ff10e656b16d8b004de50e6aac49e10beeac0ba054370878e71eaa3dd3ef \ No newline at end of file From 7da029ebf862722b4b780cc354b04d3284099661 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Mon, 6 Feb 2023 11:43:54 -0500 Subject: [PATCH 026/145] Fixed typo in docstring --- DemoPrograms/Demo_User_Settings_Auto_Load_and_Save.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DemoPrograms/Demo_User_Settings_Auto_Load_and_Save.py b/DemoPrograms/Demo_User_Settings_Auto_Load_and_Save.py index d5e1ff32..4a16fbd6 100644 --- a/DemoPrograms/Demo_User_Settings_Auto_Load_and_Save.py +++ b/DemoPrograms/Demo_User_Settings_Auto_Load_and_Save.py @@ -21,7 +21,7 @@ def make_key(key): the lack of parameters and associated docstrings when creating the layout. :param key: - :return: Dict( + :return: Dict """ return {'default_text':sg.user_settings_get_entry(key, ''), 'key':key} From f3270e00ecd4e3a21c6add112bdbb99848b32025 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Tue, 7 Feb 2023 07:17:07 -0500 Subject: [PATCH 027/145] And updated version of the "Edit Me" right menu design pattern --- DemoPrograms/Demo_Edit_Me_Option.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/DemoPrograms/Demo_Edit_Me_Option.py b/DemoPrograms/Demo_Edit_Me_Option.py index c05130f1..b5e4be90 100644 --- a/DemoPrograms/Demo_Edit_Me_Option.py +++ b/DemoPrograms/Demo_Edit_Me_Option.py @@ -1,7 +1,7 @@ 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. @@ -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 editor that you set up in the global PySimpleGUI options. - You need to do 2 things to make this work: - 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. - + A constant MENU_RIGHT_CLICK_EDITME_VER_EXIT, when set at the right click menu shows a "Version" and "Edit Me" meny item. + 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"')], [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 event, values = window.read() if event == sg.WIN_CLOSED or event == 'Exit': break 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() From 517262690fd009ad5cce9e0a394eef49d0d57a86 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Tue, 7 Feb 2023 11:37:05 -0500 Subject: [PATCH 028/145] New Demo Program Custom Images Dark Theme --- ...rk_Custom_Elements_Check_Toggle_Buttons.py | 96 +++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 DemoPrograms/Demo_Theme_Dark_Custom_Elements_Check_Toggle_Buttons.py diff --git a/DemoPrograms/Demo_Theme_Dark_Custom_Elements_Check_Toggle_Buttons.py b/DemoPrograms/Demo_Theme_Dark_Custom_Elements_Check_Toggle_Buttons.py new file mode 100644 index 00000000..9292e17e --- /dev/null +++ b/DemoPrograms/Demo_Theme_Dark_Custom_Elements_Check_Toggle_Buttons.py @@ -0,0 +1,96 @@ + +import PySimpleGUI as sg + + +DarkGreyFig = {'BACKGROUND': '#232429', + 'TEXT': '#828692', + 'INPUT': '#333742', + 'TEXT_INPUT': '#f7fbff', + 'SCROLL': '#505F69', + 'BUTTON': ('#fafdff', '#1d5ffe'), + 'PROGRESS': ('#505F69', '#32414B'), + 'BORDER': 1, 'SLIDER_DEPTH': 0, 'PROGRESS_DEPTH': 0, + } + +# Add your dictionary to the PySimpleGUI themes +sg.theme_add_new('DarkGreyFig', DarkGreyFig) + +# Switch your theme to use the newly added one +sg.theme('Dark GreyFig') + + +def Check(state=None, key=None): + return sg.Image(state, key=key, metadata=state, enable_events=True) + +def Toggle(state=None, key=None): + return sg.Image(state, key=key, metadata=state, enable_events=True) + +def DarkButton(state=None, key=None): + return sg.Image(state, key=key, metadata=state, enable_events=True) + +def main(): + gray_bg= '#333742' + + col_cb_layout = [ [Check(cb_blank, ('-CB-', 0)), sg.Text('Label')], + [Check(cb_check, ('-CB-', 1)), sg.Text('Label')], + [Check(cb_minus, ('-CB-', 2)), sg.Text('Label')], + [sg.Text(s=(1,2))], + [Toggle(toggle_light, ('-TOGGLE-', 0)), sg.Text('Light')], + [Toggle(toggle_dark, ('-TOGGLE-', 1)), sg.Text('Dark')], + ] + + col_left_layout = [ [sg.Text('Label')], + [sg.Input(key='-IN-', border_width=0, s=30)], + [sg.Frame('Tags', [[sg.Image(button_green_keyword, background_color=gray_bg), sg.Image(button_orange_keyword,background_color=gray_bg)]], background_color=gray_bg, border_width=0)], + [sg.Frame('', [[DarkButton(button_dark, key=('-DARK BUTTON-', 0)), DarkButton(button_darker, key=('-DARK BUTTON-', 1)), DarkButton(button_darker, key=('-DARK BUTTON-', 2))]])], + [sg.Image(submit_button) ] ] + + + layout = [[sg.Column(col_left_layout), sg.Col(col_cb_layout)]] + window = sg.Window('Dark Custom Mockup', layout, font='_ 16', border_depth=0, element_padding=(10,10),use_custom_titlebar=True, titlebar_background_color=sg.theme_input_background_color()) + + while True: # Event Loop + event, values = window.read() + print(event, values) + if event == sg.WIN_CLOSED or event == 'Exit': + break + + if event[0].startswith('-CB-'): + if window[event].metadata == cb_blank: + window[event].update(cb_check) + window[event].metadata = cb_check + elif window[event].metadata == cb_check: + window[event].update(cb_minus) + window[event].metadata = cb_minus + elif window[event].metadata == cb_minus: + window[event].update(cb_blank) + window[event].metadata = cb_blank + elif event[0].startswith('-TOGGLE-'): + if window[event].metadata == toggle_dark: + window[event].update(toggle_light) + window[event].metadata = toggle_light + elif window[event].metadata == toggle_light: + window[event].update(toggle_dark) + window[event].metadata = toggle_dark + elif event[0].startswith('-DARK BUTTON-'): + [window[('-DARK BUTTON-', i)].update(button_darker) for i in range(3)] + window[event].update(button_dark) + + window.close() + +if __name__ == '__main__': + button_green_keyword = b'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' + button_orange_keyword = b'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' + + cb_blank = b'iVBORw0KGgoAAAANSUhEUgAAACQAAAAkCAYAAADhAJiYAAAD+UlEQVR4nM2Y328bRRDHP7O354tTXYpLfsG/UMkIUNWWIiHEG38w4oEn0qoIgdqo/RPSR5vgNBfbt7vDw96eL46bGBqsfKWVvXt3u9+ZnZ2ZHeEDePToe83zDGt7FEWOtT1UPdb2gACYK78BMMYAoKqEEGJTRwgBVaWqKqbTKa//fC6r1r00+HD4WPf3DimKgiyzOFfjfQCUEBTnaozJAG0+Xf4F7z0qICKICAbBGFn0jaHX6+Gc4/TvMb+9+EVWEhp++UT39w+xWY/pdEZVVYQQEImvJGlvgmQGVV30NZGL/SzLEBF6vR5lWeK95927d7w5fiEANn24v39InueMxn/hfVSviKBoS8z28htJJQG6pACUON/c1YgI0/mManrB7u4uh59/xpvj+J4BePrtD7q9vc1oNKKu65ZMUnGSynt/o4ZU9QqZNO69J89zVJWiKHDOMR6PyfOcZ9/9qAD24fCxPniwy+npKSGE1ihBm8m70sfx/4IkoHOOLMuo6xprLc7Nef9+wmBwP2rIWouq4pxbKdn/BRFptelcPIXDr5+qLYoiDtYBDYJkNxvux6GxTV2sU9c13nu2t7cxRVEQQsB73xik+fBct0mr2Q0Radcven1snucEDyEo1mYE9CNJLWv48lwioCqoCiIGY6RxKWCtxWRmcZRFNqed5B66YyaeatMSuh2jNkttmQyANMJLVGgAUUHIMMnab4/QeuhGgO66JvkdEZCV4e62iUD0cTFGGmvAgNfoNDdjNGtCJdwtQrApp7MGkh3dGUIJd4ZQOnV3hlDC3SOU0g9jzEYcY3LEXceYciVVxayTJ98mluNYN1KISCTUHdwksUSiC5PyoE0RWhXpu8+M9x5jTLuPm8Klq1Kztvce45xrCW0aXQM3xlDXdSS0Se0sn7L0P8synHObP2XL6Bq39x5zcX7OvX4fo3IlhU3XlH9j8KoeCIho2yCg6lH1bXaa7oCqSp7nAFRVhXn16kicc5RlyWw2g7DY09TSzXUdYinhaysfDYEsy7DWkuc51tr2thFCaJ+9/uNILMBkcsrOzicU57Eq4ZtLY7KtbrtZQ0LMmbtaBu+VmCn6lnhSRFmWjMfjOA4wGo24uLjg08GgZZ8MLfW70l9PaGETaY5V2oZ47dnZ2QHg5dHPi+rH27e/i7Xf6N7eHgcHB1RVRVVVsfDgA9JsQV27NUg1FRMNl0OCWWg4z+LWDQYD5vM5Jycnna87GA6f6L3yPmVZsrW1hXOO2Wy2KM00VbHrEMJlDS1afG6Mod/v45xjMpnw/NefVheslvHFV8+0KAr6/T5FUQCxOra1tXUtIaMLDSYBnHN47/He49ycs7Mzjo9frlz7HzLiWEBTYnmBAAAAAElFTkSuQmCC' + + cb_check = b'iVBORw0KGgoAAAANSUhEUgAAACQAAAAkCAYAAADhAJiYAAAJq0lEQVR4nG2YS4wtV3WGv7X2rjrndPd9Y9+W35jnAMQjipOAL3bCwIgBSEhMAAEGoSjmOUBRwoQBUsQsSgiySGyLkFnGGSSRLYKNzVMgkAUY8bJ4deLLvfje7j59qmqvP4O9T3dfc4+0z6kqnaq19lr/+te/yrjO59yrPqKNrVMsNk4zX5ykm22R0iZBpusXCAccgLBodwUyCKtnLkCBppEyHTBN+6gcsNq9xLD8Pc9+/e/seravuXjytZ/Q+VvvZr55C/P5gimcEgbeg3VMBdwzgR+7Ve1JgYAix8zoAgyBGxAUG4CJeQKGXXIsef7/fsz+xWf45Xc/a3/g0PYb/lY33nEvJd/JyEmMRGCIhCy1qBiSgfwF24oWIwh3TJADEkbgyCfCR6QCBRbJsHKVDd8lD79m52df5dlvfNoAMsD26x7Q9s1/QrfxYnbLGaYyRxKGYylTZNW5AEv5OoEOTCATAwEGcmcSmGCdS1lGPmM3RMrOsiROzRacvVWs9j6snac/bxngzPnXMtt8KZevzhlTInKHeUJABOAJSUwARdc4cvwjC/BmH3C8/scczBBOkLEEKwyX2C8zTmzczA23vYadpyG/6FWf1Oapl7E3nEbdGbBcoyAjECGICMwMzy/E4QvOzSEKqIGaQKbmeq4uCmIUfZ9J3RZRlgzMWLzoFgByv3EjPttmmDaQb2AOpaimLDkpgaKdY0RM13FH7UwkW6ephkquWonqAEguYpzo6BgHQ3KmNGPK59i+8BnlvHGaMc2BxME04N4TqubcwGwNThElSH6EoSNoRzsL0AQ4KQwERYZ7ajsQUQY2FzOmETqHpBkRm7jfzKy/Dd/YOscwGRMiz6qxLhk5GxFQSt17ShURJh2umk9V8lkfNxAF9bKMI2YQZHNWy1XFJjASeDdnbw9yd4acuy3kfb0pCrhRVHdnFQhIQAFHR+wjwwRmxxInpzS8hR356V7LOcaCPOMJJgvCQRRMI31OzBcbZPMZQUciUaQKxMYlWuPhWDWZGZJwDFpKD53GSObIQFHIyQhr+DOn7zOaGpt71Ai2AMsTJMfxGUYP6irpUduBLA5/ZTpcgapBC/D1cXPeYJoGZsnoFMwtKPsX6X2JdMBQDggrDXyOwrHI9deMlBLuaUbQAxkrjsxBXtuDvIXeWhVZA29dkiGto1MjOe8cjz3meo5TeYc3/9l5+ukXdHGVnITaJgLDZVg4KaqtlDrcU1exqASkWqrHHVC6ZlnUTqG2aMtUMca0oouLbNiPeOB9t/Cpj8J73nEnc79ItqFG/ljnSQqSIEUiM8PloqggP8JD4zJcR8vWax0nA6Pgx1a2AxZ+mYX9lk/85V9wz5/C3OGdb9/k9a9+JcPe8vA5Wj/PBXJEbdpZPlJirK3UrLXD5tjRRg6PTWqVFeCBKQ53kbnMIv2cv7r/Tdx7oVJGFHj8CfjJM79lMTvLEE4QtYoxZIliwqwQDlkuQhPJArN8SHAex0JF4DaRWOGxi1kBWyD6ltaJxFXmtsMD77vAffdAaTz0xFPwhYceZVleQaR8jE0DMFyVNGVQKHgpI+5QIg4BXJRINLzgSAVNu5Th57z/Xbfy0Q/ewWb+FQw79Hkgc5kT6Vk+/oG7eOufGxqr3S8/CZ9/+GusuJNIZynWEe6UVhe1HUF2x5qOylDzqNIItTHrpCAZFBX6TogV733363n7W2Bh0JU/4pEvPkqUJXCFj91/D2++YJQBcg//8RX4wpee4upwI8rnCRbIjMkCUdOevNoyVXpxgbtqyVXFVxAFT0FQ8FkibEWJfRY9nJhBJ+gC3nYBPnn/XZy37/M3H7qb++42YgAy/OdX4MFHnmR3dR6b38RBZA5UGDUSFUGsZZKsEDYSNhBeyFDDVRowNRW6vidyYjUOyERKHWUa+Ld//RpnZ3/MfW/MdMBb3nSS173y/Zy7AaYCluCxr8Ln/uUJVul2BjvNMHaEp9obtY6OYzioIIli60IK3NQKuWnieT9jtZpwd4xE8p7V0pjKKWS388+PPMljj9eyLQHb2zAWGASPPg7/8NA3WfodrOwGVrZB8Yx1zhhBhHAlXN7Kv8pio9lSh1uoiimvhT2OQecdpYgIg5Lp+pNELNgbtrgy3sTnHv4yj34Dlg57wJDhv5+CB7/0TVbcxIpzLKODnJHBajWSPJEtY01OVnKt+jzR4axBHa0dyJHXLp8Mhsno+4TGWqC5c4o22dMNRO757ENPcWl8A3e/Eb7+Lfinh79NSbcxcIKS5qBg0kifO9wS07LQ9+ka1Vst128VCBWy0citNcjkMEWQkjOOVTYoYDCwnCicAO8ZSuKhf/8p3/vp7XznOz9gn20iThN0GM4YI33fMwwDs9xjPUwjrGcEHXNMAVKd33IZD/Buqro5GYWpifqqYxp/gYlJVcSvItOlc1zeX/LY4zukdB7PJ4jSKC8KnWc0BdkSMQmTkR2MoEhIqcnj+uyURigrcgz79FuFJcEYUdFfi7J2eedQGyFHEUCi0GPWE9qszsuq9k5qMs6v6Yv1eWBWpbCnVAcYQcpBNrFaXiHH8DyzNJCmicIca4JpXXVB7bqu5mok7FCYpdrjBCLQYR6qjDWBXBwHjtrmitcRK3kgBrCJ1bDEh+VFOu1BOSAjTI7rkEKrEOOo3beR8ciAOYERMsKqyL12Wqv3V4EHgfBcJxAzkXKgckCKA2LYJ6/2/xfXFRJzVAZMs6p90nF1XoCpht8ds0Ssx2kLCmCqjbOsc6R1vtoYdJhCx60SaXbhMdL7wIwDxr3L+Gr/Ocr4O2a5gKaj1whtrrKWuCMsrN0MpDZlUBtmpHUxXwOe9p963b3e7wQuYdPAPBVi9Tv2nv8V/twPHrRLF3+J+0j2AEozaJgSLkhyLDosZkg9KDVnwMKwMMTUIlkrytYzkHJTmy1CFCgDSSIpyDGRyx6/f+6HXPnhP9bZ/tLOjzh57iVszDqWEWAbtPcQhwLM1dWqC1BSi1zBzeuoQzk06tRmbS1tR4p1QjGRTCQ5HQfM0xV83OHyztOwtnrpe39vmzl06yvuxbqXc2BnET0ljKIOI4NPpMYBIjCbmsMFM3ArIMNjjlQrJ2xoYrvKVAO6VEmjsyVbeQ/t/YxfPPM/XHr6QTuW8KPPy9/6RfUnX8xi8wyiY5wy8p5Qj1Qrpd74gjcf6/dHYW3ALJhPYBMFVeIN0WXHpn3y9DxXL/6Yn/zXh67x4bqv1QC27/prLbbOMZudwtMmudvA04z5fN7w1cCqNhK1xIhVwxJIhYhgnFaM44ooBwzDLlcu/4aL37r+K73/B5zgYwlrSVHkAAAAAElFTkSuQmCC' + cb_minus = b'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' + toggle_light = b'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' + toggle_dark = b'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' + submit_button = b'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' + + button_dark = b'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' + + button_darker = b'iVBORw0KGgoAAAANSUhEUgAAAGsAAAA2CAMAAAD3cZcXAAACuFBMVEUfIiscHSEkJy4gIyohJCsjKC4kJjIeISghJC0jJi0gIywjJi9FSVRKTllMUFt8f4tydIBzdoJrbnl6fIh4e4Z9gIuDhpB8f4pucXwiJjF7fop/go2ChY97fodsb3p4eoV6fYh/gYyChY58fYdRVWBWWWROUlxsb3mFiJFVVmBcXWdUVWBSUl1aW2ROT1gdISp8foloa3R7fYhpbHVucXt1d4NWWWNdYGp7fYlgYWokKDF8f4l3eoR3eoVfYm1sbnlhY207PURSVF1tbngiJi9ZXGZhY24+P0YmJy0nKC4lJyxAQUdHSlVucXpiY246O0IoKS8pKzEyMzlMTVYvMDZJS1R7foh1eYI/QUc9PkVdYGtvcXs8PkMkJSpoaXN6fIZBQkl3eIJ9f4oeHyMfICQpKi9maHJtcHl2eINLS1MrLDI2Nz2Fh5EkJzBPUVc9PkNGR05BQ0pmaXNucHo7PUNNTVVoaXRISVBnaHOHiJOChI55e4VAQUhnanQ+QEc6PEJRUlqGh5J+f4lzdX8xMjgsLjQhIic8PURGR09MTlVnaHJTVmBYW2VYWmZXWWRZWmNfX2lHSlIiJS6Ago19foiFh5I6O0FkZ3IjJCl1d4JIS1NdYGmDho96e4UnJy81Nz0sLTJvcnwnKS55e4Z7fol9f4liZ21+gYyBhI5sbHZvcX1tcXttcXpwdH5pbHd4eYMwMjdlaHRtcHssLjNJTVdWWGNNUFhqb3iHiZNeYGx6fIdvcn1zdYFhZG50eIIcIyuBhI9maXGDhY6EhY+DhI+EhpJKTFh5e4d5fIZ2eoGAg4xLT1pTV2B/goxzd4B0doFOUV1VWGOHiZSGiZNdYmpfZm5/g41kZ3EhIy8gJSseIykfIywjJzBMT1ofJCpKTVdOUVtISlQdJCwlKC8fIikkJCwdICkAAACsCdXOAAAA6HRSTlP///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////8Asi2gugAAAwJJREFUeJzdmAdTE1EQx7OJSonlrxRRo2KvWFAsIAqWE1tERQRRQcWKWLGhYhcVFAWxgdjF3rBi7xV7x240X8P37iCEGaIzN8kbx525293bffebN2/fldWYi0VDjhGtzkJQVDkHgYpEZ8VyLIlJeQvL4SgmRSwRKA5jrApiWE6cJQbFJqYxOwtkiUKRk0CWi0AWaVz/U5awMmQsvUCWONQ/w6poK1DJ9pjK6lhVULXsQDW42RrjDg9VLE9ULzvgBdgYUqMmaqliGVC77EAd1LU1xhv1VLHqo0Epv2GjxorRBE2JmjVvURJq6dNK1q3b2IXV1heAdztutmcsP+b5dVBCHTsxx7czs/wD7MHqAkW8ZFZgoOJ15aFuCAruHhyEHkQ97TGvXpB6h/Tp209Cf6IBgHFg6KDBRmAIkQ+CwlhGWBCGknO4PeY1LEJWkRhOFAWM4M5II0YRRSNSDsVgNNEYlSxDqfUay47YcRLGE02AMVa+FoGJNAmYLDtxmELxvnZhTZ02fYbElmgm0ayimVAC22izgTlzuczDfHJVu16J1qwFvBSkhRIWcVaScnExYy2BRZaSXm0dJmKZxV7OamPFylWUzFlRxfOKAFavAdampK5bn5a2YSOlByBDFcuATRY7E5tlnYwtvOaNW2UvCdtoO5BleQf6q31uZGNHTglrJ1e7JM7aDcRwb48RWUR7sU9O2Z95gCgcuapYB5Fx6HDUkaPHjhOdgHQyNCSBFccpotNsfyXl5cWx/XWGKAVwO0vn2GY/T6S2Ni5YFv0iUb5suAMMfAm4rARSed6VoqyrRNc8cF0V68bNW7fvGLKzPXPvMi86H/fu04OHj4geFzyhp/zuz5TE576ZL14WvOLm6zdvVbFIp9O/S3//ofAjd7T0iavP/FTIji9fv5U15vsf7vevfG/YnfVDIEsrkBUvkCXyG1vkv4PAQhT4X6kVyNJpzDl/z7KPCO6lmAXtZpO43pde6bOZRLDE9SrJqgf707Ekk3W/12z+5eqgp7CLqRjxG7LsF9Z68qMOAAAAAElFTkSuQmCC' + main() From e047ffe684e51ddd0e6da8d4ca5a0d5ca1b83e87 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Tue, 7 Feb 2023 18:32:38 -0500 Subject: [PATCH 029/145] New Udemy Coupon Code --- docs/cookbook.md | 4 ++-- docs/index.md | 4 ++-- docs/readme.md | 4 ++-- readme.md | 4 ++-- readme_creator/markdown input files/1_HEADER_top_part.md | 4 ++-- readme_creator/output/index.md | 4 ++-- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/cookbook.md b/docs/cookbook.md index 2205af6e..53b73cc3 100644 --- a/docs/cookbook.md +++ b/docs/cookbook.md @@ -25,9 +25,9 @@ apply coupon for discount: - 266B9C51C90B3728782E + 07860559FF2298EF51E7 - diff --git a/docs/index.md b/docs/index.md index b851cf66..0b954e7f 100644 --- a/docs/index.md +++ b/docs/index.md @@ -25,9 +25,9 @@ apply coupon for discount: - 266B9C51C90B3728782E + 07860559FF2298EF51E7 - diff --git a/docs/readme.md b/docs/readme.md index bb87045c..740737f9 100644 --- a/docs/readme.md +++ b/docs/readme.md @@ -9,8 +9,8 @@ PySimpleGUI Udemy Course -
apply coupon for discount:
266B9C51C90B3728782E
- click here to visit course page +
apply coupon for discount:
07860559FF2298EF51E7
+ click here to visit course page diff --git a/readme.md b/readme.md index bb87045c..740737f9 100644 --- a/readme.md +++ b/readme.md @@ -9,8 +9,8 @@ PySimpleGUI Udemy Course -
apply coupon for discount:
266B9C51C90B3728782E
- click here to visit course page +
apply coupon for discount:
07860559FF2298EF51E7
+ click here to visit course page diff --git a/readme_creator/markdown input files/1_HEADER_top_part.md b/readme_creator/markdown input files/1_HEADER_top_part.md index 502b40f0..c7ba309d 100644 --- a/readme_creator/markdown input files/1_HEADER_top_part.md +++ b/readme_creator/markdown input files/1_HEADER_top_part.md @@ -52,9 +52,9 @@ HOW DO I INSERT IMAGES ??? apply coupon for discount: - 266B9C51C90B3728782E + 07860559FF2298EF51E7 - diff --git a/readme_creator/output/index.md b/readme_creator/output/index.md index b851cf66..0b954e7f 100644 --- a/readme_creator/output/index.md +++ b/readme_creator/output/index.md @@ -25,9 +25,9 @@ apply coupon for discount: - 266B9C51C90B3728782E + 07860559FF2298EF51E7 - From 800decc53f7d12b4ca7edfc720a08e325af24205 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Tue, 7 Feb 2023 18:32:44 -0500 Subject: [PATCH 030/145] Update PySimpleGUI.py --- PySimpleGUI.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index 819751dd..078466c3 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -359,6 +359,8 @@ _change_log = """ Fixed bind_return_key docstrings in the pre-defined buttons. Made the Button bind_return_key docstring more descriptive 4.61.0.146 Changed version numbers to 4.61.0 to try and fix the confusion about what's been released to PyPI. + 4.61.0.147 + New Udemy coupon code """ @@ -26124,7 +26126,7 @@ def main(): elif event == 'Get Text': popup_scrolled('Returned:', popup_get_text('Enter some text', keep_on_top=True)) elif event.startswith('-UDEMY-'): - webbrowser.open_new_tab(r'https://www.udemy.com/course/pysimplegui/?couponCode=266B9C51C90B3728782E') + webbrowser.open_new_tab(r'https://www.udemy.com/course/pysimplegui/?couponCode=07860559FF2298EF51E7') elif event.startswith('-SPONSOR-'): if webbrowser_available: webbrowser.open_new_tab(r'https://www.paypal.me/pythongui') @@ -26132,7 +26134,7 @@ def main(): if webbrowser_available: webbrowser.open_new_tab(r'https://www.buymeacoffee.com/PySimpleGUI') elif event in ('-EMOJI-HEARTS-', '-HEART-', '-PYTHON HEARTS-'): - popup_scrolled("Oh look! It's a Udemy discount coupon!", '266B9C51C90B3728782E', + popup_scrolled("Oh look! It's a Udemy discount coupon!", '07860559FF2298EF51E7', 'A personal message from Mike -- thank you so very much for supporting PySimpleGUI!', title='Udemy Coupon', image=EMOJI_BASE64_MIKE, keep_on_top=True) elif event == 'Themes': @@ -26292,4 +26294,4 @@ if __name__ == '__main__': exit(0) main() exit(0) -#66c76f34d425350d8350621578fe72d8a9882f2a50c36658fd108cdaaf0c8e7d367bf50f46bb3ea2c68f490c918ad05501b46cec335066934ffdb1d97b2d5108bc8a4970ec8912c810315755aca1412410b93e98154544e374a7d72a5f71ab89eddea51281d7e8eccc02703de5632c084f77a0304cf69db30c16348524cd2d72555cba024011f8f1c0bed7a4301c53295d36cad6f49bcdc2fbaaad4f457d8e7eb9e8f7113a5424fdfe3fa4014deee5e44ad1a68916c710a21d270f8940b0d763927369c8a4b8b6f1495a884d8a1af05e4d74808e306e749279c4219b72820d9d6f87cb3065cc1a0b5e9668d776627179d3a75b9592327eaf14b31e457c5f37173a5b8a06dd9677011da86a5d40142f3249cc243e67a0060b1f0ab67128014c92d24e0798f5b90b734f325331d39c265136f8d7ae6de03a934b4e173551660415627651788b23a8784bf66264857ea27bd551950961c8a657d548324781820217e3e49f39b6177a29689d587cbda05a9a89dc1098427ec9862daafb2f5e64e16b5e6af0359c3a8f2044da1685529c271d9ffc84a8bb8fdba87557a3d4bdd1fe6855564a43d8e375e5d0b311d52fe40423bdcc466351af2b7efef19b32a17271132fbc6e565e7d3899a36dafda9cf6d81468df85af00e76f6cd73324eca2812009bc09ff10e656b16d8b004de50e6aac49e10beeac0ba054370878e71eaa3dd3ef \ No newline at end of file +#753c3cc3e8af2d597bd5a08789e25369e99425377e65d1d52d4e330a7ab3f28b9f3437473c786e76333f8cb40396e30e906f346d0fde4ab86b6a518446115f06a63eadd521a0b2cf1825e1daabbe1e837590b9daa2f7c3b5588370032afa4df52779710ede2cb3da6aad71a6fca8b65d15ecd91fa73d05d3ff90288af2e4ba44ce3c83483680f5f5172eae92d49497b3460c5b2376e0d903f7c6cd5637690f7a57d2c2cf55669cfee92259a8c570ff0bd1fa0f04a2d2d4a6624aec44d96ba1e04d5c919d56b49cd5b18c648011aa9c2aa0f68cbd37982e71c7c1cf3f129c3276e70b5480f15d488c72a002bb15b6ab3a0698341175c5ca2c289f94fc6ae99724d9abc5c41b7e010423775e3e06da28e06b62b3932414b1208659c0f14d9834234de2e424b2fd1ccfcdd49f1351112eec7b60e842a91a76301aa830bfa46ab5c1468a47f1d47c99ba8e0b7171f169455785c8de71f6997e6fcb19fcccfdcf58a2a5782f538dc6f15c42bf18e2ae216efb235d95f7daafdf2d2c0ef760ebe5fd908dcd96ed2d9d04d4ddff0efcc60157b88bb37cce44728019b338e409c185f44080fc0eef7b909542d61feb85e27407a4e59377d21cdda1d42468a4952fb9c06fcd5987dc80c34059eff622e138cdf7718c287d41f0c63a8c7c521d7e0f5566c7f6b3c7861a2499a158442215cfa344b1601bdc280bee34cf7bbaafd3770f4502 \ No newline at end of file From dc84814eb28a167e4c93758917aa77f2f7bc7154 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Tue, 7 Feb 2023 19:14:36 -0500 Subject: [PATCH 031/145] 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. --- docs/call reference.md | 4 ++-- readme_creator/markdown input files/5_call_reference.md | 4 ++-- readme_creator/output/call reference.md | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/call reference.md b/docs/call reference.md index 77b324bb..ab0a24fe 100644 --- a/docs/call reference.md +++ b/docs/call reference.md @@ -25,9 +25,9 @@ apply coupon for discount: - 266B9C51C90B3728782E + 07860559FF2298EF51E7 - diff --git a/readme_creator/markdown input files/5_call_reference.md b/readme_creator/markdown input files/5_call_reference.md index b32f61e2..dd84cc90 100644 --- a/readme_creator/markdown input files/5_call_reference.md +++ b/readme_creator/markdown input files/5_call_reference.md @@ -25,9 +25,9 @@ apply coupon for discount: - 266B9C51C90B3728782E + 07860559FF2298EF51E7 - diff --git a/readme_creator/output/call reference.md b/readme_creator/output/call reference.md index 77b324bb..ab0a24fe 100644 --- a/readme_creator/output/call reference.md +++ b/readme_creator/output/call reference.md @@ -25,9 +25,9 @@ apply coupon for discount: - 266B9C51C90B3728782E + 07860559FF2298EF51E7 - From a059d92c8e277828bf6429a0408006df377e2c14 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Sat, 11 Feb 2023 09:08:50 -0500 Subject: [PATCH 032/145] Added a lambda example --- DemoPrograms/Demo_Dispatchers.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/DemoPrograms/Demo_Dispatchers.py b/DemoPrograms/Demo_Dispatchers.py index 7b9e3987..2084e9b3 100644 --- a/DemoPrograms/Demo_Dispatchers.py +++ b/DemoPrograms/Demo_Dispatchers.py @@ -12,6 +12,7 @@ * If-Else * Dictionaries * 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 @@ -22,7 +23,7 @@ event loop rather than functions, then do it in the event loop. http://www.PySimpleGUI.org - Copyright 2021 PySimpleGUI + Copyright 2021, 2022, 2023 PySimpleGUI """ import PySimpleGUI as sg @@ -76,7 +77,7 @@ def main(): [sg.Text('Status:'), sg.Text(size=(3, 1), key='-STATUS-')], [sg.Text(size=(50, 1), key='-OUT-')], [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) From a138621f9a13dce8d42f2d17c178444adcc4340d Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Sat, 11 Feb 2023 13:58:57 -0500 Subject: [PATCH 033/145] Removed print when Mac Alpha Channel of 0.99 is applied. Was accidently let in for testing. --- PySimpleGUI.py | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index 078466c3..0c81a882 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -version = __version__ = "4.61.0.145 Unreleased" +version = __version__ = "4.61.0.148 Unreleased" _change_log = """ Changelog since 4.60.0 released to PyPI on 8-May-2022 @@ -361,6 +361,8 @@ _change_log = """ Changed version numbers to 4.61.0 to try and fix the confusion about what's been released to PyPI. 4.61.0.147 New Udemy coupon code + 4.61.0.1478 + Removed the print when the Mac Alpha Channel 0.99 patch is applied """ @@ -26273,14 +26275,9 @@ if running_windows(): _read_mac_global_settings() if _mac_should_set_alpha_to_99(): - print('Applyting Mac OS 12.3+ Alpha Channel fix. Your default Alpha Channel is now 0.99') + # Applyting Mac OS 12.3+ Alpha Channel fix. Sets the default Alpha Channel to 0.99 set_options(alpha_channel=0.99) -# if running_mac(): -# print('Your Mac patches are:') -# print('Modal windows disabled:', ENABLE_MAC_MODAL_DISABLE_PATCH) -# print('No titlebar patch:', ENABLE_MAC_NOTITLEBAR_PATCH) -# print ('No grab anywhere allowed with titlebar:', ENABLE_MAC_DISABLE_GRAB_ANYWHERE_WITH_TITLEBAR) -# print('Currently the no titlebar patch ' + ('WILL' if _mac_should_apply_notitlebar_patch() else 'WILL NOT') + ' be applied') + # -------------------------------- ENTRY POINT IF RUN STANDALONE -------------------------------- # if __name__ == '__main__': @@ -26294,4 +26291,4 @@ if __name__ == '__main__': exit(0) main() exit(0) -#753c3cc3e8af2d597bd5a08789e25369e99425377e65d1d52d4e330a7ab3f28b9f3437473c786e76333f8cb40396e30e906f346d0fde4ab86b6a518446115f06a63eadd521a0b2cf1825e1daabbe1e837590b9daa2f7c3b5588370032afa4df52779710ede2cb3da6aad71a6fca8b65d15ecd91fa73d05d3ff90288af2e4ba44ce3c83483680f5f5172eae92d49497b3460c5b2376e0d903f7c6cd5637690f7a57d2c2cf55669cfee92259a8c570ff0bd1fa0f04a2d2d4a6624aec44d96ba1e04d5c919d56b49cd5b18c648011aa9c2aa0f68cbd37982e71c7c1cf3f129c3276e70b5480f15d488c72a002bb15b6ab3a0698341175c5ca2c289f94fc6ae99724d9abc5c41b7e010423775e3e06da28e06b62b3932414b1208659c0f14d9834234de2e424b2fd1ccfcdd49f1351112eec7b60e842a91a76301aa830bfa46ab5c1468a47f1d47c99ba8e0b7171f169455785c8de71f6997e6fcb19fcccfdcf58a2a5782f538dc6f15c42bf18e2ae216efb235d95f7daafdf2d2c0ef760ebe5fd908dcd96ed2d9d04d4ddff0efcc60157b88bb37cce44728019b338e409c185f44080fc0eef7b909542d61feb85e27407a4e59377d21cdda1d42468a4952fb9c06fcd5987dc80c34059eff622e138cdf7718c287d41f0c63a8c7c521d7e0f5566c7f6b3c7861a2499a158442215cfa344b1601bdc280bee34cf7bbaafd3770f4502 \ No newline at end of file +#117ed542710a8b85aedee26a97f02052f1ebae317e9016c3657faebee46d06cf821ca4d2d12fe6187ddbf37233bdcdac3adf87e0f3ef9d631f050f490d1255d3efed2a062cdd03e806cb5d986b86ae588114b51c7018ee869e2b0b606ffdc16e7cc65342c5b12a1ff53a80d0aa477b050e18f3c9ce734748f1273fff1b55d860d0003ddc4a760bdb5ec888c9c394b51286cbd1805b5807bf709581f724ac8fed75a4e5a263a9172bacc12a4992ce6ed4bca58c9c9199c41d95fc20916287d60d6b6a0f0f016ae86d751e541efe2163b46bbe6a4f2ca5b713064b0de324b448fea9474f857c8a09a1955c347e620d0a7b2e4a78664e1a204871cce8f4336affb30eff2fdbc960f24b0912e5872cfc355273dbe401efcb059f9d660a308d05079bb9d6f03b5b5705e9ab21a6b626076eac07954458a75c6fd1ca2cdc08a387e7b1f732a952ad04889c402a4e7450096009c07c59765084a6f76e353c182876869a18aa3aeee2d2f4d826de913b787f9fc5ab74c1e281d180fe83bfc5fb14102553e7e4532f70d7887125daa387a79f957eddbe094e393c277a2eef2a9524f663e536274b724cb4c06a22095edc84d481b4b0896ac099dc89ceec14bc4601ddcb77b70ebe2135b671d256ebcec80f91b42281fb2d5649221673cadc1092d568d4eeca04d4c41ce72eac9b0de2044f6ccdc7034531de0f13cabd70481057758a26d5 \ No newline at end of file From 282559db4679a0a41d0b4bbf092f731d74d36ce7 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Sun, 12 Feb 2023 11:52:33 -0500 Subject: [PATCH 034/145] Removed second print on Mac for Alpha 0.99 patch --- PySimpleGUI.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index 0c81a882..c16155f3 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -version = __version__ = "4.61.0.148 Unreleased" +version = __version__ = "4.61.0.149 Unreleased" _change_log = """ Changelog since 4.60.0 released to PyPI on 8-May-2022 @@ -361,8 +361,10 @@ _change_log = """ Changed version numbers to 4.61.0 to try and fix the confusion about what's been released to PyPI. 4.61.0.147 New Udemy coupon code - 4.61.0.1478 + 4.61.0.148 Removed the print when the Mac Alpha Channel 0.99 patch is applied + 4.61.0.149 + Removed second print when Mac patch applied """ @@ -23629,7 +23631,7 @@ def _mac_should_set_alpha_to_99(): platform_mac_ver = platform.mac_ver()[0] mac_ver = platform_mac_ver.split('.') if '.' in platform_mac_ver else (platform_mac_ver, 0) if (int(mac_ver[0]) >= 12 and int(mac_ver[1]) >= 3) or int(mac_ver[0]) >= 13 : - print("Mac OS Version is {} and patch enabled so applying the patch".format(platform_mac_ver)) + # print("Mac OS Version is {} and patch enabled so applying the patch".format(platform_mac_ver)) return True except Exception as e: warnings.warn('_mac_should_seet_alpha_to_99 Exception while trying check mac_ver. Error = {}'.format(e), UserWarning) @@ -26291,4 +26293,4 @@ if __name__ == '__main__': exit(0) main() exit(0) -#117ed542710a8b85aedee26a97f02052f1ebae317e9016c3657faebee46d06cf821ca4d2d12fe6187ddbf37233bdcdac3adf87e0f3ef9d631f050f490d1255d3efed2a062cdd03e806cb5d986b86ae588114b51c7018ee869e2b0b606ffdc16e7cc65342c5b12a1ff53a80d0aa477b050e18f3c9ce734748f1273fff1b55d860d0003ddc4a760bdb5ec888c9c394b51286cbd1805b5807bf709581f724ac8fed75a4e5a263a9172bacc12a4992ce6ed4bca58c9c9199c41d95fc20916287d60d6b6a0f0f016ae86d751e541efe2163b46bbe6a4f2ca5b713064b0de324b448fea9474f857c8a09a1955c347e620d0a7b2e4a78664e1a204871cce8f4336affb30eff2fdbc960f24b0912e5872cfc355273dbe401efcb059f9d660a308d05079bb9d6f03b5b5705e9ab21a6b626076eac07954458a75c6fd1ca2cdc08a387e7b1f732a952ad04889c402a4e7450096009c07c59765084a6f76e353c182876869a18aa3aeee2d2f4d826de913b787f9fc5ab74c1e281d180fe83bfc5fb14102553e7e4532f70d7887125daa387a79f957eddbe094e393c277a2eef2a9524f663e536274b724cb4c06a22095edc84d481b4b0896ac099dc89ceec14bc4601ddcb77b70ebe2135b671d256ebcec80f91b42281fb2d5649221673cadc1092d568d4eeca04d4c41ce72eac9b0de2044f6ccdc7034531de0f13cabd70481057758a26d5 \ No newline at end of file +#4bd4c2928c05ef62f978ee22c0209c8ce6661bc7f6757237b0fdc8d554f00ae326998ad0aec28c7011c2d089538791ad29f95dd658f9971230bfd5a9075fa230a8e7f1bcd8cb6cce0b47cfb9f71f7869b1f69ef96d70abbc89f64b9b2a59c55900f7dd047d2c26dd161b3984eeea41d503ed28762002688104d33839ab836bef661fd4afe7130d7351e64f7159227a4dec589fac243fa62153924bc1d549a85831e06780c607c17547eea96ee3edc33cd8d3daefa187917be115febb2179cab1cda0fe66113183a9c8be79689e4ddab15756afe9bd66febbf90246e8f6e6e721e46c85f82f6918ac3b0557c7d3439d0ec136b28fc8cf2e469cebdc00ffe39e48098b119ba5fbbfebf69f1840beff08b6a49587ea4df954f5b0425b3c0a73429932022bacdf5ba625c52d5064415446656f45cd87cda0dc1a414ad9d4c4ff8ca213a7ccd5d9bb07652d39c558454eedd89a7158bb8cd431d9c35c7c9588f5a74ee23ccbf7d0adecd5aea293c28482e150a064a68ce7bc226159d385ab7b07b7245deb4f9182de0aebbfeb8ae23224ec761f4b76ee4c2dd6c8227913a82d462e094a39c99a1ac5c352a14ec0678eb75132754ff4128e257ef1cea33f6705cb0ab6317e90c59cc35eef24c63e6e6f45f30573038619d5f930f2880f2518b7fbc7b11dd893ef2ac08208e0ddd598631d888c695237be60d4b01b9551889b86d3ad64 \ No newline at end of file From c963e86d3e4058b51d3da7b52880b75412576bec Mon Sep 17 00:00:00 2001 From: PySimpleGUI <46163555+PySimpleGUI@users.noreply.github.com> Date: Sun, 12 Feb 2023 18:30:19 +0000 Subject: [PATCH 035/145] Automated Update! --- docs/Screens.md | 6 ++++++ docs/Screens2.md | 9 +++++++++ 2 files changed, 15 insertions(+) diff --git a/docs/Screens.md b/docs/Screens.md index 73bcad6a..8fb2e9ad 100644 --- a/docs/Screens.md +++ b/docs/Screens.md @@ -1,3 +1,9 @@ +[PySimpleGUI](https://github.com/PySimpleGUI) 2023-02-08T22:16:35Z + +![image](https://user-images.githubusercontent.com/46163555/217663277-1e69dfcf-c816-4930-aada-610b157eaf0a.png) + +----------- + [J-Josu](https://github.com/J-Josu) 2023-01-30T13:20:08Z ![image](https://user-images.githubusercontent.com/92873227/215487552-cd9a9185-5ca1-4c63-8c4e-b084a1fce2e5.png) diff --git a/docs/Screens2.md b/docs/Screens2.md index 3d2651bb..47c8afa2 100644 --- a/docs/Screens2.md +++ b/docs/Screens2.md @@ -1,3 +1,12 @@ +[PySimpleGUI](https://github.com/PySimpleGUI) 2023-02-08T22:16:35Z +Thank you @J-Josu ![image](https://user-images.githubusercontent.com/46163555/217663277-1e69dfcf-c816-4930-aada-610b157eaf0a.png) for sharing your program and your story. I love hearing when students use PySimpleGUI! I'm glad it went well. The screenshots look great! + +Code annotation too? Do you have a GitHub Repo with your code? + +I'm impressed by bi-lingual programmers. It's hard enough coding, reading, writing, and thinking just in English. Throwing another language on top of all that is next-level stuff. Really happy you posted what you've made! + +----------- + [J-Josu](https://github.com/J-Josu) 2023-01-30T13:20:08Z Hi! I'm a stundent of Computer Science in Argentina and i`ve had to do a Final project for my Python Course. The project its about a card game where you can choose between availible themes to try to guess the correct option. The data is automtically loaded from cvs. From 83745112a661a3f81d5149204fece7dea7dc6949 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Mon, 13 Feb 2023 18:00:20 -0500 Subject: [PATCH 036/145] Tree Element - new parameter click_toggles_select --- PySimpleGUI.py | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index c16155f3..514ebcad 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -version = __version__ = "4.61.0.149 Unreleased" +version = __version__ = "4.61.0.150 Unreleased" _change_log = """ Changelog since 4.60.0 released to PyPI on 8-May-2022 @@ -365,7 +365,8 @@ _change_log = """ Removed the print when the Mac Alpha Channel 0.99 patch is applied 4.61.0.149 Removed second print when Mac patch applied - + 4.61.0.150 + Tree Element new parameter - click_toggles_select - if True then clicking a selected item will unselect it """ __version__ = version.split()[0] # For PEP 396 and PEP 345 @@ -9353,7 +9354,7 @@ class Tree(Element): def __init__(self, data=None, headings=None, visible_column_map=None, col_widths=None, col0_width=10, col0_heading='', def_col_width=10, auto_size_columns=True, max_col_width=20, select_mode=None, show_expanded=False, - change_submits=False, enable_events=False, font=None, justification='right', text_color=None, border_width=None, + change_submits=False, enable_events=False, click_toggles_select=None, font=None, justification='right', text_color=None, border_width=None, background_color=None, selected_row_colors=(None, None), header_text_color=None, header_background_color=None, header_font=None, header_border_width=None, header_relief=None, num_rows=None, sbar_trough_color=None, sbar_background_color=None, sbar_arrow_color=None, sbar_width=None, sbar_arrow_width=None, sbar_frame_color=None, sbar_relief=None, row_height=None, vertical_scroll_only=True, hide_vertical_scroll=False, pad=None, p=None, key=None, k=None, tooltip=None, @@ -9385,6 +9386,8 @@ class Tree(Element): :type change_submits: (bool) :param enable_events: Turns on the element specific events. Tree events happen when row is clicked :type enable_events: (bool) + :param click_toggles_select: If True then clicking a row will cause the selection for that row to toggle between selected and deselected + :type click_toggles_select: (bool) :param font: specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike :type font: (str or (str, int[, str]) or None) :param justification: 'left', 'right', 'center' are valid choices @@ -9467,7 +9470,7 @@ class Tree(Element): self.HeaderBorderWidth = header_border_width self.BorderWidth = border_width self.HeaderRelief = header_relief - + self.click_toggles_select = click_toggles_select if selected_row_colors == (None, None): # selected_row_colors = DEFAULT_TABLE_AND_TREE_SELECTED_ROW_COLORS selected_row_colors = theme_button_color() @@ -9518,8 +9521,14 @@ class Tree(Element): """ selections = self.TKTreeview.selection() - # self.SelectedRows = [x for x in selections] + selected_rows = [self.IdToKey[x] for x in selections] + if self.click_toggles_select: + if set(self.SelectedRows) == set(selected_rows): + for item in selections: + self.TKTreeview.selection_remove(item) + selections = [] self.SelectedRows = [self.IdToKey[x] for x in selections] + if self.ChangeSubmits: MyForm = self.ParentForm if self.Key is not None: @@ -9531,6 +9540,7 @@ class Tree(Element): # self.ParentForm.TKroot.quit() _exit_mainloop(self.ParentForm) + def add_treeview_data(self, node): """ Not a user function. Recursive method that inserts tree data into the tkinter treeview widget. @@ -26293,4 +26303,4 @@ if __name__ == '__main__': exit(0) main() exit(0) -#4bd4c2928c05ef62f978ee22c0209c8ce6661bc7f6757237b0fdc8d554f00ae326998ad0aec28c7011c2d089538791ad29f95dd658f9971230bfd5a9075fa230a8e7f1bcd8cb6cce0b47cfb9f71f7869b1f69ef96d70abbc89f64b9b2a59c55900f7dd047d2c26dd161b3984eeea41d503ed28762002688104d33839ab836bef661fd4afe7130d7351e64f7159227a4dec589fac243fa62153924bc1d549a85831e06780c607c17547eea96ee3edc33cd8d3daefa187917be115febb2179cab1cda0fe66113183a9c8be79689e4ddab15756afe9bd66febbf90246e8f6e6e721e46c85f82f6918ac3b0557c7d3439d0ec136b28fc8cf2e469cebdc00ffe39e48098b119ba5fbbfebf69f1840beff08b6a49587ea4df954f5b0425b3c0a73429932022bacdf5ba625c52d5064415446656f45cd87cda0dc1a414ad9d4c4ff8ca213a7ccd5d9bb07652d39c558454eedd89a7158bb8cd431d9c35c7c9588f5a74ee23ccbf7d0adecd5aea293c28482e150a064a68ce7bc226159d385ab7b07b7245deb4f9182de0aebbfeb8ae23224ec761f4b76ee4c2dd6c8227913a82d462e094a39c99a1ac5c352a14ec0678eb75132754ff4128e257ef1cea33f6705cb0ab6317e90c59cc35eef24c63e6e6f45f30573038619d5f930f2880f2518b7fbc7b11dd893ef2ac08208e0ddd598631d888c695237be60d4b01b9551889b86d3ad64 \ No newline at end of file +#75255ce9495078dee42b4285a47339005dbe8ae17df3a0f8074fb8c4b6db8829af1d9642cc849eeebe02b5cc6e21c4fec2dc69c2235ff42cb35a84a57be3e18547396319d1ae66e5e6956104c1dd9e89be6ea486f05b5646cd1a73766a7ce0c0eb52ab4f288603fe90d7b7cbe1395160f6d9ef75be5952d6831d3350101c1c0c07610a040cda224064c2126638ad9a4fbc04cc0c8000b4d9eea653d662d101ddb48bb1a6943214eb0ae8c06d667178d2f0d9dcc7d46164cd9ad986baf3a822ab4599b2f3721b8edc4883ed2d1128a36c58c1cec91bdd02c805270c7f2376f340fee931ba8a4b557c7b8fbd9b8bd68b2d81544fadbbb616f238871ba796f9fa7d300606ee243fc67662a537d1a240b3f6232ecc2f3565e148695abfecb757d6ee1dd6cb75eeb8c28cd1d49e61cb3365f9325fbb08d0aef679e1cb79e418a7160cb25f710f854f88b314e64e2a6fe766e246cfc5077a25ed47989a2a3cc4ec07ff3acf0ad487e6a029796b6956f9c68ab2373739322b4fbc1548a2fe9dfaceb7c680510403dd7b59733c91fb5a3dd9ecc2407c0194c12a3907531b0ceedfb572bc70bcee19e27328ad1858279a7a55293fc5cbded9b87adef21751bf5c94ecedd11fa01c249a792449c7b6ab94629d47b0412a88e0a818b314050f4b171578d8da28983e9e3a851f36eac1e3e7182693b7dc4d54b46d3127e4cdddfbbf01c4865a \ No newline at end of file From c88bd1f2ecca453669bb362011c7f5c9ae877889 Mon Sep 17 00:00:00 2001 From: PySimpleGUI <46163555+PySimpleGUI@users.noreply.github.com> Date: Tue, 14 Feb 2023 18:30:24 +0000 Subject: [PATCH 037/145] Automated Update! --- docs/Screens.md | 12 ++++++++++++ docs/Screens2.md | 28 ++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/docs/Screens.md b/docs/Screens.md index 8fb2e9ad..99280830 100644 --- a/docs/Screens.md +++ b/docs/Screens.md @@ -1,3 +1,15 @@ +[J-Josu](https://github.com/J-Josu) 2023-02-14T12:29:42Z + +![image](https://user-images.githubusercontent.com/46163555/217663277-1e69dfcf-c816-4930-aada-610b157eaf0a.png) + +----------- + +[chanon-kr](https://github.com/chanon-kr) 2023-02-14T06:27:10Z + +![image](https://user-images.githubusercontent.com/64777509/218656441-a53a0b28-76ac-4be0-a90b-3f4e57a71a56.png) + +----------- + [PySimpleGUI](https://github.com/PySimpleGUI) 2023-02-08T22:16:35Z ![image](https://user-images.githubusercontent.com/46163555/217663277-1e69dfcf-c816-4930-aada-610b157eaf0a.png) diff --git a/docs/Screens2.md b/docs/Screens2.md index 47c8afa2..f878d306 100644 --- a/docs/Screens2.md +++ b/docs/Screens2.md @@ -1,3 +1,31 @@ +[J-Josu](https://github.com/J-Josu) 2023-02-14T12:29:42Z +> Thank you @J-Josu ![image](https://user-images.githubusercontent.com/46163555/217663277-1e69dfcf-c816-4930-aada-610b157eaf0a.png) for sharing your program and your story. I love hearing when students use PySimpleGUI! I'm glad it went well. The screenshots look great! +> +> Code annotation too? Do you have a GitHub Repo with your code? +> +> I'm impressed by bi-lingual programmers. It's hard enough coding, reading, writing, and thinking just in English. Throwing another language on top of all that is next-level stuff. Really happy you posted what you've made! + +Hi @PySimpleGUI, yes i have uploaded the project to the following [repository](https://github.com/J-Josu/FiguRace) + +Thanks you for all! + +----------- + +[chanon-kr](https://github.com/chanon-kr) 2023-02-14T06:27:10Z +Hi, I use PySimpleGUI to make a Simple Object Detection GUI with YOLOv8. + +Check my GitHub repo from this link. + +[Simple Object Detection GUI](https://github.com/chanon-kr/simple_imagui_app) + +And here is a screenshot of the GUI. + +![image](https://user-images.githubusercontent.com/64777509/218656441-a53a0b28-76ac-4be0-a90b-3f4e57a71a56.png) + +Thanks to @PySimpleGUI for suggestions and improvement!! + +----------- + [PySimpleGUI](https://github.com/PySimpleGUI) 2023-02-08T22:16:35Z Thank you @J-Josu ![image](https://user-images.githubusercontent.com/46163555/217663277-1e69dfcf-c816-4930-aada-610b157eaf0a.png) for sharing your program and your story. I love hearing when students use PySimpleGUI! I'm glad it went well. The screenshots look great! From f07d658e87dfedf8c6a29244bac10ab86b451c44 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Sun, 19 Feb 2023 14:04:56 -0500 Subject: [PATCH 038/145] Fixed problem with TabGroup not identifying the currently active tab in the Values Dictionary is the label is blank on the Tab --- PySimpleGUI.py | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index 514ebcad..ca2ab525 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -version = __version__ = "4.61.0.150 Unreleased" +version = __version__ = "4.61.0.151 Unreleased" _change_log = """ Changelog since 4.60.0 released to PyPI on 8-May-2022 @@ -367,6 +367,8 @@ _change_log = """ Removed second print when Mac patch applied 4.61.0.150 Tree Element new parameter - click_toggles_select - if True then clicking a selected item will unselect it + 4.61.0.151 + Fixed problem with TabGroups when the text was blank for a Tab. Was not correctly identifying the active tab in the Values dictionary """ __version__ = version.split()[0] # For PEP 396 and PEP 345 @@ -7642,6 +7644,7 @@ class TabGroup(Element): self.Rows = [] self.TKNotebook = None # type: ttk.Notebook self.Widget = None # type: ttk.Notebook + self.tab_index_to_key = {} # has a list of the tabs in the notebook and their associated key self.TabCount = 0 self.BorderWidth = border_width self.BackgroundColor = background_color if background_color is not None else DEFAULT_BACKGROUND_COLOR @@ -7768,6 +7771,21 @@ class TabGroup(Element): return element.Key return None + + def find_currently_active_tab_key(self): + """ + Returns the key for the currently active tab in this TabGroup + :return: Returns the key or None of no key found + :rtype: key | None + """ + try: + current_index = self.TKNotebook.index('current') + key = self.tab_index_to_key.get(current_index, None) + except: + key = None + + return key + def get(self): """ Returns the current value for the Tab Group, which will be the currently selected tab's KEY or the text on @@ -7781,7 +7799,7 @@ class TabGroup(Element): try: value = self.TKNotebook.tab(self.TKNotebook.index('current'))['text'] - tab_key = self.FindKeyFromTabName(value) + tab_key = self.find_key_from_tab_name(value) if tab_key is not None: value = tab_key except: @@ -15108,7 +15126,8 @@ def _BuildResultsForSubform(form, initialize_only, top_level_form): elif element.Type == ELEM_TYPE_TAB_GROUP: try: value = element.TKNotebook.tab(element.TKNotebook.index('current'))['text'] - tab_key = element.FindKeyFromTabName(value) + tab_key = element.find_currently_active_tab_key() + # tab_key = element.FindKeyFromTabName(value) if tab_key is not None: value = tab_key except: @@ -17181,6 +17200,7 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form): # ------------------------- Tab placement element ------------------------- # elif element_type == ELEM_TYPE_TAB: element = element # type: Tab + form = form # type: TabGroup element.TKFrame = element.Widget = tk.Frame(form.TKNotebook) PackFormIntoFrame(element, element.TKFrame, toplevel_form) state = 'normal' @@ -17232,6 +17252,7 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form): element.ParentNotebook = form.TKNotebook element.TabID = form.TabCount + form.tab_index_to_key[element.TabID] = element.key # has a list of the tabs in the notebook and their associated key form.TabCount += 1 if element.BackgroundColor not in (COLOR_SYSTEM_DEFAULT, None): element.TKFrame.configure(background=element.BackgroundColor, highlightbackground=element.BackgroundColor, highlightcolor=element.BackgroundColor) @@ -26303,4 +26324,4 @@ if __name__ == '__main__': exit(0) main() exit(0) -#75255ce9495078dee42b4285a47339005dbe8ae17df3a0f8074fb8c4b6db8829af1d9642cc849eeebe02b5cc6e21c4fec2dc69c2235ff42cb35a84a57be3e18547396319d1ae66e5e6956104c1dd9e89be6ea486f05b5646cd1a73766a7ce0c0eb52ab4f288603fe90d7b7cbe1395160f6d9ef75be5952d6831d3350101c1c0c07610a040cda224064c2126638ad9a4fbc04cc0c8000b4d9eea653d662d101ddb48bb1a6943214eb0ae8c06d667178d2f0d9dcc7d46164cd9ad986baf3a822ab4599b2f3721b8edc4883ed2d1128a36c58c1cec91bdd02c805270c7f2376f340fee931ba8a4b557c7b8fbd9b8bd68b2d81544fadbbb616f238871ba796f9fa7d300606ee243fc67662a537d1a240b3f6232ecc2f3565e148695abfecb757d6ee1dd6cb75eeb8c28cd1d49e61cb3365f9325fbb08d0aef679e1cb79e418a7160cb25f710f854f88b314e64e2a6fe766e246cfc5077a25ed47989a2a3cc4ec07ff3acf0ad487e6a029796b6956f9c68ab2373739322b4fbc1548a2fe9dfaceb7c680510403dd7b59733c91fb5a3dd9ecc2407c0194c12a3907531b0ceedfb572bc70bcee19e27328ad1858279a7a55293fc5cbded9b87adef21751bf5c94ecedd11fa01c249a792449c7b6ab94629d47b0412a88e0a818b314050f4b171578d8da28983e9e3a851f36eac1e3e7182693b7dc4d54b46d3127e4cdddfbbf01c4865a \ No newline at end of file +#1ddab5912c76bfc3ff46839491a5aa200d7c5bb80fb2c4579f727a0cf0894a114c9701f5977d1edf3f6ea304828fd25042798d2e05491753c617d2bb39360d7de5bb75525b0126432244dd7fa9b70584ddeb5e7fdda756e682042aee6a35ac125a6d079ed7dcf0fe890d1a9405a1c3e2ae32c6e6ee4566a2f351f178a1cf628bc4d705c8a296a468fbbb24d9230d39410fab4de94c71565558534a40645fb8cd91d6ab114b827587f57132c2d520e192af92004e5d22967e6d99283e80ad8e3c5b834b1918bdaa27206df72b8da3661b09b3098070145945cca71ec7c7bede3cef364707ad021ab75addeb9e1fb3d141adaf97618aff27a7dd1711d4ed96af62fa093fc0a5f2279b67b1eaf4f2028d57e58989d15f9c35605a724557c791f26f9d1bec46598d54664ebc50123adaa422ec4bedff5a64ae92a32eba09cb241d659ea0947faa8444233218822fd6b7960581ddd3fb4a81396d830c7dbd541905e5f72d634881ccb243c0591557043fbc423edbdc0f97cd2d4d00b2bfbcaf9cfe76765f0299fc866f52025c44d41b66471fa9648abc2981dfd0ac92b88425def2052758902e0544a8c4a8f7866ecdf4287d1cfc719d61bf56ed02864c86f9a6303a63540e2c9337f83e0a0dd6f910e02377bd6f6e1be65c3f0d4f1d824234233f12dedeae4b4375547b5feba450b984b3b2e5c1b72a883a060fb93978a1a2fbb4bc \ No newline at end of file From c8da36c9e30d3dd42680a2086a62c962ceed7a60 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Sun, 19 Feb 2023 14:57:49 -0500 Subject: [PATCH 039/145] changed TabGroup.get to use the same method as the values dictionary does that was just added in prior check-in --- PySimpleGUI.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index ca2ab525..2cff6c7e 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -version = __version__ = "4.61.0.151 Unreleased" +version = __version__ = "4.61.0.152 Unreleased" _change_log = """ Changelog since 4.60.0 released to PyPI on 8-May-2022 @@ -369,6 +369,8 @@ _change_log = """ Tree Element new parameter - click_toggles_select - if True then clicking a selected item will unselect it 4.61.0.151 Fixed problem with TabGroups when the text was blank for a Tab. Was not correctly identifying the active tab in the Values dictionary + 4.61.0.152 + Updated TabGroup.get to use the same method to find the currently active tab that was just added above. """ __version__ = version.split()[0] # For PEP 396 and PEP 345 @@ -7790,21 +7792,20 @@ class TabGroup(Element): """ Returns the current value for the Tab Group, which will be the currently selected tab's KEY or the text on the tab if no key is defined. Returns None if an error occurs. - Note that this is exactly the same data that would be returned from a call to Window.Read. Are you sure you + Note that this is exactly the same data that would be returned from a call to Window.read. Are you sure you are using this method correctly? - :return: The key of the currently selected tab or the tab's text if it has no key + :return: The key of the currently selected tab or None if there is an error :rtype: Any | None """ try: - value = self.TKNotebook.tab(self.TKNotebook.index('current'))['text'] - tab_key = self.find_key_from_tab_name(value) - if tab_key is not None: - value = tab_key + current_index = self.TKNotebook.index('current') + key = self.tab_index_to_key.get(current_index, None) except: - value = None - return value + key = None + + return key def add_tab(self, tab_element): """ @@ -26324,4 +26325,4 @@ if __name__ == '__main__': exit(0) main() exit(0) -#1ddab5912c76bfc3ff46839491a5aa200d7c5bb80fb2c4579f727a0cf0894a114c9701f5977d1edf3f6ea304828fd25042798d2e05491753c617d2bb39360d7de5bb75525b0126432244dd7fa9b70584ddeb5e7fdda756e682042aee6a35ac125a6d079ed7dcf0fe890d1a9405a1c3e2ae32c6e6ee4566a2f351f178a1cf628bc4d705c8a296a468fbbb24d9230d39410fab4de94c71565558534a40645fb8cd91d6ab114b827587f57132c2d520e192af92004e5d22967e6d99283e80ad8e3c5b834b1918bdaa27206df72b8da3661b09b3098070145945cca71ec7c7bede3cef364707ad021ab75addeb9e1fb3d141adaf97618aff27a7dd1711d4ed96af62fa093fc0a5f2279b67b1eaf4f2028d57e58989d15f9c35605a724557c791f26f9d1bec46598d54664ebc50123adaa422ec4bedff5a64ae92a32eba09cb241d659ea0947faa8444233218822fd6b7960581ddd3fb4a81396d830c7dbd541905e5f72d634881ccb243c0591557043fbc423edbdc0f97cd2d4d00b2bfbcaf9cfe76765f0299fc866f52025c44d41b66471fa9648abc2981dfd0ac92b88425def2052758902e0544a8c4a8f7866ecdf4287d1cfc719d61bf56ed02864c86f9a6303a63540e2c9337f83e0a0dd6f910e02377bd6f6e1be65c3f0d4f1d824234233f12dedeae4b4375547b5feba450b984b3b2e5c1b72a883a060fb93978a1a2fbb4bc \ No newline at end of file +#5e9cfffaecef53291e73f11fc7bf1177bd35817e37b11537cdd2d8c784ed26ae4edf6f6b61fe1c48e7c4906af42108931762fefc04569827c7e01af1f93bf32ab317c1a8d8ac217036f2b1c61ec92fd0db526a3f4324bc123733eae92d2365026140925f104132afba06e1867b4eb4757444d8bf36bf9cd590d78bee5d768936ef17feacbae9109fee40db4b839fc9d48c4894245225747f9430b7327ef3489890bd5aabbb1a203d02c9474fe956c5dc2b889e7aff60bebbce790c2dc01a78d32e5c1d24e580c61cf34bc2354bf959ef990dcd249d9823afe4d9dfcdf84f0a08699ea346e3e4d1ce11157d576b7ef683a4032ba24d2f2acc603aa1ff507e76fbdc35aad2777422b0fcbf30e2ff6691710201cd64d7cc686983abe09d7300b395012c95969657ddc54ab6925a523ec8aa2f236ab679bed628e00d4f682bb734e8b3bbf705e07b60e6cbcc32a3742622b41cdeee8c8488c5b34274bd5c2f79f07da64241c3a46904e2b6e1006ff50336deffabd16a3d5817e35c0150b8eb55d1119ce530fe2f6533800198a2343c536b9d945075797b2c6a5bf40d74477706c4b441bb51dbd1fd4b6ab31702806f9f90acd31f24f8e58444d4899bb12c58de734566600f895ec73c2d92af242abcf65e6d28904d0a436343d40763d03f98a06537a726314d19c660f6a9ff8edd779aa66773868dfadeacf7cc31dad706df4aa013 \ No newline at end of file From 57528fdb5cde4030d1c49c1230ae45cd5001fcc1 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Tue, 21 Feb 2023 11:46:31 -0500 Subject: [PATCH 040/145] Changed layout error message (added "sometimes" to description)) --- PySimpleGUI.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index 2cff6c7e..ad166658 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -7088,7 +7088,7 @@ class Frame(Element): if type(element) == list: PopupError('Error creating Frame layout', 'Layout has a LIST instead of an ELEMENT', - 'This means you have a badly placed ]', + 'This sometimes means you have a badly placed ]', 'The offensive list is:', element, 'This list will be stripped from your layout', @@ -7427,7 +7427,7 @@ class Tab(Element): if type(element) == list: popup_error_with_traceback('Error creating Tab layout', 'Layout has a LIST instead of an ELEMENT', - 'This means you have a badly placed ]', + 'This sometimes means you have a badly placed ]', 'The offensive list is:', element, 'This list will be stripped from your layout') @@ -7685,7 +7685,7 @@ class TabGroup(Element): if type(element) == list: PopupError('Error creating Tab layout', 'Layout has a LIST instead of an ELEMENT', - 'This means you have a badly placed ]', + 'This sometimes means you have a badly placed ]', 'The offensive list is:', element, 'This list will be stripped from your layout', keep_on_top=True, image=_random_error_emoji() @@ -8346,7 +8346,7 @@ class Column(Element): if type(element) == list: PopupError('Error creating Column layout', 'Layout has a LIST instead of an ELEMENT', - 'This means you have a badly placed ]', + 'This sometimes means you have a badly placed ]', 'The offensive list is:', element, 'This list will be stripped from your layout', keep_on_top=True, image=_random_error_emoji() @@ -10372,7 +10372,7 @@ class Window: continue _error_popup_with_traceback('Error creating Window layout', 'Layout has a LIST instead of an ELEMENT', - 'This means you have a badly placed ]', + 'This sometimes means you have a badly placed ]', 'The offensive list is:', element, 'This list will be stripped from your layout' @@ -26325,4 +26325,4 @@ if __name__ == '__main__': exit(0) main() exit(0) -#5e9cfffaecef53291e73f11fc7bf1177bd35817e37b11537cdd2d8c784ed26ae4edf6f6b61fe1c48e7c4906af42108931762fefc04569827c7e01af1f93bf32ab317c1a8d8ac217036f2b1c61ec92fd0db526a3f4324bc123733eae92d2365026140925f104132afba06e1867b4eb4757444d8bf36bf9cd590d78bee5d768936ef17feacbae9109fee40db4b839fc9d48c4894245225747f9430b7327ef3489890bd5aabbb1a203d02c9474fe956c5dc2b889e7aff60bebbce790c2dc01a78d32e5c1d24e580c61cf34bc2354bf959ef990dcd249d9823afe4d9dfcdf84f0a08699ea346e3e4d1ce11157d576b7ef683a4032ba24d2f2acc603aa1ff507e76fbdc35aad2777422b0fcbf30e2ff6691710201cd64d7cc686983abe09d7300b395012c95969657ddc54ab6925a523ec8aa2f236ab679bed628e00d4f682bb734e8b3bbf705e07b60e6cbcc32a3742622b41cdeee8c8488c5b34274bd5c2f79f07da64241c3a46904e2b6e1006ff50336deffabd16a3d5817e35c0150b8eb55d1119ce530fe2f6533800198a2343c536b9d945075797b2c6a5bf40d74477706c4b441bb51dbd1fd4b6ab31702806f9f90acd31f24f8e58444d4899bb12c58de734566600f895ec73c2d92af242abcf65e6d28904d0a436343d40763d03f98a06537a726314d19c660f6a9ff8edd779aa66773868dfadeacf7cc31dad706df4aa013 \ No newline at end of file +#53b9d7c8cee4e60b4eb060f64170990c5fa5dfa2168dc6a65c062ecaec143d3d7d0a25bbc46c7b94417674ea9c91591856af3f6503e1acf1c61f885ad55e2bc6a030b22a0b6165fb426925ab544a1b4063bfc261af6be3120da31b75d68db047574c1b5c4a6b2486c7581fcd6fbf3df70e859af8af8d19b72a7284facfe30a44b8b98e88e69932df8758f382eb9d994afe894c5a6c25e785fd3dc9db3a49556d211f8e8fa72936c99fe36b8a55586398665fc04deb8979720ddb0a177f5f1c963b76b4ca8ac59b046e362f5a49cc4da3f8e65b2c0067675533c70bc15908faebeb1fb611486cea4ccab9d52c8223de11681d2731cf740c34d5ff91c7f581d35d210131863d89d44a8b15600445968e01bcead9cfb64ecec9d7e298233db246a2185997cd1721c2ab82a14159420f23f7b9d1270797950f1eb8b438ac3d4e1388b5ec68cd5fe8c37d19a29d36c1f10c3766c6ec464a99a7b4d0d12fe12145427b96e98d777095b7e154ad1c6f7e4f9d5395e933738c6575599040b560252532948cd9497edb334260c712ac07738b5ee6e3caba6b353cfe1c41b992059c238d479bad1e0df027e396d14eb44b13e62fe01d7cc5478ad2225b8386e86050afd3fd44d2bb3078ac87edaf1a6721b813add517175b0115fc1137f362597ca734ecd1a7d8b337283f32c9258ebc187379682a53c7bd93086ff394336b9645f245e6e0 \ No newline at end of file From 98f383bffb87dac37272f58feee4eaf28ef7d44a Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Tue, 21 Feb 2023 11:58:59 -0500 Subject: [PATCH 041/145] Ooops... forgot to bump version number --- PySimpleGUI.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index ad166658..b342c614 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -version = __version__ = "4.61.0.152 Unreleased" +version = __version__ = "4.61.0.153 Unreleased" _change_log = """ Changelog since 4.60.0 released to PyPI on 8-May-2022 @@ -371,6 +371,8 @@ _change_log = """ Fixed problem with TabGroups when the text was blank for a Tab. Was not correctly identifying the active tab in the Values dictionary 4.61.0.152 Updated TabGroup.get to use the same method to find the currently active tab that was just added above. + 4.61.0.153 + Updated layout error messages to include "sometimes" in the description of what may be causing error """ __version__ = version.split()[0] # For PEP 396 and PEP 345 @@ -26325,4 +26327,4 @@ if __name__ == '__main__': exit(0) main() exit(0) -#53b9d7c8cee4e60b4eb060f64170990c5fa5dfa2168dc6a65c062ecaec143d3d7d0a25bbc46c7b94417674ea9c91591856af3f6503e1acf1c61f885ad55e2bc6a030b22a0b6165fb426925ab544a1b4063bfc261af6be3120da31b75d68db047574c1b5c4a6b2486c7581fcd6fbf3df70e859af8af8d19b72a7284facfe30a44b8b98e88e69932df8758f382eb9d994afe894c5a6c25e785fd3dc9db3a49556d211f8e8fa72936c99fe36b8a55586398665fc04deb8979720ddb0a177f5f1c963b76b4ca8ac59b046e362f5a49cc4da3f8e65b2c0067675533c70bc15908faebeb1fb611486cea4ccab9d52c8223de11681d2731cf740c34d5ff91c7f581d35d210131863d89d44a8b15600445968e01bcead9cfb64ecec9d7e298233db246a2185997cd1721c2ab82a14159420f23f7b9d1270797950f1eb8b438ac3d4e1388b5ec68cd5fe8c37d19a29d36c1f10c3766c6ec464a99a7b4d0d12fe12145427b96e98d777095b7e154ad1c6f7e4f9d5395e933738c6575599040b560252532948cd9497edb334260c712ac07738b5ee6e3caba6b353cfe1c41b992059c238d479bad1e0df027e396d14eb44b13e62fe01d7cc5478ad2225b8386e86050afd3fd44d2bb3078ac87edaf1a6721b813add517175b0115fc1137f362597ca734ecd1a7d8b337283f32c9258ebc187379682a53c7bd93086ff394336b9645f245e6e0 \ No newline at end of file +#224c2bf05eb43cd62fd9d35697b493668caab82e63b920e5c14a364a5020dacbf5eeaec4540d626978dd44352f40a6545fa6530af35ac0ad493948762dbd72ee99e47b5d124e5840c1795a29679fdf752a68334ae08cbb4e9128e34288c331f193e5f5607300fc9a80db915d5cb3a3160a643d8a0c4ab7592014539db972200012a4850335072b464eea1131c13f6f764c418712719e3bd67908ba25d1bae63a3f088e3387aa510c48d68ef1fda1bf21c342782ac15425bc76a9617b2fa34fe49e3974e09aef68850a1a226efcaf11aef021571dc226a442c11757c429727a95876935d191dac9a8681a261a99578965c10ce0c38010b1e772c9899e39cdeecf29a8ace331b299028fefceae30453e156c36741d2f9692e4e087b6eeeaeb1375452897e7e01b3ba09142de6e4dd3248f1a0ff684e933f4d62118aff44a6aadefc9ca28e6c76fd343c0340f5dfba0dcc8fa38c978b4463bbd6c3ead08ddb9a6d2ce18dff38ef321bd2f2e4de4d683302d84d8848249461d86dd690e76c16d287e8b06850a994d21113437fd22852d4e6c109dd843226575138f441c3d6de5a0f1d5a7249dc79a85d9047ca2c09fdc510f419dc04b170595ea13de083a2ccf66df8e02c7340198200757f99dc9b771622aef79597308a53357c63f8acdb8a8f76e986c0994b5bd1337cc15e4b82a61caf66ebf86395007f31ff2f701a42d139671 \ No newline at end of file From c4e37eff04c6c3970974df4b497a0c58c3e62f3e Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Thu, 23 Feb 2023 11:51:55 -0500 Subject: [PATCH 042/145] Addition of the Window Timer API Calls currently on GitHub --- docs/call reference.md | 63 +++++++++++++++++-- .../markdown input files/5_call_reference.md | 12 ++++ readme_creator/output/call reference.md | 63 +++++++++++++++++-- 3 files changed, 130 insertions(+), 8 deletions(-) diff --git a/docs/call reference.md b/docs/call reference.md index ab0a24fe..181d9c76 100644 --- a/docs/call reference.md +++ b/docs/call reference.md @@ -10988,14 +10988,14 @@ Parameter Descriptions: Returns the current value for the Tab Group, which will be the currently selected tab's KEY or the text on the tab if no key is defined. Returns None if an error occurs. -Note that this is exactly the same data that would be returned from a call to Window.Read. Are you sure you +Note that this is exactly the same data that would be returned from a call to Window.read. Are you sure you are using this method correctly? `get()` |Type|Name|Meaning| |---|---|---| -|Any | None| **return** | The key of the currently selected tab or the tab's text if it has no key | +|Any | None| **return** | The key of the currently selected tab or None if there is an error | ### get_next_focus @@ -11220,14 +11220,14 @@ Parameter Descriptions: Returns the current value for the Tab Group, which will be the currently selected tab's KEY or the text on the tab if no key is defined. Returns None if an error occurs. -Note that this is exactly the same data that would be returned from a call to Window.Read. Are you sure you +Note that this is exactly the same data that would be returned from a call to Window.read. Are you sure you are using this method correctly? `Get()` |Type|Name|Meaning| |---|---|---| -|Any | None| **return** | The key of the currently selected tab or the tab's text if it has no key | +|Any | None| **return** | The key of the currently selected tab or None if there is an error | ### SetFocus @@ -12198,6 +12198,7 @@ Tree(data = None, show_expanded = False, change_submits = False, enable_events = False, + click_toggles_select = None, font = None, justification = "right", text_color = None, @@ -12249,6 +12250,7 @@ Parameter Descriptions: | bool | show_expanded | if True then the tree will be initially shown with all nodes completely expanded | | bool | change_submits | DO NOT USE. Only listed for backwards compat - Use enable_events instead | | bool | enable_events | Turns on the element specific events. Tree events happen when row is clicked | +| bool | click_toggles_select | If True then clicking a row will cause the selection for that row to toggle between selected and deselected | | (str or (str, int[, str]) or None) | font | specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike | | str | justification | 'left', 'right', 'center' are valid choices | | str | text_color | color of the text | @@ -13852,6 +13854,59 @@ Parameter Descriptions: | Any | end_key | The key that will be generated when the function returns | | threading.Thread | **RETURN** | The id of the thread +### timer_get_active_timers + +Returns a list of currently active timers for a window + +`timer_get_active_timers()` + +|Type|Name|Meaning| +|---|---|---| +|List[int]| **return** | List of timers for the window | + +### timer_start + +Starts a timer that gnerates Timer Events. The default is to repeat the timer events until timer is stopped. +You can provide your own key or a default key will be used. +The values dictionary will contain the timer ID that is returned from this function. + +``` +timer_start(frequency_ms, + key = "__TIMER EVENT__", + repeating = True) +``` + +Parameter Descriptions: + +|Type|Name|Meaning| +|--|--|--| +| int | frequency_ms | How often to generate timer events in milliseconds | +| str or int or tuple or object | key | Key to be returned as the timer event | +| bool | repeating | If True then repeat timer events until timer is explicitly stopped | +| int | **RETURN** | Timer ID for the timer + +### timer_stop + +Stops a timer with a given ID + +``` +timer_stop(timer_id) +``` + +Parameter Descriptions: + +|Type|Name|Meaning| +|--|--|--| +| int | timer_id | Timer ID of timer to stop | + +### timer_stop_all + +Stops all timers for THIS window + +```python +timer_stop_all() +``` + ### un_hide Used to bring back a window that was previously hidden using the Hide method diff --git a/readme_creator/markdown input files/5_call_reference.md b/readme_creator/markdown input files/5_call_reference.md index dd84cc90..dceca671 100644 --- a/readme_creator/markdown input files/5_call_reference.md +++ b/readme_creator/markdown input files/5_call_reference.md @@ -3040,6 +3040,18 @@ Example: If first row has a `VPush`, then your layout will be At the bottom of ### start_thread +### timer_get_active_timers + + +### timer_start + + +### timer_stop + + +### timer_stop_all + + ### un_hide diff --git a/readme_creator/output/call reference.md b/readme_creator/output/call reference.md index ab0a24fe..181d9c76 100644 --- a/readme_creator/output/call reference.md +++ b/readme_creator/output/call reference.md @@ -10988,14 +10988,14 @@ Parameter Descriptions: Returns the current value for the Tab Group, which will be the currently selected tab's KEY or the text on the tab if no key is defined. Returns None if an error occurs. -Note that this is exactly the same data that would be returned from a call to Window.Read. Are you sure you +Note that this is exactly the same data that would be returned from a call to Window.read. Are you sure you are using this method correctly? `get()` |Type|Name|Meaning| |---|---|---| -|Any | None| **return** | The key of the currently selected tab or the tab's text if it has no key | +|Any | None| **return** | The key of the currently selected tab or None if there is an error | ### get_next_focus @@ -11220,14 +11220,14 @@ Parameter Descriptions: Returns the current value for the Tab Group, which will be the currently selected tab's KEY or the text on the tab if no key is defined. Returns None if an error occurs. -Note that this is exactly the same data that would be returned from a call to Window.Read. Are you sure you +Note that this is exactly the same data that would be returned from a call to Window.read. Are you sure you are using this method correctly? `Get()` |Type|Name|Meaning| |---|---|---| -|Any | None| **return** | The key of the currently selected tab or the tab's text if it has no key | +|Any | None| **return** | The key of the currently selected tab or None if there is an error | ### SetFocus @@ -12198,6 +12198,7 @@ Tree(data = None, show_expanded = False, change_submits = False, enable_events = False, + click_toggles_select = None, font = None, justification = "right", text_color = None, @@ -12249,6 +12250,7 @@ Parameter Descriptions: | bool | show_expanded | if True then the tree will be initially shown with all nodes completely expanded | | bool | change_submits | DO NOT USE. Only listed for backwards compat - Use enable_events instead | | bool | enable_events | Turns on the element specific events. Tree events happen when row is clicked | +| bool | click_toggles_select | If True then clicking a row will cause the selection for that row to toggle between selected and deselected | | (str or (str, int[, str]) or None) | font | specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike | | str | justification | 'left', 'right', 'center' are valid choices | | str | text_color | color of the text | @@ -13852,6 +13854,59 @@ Parameter Descriptions: | Any | end_key | The key that will be generated when the function returns | | threading.Thread | **RETURN** | The id of the thread +### timer_get_active_timers + +Returns a list of currently active timers for a window + +`timer_get_active_timers()` + +|Type|Name|Meaning| +|---|---|---| +|List[int]| **return** | List of timers for the window | + +### timer_start + +Starts a timer that gnerates Timer Events. The default is to repeat the timer events until timer is stopped. +You can provide your own key or a default key will be used. +The values dictionary will contain the timer ID that is returned from this function. + +``` +timer_start(frequency_ms, + key = "__TIMER EVENT__", + repeating = True) +``` + +Parameter Descriptions: + +|Type|Name|Meaning| +|--|--|--| +| int | frequency_ms | How often to generate timer events in milliseconds | +| str or int or tuple or object | key | Key to be returned as the timer event | +| bool | repeating | If True then repeat timer events until timer is explicitly stopped | +| int | **RETURN** | Timer ID for the timer + +### timer_stop + +Stops a timer with a given ID + +``` +timer_stop(timer_id) +``` + +Parameter Descriptions: + +|Type|Name|Meaning| +|--|--|--| +| int | timer_id | Timer ID of timer to stop | + +### timer_stop_all + +Stops all timers for THIS window + +```python +timer_stop_all() +``` + ### un_hide Used to bring back a window that was previously hidden using the Hide method From 86afe5ae5760387d5b816145783ed993afa153ce Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Thu, 23 Feb 2023 11:56:20 -0500 Subject: [PATCH 043/145] 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. --- docs/call reference.md | 6 +++--- readme_creator/markdown input files/5_call_reference.md | 6 +++--- readme_creator/output/call reference.md | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/call reference.md b/docs/call reference.md index 181d9c76..654561b7 100644 --- a/docs/call reference.md +++ b/docs/call reference.md @@ -7208,11 +7208,11 @@ Parameter Descriptions: --------- -## Output Element (No longer recommended - USE `Multiline` instead) +## Output Element -Rather than use the `Output` element, it's recommended that you use the `Multiline` element instead. The reason for this is that more controls have been added to the Multiline and in the future you can expect more features will be added to the Multiline while the `Output` element has stopped being enhanced. +Output Element - a multi-lined text area to where stdout, stderr, cprint are rerouted. -You can control which Multiline Element receives your stdout output as well as use the color-print (`cprint`) with a Multiline. +Now based on the `Multiline` element Output Element - a multi-lined text area to where stdout, stderr, cprint are rerouted. diff --git a/readme_creator/markdown input files/5_call_reference.md b/readme_creator/markdown input files/5_call_reference.md index dceca671..04b093c4 100644 --- a/readme_creator/markdown input files/5_call_reference.md +++ b/readme_creator/markdown input files/5_call_reference.md @@ -1557,11 +1557,11 @@ The following methods are here for backwards compatibility reference. You will --------- -## Output Element (No longer recommended - USE `Multiline` instead) +## Output Element -Rather than use the `Output` element, it's recommended that you use the `Multiline` element instead. The reason for this is that more controls have been added to the Multiline and in the future you can expect more features will be added to the Multiline while the `Output` element has stopped being enhanced. +Output Element - a multi-lined text area to where stdout, stderr, cprint are rerouted. -You can control which Multiline Element receives your stdout output as well as use the color-print (`cprint`) with a Multiline. +Now based on the `Multiline` element diff --git a/readme_creator/output/call reference.md b/readme_creator/output/call reference.md index 181d9c76..654561b7 100644 --- a/readme_creator/output/call reference.md +++ b/readme_creator/output/call reference.md @@ -7208,11 +7208,11 @@ Parameter Descriptions: --------- -## Output Element (No longer recommended - USE `Multiline` instead) +## Output Element -Rather than use the `Output` element, it's recommended that you use the `Multiline` element instead. The reason for this is that more controls have been added to the Multiline and in the future you can expect more features will be added to the Multiline while the `Output` element has stopped being enhanced. +Output Element - a multi-lined text area to where stdout, stderr, cprint are rerouted. -You can control which Multiline Element receives your stdout output as well as use the color-print (`cprint`) with a Multiline. +Now based on the `Multiline` element Output Element - a multi-lined text area to where stdout, stderr, cprint are rerouted. From 2cc5b70aed3e042a8e13dde185bfc4d3cb0925de Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Thu, 23 Feb 2023 12:00:25 -0500 Subject: [PATCH 044/145] Added the variable name constants EVENT_TIMER and TIMER_KEY to the Window.start_timer docstring --- PySimpleGUI.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index b342c614..683bd389 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -version = __version__ = "4.61.0.153 Unreleased" +version = __version__ = "4.61.0.154 Unreleased" _change_log = """ Changelog since 4.60.0 released to PyPI on 8-May-2022 @@ -373,6 +373,8 @@ _change_log = """ Updated TabGroup.get to use the same method to find the currently active tab that was just added above. 4.61.0.153 Updated layout error messages to include "sometimes" in the description of what may be causing error + 4.61.0.154 + Updated Window.start_timer docstring to include the constants EVENT_TIMER and TIMER_KEY since the call reference doesn't show the variable names but rather the string value. """ __version__ = version.split()[0] # For PEP 396 and PEP 345 @@ -12579,7 +12581,8 @@ class Window: def timer_start(self, frequency_ms, key=EVENT_TIMER, repeating=True): """ Starts a timer that gnerates Timer Events. The default is to repeat the timer events until timer is stopped. - You can provide your own key or a default key will be used. + You can provide your own key or a default key will be used. The default key is defined + with the constants EVENT_TIMER or TIMER_KEY. They both equal the same value. The values dictionary will contain the timer ID that is returned from this function. :param frequency_ms: How often to generate timer events in milliseconds @@ -26327,4 +26330,4 @@ if __name__ == '__main__': exit(0) main() exit(0) -#224c2bf05eb43cd62fd9d35697b493668caab82e63b920e5c14a364a5020dacbf5eeaec4540d626978dd44352f40a6545fa6530af35ac0ad493948762dbd72ee99e47b5d124e5840c1795a29679fdf752a68334ae08cbb4e9128e34288c331f193e5f5607300fc9a80db915d5cb3a3160a643d8a0c4ab7592014539db972200012a4850335072b464eea1131c13f6f764c418712719e3bd67908ba25d1bae63a3f088e3387aa510c48d68ef1fda1bf21c342782ac15425bc76a9617b2fa34fe49e3974e09aef68850a1a226efcaf11aef021571dc226a442c11757c429727a95876935d191dac9a8681a261a99578965c10ce0c38010b1e772c9899e39cdeecf29a8ace331b299028fefceae30453e156c36741d2f9692e4e087b6eeeaeb1375452897e7e01b3ba09142de6e4dd3248f1a0ff684e933f4d62118aff44a6aadefc9ca28e6c76fd343c0340f5dfba0dcc8fa38c978b4463bbd6c3ead08ddb9a6d2ce18dff38ef321bd2f2e4de4d683302d84d8848249461d86dd690e76c16d287e8b06850a994d21113437fd22852d4e6c109dd843226575138f441c3d6de5a0f1d5a7249dc79a85d9047ca2c09fdc510f419dc04b170595ea13de083a2ccf66df8e02c7340198200757f99dc9b771622aef79597308a53357c63f8acdb8a8f76e986c0994b5bd1337cc15e4b82a61caf66ebf86395007f31ff2f701a42d139671 \ No newline at end of file +#42b79b1bcb52a826b059ac9bb2ca70dba9418f275efc296cfac8eb77e2867f7c00de66abe0321614edd1eb498efe67bea8dc5bf4cb5f5c7ef1f49fd6df0e962387474b0ef0ce819e6b06bf69d1e3725b237a9041a9b09faeae2235178153f835f61e7bffec87d14f06fe47bcdb8c26bdd097d69f014a50130035811436bd02002c688248f367f3f60c22cb420e6101e2544dde863487cc19c6ba3880c781a8a9b23998ff6846b1a4f4149b7d7aa25f7affa41beb638b11175800f66eb772a946876f74ab0617d58360e90d879fb5a9dcc7b3635e93e0f64a8fcfc42dc344285d76e9e75ffa8de775b8514a98c3dc7f74af47b9a03e108b91386c84096e6adb013e6f5b49ab1b19b348988790d37cfe50f5e5c432f699298dde62942ca4166938a1169b0229da697494bf15c0ca060439f9d5de7072af8d3a1201c476829cde81cba2c7e42dc1e38620c3f09d27eb504213d5038538ac15e42df6df9f3e5d7f9e27b2beef7f2a885f5742d00161a4da326d1a2ac7ec8876362c76732e15c307d260f90e712633e805710ba861596faf62532b6baf1a332eb0e30e4f62011a71ed2c9eff338089958eace69aed2e6d1ca406bd2f20626a835c9a66db9b751a9bbd8427281cfe8be305dce8385eec3d5609d5370d3e8fc9cd881d010a4c830cbbd4138a0f2997cc589fd15daf783e377ef1c8762beb60062d0f7b47b32cf6f31248 \ No newline at end of file From 1ae844e7fc8e8e5cd510618653b7058ae882b68a Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Thu, 23 Feb 2023 12:01:31 -0500 Subject: [PATCH 045/145] Picked up docstring changes for Window.timer_start in the call reference --- docs/call reference.md | 3 ++- readme_creator/output/call reference.md | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/call reference.md b/docs/call reference.md index 654561b7..935ad72a 100644 --- a/docs/call reference.md +++ b/docs/call reference.md @@ -13867,7 +13867,8 @@ Returns a list of currently active timers for a window ### timer_start Starts a timer that gnerates Timer Events. The default is to repeat the timer events until timer is stopped. -You can provide your own key or a default key will be used. +You can provide your own key or a default key will be used. The default key is defined +with the constants EVENT_TIMER or TIMER_KEY. They both equal the same value. The values dictionary will contain the timer ID that is returned from this function. ``` diff --git a/readme_creator/output/call reference.md b/readme_creator/output/call reference.md index 654561b7..935ad72a 100644 --- a/readme_creator/output/call reference.md +++ b/readme_creator/output/call reference.md @@ -13867,7 +13867,8 @@ Returns a list of currently active timers for a window ### timer_start Starts a timer that gnerates Timer Events. The default is to repeat the timer events until timer is stopped. -You can provide your own key or a default key will be used. +You can provide your own key or a default key will be used. The default key is defined +with the constants EVENT_TIMER or TIMER_KEY. They both equal the same value. The values dictionary will contain the timer ID that is returned from this function. ``` From ad67fe233e3828b230de407755c12e2abb1d485e Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Fri, 24 Feb 2023 04:37:37 -0500 Subject: [PATCH 046/145] Added autoscroll_only_at_bottom parameter to Multiline element --- PySimpleGUI.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index 683bd389..7f30da39 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -version = __version__ = "4.61.0.154 Unreleased" +version = __version__ = "4.61.0.155 Unreleased" _change_log = """ Changelog since 4.60.0 released to PyPI on 8-May-2022 @@ -375,6 +375,8 @@ _change_log = """ Updated layout error messages to include "sometimes" in the description of what may be causing error 4.61.0.154 Updated Window.start_timer docstring to include the constants EVENT_TIMER and TIMER_KEY since the call reference doesn't show the variable names but rather the string value. + 4.61.0.155 + Multiline new parameter autoscroll_only_at_bottom. When True, the element will autoscroll (keep scrollbar at the bottom) only if the scrollbar is already at the bottom. """ __version__ = version.split()[0] # For PEP 396 and PEP 345 @@ -3755,7 +3757,7 @@ class Multiline(Element): one up in the future too. """ - def __init__(self, default_text='', enter_submits=False, disabled=False, autoscroll=False, border_width=None, + def __init__(self, default_text='', enter_submits=False, disabled=False, autoscroll=False, autoscroll_only_at_bottom=False, border_width=None, size=(None, None), s=(None, None), auto_size_text=None, background_color=None, text_color=None, selected_text_color=None, selected_background_color=None, horizontal_scroll=False, change_submits=False, enable_events=False, do_not_clear=True, key=None, k=None, write_only=False, auto_refresh=False, reroute_stdout=False, reroute_stderr=False, reroute_cprint=False, echo_stdout_stderr=False, focus=False, font=None, pad=None, p=None, tooltip=None, justification=None, no_scrollbar=False, wrap_lines=None, sbar_trough_color=None, sbar_background_color=None, sbar_arrow_color=None, sbar_width=None, sbar_arrow_width=None, sbar_frame_color=None, sbar_relief=None, @@ -3769,6 +3771,8 @@ class Multiline(Element): :type disabled: (bool) :param autoscroll: If True the contents of the element will automatically scroll as more data added to the end :type autoscroll: (bool) + :param autoscroll_only_at_bottom: If True the contents of the element will automatically scroll only if the scrollbar is at the bottom of the multiline + :type autoscroll_only_at_bottom: (bool) :param border_width: width of border around element in pixels :type border_width: (int) :param size: (w, h) w=characters-wide, h=rows-high. If an int instead of a tuple is supplied, then height is auto-set to 1 @@ -3889,6 +3893,7 @@ class Multiline(Element): self.reroute_stderr = reroute_stderr self.no_scrollbar = no_scrollbar self.hscrollbar = None # The horizontal scrollbar + self.auto_scroll_only_at_bottom = autoscroll_only_at_bottom sz = size if size != (None, None) else s super().__init__(ELEM_TYPE_INPUT_MULTILINE, size=sz, auto_size_text=auto_size_text, background_color=bg, @@ -3943,6 +3948,7 @@ class Multiline(Element): if autoscroll is not None: self.Autoscroll = autoscroll + current_scroll_position = self.TKText.yview()[1] if justification is not None: if justification.startswith('l'): @@ -3989,8 +3995,11 @@ class Multiline(Element): self.TKText.configure(state='disabled') self.DefaultText = value + # if self.Autoscroll: + # self.TKText.see(tk.END) if self.Autoscroll: - self.TKText.see(tk.END) + if not self.auto_scroll_only_at_bottom or (self.auto_scroll_only_at_bottom and current_scroll_position == 1.0): + self.TKText.see(tk.END) if disabled is True: self.TKText.configure(state='disabled') elif disabled is False: @@ -26330,4 +26339,4 @@ if __name__ == '__main__': exit(0) main() exit(0) -#42b79b1bcb52a826b059ac9bb2ca70dba9418f275efc296cfac8eb77e2867f7c00de66abe0321614edd1eb498efe67bea8dc5bf4cb5f5c7ef1f49fd6df0e962387474b0ef0ce819e6b06bf69d1e3725b237a9041a9b09faeae2235178153f835f61e7bffec87d14f06fe47bcdb8c26bdd097d69f014a50130035811436bd02002c688248f367f3f60c22cb420e6101e2544dde863487cc19c6ba3880c781a8a9b23998ff6846b1a4f4149b7d7aa25f7affa41beb638b11175800f66eb772a946876f74ab0617d58360e90d879fb5a9dcc7b3635e93e0f64a8fcfc42dc344285d76e9e75ffa8de775b8514a98c3dc7f74af47b9a03e108b91386c84096e6adb013e6f5b49ab1b19b348988790d37cfe50f5e5c432f699298dde62942ca4166938a1169b0229da697494bf15c0ca060439f9d5de7072af8d3a1201c476829cde81cba2c7e42dc1e38620c3f09d27eb504213d5038538ac15e42df6df9f3e5d7f9e27b2beef7f2a885f5742d00161a4da326d1a2ac7ec8876362c76732e15c307d260f90e712633e805710ba861596faf62532b6baf1a332eb0e30e4f62011a71ed2c9eff338089958eace69aed2e6d1ca406bd2f20626a835c9a66db9b751a9bbd8427281cfe8be305dce8385eec3d5609d5370d3e8fc9cd881d010a4c830cbbd4138a0f2997cc589fd15daf783e377ef1c8762beb60062d0f7b47b32cf6f31248 \ No newline at end of file +#5bc1d5b124c2216b47e22ac8ad4b7056272a9f7c35fc0983deabbcb752071e82133158d85f70d7a54b5efd1fe80f615487a881be28732875ec59108338aa747b4f18940fbb47aa3414068d71da2d4ec64c83cd0305d0b74be2e84d26519a104c7233c84b24ff68f6f470668a27f0ebd75ade3059d0386decf9274874c5d18565266b972e4ed06c84a5d4d66482c270543329af1778d100a20328793c02adc21228cd28d7d8ef85a3bad75a8dc97e861d11360f15c0e0947f0cf0ce354821ee3154e8c71d204ff996b6afa21615ee5eca314af589bfbe3e9be6455376646332c8b2b77c758e7b65608c4fec97fc3cbe628718a9249996b5a00ed9429059a377b042acea20eca277516d23739d6a94f0d89fded115ee19c1755a53896fdff68e13c61a88ce10d78b964d1c63f9d7089765783d80a7ddc18d304994e6d6a5fd7cffa1489d6a3da08a1c9d04c707f41c52fb97a76bbef32c216e2acdac203910cfcafc3e22e21d640f31bd473e8409cc7fa3fe4e9142304394a857afa100cff69d2a278cee3bdbf239088ad350002992ffdce24d4aba46fc98043b8573e9f6e1c2fb6360c1841a0e9dbf5b203d9625e5f1b5ebb59c2bd2b6d7824a397dff3954d525601d8261675599ff81c67ba9c2b4bd7e3dc4e49a615adfb3e1496f5cb0d0ff4272e96704d577bdcd376a9e646bc49c692e57288ab8ad2bf684339728bd78d6d0 \ No newline at end of file From 73c692ebccd6dd64984e08d50c395eb6f064dc8b Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Fri, 24 Feb 2023 04:51:25 -0500 Subject: [PATCH 047/145] Added autoscroll_only_at_bottom to Output element too --- PySimpleGUI.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index 7f30da39..20c15dfd 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -version = __version__ = "4.61.0.155 Unreleased" +version = __version__ = "4.61.0.156 Unreleased" _change_log = """ Changelog since 4.60.0 released to PyPI on 8-May-2022 @@ -377,6 +377,8 @@ _change_log = """ Updated Window.start_timer docstring to include the constants EVENT_TIMER and TIMER_KEY since the call reference doesn't show the variable names but rather the string value. 4.61.0.155 Multiline new parameter autoscroll_only_at_bottom. When True, the element will autoscroll (keep scrollbar at the bottom) only if the scrollbar is already at the bottom. + 4.61.0.156 + Added the new Multiline parameter autoscroll_only_at_bottom so that the Output element can also use this option """ __version__ = version.split()[0] # For PEP 396 and PEP 345 @@ -4780,7 +4782,7 @@ class Output(Multiline): so that an item is not included in the values dictionary on every window.read call """ - def __init__(self, size=(None, None), s=(None, None), background_color=None, text_color=None, pad=None, p=None, echo_stdout_stderr=False, font=None, tooltip=None, + def __init__(self, size=(None, None), s=(None, None), background_color=None, text_color=None, pad=None, p=None, autoscroll_only_at_bottom=False, echo_stdout_stderr=False, font=None, tooltip=None, key=None, k=None, right_click_menu=None, expand_x=False, expand_y=False, visible=True, metadata=None, wrap_lines=None, horizontal_scroll=None, sbar_trough_color=None, sbar_background_color=None, sbar_arrow_color=None, sbar_width=None, sbar_arrow_width=None, sbar_frame_color=None, sbar_relief=None): """ @@ -4796,6 +4798,8 @@ class Output(Multiline): :type pad: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int) | int :param p: Same as pad parameter. It's an alias. If EITHER of them are set, then the one that's set will be used. If BOTH are set, pad will be used :type p: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int) | int + :param autoscroll_only_at_bottom: If True the contents of the element will automatically scroll only if the scrollbar is at the bottom of the multiline + :type autoscroll_only_at_bottom: (bool) :param echo_stdout_stderr: If True then output to stdout will be output to this element AND also to the normal console location :type echo_stdout_stderr: (bool) :param font: specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike @@ -4837,7 +4841,7 @@ class Output(Multiline): """ - super().__init__(size=size, s=s, background_color=background_color, text_color=text_color, pad=pad, p=p, echo_stdout_stderr=echo_stdout_stderr, font=font, tooltip=tooltip, wrap_lines=wrap_lines, horizontal_scroll=horizontal_scroll, key=key, k=k, right_click_menu=right_click_menu, write_only=True, reroute_stdout=True, reroute_stderr=True, reroute_cprint=True, autoscroll=True, auto_refresh=True, expand_x=expand_x, expand_y=expand_y, visible=visible, metadata=metadata, sbar_trough_color=sbar_trough_color, sbar_background_color=sbar_background_color, sbar_arrow_color=sbar_arrow_color, sbar_width=sbar_width, sbar_arrow_width=sbar_arrow_width, sbar_frame_color=sbar_frame_color, sbar_relief=sbar_relief) + super().__init__(size=size, s=s, background_color=background_color, autoscroll_only_at_bottom=autoscroll_only_at_bottom, text_color=text_color, pad=pad, p=p, echo_stdout_stderr=echo_stdout_stderr, font=font, tooltip=tooltip, wrap_lines=wrap_lines, horizontal_scroll=horizontal_scroll, key=key, k=k, right_click_menu=right_click_menu, write_only=True, reroute_stdout=True, reroute_stderr=True, reroute_cprint=True, autoscroll=True, auto_refresh=True, expand_x=expand_x, expand_y=expand_y, visible=visible, metadata=metadata, sbar_trough_color=sbar_trough_color, sbar_background_color=sbar_background_color, sbar_arrow_color=sbar_arrow_color, sbar_width=sbar_width, sbar_arrow_width=sbar_arrow_width, sbar_frame_color=sbar_frame_color, sbar_relief=sbar_relief) @@ -26339,4 +26343,4 @@ if __name__ == '__main__': exit(0) main() exit(0) -#5bc1d5b124c2216b47e22ac8ad4b7056272a9f7c35fc0983deabbcb752071e82133158d85f70d7a54b5efd1fe80f615487a881be28732875ec59108338aa747b4f18940fbb47aa3414068d71da2d4ec64c83cd0305d0b74be2e84d26519a104c7233c84b24ff68f6f470668a27f0ebd75ade3059d0386decf9274874c5d18565266b972e4ed06c84a5d4d66482c270543329af1778d100a20328793c02adc21228cd28d7d8ef85a3bad75a8dc97e861d11360f15c0e0947f0cf0ce354821ee3154e8c71d204ff996b6afa21615ee5eca314af589bfbe3e9be6455376646332c8b2b77c758e7b65608c4fec97fc3cbe628718a9249996b5a00ed9429059a377b042acea20eca277516d23739d6a94f0d89fded115ee19c1755a53896fdff68e13c61a88ce10d78b964d1c63f9d7089765783d80a7ddc18d304994e6d6a5fd7cffa1489d6a3da08a1c9d04c707f41c52fb97a76bbef32c216e2acdac203910cfcafc3e22e21d640f31bd473e8409cc7fa3fe4e9142304394a857afa100cff69d2a278cee3bdbf239088ad350002992ffdce24d4aba46fc98043b8573e9f6e1c2fb6360c1841a0e9dbf5b203d9625e5f1b5ebb59c2bd2b6d7824a397dff3954d525601d8261675599ff81c67ba9c2b4bd7e3dc4e49a615adfb3e1496f5cb0d0ff4272e96704d577bdcd376a9e646bc49c692e57288ab8ad2bf684339728bd78d6d0 \ No newline at end of file +#29f00650f6027a50a70e9ed99df59876f83c29dbb03918935601275473d178e66f3e24ef76f973d2d8b5f32736ad3ad4178606a1dc46e350f8eaa4d76ceaee2690a5b62ab06e77765601fcd09c9eec05914c355fcbbc027500703a90577976c830232d550e074c7eb265687c33afb7028739fdbd7d6ece2e79899b99da85c75970bf603bad96e94b6899f78d9acc8eadeff67c6896c71b3ca41c40bf1e8100b64bbf640baef9092c2e5d53ce9ab235be342de5506cac579ea146e4642a3b1e10a581f039d139a398cf7cda6bc7958024c872782264998580e0c54d73eb82203b25df0c2e9c69b73aab882dbbc2181e8777c4b9a04a3dd7e894a2e1705d451666d39345356e84b22e2f10dc8828bcae58c238b565e0bdaaa181db7124cc88192224ae5f10e58a313d997cc56eb46f3e0522288d7b2a0b6d240393d7ee05fbd899bea63819af50e2eeab739aee0eb567f0b291fdee48d5208b5c84263daa0b0d257b9b6fdc2b750f17248f6f17c7c1c6cda7c4dd2a0d2d1b60cc263043e338550d313aaccff51b143cd8fb6001349796e629a9255f7e03b20855015db22673615ceb882dc6771355a83fd877988671e5a0cebae22f79b4c9f7f73f9e20c96dc46269e0366afc37c98e706fe63ffc64e97392c922109d7366919609e225951a627bbdd6ecac8f6852ed447ffd3a7fde7ccf732134385ec03e40fc1422ec2adcac4a \ No newline at end of file From 0cf29cc20fdcd986bd4a63fd731cc847f860dde3 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Fri, 24 Feb 2023 08:57:26 -0500 Subject: [PATCH 048/145] Addition of Timer API Calls section --- .../markdown input files/2_readme.md | 49 ++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/readme_creator/markdown input files/2_readme.md b/readme_creator/markdown input files/2_readme.md index 979af1f3..bdd7cebe 100644 --- a/readme_creator/markdown input files/2_readme.md +++ b/readme_creator/markdown input files/2_readme.md @@ -5574,13 +5574,60 @@ There are a number of demo programs that show how to use UserSettings to create If you're using the default path, remember that previous runs of your file may have old settings that are still in your settings file. It can get confusing when you've forgotten that you previously wrote a setting. Not seeing the filename can have drawbacks like this. -Also, because the settings automatically save after every update, it can be easy to accidently overwrite a previously saved setting. If you want to avoid this, then perhaps it's best that you work with a dictionary within your code and then explicitly save your dictionary when you're ready to commit it to disk. +Also, because the settings automatically save after every update, it can be easy to accidentally overwrite a previously saved setting. If you want to avoid this, then perhaps it's best that you work with a dictionary within your code and then explicitly save your dictionary when you're ready to commit it to disk. To save your Python dictionary to a settings file, simply call `user_settings_write_new_dictionary(dict)`, passing in your dictionary as the parameter. ------------------------- +# Timer API + +The Timer API calls are in version 4.61.0 that is currently only available on the PySimpleGUI GitHub. It has not been released to PyPI yet. + +## Do Not Use Sleeps In Your Event Loop... + +Instead of sleeping, you can request that an event be generated after some period of time. If you need to "Sleep for 3 seconds" as part of some operation, instead schedule a timer for 3 seconds. Your `window.read` call will return a value of `sg.TIMER_KEY` or `sg.EVENT_TIMER` (they are aliases and thus have the same value). + + +## Timer API Calls + +These are the API calls that you'll use to manage timers: + + +`window.timer_start` starts a timer + +`window.timer_stop` stops a single timer + +`window.timer_stop_all` stops all timers + +`window.timer_get_active_timers` returns a list of active timer IDs + +Example - start a 3 second timer that does not repeat: + +```python +window.timer_start(3000, repeating=False) # start a 3-second timer +``` + +When this timer expires, you'll get an event `sg.EVENT_TIMER`. If you want to specify your own key to be returned, then use the `key` parameter: + +```python +window.timer_start(3000, key='-MY TIMER KEY-', repeating=False) +``` + + +See the call reference for the details of each call. + +## Timer Demo Programs + +Using the PySimpleGUI Demo Browser, search for `window.timer_` to find Demo Programs that use the Timer API calls. + +The program `Demo_WindowTimer.py` demonstrates both repeating and non-repeating timers as well as using custom keys. It's a simple set of API calls to use and the docstrings in combination with the Demo Programs should give you all you need to start using this capability. + + + +--------------------------- + # Extending PySimpleGUI From 3275279f9c86c8761a6b8fdcc38d365a959cb898 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Fri, 24 Feb 2023 08:57:48 -0500 Subject: [PATCH 049/145] Addition of Timer API Calls --- docs/index.md | 44 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/docs/index.md b/docs/index.md index 0b954e7f..4121f51d 100644 --- a/docs/index.md +++ b/docs/index.md @@ -7112,12 +7112,54 @@ There are a number of demo programs that show how to use UserSettings to create If you're using the default path, remember that previous runs of your file may have old settings that are still in your settings file. It can get confusing when you've forgotten that you previously wrote a setting. Not seeing the filename can have drawbacks like this. -Also, because the settings automatically save after every update, it can be easy to accidently overwrite a previously saved setting. If you want to avoid this, then perhaps it's best that you work with a dictionary within your code and then explicitly save your dictionary when you're ready to commit it to disk. +Also, because the settings automatically save after every update, it can be easy to accidentally overwrite a previously saved setting. If you want to avoid this, then perhaps it's best that you work with a dictionary within your code and then explicitly save your dictionary when you're ready to commit it to disk. To save your Python dictionary to a settings file, simply call `user_settings_write_new_dictionary(dict)`, passing in your dictionary as the parameter. ------------------------- +# Timer API + +The Timer API calls are in version 4.61.0 that is currently only available on the PySimpleGUI GitHub. It has not been released to PyPI yet. + +## Do Not Use Sleeps In Your Event Loop... + +Instead of sleeping, you can request that an event be generated after some period of time. If you need to "Sleep for 3 seconds" as part of some operation, instead schedule a timer for 3 seconds. Your `window.read` call will return a value of `sg.TIMER_KEY` or `sg.EVENT_TIMER` (they are aliases and thus have the same value). + +## Timer API Calls + +These are the API calls that you'll use to manage timers: + +`window.timer_start` starts a timer + +`window.timer_stop` stops a single timer + +`window.timer_stop_all` stops all timers + +`window.timer_get_active_timers` returns a list of active timer IDs + +Example - start a 3 second timer that does not repeat: + +```python +window.timer_start(3000, repeating=False) # start a 3-second timer +``` + +When this timer expires, you'll get an event `sg.EVENT_TIMER`. If you want to specify your own key to be returned, then use the `key` parameter: + +```python +window.timer_start(3000, key='-MY TIMER KEY-', repeating=False) +``` + +See the call reference for the details of each call. + +## Timer Demo Programs + +Using the PySimpleGUI Demo Browser, search for `window.timer_` to find Demo Programs that use the Timer API calls. + +The program `Demo_WindowTimer.py` demonstrates both repeating and non-repeating timers as well as using custom keys. It's a simple set of API calls to use and the docstrings in combination with the Demo Programs should give you all you need to start using this capability. + +--------------------------- + # Extending PySimpleGUI PySimpleGUI doesn't and can't provide every single setting available in the underlying GUI framework. Not all tkinter options are available for a `Text` Element. Same with PySimpleGUIQt and the other ports. From ba0e5fed78660a48dbf90b1073db167e9be9558c Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Fri, 24 Feb 2023 08:58:02 -0500 Subject: [PATCH 050/145] Addition of Timer API calls --- readme_creator/output/index.md | 44 +++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/readme_creator/output/index.md b/readme_creator/output/index.md index 0b954e7f..4121f51d 100644 --- a/readme_creator/output/index.md +++ b/readme_creator/output/index.md @@ -7112,12 +7112,54 @@ There are a number of demo programs that show how to use UserSettings to create If you're using the default path, remember that previous runs of your file may have old settings that are still in your settings file. It can get confusing when you've forgotten that you previously wrote a setting. Not seeing the filename can have drawbacks like this. -Also, because the settings automatically save after every update, it can be easy to accidently overwrite a previously saved setting. If you want to avoid this, then perhaps it's best that you work with a dictionary within your code and then explicitly save your dictionary when you're ready to commit it to disk. +Also, because the settings automatically save after every update, it can be easy to accidentally overwrite a previously saved setting. If you want to avoid this, then perhaps it's best that you work with a dictionary within your code and then explicitly save your dictionary when you're ready to commit it to disk. To save your Python dictionary to a settings file, simply call `user_settings_write_new_dictionary(dict)`, passing in your dictionary as the parameter. ------------------------- +# Timer API + +The Timer API calls are in version 4.61.0 that is currently only available on the PySimpleGUI GitHub. It has not been released to PyPI yet. + +## Do Not Use Sleeps In Your Event Loop... + +Instead of sleeping, you can request that an event be generated after some period of time. If you need to "Sleep for 3 seconds" as part of some operation, instead schedule a timer for 3 seconds. Your `window.read` call will return a value of `sg.TIMER_KEY` or `sg.EVENT_TIMER` (they are aliases and thus have the same value). + +## Timer API Calls + +These are the API calls that you'll use to manage timers: + +`window.timer_start` starts a timer + +`window.timer_stop` stops a single timer + +`window.timer_stop_all` stops all timers + +`window.timer_get_active_timers` returns a list of active timer IDs + +Example - start a 3 second timer that does not repeat: + +```python +window.timer_start(3000, repeating=False) # start a 3-second timer +``` + +When this timer expires, you'll get an event `sg.EVENT_TIMER`. If you want to specify your own key to be returned, then use the `key` parameter: + +```python +window.timer_start(3000, key='-MY TIMER KEY-', repeating=False) +``` + +See the call reference for the details of each call. + +## Timer Demo Programs + +Using the PySimpleGUI Demo Browser, search for `window.timer_` to find Demo Programs that use the Timer API calls. + +The program `Demo_WindowTimer.py` demonstrates both repeating and non-repeating timers as well as using custom keys. It's a simple set of API calls to use and the docstrings in combination with the Demo Programs should give you all you need to start using this capability. + +--------------------------- + # Extending PySimpleGUI PySimpleGUI doesn't and can't provide every single setting available in the underlying GUI framework. Not all tkinter options are available for a `Text` Element. Same with PySimpleGUIQt and the other ports. From 8f74aa5c8dcd151a7c859724484b73e2f09cbe31 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Fri, 24 Feb 2023 08:58:41 -0500 Subject: [PATCH 051/145] Picking up the latest Multiline & Output element feature that's on GitHub - new parameter autoscroll_only_at_bottom --- docs/call reference.md | 54 +++++++++++++------------ readme_creator/output/call reference.md | 54 +++++++++++++------------ 2 files changed, 58 insertions(+), 50 deletions(-) diff --git a/docs/call reference.md b/docs/call reference.md index 935ad72a..98c2f2a2 100644 --- a/docs/call reference.md +++ b/docs/call reference.md @@ -6248,6 +6248,7 @@ Multiline(default_text = "", enter_submits = False, disabled = False, autoscroll = False, + autoscroll_only_at_bottom = False, border_width = None, size = (None, None), s = (None, None), @@ -6299,6 +6300,7 @@ Parameter Descriptions: | bool | enter_submits | if True, the Window.read call will return is enter key is pressed in this element | | bool | disabled | set disable state | | bool | autoscroll | If True the contents of the element will automatically scroll as more data added to the end | +| bool | autoscroll_only_at_bottom | If True the contents of the element will automatically scroll only if the scrollbar is at the bottom of the multiline | | int | border_width | width of border around element in pixels | | (int, int) or (None, None) or int | size | (w, h) w=characters-wide, h=rows-high. If an int instead of a tuple is supplied, then height is auto-set to 1 | | (int, int) or (None, None) or int | s | Same as size parameter. It's an alias. If EITHER of them are set, then the one that's set will be used. If BOTH are set, size will be used | @@ -7235,6 +7237,7 @@ Output(size = (None, None), text_color = None, pad = None, p = None, + autoscroll_only_at_bottom = False, echo_stdout_stderr = False, font = None, tooltip = None, @@ -7260,31 +7263,32 @@ Parameter Descriptions: |Type|Name|Meaning| |--|--|--| -| (int, int) or (None, None) or int | size | (w, h) w=characters-wide, h=rows-high. If an int instead of a tuple is supplied, then height is auto-set to 1 | -| (int, int) or (None, None) or int | s | Same as size parameter. It's an alias. If EITHER of them are set, then the one that's set will be used. If BOTH are set, size will be used | -| str | background_color | color of background | -| str | text_color | color of the text | -| (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | pad | Amount of padding to put around element in pixels (left/right, top/bottom) or ((left, right), (top, bottom)) or an int. If an int, then it's converted into a tuple (int, int) | -| (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | p | Same as pad parameter. It's an alias. If EITHER of them are set, then the one that's set will be used. If BOTH are set, pad will be used | -| bool | echo_stdout_stderr | If True then output to stdout will be output to this element AND also to the normal console location | -| (str or (str, int[, str]) or None) | font | specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike | -| str | tooltip | text, that will appear when mouse hovers over the element | -| str or int or tuple or object | key | Used with window.find_element and with return values to uniquely identify this element to uniquely identify this element | -| str or int or tuple or object | k | Same as the Key. You can use either k or key. Which ever is set will be used. | -| List[List[ List[str] or str ]] | right_click_menu | A list of lists of Menu items to show when this element is right clicked. See user docs for exact format. | -| bool | expand_x | If True the element will automatically expand in the X direction to fill available space | -| bool | expand_y | If True the element will automatically expand in the Y direction to fill available space | -| bool | visible | set visibility state of the element | -| Any | metadata | User metadata that can be set to ANYTHING | -| bool | wrap_lines | If True, the lines will be wrapped automatically. Other parms affect this setting, but this one will override them all. Default is it does nothing and uses previous settings for wrapping. | -| bool | horizontal_scroll | Controls if a horizontal scrollbar should be shown. If True, then line wrapping will be off by default | -| str | sbar_trough_color | Scrollbar color of the trough | -| str | sbar_background_color | Scrollbar color of the background of the arrow buttons at the ends AND the color of the "thumb" (the thing you grab and slide). Switches to arrow color when mouse is over | -| str | sbar_arrow_color | Scrollbar color of the arrow at the ends of the scrollbar (it looks like a button). Switches to background color when mouse is over | -| int | sbar_width | Scrollbar width in pixels | -| int | sbar_arrow_width | Scrollbar width of the arrow on the scrollbar. It will potentially impact the overall width of the scrollbar | -| str | sbar_frame_color | Scrollbar Color of frame around scrollbar (available only on some ttk themes) | -| str | sbar_relief | Scrollbar relief that will be used for the "thumb" of the scrollbar (the thing you grab that slides). Should be a constant that is defined at starting with "RELIEF_" - RELIEF_RAISED, RELIEF_SUNKEN, RELIEF_FLAT, RELIEF_RIDGE, RELIEF_GROOVE, RELIEF_SOLID | +| (int, int) or (None, None) or int | size | (w, h) w=characters-wide, h=rows-high. If an int instead of a tuple is supplied, then height is auto-set to 1 | +| (int, int) or (None, None) or int | s | Same as size parameter. It's an alias. If EITHER of them are set, then the one that's set will be used. If BOTH are set, size will be used | +| str | background_color | color of background | +| str | text_color | color of the text | +| (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | pad | Amount of padding to put around element in pixels (left/right, top/bottom) or ((left, right), (top, bottom)) or an int. If an int, then it's converted into a tuple (int, int) | +| (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | p | Same as pad parameter. It's an alias. If EITHER of them are set, then the one that's set will be used. If BOTH are set, pad will be used | +| bool | autoscroll_only_at_bottom | If True the contents of the element will automatically scroll only if the scrollbar is at the bottom of the multiline | +| bool | echo_stdout_stderr | If True then output to stdout will be output to this element AND also to the normal console location | +| (str or (str, int[, str]) or None) | font | specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike | +| str | tooltip | text, that will appear when mouse hovers over the element | +| str or int or tuple or object | key | Used with window.find_element and with return values to uniquely identify this element to uniquely identify this element | +| str or int or tuple or object | k | Same as the Key. You can use either k or key. Which ever is set will be used. | +| List[List[ List[str] or str ]] | right_click_menu | A list of lists of Menu items to show when this element is right clicked. See user docs for exact format. | +| bool | expand_x | If True the element will automatically expand in the X direction to fill available space | +| bool | expand_y | If True the element will automatically expand in the Y direction to fill available space | +| bool | visible | set visibility state of the element | +| Any | metadata | User metadata that can be set to ANYTHING | +| bool | wrap_lines | If True, the lines will be wrapped automatically. Other parms affect this setting, but this one will override them all. Default is it does nothing and uses previous settings for wrapping. | +| bool | horizontal_scroll | Controls if a horizontal scrollbar should be shown. If True, then line wrapping will be off by default | +| str | sbar_trough_color | Scrollbar color of the trough | +| str | sbar_background_color | Scrollbar color of the background of the arrow buttons at the ends AND the color of the "thumb" (the thing you grab and slide). Switches to arrow color when mouse is over | +| str | sbar_arrow_color | Scrollbar color of the arrow at the ends of the scrollbar (it looks like a button). Switches to background color when mouse is over | +| int | sbar_width | Scrollbar width in pixels | +| int | sbar_arrow_width | Scrollbar width of the arrow on the scrollbar. It will potentially impact the overall width of the scrollbar | +| str | sbar_frame_color | Scrollbar Color of frame around scrollbar (available only on some ttk themes) | +| str | sbar_relief | Scrollbar relief that will be used for the "thumb" of the scrollbar (the thing you grab that slides). Should be a constant that is defined at starting with "RELIEF_" - RELIEF_RAISED, RELIEF_SUNKEN, RELIEF_FLAT, RELIEF_RIDGE, RELIEF_GROOVE, RELIEF_SOLID | ### bind diff --git a/readme_creator/output/call reference.md b/readme_creator/output/call reference.md index 935ad72a..98c2f2a2 100644 --- a/readme_creator/output/call reference.md +++ b/readme_creator/output/call reference.md @@ -6248,6 +6248,7 @@ Multiline(default_text = "", enter_submits = False, disabled = False, autoscroll = False, + autoscroll_only_at_bottom = False, border_width = None, size = (None, None), s = (None, None), @@ -6299,6 +6300,7 @@ Parameter Descriptions: | bool | enter_submits | if True, the Window.read call will return is enter key is pressed in this element | | bool | disabled | set disable state | | bool | autoscroll | If True the contents of the element will automatically scroll as more data added to the end | +| bool | autoscroll_only_at_bottom | If True the contents of the element will automatically scroll only if the scrollbar is at the bottom of the multiline | | int | border_width | width of border around element in pixels | | (int, int) or (None, None) or int | size | (w, h) w=characters-wide, h=rows-high. If an int instead of a tuple is supplied, then height is auto-set to 1 | | (int, int) or (None, None) or int | s | Same as size parameter. It's an alias. If EITHER of them are set, then the one that's set will be used. If BOTH are set, size will be used | @@ -7235,6 +7237,7 @@ Output(size = (None, None), text_color = None, pad = None, p = None, + autoscroll_only_at_bottom = False, echo_stdout_stderr = False, font = None, tooltip = None, @@ -7260,31 +7263,32 @@ Parameter Descriptions: |Type|Name|Meaning| |--|--|--| -| (int, int) or (None, None) or int | size | (w, h) w=characters-wide, h=rows-high. If an int instead of a tuple is supplied, then height is auto-set to 1 | -| (int, int) or (None, None) or int | s | Same as size parameter. It's an alias. If EITHER of them are set, then the one that's set will be used. If BOTH are set, size will be used | -| str | background_color | color of background | -| str | text_color | color of the text | -| (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | pad | Amount of padding to put around element in pixels (left/right, top/bottom) or ((left, right), (top, bottom)) or an int. If an int, then it's converted into a tuple (int, int) | -| (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | p | Same as pad parameter. It's an alias. If EITHER of them are set, then the one that's set will be used. If BOTH are set, pad will be used | -| bool | echo_stdout_stderr | If True then output to stdout will be output to this element AND also to the normal console location | -| (str or (str, int[, str]) or None) | font | specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike | -| str | tooltip | text, that will appear when mouse hovers over the element | -| str or int or tuple or object | key | Used with window.find_element and with return values to uniquely identify this element to uniquely identify this element | -| str or int or tuple or object | k | Same as the Key. You can use either k or key. Which ever is set will be used. | -| List[List[ List[str] or str ]] | right_click_menu | A list of lists of Menu items to show when this element is right clicked. See user docs for exact format. | -| bool | expand_x | If True the element will automatically expand in the X direction to fill available space | -| bool | expand_y | If True the element will automatically expand in the Y direction to fill available space | -| bool | visible | set visibility state of the element | -| Any | metadata | User metadata that can be set to ANYTHING | -| bool | wrap_lines | If True, the lines will be wrapped automatically. Other parms affect this setting, but this one will override them all. Default is it does nothing and uses previous settings for wrapping. | -| bool | horizontal_scroll | Controls if a horizontal scrollbar should be shown. If True, then line wrapping will be off by default | -| str | sbar_trough_color | Scrollbar color of the trough | -| str | sbar_background_color | Scrollbar color of the background of the arrow buttons at the ends AND the color of the "thumb" (the thing you grab and slide). Switches to arrow color when mouse is over | -| str | sbar_arrow_color | Scrollbar color of the arrow at the ends of the scrollbar (it looks like a button). Switches to background color when mouse is over | -| int | sbar_width | Scrollbar width in pixels | -| int | sbar_arrow_width | Scrollbar width of the arrow on the scrollbar. It will potentially impact the overall width of the scrollbar | -| str | sbar_frame_color | Scrollbar Color of frame around scrollbar (available only on some ttk themes) | -| str | sbar_relief | Scrollbar relief that will be used for the "thumb" of the scrollbar (the thing you grab that slides). Should be a constant that is defined at starting with "RELIEF_" - RELIEF_RAISED, RELIEF_SUNKEN, RELIEF_FLAT, RELIEF_RIDGE, RELIEF_GROOVE, RELIEF_SOLID | +| (int, int) or (None, None) or int | size | (w, h) w=characters-wide, h=rows-high. If an int instead of a tuple is supplied, then height is auto-set to 1 | +| (int, int) or (None, None) or int | s | Same as size parameter. It's an alias. If EITHER of them are set, then the one that's set will be used. If BOTH are set, size will be used | +| str | background_color | color of background | +| str | text_color | color of the text | +| (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | pad | Amount of padding to put around element in pixels (left/right, top/bottom) or ((left, right), (top, bottom)) or an int. If an int, then it's converted into a tuple (int, int) | +| (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | p | Same as pad parameter. It's an alias. If EITHER of them are set, then the one that's set will be used. If BOTH are set, pad will be used | +| bool | autoscroll_only_at_bottom | If True the contents of the element will automatically scroll only if the scrollbar is at the bottom of the multiline | +| bool | echo_stdout_stderr | If True then output to stdout will be output to this element AND also to the normal console location | +| (str or (str, int[, str]) or None) | font | specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike | +| str | tooltip | text, that will appear when mouse hovers over the element | +| str or int or tuple or object | key | Used with window.find_element and with return values to uniquely identify this element to uniquely identify this element | +| str or int or tuple or object | k | Same as the Key. You can use either k or key. Which ever is set will be used. | +| List[List[ List[str] or str ]] | right_click_menu | A list of lists of Menu items to show when this element is right clicked. See user docs for exact format. | +| bool | expand_x | If True the element will automatically expand in the X direction to fill available space | +| bool | expand_y | If True the element will automatically expand in the Y direction to fill available space | +| bool | visible | set visibility state of the element | +| Any | metadata | User metadata that can be set to ANYTHING | +| bool | wrap_lines | If True, the lines will be wrapped automatically. Other parms affect this setting, but this one will override them all. Default is it does nothing and uses previous settings for wrapping. | +| bool | horizontal_scroll | Controls if a horizontal scrollbar should be shown. If True, then line wrapping will be off by default | +| str | sbar_trough_color | Scrollbar color of the trough | +| str | sbar_background_color | Scrollbar color of the background of the arrow buttons at the ends AND the color of the "thumb" (the thing you grab and slide). Switches to arrow color when mouse is over | +| str | sbar_arrow_color | Scrollbar color of the arrow at the ends of the scrollbar (it looks like a button). Switches to background color when mouse is over | +| int | sbar_width | Scrollbar width in pixels | +| int | sbar_arrow_width | Scrollbar width of the arrow on the scrollbar. It will potentially impact the overall width of the scrollbar | +| str | sbar_frame_color | Scrollbar Color of frame around scrollbar (available only on some ttk themes) | +| str | sbar_relief | Scrollbar relief that will be used for the "thumb" of the scrollbar (the thing you grab that slides). Should be a constant that is defined at starting with "RELIEF_" - RELIEF_RAISED, RELIEF_SUNKEN, RELIEF_FLAT, RELIEF_RIDGE, RELIEF_GROOVE, RELIEF_SOLID | ### bind From 8e6fa8100abb2758fbf63331de3ed7ad5174ab8a Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Sat, 25 Feb 2023 13:21:26 -0500 Subject: [PATCH 052/145] New Demo Program - Table with checkmarks --- DemoPrograms/Demo_Table_Checkmark.py | 85 ++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 DemoPrograms/Demo_Table_Checkmark.py diff --git a/DemoPrograms/Demo_Table_Checkmark.py b/DemoPrograms/Demo_Table_Checkmark.py new file mode 100644 index 00000000..83e7fd77 --- /dev/null +++ b/DemoPrograms/Demo_Table_Checkmark.py @@ -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() + From efa236369f926247930757d048da15938b8fc76c Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Tue, 28 Feb 2023 06:27:57 -0500 Subject: [PATCH 053/145] New Demo Program - CPU Utilization shown on a very nice VU Meter Graphic --- DemoPrograms/Demo_Graph_Elem_CPU_Meter.py | 156 ++++++++++++++++++++++ 1 file changed, 156 insertions(+) create mode 100644 DemoPrograms/Demo_Graph_Elem_CPU_Meter.py diff --git a/DemoPrograms/Demo_Graph_Elem_CPU_Meter.py b/DemoPrograms/Demo_Graph_Elem_CPU_Meter.py new file mode 100644 index 00000000..f12c6213 --- /dev/null +++ b/DemoPrograms/Demo_Graph_Elem_CPU_Meter.py @@ -0,0 +1,156 @@ +import PySimpleGUI as sg +import math +import psutil + +""" + Demo Program - Display CPI Usage as a VU Meter + + Artwork and algorithm for handling of needle positioning generously provided by GitHub user neovich. + + A long-time PySimpleGUI user and brilliant programmer posted a screenshot of an incredibly + complex audio recording mixing application with features like custom sliders and VU meters made + entirely of Graph elements. I asked him to draw us some special artwork for this demo. An ENORMOUS + thank you to him for the encouragement, support, and hard work! + + This demo uses the psutil library to get the CPI utilization. It is then shown on a nicely rendered + VU meter. + + Copyright 2023 PySimpleGUI +""" + +# --- VU Meter Parameters ---------------------------------------------- + +x_needle_base = 169 +y_needle_base = 10 +needle_length = 280 +needle_multiply = 2 +needle_width = 2 +needle_color = '#434443' +needle_cutoff = 100 +angle_min = 60 +angle_max = 122 +CANVAS_KEY = 'CANVAS_vu_meter' + +# --- Colours ---------------------------------------------------------- +tick1_color = '#222222' +tick2_color = tick1_color +background = '#626059' +module_background = '#F2E2CA' +win0_background_color = background +tab_inner_colour = 'black' +background_main = background + + +sg.set_options(background_color=background, element_background_color=background) + +# ---------------------- Definitions ----------------------------------- + + +def VU_METER_update(CONT_CANVAS_vu_meter, a): + if a < angle_min : + a = angle_min + if a > angle_max: + a = angle_max + CONT_CANVAS_vu_meter.erase() + OBJ_VU_meter = CONT_CANVAS_vu_meter.draw_image(data=vu_meter_2,location= (0,234)) + x_angle = math.cos(math.radians(180-a)) + y_angle = math.sin(math.radians(180-a)) + x_cur = x_needle_base+(x_angle * needle_length) + y_cur = y_needle_base+int((y_angle * needle_length)*0.7) + x_cur_low = int(x_needle_base+(x_angle * (needle_length/needle_multiply))) + y_cur_low = int(y_needle_base+int((y_angle * (needle_length/needle_multiply))*0.7)) + OBJ_VU_meter_needle = CONT_CANVAS_vu_meter.draw_line( (x_cur_low,y_cur_low),(int(x_cur),int(y_cur)) ,color=needle_color,width=needle_width) + + +def main(): + # ------------------------- Init the VU_Meter -------------------------- + + + VU_METER_cont = [[sg.Graph ( canvas_size = ( 339,234 ), + graph_bottom_left=(0,0), + graph_top_right=(339,234), + background_color=module_background, + drag_submits=True, + enable_events=True, + float_values=True, + key=CANVAS_KEY )]] + + + # ------------------------- Tab Set Ups -------------------------------- + layout = [[sg.Column(VU_METER_cont ,background_color=module_background )]] + + + + location = sg.user_settings_get_entry('-location-', (None, None)) + + # ------------------------ Finalize Windows ---------------------------- + + window = sg.Window('CPU Usage as a VU Meter', layout, + no_titlebar=True, + auto_size_buttons=False, + keep_on_top=True, + grab_anywhere=True, + force_toplevel=False, + finalize=True, + location=location, + right_click_menu=sg.MENU_RIGHT_CLICK_EDITME_VER_EXIT, + enable_close_attempted_event=True) + + # ------------------------ Init the VU_Meter --------------------------- + + CONT_CANVAS_vu_meter = window[CANVAS_KEY] + angle = angle_min + x_angle = math.cos(math.radians(180-angle)) + y_angle = math.sin(math.radians(180-angle)) + x_cur = x_needle_base+(x_angle * needle_length) + y_cur = y_needle_base+int((y_angle * needle_length)*0.7) + x_cur_low = int(x_needle_base+(x_angle * (needle_length/needle_multiply))) + y_cur_low = int(y_needle_base+int((y_angle * (needle_length/needle_multiply))*0.7)) + OBJ_VU_meter_needle = CONT_CANVAS_vu_meter.draw_line( (x_cur_low,y_cur_low),(int(x_cur),int(y_cur)) ,color=needle_color,width=needle_width) + window.refresh() + + ######################################################################## + ## MAIN LOOP ## + ######################################################################## + temp_angle = 0 + angle_impulse = 2 + angle_range = angle_max-angle_min + while True: + event, values = window.read(timeout=30) + 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 + 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) + + + cpu_percent = psutil.cpu_percent(interval=1) + target_angle = angle_range * cpu_percent/100 + angle_min + if temp_angle == 0: + temp_angle = target_angle + + delta = abs(temp_angle - target_angle) + if temp_angle > target_angle: + temp_angle -= min(angle_impulse, delta) + else: + temp_angle += min(angle_impulse, delta) + VU_METER_update(CONT_CANVAS_vu_meter, temp_angle) + CONT_CANVAS_vu_meter.draw_text(f'{int(cpu_percent)}% CPU USED', (170, 40), color=module_background, font='_ 18') + + + + +if __name__ == '__main__': + + # --------- Images ----------------------------------------------------- + + needle = b'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' + + + vu_meter_2 = b'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' + + dot3 = b'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' + + main() From 8bd030f1a1381c40a821a26bc0c4ed7ddb30838d Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Wed, 1 Mar 2023 12:10:23 -0500 Subject: [PATCH 054/145] Changed Checkbox to not change color on mouseover on Linux. Added the optional window data row for internal texting ONLY --- PySimpleGUI.py | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index 20c15dfd..723fad32 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -version = __version__ = "4.61.0.156 Unreleased" +version = __version__ = "4.61.0.158 Unreleased" _change_log = """ Changelog since 4.60.0 released to PyPI on 8-May-2022 @@ -379,6 +379,10 @@ _change_log = """ Multiline new parameter autoscroll_only_at_bottom. When True, the element will autoscroll (keep scrollbar at the bottom) only if the scrollbar is already at the bottom. 4.61.0.156 Added the new Multiline parameter autoscroll_only_at_bottom so that the Output element can also use this option + 4.61.0.157 + Added the _optional_window_data function that is used to help with local PySimpleGUI testing of release candidates. Not meant to be used by end-users. + 4.61.0.158 + Checked checkbox activeforeground to be the same as the text so mouseover doesn't change color """ __version__ = version.split()[0] # For PEP 396 and PEP 345 @@ -10449,6 +10453,10 @@ class Window: 'This item will be stripped from your layout') continue self.add_row(*row) + if _optional_window_data(self) is not None: + self.add_row(_optional_window_data(self)) + + def layout(self, rows): """ @@ -16899,6 +16907,7 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form): element.TKCheckbutton.configure(activebackground=element.BackgroundColor) if text_color is not None and text_color != COLOR_SYSTEM_DEFAULT: element.TKCheckbutton.configure(fg=text_color) + element.TKCheckbutton.configure(activeforeground=element.TextColor) element.Widget.configure(highlightthickness=1) if element.BackgroundColor != COLOR_SYSTEM_DEFAULT: @@ -26300,6 +26309,18 @@ TimerStop = timer_stop test = main sdk_help = main_sdk_help +def _optional_window_data(window): + """ + A function to help with testing PySimpleGUI releases. Makes it easier to add a watermarked line to the bottom + of a window while testing release candidates. + + :param window: + :type window: Window + :return: An element that will be added to the bottom of the layout + :rtype: None | Element + """ + return None + pysimplegui_user_settings = UserSettings(filename=DEFAULT_USER_SETTINGS_PYSIMPLEGUI_FILENAME, path=DEFAULT_USER_SETTINGS_PYSIMPLEGUI_PATH) # ------------------------ Set the "Official PySimpleGUI Theme Colors" ------------------------ @@ -26343,4 +26364,4 @@ if __name__ == '__main__': exit(0) main() exit(0) -#29f00650f6027a50a70e9ed99df59876f83c29dbb03918935601275473d178e66f3e24ef76f973d2d8b5f32736ad3ad4178606a1dc46e350f8eaa4d76ceaee2690a5b62ab06e77765601fcd09c9eec05914c355fcbbc027500703a90577976c830232d550e074c7eb265687c33afb7028739fdbd7d6ece2e79899b99da85c75970bf603bad96e94b6899f78d9acc8eadeff67c6896c71b3ca41c40bf1e8100b64bbf640baef9092c2e5d53ce9ab235be342de5506cac579ea146e4642a3b1e10a581f039d139a398cf7cda6bc7958024c872782264998580e0c54d73eb82203b25df0c2e9c69b73aab882dbbc2181e8777c4b9a04a3dd7e894a2e1705d451666d39345356e84b22e2f10dc8828bcae58c238b565e0bdaaa181db7124cc88192224ae5f10e58a313d997cc56eb46f3e0522288d7b2a0b6d240393d7ee05fbd899bea63819af50e2eeab739aee0eb567f0b291fdee48d5208b5c84263daa0b0d257b9b6fdc2b750f17248f6f17c7c1c6cda7c4dd2a0d2d1b60cc263043e338550d313aaccff51b143cd8fb6001349796e629a9255f7e03b20855015db22673615ceb882dc6771355a83fd877988671e5a0cebae22f79b4c9f7f73f9e20c96dc46269e0366afc37c98e706fe63ffc64e97392c922109d7366919609e225951a627bbdd6ecac8f6852ed447ffd3a7fde7ccf732134385ec03e40fc1422ec2adcac4a \ No newline at end of file +#0d0ea93fb64af026d84d2013aa9668fa13acac5b5c3d26ea2b2210e0a6e41099998caabd813b486f52a22cf3bccc2b436ccb5bc40cd7f20304fe2445708fefaeb36f6438c79adf18db1c0a1ea942010adb37c97a5671f68ed639991d2df6396a2d76c81e8c91fdd42d54c61548253f9e34f991f0f4dcae66bd06eb370f2985d0ee8b7cf7768776bae229e860c019357a4fc8aaa956c93ab7b9d2b871e01a30f8485c04a35bb8a86798ba8f47d33f7afb8c2008a7687200feacb10835a9259620215d7ae19e87a45bcc7cc5c2ceda2419a137deeeb321cb227cfa5d3b5deca3fb2c06aeb98a0379cf61a4a52240129b091724cfc9c0693045a59d9707c0554f797eb6cf921849fd72bf2ff11c2e8ecf347c8b5bb89210a8b099d82ba614ad18b986f35ebea96a921bc9d667fa9c71e0e166451b9d7a45fe8fec665f7dd261354188bc0cc820dfd479da7aaf151934c72918b1dcec66ba8fee0790b495623f32f489a2c3430824186b7910cd91cc398202399ff9787d7cd1f5ad9bf58fbfe0ff79914f09c34a462a1d9d01ad17dc58d16e97a513130228fb3b8cc33eca70ae1b8aa69c1b1ae8b85f8bf2f0c412a40fdc94c5ec4469bc4a650141c50cc3ab3cf356dfc08b9062fd5bdac2e9d24240a3545549c1a9e3e17da862d5d1a85dea10556fecf62b1229cdfcfc10486435b41b519ca8a8ce3bbdbb52b7154fc34184539b73 \ No newline at end of file From c24d8b6b87778aa6659f4b9bed7037b6bb9f7471 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Mon, 6 Mar 2023 09:00:57 -0500 Subject: [PATCH 055/145] New Global Settings Feature - Window watermarking.... Use global settings window to control or force on/off when making a window. --- PySimpleGUI.py | 64 ++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 57 insertions(+), 7 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index 723fad32..f0cf0992 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -version = __version__ = "4.61.0.158 Unreleased" +version = __version__ = "4.61.0.159 Unreleased" _change_log = """ Changelog since 4.60.0 released to PyPI on 8-May-2022 @@ -383,6 +383,8 @@ _change_log = """ Added the _optional_window_data function that is used to help with local PySimpleGUI testing of release candidates. Not meant to be used by end-users. 4.61.0.158 Checked checkbox activeforeground to be the same as the text so mouseover doesn't change color + 4.61.0.159 + New Global Settings feature - Window watermarking. Can be forced on temporarily by settings watermark=True in your Window creation """ __version__ = version.split()[0] # For PEP 396 and PEP 345 @@ -10019,6 +10021,8 @@ class Window: _rerouted_stderr_stack = [] # type: List[Tuple[Window, Element]] _original_stdout = None _original_stderr = None + _watermark = None + _watermark_temp_forced = False def __init__(self, title, layout=None, default_element_size=None, default_button_element_size=(None, None), auto_size_text=None, auto_size_buttons=None, location=(None, None), relative_location=(None, None), size=(None, None), @@ -10033,7 +10037,7 @@ class Window: finalize=False, element_justification='left', ttk_theme=None, use_ttk_buttons=None, modal=False, enable_close_attempted_event=False, enable_window_config_events=False, titlebar_background_color=None, titlebar_text_color=None, titlebar_font=None, titlebar_icon=None, use_custom_titlebar=None, scaling=None, - sbar_trough_color=None, sbar_background_color=None, sbar_arrow_color=None, sbar_width=None, sbar_arrow_width=None, sbar_frame_color=None, sbar_relief=None, + sbar_trough_color=None, sbar_background_color=None, sbar_arrow_color=None, sbar_width=None, sbar_arrow_width=None, sbar_frame_color=None, sbar_relief=None, watermark=None, metadata=None): """ :param title: The title that will be displayed in the Titlebar and on the Taskbar @@ -10156,6 +10160,8 @@ class Window: :type sbar_frame_color: (str) :param sbar_relief: Scrollbar relief that will be used for the "thumb" of the scrollbar (the thing you grab that slides). Should be a constant that is defined at starting with "RELIEF_" - RELIEF_RAISED, RELIEF_SUNKEN, RELIEF_FLAT, RELIEF_RIDGE, RELIEF_GROOVE, RELIEF_SOLID :type sbar_relief: (str) + :param watermark: If True, then turns on watermarking temporarily for ALL windows created from this point forward. See global settings doc for more info + :type watermark: bool :param metadata: User metadata that can be set to ANYTHING :type metadata: (Any) """ @@ -10294,6 +10300,14 @@ class Window: self.Margins = (0, 0) self.NoTitleBar = True + if watermark is True: + Window._watermark_temp_forced = True + _global_settings_get_watermark_info() + elif watermark is False: + Window._watermark = None + Window._watermark_temp_forced = False + + self.ttk_part_overrides = TTKPartOverrides(sbar_trough_color=sbar_trough_color, sbar_background_color=sbar_background_color, sbar_arrow_color=sbar_arrow_color, sbar_width=sbar_width, sbar_arrow_width=sbar_arrow_width, sbar_frame_color=sbar_frame_color, sbar_relief=sbar_relief) if no_titlebar is True: @@ -10453,8 +10467,10 @@ class Window: 'This item will be stripped from your layout') continue self.add_row(*row) - if _optional_window_data(self) is not None: - self.add_row(_optional_window_data(self)) + # if _optional_window_data(self) is not None: + # self.add_row(_optional_window_data(self)) + if Window._watermark is not None: + self.add_row(Window._watermark(self)) @@ -25472,6 +25488,20 @@ def _global_settings_get_ttk_scrollbar_info(): DEFAULT_TTK_THEME = pysimplegui_user_settings.get('-ttk theme-', DEFAULT_TTK_THEME) +def _global_settings_get_watermark_info(): + if not pysimplegui_user_settings.get('-watermark-', False) and not Window._watermark_temp_forced: + Window._watermark = None + return + forced = Window._watermark_temp_forced + prefix_text = pysimplegui_user_settings.get('-watermark text-', '') + ver_text = ' ' + version if pysimplegui_user_settings.get('-watermark ver-', False if not forced else True) or forced else '' + framework_ver_text = ' ' + framework_version if pysimplegui_user_settings.get('-watermark framework ver-', False if not forced else True) or forced else '' + watermark_font = pysimplegui_user_settings.get('-watermark font-', '_ 9 Bold') + background_color = pysimplegui_user_settings.get('-watermark bg color-', 'window.BackgroundColor') + + Window._watermark = lambda window: Text(prefix_text + ver_text + framework_ver_text, font=watermark_font, background_color= window.BackgroundColor) + + def main_global_get_screen_snapshot_symcode(): pysimplegui_user_settings = UserSettings(filename=DEFAULT_USER_SETTINGS_PYSIMPLEGUI_FILENAME, path=DEFAULT_USER_SETTINGS_PYSIMPLEGUI_PATH) @@ -25608,8 +25638,18 @@ def main_global_pysimplegui_settings(): theme_tab = Tab('Theme', [[T('Leave blank for "official" PySimpleGUI default theme: {}'.format(OFFICIAL_PYSIMPLEGUI_THEME))], [T('Default Theme For All Programs:'), - Combo([''] + theme_list(), settings.get('-theme-', None), readonly=True, k='-THEME-', tooltip=tooltip_theme), Checkbox('Always use custom Titlebar', default=pysimplegui_user_settings.get('-custom titlebar-',False), k='-CUSTOM TITLEBAR-')]], - font='_ 16', expand_x=True) + Combo([''] + theme_list(), settings.get('-theme-', None), readonly=True, k='-THEME-', tooltip=tooltip_theme), Checkbox('Always use custom Titlebar', default=pysimplegui_user_settings.get('-custom titlebar-',False), k='-CUSTOM TITLEBAR-')], + [Frame('Window Watermarking', + [[Checkbox('Enable Window Watermarking', pysimplegui_user_settings.get('-watermark-', False), k='-WATERMARK-')], + [T('Prefix Text String:'), Input(pysimplegui_user_settings.get('-watermark text-', ''), k='-WATERMARK TEXT-')], + [Checkbox('PySimpleGUI Version', pysimplegui_user_settings.get('-watermark ver-', False), k='-WATERMARK VER-')], + [Checkbox('Framework Version',pysimplegui_user_settings.get('-watermark framework ver-', False), k='-WATERMARK FRAMEWORK VER-')], + [T('Font:'), Input(pysimplegui_user_settings.get('-watermark font-', '_ 9 bold'), k='-WATERMARK FONT-')], + # [T('Background Color:'), Input(pysimplegui_user_settings.get('-watermark bg color-', 'window.BackgroundColor'), k='-WATERMARK BG COLOR-')], + ], + font='_ 16', expand_x=True)]]) + + # ------------------------- Security Tab ------------------------- security_tab = Tab('Security', @@ -25641,6 +25681,12 @@ def main_global_pysimplegui_settings(): pysimplegui_user_settings.set('-python command-', values['-PYTHON COMMAND-']) pysimplegui_user_settings.set('-custom titlebar-', values['-CUSTOM TITLEBAR-']) pysimplegui_user_settings.set('-theme-', new_theme) + pysimplegui_user_settings.set('-watermark-', values['-WATERMARK-']) + pysimplegui_user_settings.set('-watermark text-', values['-WATERMARK TEXT-']) + pysimplegui_user_settings.set('-watermark ver-', values['-WATERMARK VER-']) + pysimplegui_user_settings.set('-watermark framework ver-', values['-WATERMARK FRAMEWORK VER-']) + pysimplegui_user_settings.set('-watermark font-', values['-WATERMARK FONT-']) + # pysimplegui_user_settings.set('-watermark bg color-', values['-WATERMARK BG COLOR-']) # TTK SETTINGS pysimplegui_user_settings.set('-ttk theme-', values['-TTK THEME-']) @@ -25671,6 +25717,7 @@ def main_global_pysimplegui_settings(): theme(new_theme) _global_settings_get_ttk_scrollbar_info() + _global_settings_get_watermark_info() window.close() return True @@ -26329,6 +26376,9 @@ theme(theme_global()) # ------------------------ Read the ttk scrollbar info ------------------------ _global_settings_get_ttk_scrollbar_info() +# ------------------------ Read the window watermark info ------------------------ +_global_settings_get_watermark_info() + # See if running on Trinket. If Trinket, then use custom titlebars since Trinket doesn't supply any if running_trinket(): USE_CUSTOM_TITLEBAR = True @@ -26364,4 +26414,4 @@ if __name__ == '__main__': exit(0) main() exit(0) -#0d0ea93fb64af026d84d2013aa9668fa13acac5b5c3d26ea2b2210e0a6e41099998caabd813b486f52a22cf3bccc2b436ccb5bc40cd7f20304fe2445708fefaeb36f6438c79adf18db1c0a1ea942010adb37c97a5671f68ed639991d2df6396a2d76c81e8c91fdd42d54c61548253f9e34f991f0f4dcae66bd06eb370f2985d0ee8b7cf7768776bae229e860c019357a4fc8aaa956c93ab7b9d2b871e01a30f8485c04a35bb8a86798ba8f47d33f7afb8c2008a7687200feacb10835a9259620215d7ae19e87a45bcc7cc5c2ceda2419a137deeeb321cb227cfa5d3b5deca3fb2c06aeb98a0379cf61a4a52240129b091724cfc9c0693045a59d9707c0554f797eb6cf921849fd72bf2ff11c2e8ecf347c8b5bb89210a8b099d82ba614ad18b986f35ebea96a921bc9d667fa9c71e0e166451b9d7a45fe8fec665f7dd261354188bc0cc820dfd479da7aaf151934c72918b1dcec66ba8fee0790b495623f32f489a2c3430824186b7910cd91cc398202399ff9787d7cd1f5ad9bf58fbfe0ff79914f09c34a462a1d9d01ad17dc58d16e97a513130228fb3b8cc33eca70ae1b8aa69c1b1ae8b85f8bf2f0c412a40fdc94c5ec4469bc4a650141c50cc3ab3cf356dfc08b9062fd5bdac2e9d24240a3545549c1a9e3e17da862d5d1a85dea10556fecf62b1229cdfcfc10486435b41b519ca8a8ce3bbdbb52b7154fc34184539b73 \ No newline at end of file +#12fbca39ac400901c64a05c219145aca0904491fcb8decd81a8a4532f85730408eddcd9cedbeed4931de6fe46a7510f0381b4d38563405db543c53db01e1bc3eee1270aeb12c473729130d2b1e4630da8ae060b0fae190b93c792e91d122ce455b1919b5baa96eaa6c719dd893490fb0520e9ea4cbd0db32f947df2da66af38b03131f8a718c2a810171bbd37c5d29157c24579f859645690c5ca3056888d5d263341c94e28c8b2f956aad0f4dc737a20bc94bbb5ad332b4586c763a4cfeca8ae8ba0f3c4c5d90f1d4a9ef19b22a854844a015e84aecbe769ab66dbf68503c1d00b8205909a8d9126a9ffc79439fd2f0efb27610f3f3ccfd9824407a35f47a301bbe461a24040f23b7e9c1a632d3ef91e3c61646b74037d72ab93477a573acdeb6b88f55b56bb7d4a74cca8cbd77018db330b2476e07e5dec88faec29e4ec49440059b030275fe91ca27754a58593b1517c908f66576b98ee4bd8eb26badb89338372f2d679372deb022582d2eac8d55b85f3afdf6e332e140215bf9e708bd7d279b2d45e53dcc2928505e3d0deb9745b08375c1a05ecf59ffefdd061837e0791b2c95ecf101d8df72baf447f03a0bacdb30331def1f78984682586551f9905d3409733901b6dbc9541290e2ac61edcce39bdfe917c328dd407dbaf051dd1e4e32d60c57b0461524f5d206ddae91959c226ce5f777c8a8f7d6d71f61f1aab91b \ No newline at end of file From d447633ec329f982414cf37587557aecea125dfc Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Mon, 6 Mar 2023 14:21:06 -0500 Subject: [PATCH 056/145] Fixed Mac crash due to "Bold" font modifier in watermark feature --- PySimpleGUI.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index f0cf0992..7b371ace 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -version = __version__ = "4.61.0.159 Unreleased" +version = __version__ = "4.61.0.160 Unreleased" _change_log = """ Changelog since 4.60.0 released to PyPI on 8-May-2022 @@ -385,6 +385,8 @@ _change_log = """ Checked checkbox activeforeground to be the same as the text so mouseover doesn't change color 4.61.0.159 New Global Settings feature - Window watermarking. Can be forced on temporarily by settings watermark=True in your Window creation + 4.61.0.160 + Fix "Bold" crash from watermarking feature """ __version__ = version.split()[0] # For PEP 396 and PEP 345 @@ -25496,7 +25498,7 @@ def _global_settings_get_watermark_info(): prefix_text = pysimplegui_user_settings.get('-watermark text-', '') ver_text = ' ' + version if pysimplegui_user_settings.get('-watermark ver-', False if not forced else True) or forced else '' framework_ver_text = ' ' + framework_version if pysimplegui_user_settings.get('-watermark framework ver-', False if not forced else True) or forced else '' - watermark_font = pysimplegui_user_settings.get('-watermark font-', '_ 9 Bold') + watermark_font = pysimplegui_user_settings.get('-watermark font-', '_ 9 bold') background_color = pysimplegui_user_settings.get('-watermark bg color-', 'window.BackgroundColor') Window._watermark = lambda window: Text(prefix_text + ver_text + framework_ver_text, font=watermark_font, background_color= window.BackgroundColor) @@ -26414,4 +26416,4 @@ if __name__ == '__main__': exit(0) main() exit(0) -#12fbca39ac400901c64a05c219145aca0904491fcb8decd81a8a4532f85730408eddcd9cedbeed4931de6fe46a7510f0381b4d38563405db543c53db01e1bc3eee1270aeb12c473729130d2b1e4630da8ae060b0fae190b93c792e91d122ce455b1919b5baa96eaa6c719dd893490fb0520e9ea4cbd0db32f947df2da66af38b03131f8a718c2a810171bbd37c5d29157c24579f859645690c5ca3056888d5d263341c94e28c8b2f956aad0f4dc737a20bc94bbb5ad332b4586c763a4cfeca8ae8ba0f3c4c5d90f1d4a9ef19b22a854844a015e84aecbe769ab66dbf68503c1d00b8205909a8d9126a9ffc79439fd2f0efb27610f3f3ccfd9824407a35f47a301bbe461a24040f23b7e9c1a632d3ef91e3c61646b74037d72ab93477a573acdeb6b88f55b56bb7d4a74cca8cbd77018db330b2476e07e5dec88faec29e4ec49440059b030275fe91ca27754a58593b1517c908f66576b98ee4bd8eb26badb89338372f2d679372deb022582d2eac8d55b85f3afdf6e332e140215bf9e708bd7d279b2d45e53dcc2928505e3d0deb9745b08375c1a05ecf59ffefdd061837e0791b2c95ecf101d8df72baf447f03a0bacdb30331def1f78984682586551f9905d3409733901b6dbc9541290e2ac61edcce39bdfe917c328dd407dbaf051dd1e4e32d60c57b0461524f5d206ddae91959c226ce5f777c8a8f7d6d71f61f1aab91b \ No newline at end of file +#2e985cee1c05c21e66c65647555cdb19d022a40185cfad6fc96617a35f12286adcdeb20234a21b9cd4ffe4ccd3e5a259aa9bbdf3d772c389d0e5550ee89901ea46ac134062a39601e62fab71080f784137d54e8d6ee0eb35d9e2b7f0517147534b79aaf35f2b1d7194f0ad6dc0ae79167c616e719a74054d5bfaecb394aa78556ef3c0dd37fbd275c6f22008294cd4e0734cc9b5d151b49a2f42b754b736eb7322a0f3fc24efb638fba9b5ecc8b49ee2df3b2d0ffea18fd736978f1cfea73eb41dfaee1e4a339fa02df2660851accc6ec1e07f37b83b26edece5fb3e3f04c0163e6a499aa3bad9df6843b864cc8f2ae7ea2dadcdd69814997c4a97599f860ec8482e9bbf3969d27c7c288069a7218dceebaa410a9af1bd40edc331b7d96b2faaf0861b5a9cc7234f91d00c545efc94f4874aed65646105c61776b900d90c2c84578cf054ba409e21034a00a7e30a7e971027cb08433de7ff9f5d7b56c31977acb08bc18c4da434928e02257810856237cc6e81bdd4ca95d97ba2e9d43f1ded28f9a21ef3136f8ac6075117feddc13daa808a3c6e419e355b2a1ee86d057f47f0fa51e6e344c39a0c95ccb9e3dd98d89c4fde2411ec0877137fa27065a4e9ca1e75d27dc6b69c1df15c32052d8b303504243916275195f28daccc02c7cd539bc66d407bd89a77da1fc183c756e94b44fd947b72d53464d9a4ecab02cc17501e9e \ No newline at end of file From 3b7a17f6b66a6f1f8fb9a6f5984c829024a22ad2 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Tue, 7 Mar 2023 20:14:08 -0500 Subject: [PATCH 057/145] Demo Program to show new Watermark features --- DemoPrograms/Demo_Watermark_Window.py | 109 ++++++++++++++++++++++++++ PySimpleGUI.py | 23 ++++-- 2 files changed, 127 insertions(+), 5 deletions(-) create mode 100644 DemoPrograms/Demo_Watermark_Window.py diff --git a/DemoPrograms/Demo_Watermark_Window.py b/DemoPrograms/Demo_Watermark_Window.py new file mode 100644 index 00000000..49b61713 --- /dev/null +++ b/DemoPrograms/Demo_Watermark_Window.py @@ -0,0 +1,109 @@ +import PySimpleGUI as sg + +""" + Demo - Watermarking all windows + + Watermarking windows can be done in 4.60.0.160 and greater. It's a very simple mechanism for now. + + The option is normally set in the Global Settings control panel. However, you can "Force" the watermark + on all windows by setting the Window paramter watermark=True on any window you create and from then on + all windows will have the watermark. + + Copyright 2023 PySimpleGUI +""" + +""" +M"""""""`YM +M mmmm. M +M MMMMM M .d8888b. +M MMMMM M 88' `88 +M MMMMM M 88. .88 +M MMMMM M `88888P' +MMMMMMMMMMM + +M""MMM""MMM""M dP dP +M MMM MMM M 88 88 +M MMP MMP M .d8888b. d8888P .d8888b. 88d888b. 88d8b.d8b. .d8888b. 88d888b. 88 .dP +M MM' MM' .M 88' `88 88 88ooood8 88' `88 88'`88'`88 88' `88 88' `88 88888" +M `' . '' .MM 88. .88 88 88. ... 88 88 88 88 88. .88 88 88 `8b. +M .d .dMMM `88888P8 dP `88888P' dP dP dP dP `88888P8 dP dP `YP +MMMMMMMMMMMMMM +""" + +layout = [ [sg.Text('No Watermark')], + [sg.Button('Exit')] ] + +window = sg.Window('No Watermark', layout) + +while True: + event, values = window.read() + if event == sg.WIN_CLOSED or event == 'Exit': + break + +window.close() + + +""" +MP""""""`MM dP +M mmmmm..M 88 +M. `YM dP dP .d8888b. d8888P .d8888b. 88d8b.d8b. +MMMMMMM. M 88 88 Y8ooooo. 88 88ooood8 88'`88'`88 +M. .MMM' M 88. .88 88 88 88. ... 88 88 88 +Mb. .dM `8888P88 `88888P' dP `88888P' dP dP dP +MMMMMMMMMMM .88 + d8888P +M""MMM""MMM""M dP dP +M MMM MMM M 88 88 +M MMP MMP M .d8888b. d8888P .d8888b. 88d888b. 88d8b.d8b. .d8888b. 88d888b. 88 .dP +M MM' MM' .M 88' `88 88 88ooood8 88' `88 88'`88'`88 88' `88 88' `88 88888" +M `' . '' .MM 88. .88 88 88. ... 88 88 88 88 88. .88 88 88 `8b. +M .d .dMMM `88888P8 dP `88888P' dP dP dP dP `88888P8 dP dP `YP +MMMMMMMMMMMMMM +""" + +sg.set_options(watermark_text='') # noramlly not requird unless previously set by user + +layout = [ [sg.Text('System Provided Watermark')], + [sg.Button('Exit')] ] + +window = sg.Window('System Watermark', layout, watermark=True) + +while True: + event, values = window.read() + if event == sg.WIN_CLOSED or event == 'Exit': + break + +window.close() + + +""" +M""MMMMM""M +M MMMMM M +M MMMMM M .d8888b. .d8888b. 88d888b. +M MMMMM M Y8ooooo. 88ooood8 88' `88 +M `MMM' M 88 88. ... 88 +Mb dM `88888P' `88888P' dP +MMMMMMMMMMM + +M""MMM""MMM""M dP dP +M MMM MMM M 88 88 +M MMP MMP M .d8888b. d8888P .d8888b. 88d888b. 88d8b.d8b. .d8888b. 88d888b. 88 .dP +M MM' MM' .M 88' `88 88 88ooood8 88' `88 88'`88'`88 88' `88 88' `88 88888" +M `' . '' .MM 88. .88 88 88. ... 88 88 88 88 88. .88 88 88 `8b. +M .d .dMMM `88888P8 dP `88888P' dP dP dP dP `88888P8 dP dP `YP +MMMMMMMMMMMMMM +""" + +sg.set_options(watermark_text='User Supplied Version 1.0') + +layout = [ [sg.Text('User Supplied Watermark')], + [sg.Button('Exit')] ] + +window = sg.Window('User Supplied Watermark', layout, watermark=True) + +while True: + event, values = window.read() + if event == sg.WIN_CLOSED or event == 'Exit': + break + +window.close() diff --git a/PySimpleGUI.py b/PySimpleGUI.py index 7b371ace..a946ca7d 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -version = __version__ = "4.61.0.160 Unreleased" +version = __version__ = "4.61.0.161 Unreleased" _change_log = """ Changelog since 4.60.0 released to PyPI on 8-May-2022 @@ -387,6 +387,8 @@ _change_log = """ New Global Settings feature - Window watermarking. Can be forced on temporarily by settings watermark=True in your Window creation 4.61.0.160 Fix "Bold" crash from watermarking feature + 4.61.0.161 + New set_options to control user-defined watermarks """ __version__ = version.split()[0] # For PEP 396 and PEP 345 @@ -19013,7 +19015,7 @@ def set_options(icon=None, button_color=None, element_size=(None, None), button_ enable_mac_notitlebar_patch=None, use_custom_titlebar=None, titlebar_background_color=None, titlebar_text_color=None, titlebar_font=None, titlebar_icon=None, user_settings_path=None, pysimplegui_settings_path=None, pysimplegui_settings_filename=None, keep_on_top=None, dpi_awareness=None, scaling=None, disable_modal_windows=None, force_modal_windows=None, tooltip_offset=(None, None), sbar_trough_color=None, sbar_background_color=None, sbar_arrow_color=None, sbar_width=None, sbar_arrow_width=None, sbar_frame_color=None, sbar_relief=None, alpha_channel=None, - hide_window_when_creating=None, use_button_shortcuts=None): + hide_window_when_creating=None, use_button_shortcuts=None, watermark_text=None): """ :param icon: Can be either a filename or Base64 value. For Windows if filename, it MUST be ICO format. For Linux, must NOT be ICO. Most portable is to use a Base64 of a PNG file. This works universally across all OS's :type icon: bytes | str @@ -19147,6 +19149,8 @@ def set_options(icon=None, button_color=None, element_size=(None, None), button_ :type hide_window_when_creating: (bool) :param use_button_shortcuts: If True then Shortcut Char will be used with Buttons :type use_button_shortcuts: (bool) + :param watermark_text: Set the text that will be used if a window is watermarked + :type watermark_text: (str) :return: None :rtype: None """ @@ -19424,6 +19428,10 @@ def set_options(icon=None, button_color=None, element_size=(None, None), button_ if use_button_shortcuts is not None: DEFAULT_USE_BUTTON_SHORTCUTS = use_button_shortcuts + + if watermark_text is not None: + pysimplegui_user_settings.set('-watermark user text-', watermark_text) + return True @@ -25499,9 +25507,14 @@ def _global_settings_get_watermark_info(): ver_text = ' ' + version if pysimplegui_user_settings.get('-watermark ver-', False if not forced else True) or forced else '' framework_ver_text = ' ' + framework_version if pysimplegui_user_settings.get('-watermark framework ver-', False if not forced else True) or forced else '' watermark_font = pysimplegui_user_settings.get('-watermark font-', '_ 9 bold') - background_color = pysimplegui_user_settings.get('-watermark bg color-', 'window.BackgroundColor') + # background_color = pysimplegui_user_settings.get('-watermark bg color-', 'window.BackgroundColor') + user_text = pysimplegui_user_settings.get('-watermark user text-', '') + if user_text: + text = str(user_text) + else: + text = prefix_text + ver_text + framework_ver_text + Window._watermark = lambda window: Text(text, font=watermark_font, background_color= window.BackgroundColor) - Window._watermark = lambda window: Text(prefix_text + ver_text + framework_ver_text, font=watermark_font, background_color= window.BackgroundColor) def main_global_get_screen_snapshot_symcode(): @@ -26416,4 +26429,4 @@ if __name__ == '__main__': exit(0) main() exit(0) -#2e985cee1c05c21e66c65647555cdb19d022a40185cfad6fc96617a35f12286adcdeb20234a21b9cd4ffe4ccd3e5a259aa9bbdf3d772c389d0e5550ee89901ea46ac134062a39601e62fab71080f784137d54e8d6ee0eb35d9e2b7f0517147534b79aaf35f2b1d7194f0ad6dc0ae79167c616e719a74054d5bfaecb394aa78556ef3c0dd37fbd275c6f22008294cd4e0734cc9b5d151b49a2f42b754b736eb7322a0f3fc24efb638fba9b5ecc8b49ee2df3b2d0ffea18fd736978f1cfea73eb41dfaee1e4a339fa02df2660851accc6ec1e07f37b83b26edece5fb3e3f04c0163e6a499aa3bad9df6843b864cc8f2ae7ea2dadcdd69814997c4a97599f860ec8482e9bbf3969d27c7c288069a7218dceebaa410a9af1bd40edc331b7d96b2faaf0861b5a9cc7234f91d00c545efc94f4874aed65646105c61776b900d90c2c84578cf054ba409e21034a00a7e30a7e971027cb08433de7ff9f5d7b56c31977acb08bc18c4da434928e02257810856237cc6e81bdd4ca95d97ba2e9d43f1ded28f9a21ef3136f8ac6075117feddc13daa808a3c6e419e355b2a1ee86d057f47f0fa51e6e344c39a0c95ccb9e3dd98d89c4fde2411ec0877137fa27065a4e9ca1e75d27dc6b69c1df15c32052d8b303504243916275195f28daccc02c7cd539bc66d407bd89a77da1fc183c756e94b44fd947b72d53464d9a4ecab02cc17501e9e \ No newline at end of file +#0ca08f0f911461d1d3ae002c055cdf86ca5d243565b37eef48a6b3e02a3e917ab3af8d7317296be3d6074b3257e506129a87b27b5ac89ab40f1ff33fbb907e4d32f218f30eb86903bcf017466d2291a534180cc363996ebac425524929e3caebd4d524524f380c2471d7497ac7f62df5a3525cbd9ebff46b6dcca3caf749c5c6e32b3697685a524169887216d4b24c66760e31c4b92f52e15c00a4adbf0b66b2b474fc8883def17a066b98ce9c0839f6c7900a4df01b49321b8410894264a7dd24babe7a66556ce725d0fe18810ba616e777c8db14978e56679262ef41c917dc52a2454b4926c52aa8c4415f86b824dbaadb89c15b020de386d263e13b609cd26a76925840970bcfb198ecc165609780d9fc24453a25d917254404251a69aa68b4503f761d5cdedbcb68ab281be964d1e04182d8f87135648a71b25a9655d02662593556b55f79d60109151403a478d4824c09264fb2b5b056b4fa57fbf7c391cf746c48ec98da618a509b2a72434d86c92c10961c85744c6172b37a183b3553299ae092a265764bf85d3d6c061f86dbf3c64c089bfa6f570beda30138c8c3427fe97b4a9c9b80571e7c67f718723f802d8d1959378b26df664ec7e1b0176c5cfbedb6f8d0280298633304d18bfdf3fd5d7900182bc47414d3b2ab7624f9756c33332e022160f619a0df34df54aebba8dc622b1cc68cb05807dd31372009363a \ No newline at end of file From 4d02f3a515284eb610523612a5cd768b88bc9532 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Thu, 9 Mar 2023 05:43:20 -0500 Subject: [PATCH 058/145] Combo.update - added text and background color. Also made font parm work correctly with the dropdown list. (TRICKY!) --- PySimpleGUI.py | 94 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 70 insertions(+), 24 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index a946ca7d..f2747b57 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -version = __version__ = "4.61.0.161 Unreleased" +version = __version__ = "4.61.0.162 Unreleased" _change_log = """ Changelog since 4.60.0 released to PyPI on 8-May-2022 @@ -389,6 +389,8 @@ _change_log = """ Fix "Bold" crash from watermarking feature 4.61.0.161 New set_options to control user-defined watermarks + 4.61.0.162 + Addition of new parms to Combo.update - text color, background color. Also font now applied correctly to dropdown list """ __version__ = version.split()[0] # For PEP 396 and PEP 345 @@ -2624,7 +2626,7 @@ class Combo(Element): super().__init__(ELEM_TYPE_INPUT_COMBO, size=sz, auto_size_text=auto_size_text, background_color=bg, text_color=fg, key=key, pad=pad, tooltip=tooltip, font=font or DEFAULT_FONT, visible=visible, metadata=metadata) - def update(self, value=None, values=None, set_to_index=None, disabled=None, readonly=None, font=None, visible=None, size=(None, None), select=None): + def update(self, value=None, values=None, set_to_index=None, disabled=None, readonly=None, font=None, visible=None, size=(None, None), select=None, text_color=None, background_color=None): """ Changes some of the settings for the Combo Element. Must call `Window.Read` or `Window.Finalize` prior. Note that the state can be in 3 states only.... enabled, disabled, readonly even @@ -2637,25 +2639,30 @@ class Combo(Element): function "pin" to ensure your element is "pinned" to that location in your layout so that it returns there when made visible. - :param value: change which value is current selected based on new list of previous list of choices - :type value: (Any) - :param values: change list of choices - :type values: List[Any] - :param set_to_index: change selection to a particular choice starting with index = 0 - :type set_to_index: (int) - :param disabled: disable or enable state of the element - :type disabled: (bool) - :param readonly: if True make element readonly (user cannot change any choices). Enables the element if either choice are made. - :type readonly: (bool) - :param font: specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike - :type font: (str or (str, int[, str]) or None) - :param visible: control visibility of element - :type visible: (bool) - :param size: width, height. Width = characters-wide, height = NOTE it's the number of entries to show in the list - :type size: (int, int) - :param select: if True, then the text will be selected, if False then selection will be cleared - :type select: (bool) + :param value: change which value is current selected based on new list of previous list of choices + :type value: (Any) + :param values: change list of choices + :type values: List[Any] + :param set_to_index: change selection to a particular choice starting with index = 0 + :type set_to_index: (int) + :param disabled: disable or enable state of the element + :type disabled: (bool) + :param readonly: if True make element readonly (user cannot change any choices). Enables the element if either choice are made. + :type readonly: (bool) + :param font: specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike + :type font: (str or (str, int[, str]) or None) + :param visible: control visibility of element + :type visible: (bool) + :param size: width, height. Width = characters-wide, height = NOTE it's the number of entries to show in the list + :type size: (int, int) + :param select: if True, then the text will be selected, if False then selection will be cleared + :type select: (bool) + :param background_color: color of background + :type background_color: (str) + :param text_color: color of the text + :type text_color: (str) """ + if size != (None, None): if isinstance(size, int): size = (size, 1) @@ -2720,8 +2727,44 @@ class Combo(Element): elif disabled is False and self.Readonly is False: self.TKCombo['state'] = 'enable' self.Disabled = disabled if disabled is not None else self.Disabled + + combostyle = self.ttk_style + style_name = self.ttk_style_name + if text_color is not None: + combostyle.configure(style_name, foreground=text_color) + combostyle.configure(style_name, selectbackground=text_color) + combostyle.configure(style_name, insertcolor=text_color) + combostyle.map(style_name, fieldforeground=[('readonly', text_color)]) + self.TextColor = text_color + if background_color is not None: + combostyle.configure(style_name, selectforeground=background_color) + combostyle.map(style_name, fieldbackground=[('readonly', background_color)]) + combostyle.configure(style_name, fieldbackground=background_color) + self.BackgroundColor = background_color + + if self.Readonly is True: + if text_color not in (None, COLOR_SYSTEM_DEFAULT): + combostyle.configure(style_name, selectforeground=text_color) + if background_color not in (None, COLOR_SYSTEM_DEFAULT): + combostyle.configure(style_name, selectbackground=background_color) + + if font is not None: + self.Font = font self.TKCombo.configure(font=font) + self._dropdown_newfont = tkinter.font.Font(font=font) + self.ParentRowFrame.option_add("*TCombobox*Listbox*Font", self._dropdown_newfont) + + + # make tcl call to deal with colors for the drop-down formatting + try: + if self.BackgroundColor not in (None, COLOR_SYSTEM_DEFAULT) and \ + self.TextColor not in (None, COLOR_SYSTEM_DEFAULT): + self.Widget.tk.eval( + '[ttk::combobox::PopdownWindow {}].f.l configure -foreground {} -background {} -selectforeground {} -selectbackground {} -font {}'.format(self.Widget, self.TextColor, self.BackgroundColor, self.BackgroundColor, self.TextColor, self._dropdown_newfont)) + except Exception as e: + pass # going to let this one slide + if visible is False: self._pack_forget_save_settings() # self.TKCombo.pack_forget() @@ -2735,6 +2778,7 @@ class Combo(Element): elif select is False: self.TKCombo.select_clear() + def get(self): """ Returns the current (right now) value of the Combo. DO NOT USE THIS AS THE NORMAL WAY OF READING A COMBO! @@ -10027,6 +10071,8 @@ class Window: _original_stderr = None _watermark = None _watermark_temp_forced = False + _watermark_user_text = '' + def __init__(self, title, layout=None, default_element_size=None, default_button_element_size=(None, None), auto_size_text=None, auto_size_buttons=None, location=(None, None), relative_location=(None, None), size=(None, None), @@ -16619,8 +16665,8 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form): "Parent Window's Title: {}".format(toplevel_form.Title)) # Strange code that is needed to set the font for the drop-down list - element._newfont = tkinter.font.Font(font=font) - tk_row_frame.option_add("*TCombobox*Listbox*Font", element._newfont) + element._dropdown_newfont = tkinter.font.Font(font=font) + tk_row_frame.option_add("*TCombobox*Listbox*Font", element._dropdown_newfont) element.TKCombo = element.Widget = ttk.Combobox(tk_row_frame, width=width, textvariable=element.TKStringVar, font=font, style=style_name) @@ -19430,7 +19476,7 @@ def set_options(icon=None, button_color=None, element_size=(None, None), button_ DEFAULT_USE_BUTTON_SHORTCUTS = use_button_shortcuts if watermark_text is not None: - pysimplegui_user_settings.set('-watermark user text-', watermark_text) + Window._watermark_user_text = watermark_text return True @@ -26429,4 +26475,4 @@ if __name__ == '__main__': exit(0) main() exit(0) -#0ca08f0f911461d1d3ae002c055cdf86ca5d243565b37eef48a6b3e02a3e917ab3af8d7317296be3d6074b3257e506129a87b27b5ac89ab40f1ff33fbb907e4d32f218f30eb86903bcf017466d2291a534180cc363996ebac425524929e3caebd4d524524f380c2471d7497ac7f62df5a3525cbd9ebff46b6dcca3caf749c5c6e32b3697685a524169887216d4b24c66760e31c4b92f52e15c00a4adbf0b66b2b474fc8883def17a066b98ce9c0839f6c7900a4df01b49321b8410894264a7dd24babe7a66556ce725d0fe18810ba616e777c8db14978e56679262ef41c917dc52a2454b4926c52aa8c4415f86b824dbaadb89c15b020de386d263e13b609cd26a76925840970bcfb198ecc165609780d9fc24453a25d917254404251a69aa68b4503f761d5cdedbcb68ab281be964d1e04182d8f87135648a71b25a9655d02662593556b55f79d60109151403a478d4824c09264fb2b5b056b4fa57fbf7c391cf746c48ec98da618a509b2a72434d86c92c10961c85744c6172b37a183b3553299ae092a265764bf85d3d6c061f86dbf3c64c089bfa6f570beda30138c8c3427fe97b4a9c9b80571e7c67f718723f802d8d1959378b26df664ec7e1b0176c5cfbedb6f8d0280298633304d18bfdf3fd5d7900182bc47414d3b2ab7624f9756c33332e022160f619a0df34df54aebba8dc622b1cc68cb05807dd31372009363a \ No newline at end of file +#0f39d7ccc690f323707b2c591286af1aa7833c959432b3478340c6818dff6f76095f647e438ccdd3bccf0b24b1ea4f2e65b3dd131346e60e564361f2638b765cc96144915a9e22af993eec69165cee78a4234a49360501170277d846db7b9d1503e1c73f55252cb82865bd79554d67a769ddb860d568c93e202e0944b5676ed64dabc0373a6ed98c283c8e91980b43e7b2ce817dae72ab7fc4199949f34e8953f7b8f17a3fefda65baeb53f49c8d55896f2402675298a42f3a0ffb8046b58c26e52fb40ec9118b8c7d369f75e77e6c91d95f9db37462e0f62b9a10cf98ac7cfe769235ce6310136ec9c88c22332ca877bfb8508c26b39a94b6b0c90160692d4756569aba1ff4ce0115840d145bf6b509b8de50fba63f56509ebb72401337697e6b9bb2d669e4e28210f5e753db71bd97432dc55759d0251346b5239d6c4f120d56141c1e7f8269c0dc4bcfac73ee79dd2b8d70f4049a5f93554bd87b246708c808ae1dc3f2bfb224ee6479824b3c1b653ed1c5918198670840d02e3eb2162319049dd1bf486492fb202fc87810127bc3f00770ba7b7251b7f33880b02284bf9e103428186576d28f89e6749e4f4dea026ef740528d21ab022858ab0f78b08186d9c919e5ea02b819c9934670f8437f869ba5026de5e0321030b9d863cb0b1b5e33c3e91f6e14034d89ecb13210ffaa6d23cb910bd8cbd33457a588a4c3c52439 \ No newline at end of file From 3507b2708b984bc1d464627345a741adfa1d3335 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Thu, 9 Mar 2023 05:49:42 -0500 Subject: [PATCH 059/145] Added nightlight thickness parm to Checkbox so focus ring thickness can be controlled when creating element --- PySimpleGUI.py | 102 ++++++++++++++++++++++++++----------------------- 1 file changed, 54 insertions(+), 48 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index f2747b57..c783e919 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -version = __version__ = "4.61.0.162 Unreleased" +version = __version__ = "4.61.0.163 Unreleased" _change_log = """ Changelog since 4.60.0 released to PyPI on 8-May-2022 @@ -391,6 +391,8 @@ _change_log = """ New set_options to control user-defined watermarks 4.61.0.162 Addition of new parms to Combo.update - text color, background color. Also font now applied correctly to dropdown list + 4.61.0.163 + Checkbox - added highlight thickness parm to control how thick the focus ring is. Defaults to 1 still but now changable """ __version__ = version.split()[0] # For PEP 396 and PEP 345 @@ -3423,56 +3425,59 @@ class Checkbox(Element): """ def __init__(self, text, default=False, size=(None, None), s=(None, None), auto_size_text=None, font=None, background_color=None, - text_color=None, checkbox_color=None, change_submits=False, enable_events=False, disabled=False, key=None, k=None, pad=None, p=None, tooltip=None, + text_color=None, checkbox_color=None, highlight_thickness=1, change_submits=False, enable_events=False, disabled=False, key=None, k=None, pad=None, p=None, tooltip=None, right_click_menu=None, expand_x=False, expand_y=False, visible=True, metadata=None): """ - :param text: Text to display next to checkbox - :type text: (str) - :param default: Set to True if you want this checkbox initially checked - :type default: (bool) - :param size: (w, h) w=characters-wide, h=rows-high. If an int instead of a tuple is supplied, then height is auto-set to 1 - :type size: (int, int) | (None, None) | int - :param s: Same as size parameter. It's an alias. If EITHER of them are set, then the one that's set will be used. If BOTH are set, size will be used - :type s: (int, int) | (None, None) | int - :param auto_size_text: if True will size the element to match the length of the text - :type auto_size_text: (bool) - :param font: specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike - :type font: (str or (str, int[, str]) or None) - :param background_color: color of background - :type background_color: (str) - :param text_color: color of the text - :type text_color: (str) - :param checkbox_color: color of background of the box that has the check mark in it. The checkmark is the same color as the text - :type checkbox_color: (str) - :param change_submits: DO NOT USE. Only listed for backwards compat - Use enable_events instead - :type change_submits: (bool) - :param enable_events: Turns on the element specific events. Checkbox events happen when an item changes - :type enable_events: (bool) - :param disabled: set disable state - :type disabled: (bool) - :param key: Used with window.find_element and with return values to uniquely identify this element - :type key: str | int | tuple | object - :param k: Same as the Key. You can use either k or key. Which ever is set will be used. - :type k: str | int | tuple | object - :param pad: Amount of padding to put around element in pixels (left/right, top/bottom) or ((left, right), (top, bottom)) or an int. If an int, then it's converted into a tuple (int, int) - :type pad: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int) | int - :param p: Same as pad parameter. It's an alias. If EITHER of them are set, then the one that's set will be used. If BOTH are set, pad will be used - :type p: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int) | int - :param tooltip: text, that will appear when mouse hovers over the element - :type tooltip: (str) - :param right_click_menu: A list of lists of Menu items to show when this element is right clicked. See user docs for exact format. - :type right_click_menu: List[List[ List[str] | str ]] - :param expand_x: If True the element will automatically expand in the X direction to fill available space - :type expand_x: (bool) - :param expand_y: If True the element will automatically expand in the Y direction to fill available space - :type expand_y: (bool) - :param visible: set visibility state of the element - :type visible: (bool) - :param metadata: User metadata that can be set to ANYTHING - :type metadata: (Any) + :param text: Text to display next to checkbox + :type text: (str) + :param default: Set to True if you want this checkbox initially checked + :type default: (bool) + :param size: (w, h) w=characters-wide, h=rows-high. If an int instead of a tuple is supplied, then height is auto-set to 1 + :type size: (int, int) | (None, None) | int + :param s: Same as size parameter. It's an alias. If EITHER of them are set, then the one that's set will be used. If BOTH are set, size will be used + :type s: (int, int) | (None, None) | int + :param auto_size_text: if True will size the element to match the length of the text + :type auto_size_text: (bool) + :param font: specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike + :type font: (str or (str, int[, str]) or None) + :param background_color: color of background + :type background_color: (str) + :param text_color: color of the text + :type text_color: (str) + :param checkbox_color: color of background of the box that has the check mark in it. The checkmark is the same color as the text + :type checkbox_color: (str) + :param highlight_thickness: thickness of border around checkbox when gets focus + :type highlight_thickness: (int) + :param change_submits: DO NOT USE. Only listed for backwards compat - Use enable_events instead + :type change_submits: (bool) + :param enable_events: Turns on the element specific events. Checkbox events happen when an item changes + :type enable_events: (bool) + :param disabled: set disable state + :type disabled: (bool) + :param key: Used with window.find_element and with return values to uniquely identify this element + :type key: str | int | tuple | object + :param k: Same as the Key. You can use either k or key. Which ever is set will be used. + :type k: str | int | tuple | object + :param pad: Amount of padding to put around element in pixels (left/right, top/bottom) or ((left, right), (top, bottom)) or an int. If an int, then it's converted into a tuple (int, int) + :type pad: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int) | int + :param p: Same as pad parameter. It's an alias. If EITHER of them are set, then the one that's set will be used. If BOTH are set, pad will be used + :type p: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int) | int + :param tooltip: text, that will appear when mouse hovers over the element + :type tooltip: (str) + :param right_click_menu: A list of lists of Menu items to show when this element is right clicked. See user docs for exact format. + :type right_click_menu: List[List[ List[str] | str ]] + :param expand_x: If True the element will automatically expand in the X direction to fill available space + :type expand_x: (bool) + :param expand_y: If True the element will automatically expand in the Y direction to fill available space + :type expand_y: (bool) + :param visible: set visibility state of the element + :type visible: (bool) + :param metadata: User metadata that can be set to ANYTHING + :type metadata: (Any) """ + self.Text = text self.InitialState = bool(default) self.Value = None @@ -3480,6 +3485,7 @@ class Checkbox(Element): self.Disabled = disabled self.TextColor = text_color if text_color else theme_text_color() self.RightClickMenu = right_click_menu + self.highlight_thickness = highlight_thickness # ---- compute color of circle background --- if checkbox_color is None: @@ -16975,7 +16981,7 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form): element.TKCheckbutton.configure(fg=text_color) element.TKCheckbutton.configure(activeforeground=element.TextColor) - element.Widget.configure(highlightthickness=1) + element.Widget.configure(highlightthickness=element.highlight_thickness) if element.BackgroundColor != COLOR_SYSTEM_DEFAULT: element.TKCheckbutton.config(highlightbackground=element.BackgroundColor) if element.TextColor != COLOR_SYSTEM_DEFAULT: @@ -26475,4 +26481,4 @@ if __name__ == '__main__': exit(0) main() exit(0) -#0f39d7ccc690f323707b2c591286af1aa7833c959432b3478340c6818dff6f76095f647e438ccdd3bccf0b24b1ea4f2e65b3dd131346e60e564361f2638b765cc96144915a9e22af993eec69165cee78a4234a49360501170277d846db7b9d1503e1c73f55252cb82865bd79554d67a769ddb860d568c93e202e0944b5676ed64dabc0373a6ed98c283c8e91980b43e7b2ce817dae72ab7fc4199949f34e8953f7b8f17a3fefda65baeb53f49c8d55896f2402675298a42f3a0ffb8046b58c26e52fb40ec9118b8c7d369f75e77e6c91d95f9db37462e0f62b9a10cf98ac7cfe769235ce6310136ec9c88c22332ca877bfb8508c26b39a94b6b0c90160692d4756569aba1ff4ce0115840d145bf6b509b8de50fba63f56509ebb72401337697e6b9bb2d669e4e28210f5e753db71bd97432dc55759d0251346b5239d6c4f120d56141c1e7f8269c0dc4bcfac73ee79dd2b8d70f4049a5f93554bd87b246708c808ae1dc3f2bfb224ee6479824b3c1b653ed1c5918198670840d02e3eb2162319049dd1bf486492fb202fc87810127bc3f00770ba7b7251b7f33880b02284bf9e103428186576d28f89e6749e4f4dea026ef740528d21ab022858ab0f78b08186d9c919e5ea02b819c9934670f8437f869ba5026de5e0321030b9d863cb0b1b5e33c3e91f6e14034d89ecb13210ffaa6d23cb910bd8cbd33457a588a4c3c52439 \ No newline at end of file +#775d50bc7a349101f5f8cf0fa731a832480c6dbdfe73bdd2dcd1d96a86c9c4b7fddaf350d28ed990dded140d52689328f7f68ade01cb281e58332887235cc76411a24c9bc3cfb32fd32eb17a5d94660ec9117979f92137899377742bc6c1c45a7def3d6886e4d650ef8fd19b53dd8319dd1615df41aa4e6a967a8a7b01830e074b90d1dcfabd8ae7a5848cac7f3fc82cb1ec51e0fa4c3b2fd6b82a8ede0f6c257973ff4f8263bb41abe488a4bec28a15d9e9981aecfa59f5f46fcea8b9134acd3d43b2b0ceb15837aa1753f13ef12c4c9d4c2559302a02600f9cc32fb7dacc50f2c144dd996e4c5c1abb5ada3dc50b045e23e730c24dce5684132fc8d98c0725b2e61745b33ce258b6d695b2ddc13656ee8e4d867646807bc5e578eb5bbd51fa069bdd24f3ad4ade1971833a7a41e1d35d23ee41a54f276946e3b109e08ff72ce1994462021bcbdb337693caa803134196212f802e914026dfa8e055b8258fce2888c5affaac665c644f56af42a62935bec8b58dcf5d98f6d556337b26b6fa00a6aa33b76c73768713a666f58623304e59739e91587aa664055091465903ecfbde1d9aecd6696af5ff9b92096a2f007a1821cf74c107f58bc1d390c9d233af00e341a8ead04dfb29d748749a4d2ce1c59afb7efa501dd046cce5a3ef9d5fc05ad2aed21b32c4cd80364f40044396308bfbe3ae6dd1afb594b1380e42854d7ece \ No newline at end of file From a22884e2e3310e54dec3ea3f4f80447ccea065ff Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Sun, 12 Mar 2023 08:39:17 -0400 Subject: [PATCH 060/145] 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. --- PySimpleGUI.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index c783e919..9de0cf06 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -version = __version__ = "4.61.0.163 Unreleased" +version = __version__ = "4.61.0.164 Unreleased" _change_log = """ Changelog since 4.60.0 released to PyPI on 8-May-2022 @@ -393,6 +393,8 @@ _change_log = """ Addition of new parms to Combo.update - text color, background color. Also font now applied correctly to dropdown list 4.61.0.163 Checkbox - added highlight thickness parm to control how thick the focus ring is. Defaults to 1 still but now changable + 4.61.0.164 + Input element - fixed problem where the input 'cursor' (the I-beam) was being set to the THEME'S color, not the color indicated by the individual element """ __version__ = version.split()[0] # For PEP 396 and PEP 345 @@ -16588,8 +16590,10 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form): if element.BackgroundColor not in (None, COLOR_SYSTEM_DEFAULT): element.TKEntry.configure(background=element.BackgroundColor, selectforeground=element.BackgroundColor) + if text_color not in (None, COLOR_SYSTEM_DEFAULT): element.TKEntry.configure(fg=text_color, selectbackground=text_color) + element.TKEntry.config(insertbackground=text_color) if element.selected_background_color not in (None, COLOR_SYSTEM_DEFAULT): element.TKEntry.configure(selectbackground=element.selected_background_color) if element.selected_text_color not in (None, COLOR_SYSTEM_DEFAULT): @@ -16618,8 +16622,6 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form): if element.Tooltip is not None: element.TooltipObject = ToolTip(element.TKEntry, text=element.Tooltip, timeout=DEFAULT_TOOLTIP_TIME) _add_right_click_menu_and_grab(element) - if theme_input_text_color() not in (COLOR_SYSTEM_DEFAULT, None): - element.Widget.config(insertbackground=theme_input_text_color()) # row_should_expand = True @@ -26481,4 +26483,4 @@ if __name__ == '__main__': exit(0) main() exit(0) -#775d50bc7a349101f5f8cf0fa731a832480c6dbdfe73bdd2dcd1d96a86c9c4b7fddaf350d28ed990dded140d52689328f7f68ade01cb281e58332887235cc76411a24c9bc3cfb32fd32eb17a5d94660ec9117979f92137899377742bc6c1c45a7def3d6886e4d650ef8fd19b53dd8319dd1615df41aa4e6a967a8a7b01830e074b90d1dcfabd8ae7a5848cac7f3fc82cb1ec51e0fa4c3b2fd6b82a8ede0f6c257973ff4f8263bb41abe488a4bec28a15d9e9981aecfa59f5f46fcea8b9134acd3d43b2b0ceb15837aa1753f13ef12c4c9d4c2559302a02600f9cc32fb7dacc50f2c144dd996e4c5c1abb5ada3dc50b045e23e730c24dce5684132fc8d98c0725b2e61745b33ce258b6d695b2ddc13656ee8e4d867646807bc5e578eb5bbd51fa069bdd24f3ad4ade1971833a7a41e1d35d23ee41a54f276946e3b109e08ff72ce1994462021bcbdb337693caa803134196212f802e914026dfa8e055b8258fce2888c5affaac665c644f56af42a62935bec8b58dcf5d98f6d556337b26b6fa00a6aa33b76c73768713a666f58623304e59739e91587aa664055091465903ecfbde1d9aecd6696af5ff9b92096a2f007a1821cf74c107f58bc1d390c9d233af00e341a8ead04dfb29d748749a4d2ce1c59afb7efa501dd046cce5a3ef9d5fc05ad2aed21b32c4cd80364f40044396308bfbe3ae6dd1afb594b1380e42854d7ece \ No newline at end of file +#1c230bde4c3f139d563fda282c8f2524ee39106dd7788fc6410723b3bfa42ae4dd17ca7005afbaad58a9b4565d4e911be7ac9d5b021b8e5614eba2853c33fdc167ac180241ccc6d564cca79493816ed599b82423be23ab4c46833cae5ec471a98b08d2ca46b18be736818e71168b19877515246d92ffa1cd40202356cb3b3e09e50e75db6cb1584893dc242ad63f8c8b4d2574bdbaa958b5da63f043813c4534315cff6d39dade82cd3aa8231dafd0f7133e212f9a72051d0af5c25ce64f9be042a0077d3837b44a937d5d2c0871461e3422a40605039fae563d238ddd4a590d44a8c57475d46bf78083ded3544ee2b8b2c8f88d703e150d1e14edcbdf31b902a5596096570e21cbb5fb4d48b904460b477ea6747a69e66f03d2d1874eff2aed73ce733e98e7346ee99f5bbe9a791de36e6a96bd5367ea9cd6c34852c5b3ec2a9e1d8cd1c5602bc9e7a12eb0fdeeaa2355c28d589ffc922c586db55dcca3fa0758fa511662ba18ecf5914841d874c9013d0674e152d8dd74e7113a33eeea9d187b8ef8b312017a733f2490d228b5295f3bd323949a2ef199c6efdd4acd5da641059eed7d95be005f7c4f508fdc83bb2e0e22d85cdf9376e948ba95f4405e4ddd23cf4f26aa44f6e4f7d2b82d4627847fc73c642eb9356311c9096e63c91c9666c6230a24c9323552bf4f44fe4397bef40df1644859e52019d29283c5f67ca173 \ No newline at end of file From 07f772c68035f254d51f946e595b99f9196cd21b Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Mon, 13 Mar 2023 05:54:59 -0400 Subject: [PATCH 061/145] 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 --- PySimpleGUI.py | 89 +++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 80 insertions(+), 9 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index 9de0cf06..a943780e 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -version = __version__ = "4.61.0.164 Unreleased" +version = __version__ = "4.61.0.165 Unreleased" _change_log = """ Changelog since 4.60.0 released to PyPI on 8-May-2022 @@ -395,6 +395,9 @@ _change_log = """ Checkbox - added highlight thickness parm to control how thick the focus ring is. Defaults to 1 still but now changable 4.61.0.164 Input element - fixed problem where the input 'cursor' (the I-beam) was being set to the THEME'S color, not the color indicated by the individual element + 4.61.0.165 + Multiline & Spin - Applied same fix for input "cursor" (I-Beam) color that was added to the Input element. + Added new method - set_ibeam_color to Input, Multiline and Spin elements. Combo is a ttk element so it's not available using this call yet """ __version__ = version.split()[0] # For PEP 396 and PEP 345 @@ -2517,6 +2520,28 @@ class Input(Element): + def set_ibeam_color(self, ibeam_color=None): + """ + Sets the color of the I-Beam that is used to "insert" characters. This is oftens called a "Cursor" by + many users. To keep from being confused with tkinter's definition of cursor (the mouse pointer), the term + ibeam is used in this case. + :param ibeam_color: color to set the "I-Beam" used to indicate where characters will be inserted + :type ibeam_color: (str) + """ + + if not self._widget_was_created(): + return + if ibeam_color is not None: + try: + self.Widget.config(insertbackground=ibeam_color) + except Exception as e: + _error_popup_with_traceback('Error setting I-Beam color in set_ibeam_color', + 'The element has a key:', self.Key, + 'The color passed in was:', ibeam_color) + + + + def get(self): """ Read and return the current value of the input element. Must call `Window.Read` or `Window.Finalize` prior @@ -3788,6 +3813,30 @@ class Spin(Element): # Window._window_that_exited = self.ParentForm # self.ParentForm.TKroot.quit() # kick the users out of the mainloop + + + + def set_ibeam_color(self, ibeam_color=None): + """ + Sets the color of the I-Beam that is used to "insert" characters. This is oftens called a "Cursor" by + many users. To keep from being confused with tkinter's definition of cursor (the mouse pointer), the term + ibeam is used in this case. + :param ibeam_color: color to set the "I-Beam" used to indicate where characters will be inserted + :type ibeam_color: (str) + """ + + if not self._widget_was_created(): + return + if ibeam_color is not None: + try: + self.Widget.config(insertbackground=ibeam_color) + except Exception as e: + _error_popup_with_traceback('Error setting I-Beam color in set_ibeam_color', + 'The element has a key:', self.Key, + 'The color passed in was:', ibeam_color) + + + def get(self): """ Return the current chosen value showing in spinbox. @@ -4230,6 +4279,31 @@ class Multiline(Element): # pass return + + + + + def set_ibeam_color(self, ibeam_color=None): + """ + Sets the color of the I-Beam that is used to "insert" characters. This is oftens called a "Cursor" by + many users. To keep from being confused with tkinter's definition of cursor (the mouse pointer), the term + ibeam is used in this case. + :param ibeam_color: color to set the "I-Beam" used to indicate where characters will be inserted + :type ibeam_color: (str) + """ + + if not self._widget_was_created(): + return + if ibeam_color is not None: + try: + self.Widget.config(insertbackground=ibeam_color) + except Exception as e: + _error_popup_with_traceback('Error setting I-Beam color in set_ibeam_color', + 'The element has a key:', self.Key, + 'The color passed in was:', ibeam_color) + + + def __del__(self): """ AT ONE TIME --- If this Widget is deleted, be sure and restore the old stdout, stderr @@ -16898,6 +16972,7 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form): element.TKText.config(highlightthickness=0) if text_color is not None and text_color != COLOR_SYSTEM_DEFAULT: element.TKText.configure(fg=text_color, selectbackground=text_color) + element.TKText.config(insertbackground=text_color) if element.BackgroundColor is not None and element.BackgroundColor != COLOR_SYSTEM_DEFAULT: element.TKText.configure(background=element.BackgroundColor, selectforeground=element.BackgroundColor) if element.selected_background_color not in (None, COLOR_SYSTEM_DEFAULT): @@ -16940,7 +17015,6 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form): element.TKText.focus_set() - if element.Disabled is True: element.TKText['state'] = 'disabled' if element.Tooltip is not None: @@ -16950,8 +17024,6 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form): cprint_set_output_destination(toplevel_form, element.Key) _add_right_click_menu_and_grab(element) - if theme_input_text_color() not in (COLOR_SYSTEM_DEFAULT, None): - element.Widget.config(insertbackground=theme_input_text_color()) if element.reroute_stdout: element.reroute_stdout_to_here() @@ -17091,6 +17163,9 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form): if element.BackgroundColor is not None and element.BackgroundColor != COLOR_SYSTEM_DEFAULT: element.TKSpinBox.configure(background=element.BackgroundColor) element.TKSpinBox.configure(buttonbackground=element.BackgroundColor) + if text_color not in (None, COLOR_SYSTEM_DEFAULT): + element.TKSpinBox.configure(fg=text_color) + element.TKSpinBox.config(insertbackground=text_color) element.Widget.config(highlightthickness=0) if element.wrap is True: element.Widget.configure(wrap=True) @@ -17099,8 +17174,6 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form): if element.visible is False: element._pack_forget_save_settings() # element.TKSpinBox.pack_forget() - if text_color is not None and text_color != COLOR_SYSTEM_DEFAULT: - element.TKSpinBox.configure(fg=text_color) if element.ChangeSubmits: element.TKSpinBox.configure(command=element._SpinboxSelectHandler) # element.TKSpinBox.bind('', element._SpinChangedHandler) @@ -17114,8 +17187,6 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form): element.TooltipObject = ToolTip(element.TKSpinBox, text=element.Tooltip, timeout=DEFAULT_TOOLTIP_TIME) if element.BindReturnKey: element.TKSpinBox.bind('', element._SpinboxSelectHandler) - if theme_input_text_color() not in (COLOR_SYSTEM_DEFAULT, None): - element.Widget.config(insertbackground=theme_input_text_color()) _add_right_click_menu_and_grab(element) # ------------------------- IMAGE placement element ------------------------- # elif element_type == ELEM_TYPE_IMAGE: @@ -26483,4 +26554,4 @@ if __name__ == '__main__': exit(0) main() exit(0) -#1c230bde4c3f139d563fda282c8f2524ee39106dd7788fc6410723b3bfa42ae4dd17ca7005afbaad58a9b4565d4e911be7ac9d5b021b8e5614eba2853c33fdc167ac180241ccc6d564cca79493816ed599b82423be23ab4c46833cae5ec471a98b08d2ca46b18be736818e71168b19877515246d92ffa1cd40202356cb3b3e09e50e75db6cb1584893dc242ad63f8c8b4d2574bdbaa958b5da63f043813c4534315cff6d39dade82cd3aa8231dafd0f7133e212f9a72051d0af5c25ce64f9be042a0077d3837b44a937d5d2c0871461e3422a40605039fae563d238ddd4a590d44a8c57475d46bf78083ded3544ee2b8b2c8f88d703e150d1e14edcbdf31b902a5596096570e21cbb5fb4d48b904460b477ea6747a69e66f03d2d1874eff2aed73ce733e98e7346ee99f5bbe9a791de36e6a96bd5367ea9cd6c34852c5b3ec2a9e1d8cd1c5602bc9e7a12eb0fdeeaa2355c28d589ffc922c586db55dcca3fa0758fa511662ba18ecf5914841d874c9013d0674e152d8dd74e7113a33eeea9d187b8ef8b312017a733f2490d228b5295f3bd323949a2ef199c6efdd4acd5da641059eed7d95be005f7c4f508fdc83bb2e0e22d85cdf9376e948ba95f4405e4ddd23cf4f26aa44f6e4f7d2b82d4627847fc73c642eb9356311c9096e63c91c9666c6230a24c9323552bf4f44fe4397bef40df1644859e52019d29283c5f67ca173 \ No newline at end of file +#491b45b926a0f4407364c8e3fe2d56e3c83693fbdcfea2f3ebe6a10bc6cf66ec10d1ee9f0754a70ea812aed411be7b8dde143fc345648c6f24ebf88205405d66dbdbb646ee77d0a3a241f13853623acead20c030948a771c86676303f5823fdf0e59c5d20d622c589cd3ec5da0a4eb3a8b1d84f964b0e67036f534b4499f7126cf8c9b39ad46fce9ee986fadb2cf89007b79b9f8ccc897a627653414ffda66f4dc140fa798559104d01f05584d7df51bc9b5b32a5c885efd6d19f9d77278e908d36cdffe0d7e3db0bd45722913b28a61c6e3cf9826bbaf0b60fd15b98296529727f67f6bcd4cfa21aff266072bb66a778732a9263f1a81251721755b28a6383b8763b31545db380bfbf663756a9bd4ba78ae2df1c3085eae809a2adc9ee04987e3d564b06558f52645259250506b24d32109a62e33d3794d343634720d2712618d670b32d7a60b2016791d050b772df9f2a80ef7e5c2c182f06e57a207e16ccde97cc248a071f873d563caea2ff7a36e15dc5f0c8495c6ec85c37895856f3bd0138b457d62bfc83e34e1934cee2308de94fcd185c85e9611d5eac8534927accca9ac53e0aa9cea56c6b9e6f1b06eb68c8d4ca3253314332f593c6473d73017a34608393853dc5db923a8bf1a96ddd9af17127952770bb89f2e753579c0e4ace28aea294d157417f1db9b0160e3cd1bc3c4d801adca5f1a0a9b34f25f0b3ca595 \ No newline at end of file From 2eed0afaeb95d9dbbfbb7be0bb8ed61e97db4aae Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Mon, 13 Mar 2023 06:16:07 -0400 Subject: [PATCH 062/145] New SDK call ref with net set_ibeam_color method added. New Udemy Coupon added to docs --- docs/call reference.md | 156 ++++++++++++------ docs/cookbook.md | 4 +- docs/index.md | 4 +- docs/readme.md | 4 +- .../markdown input files/1_HEADER_top_part.md | 4 +- .../markdown input files/5_call_reference.md | 13 +- readme_creator/output/call reference.md | 156 ++++++++++++------ readme_creator/output/index.md | 4 +- 8 files changed, 241 insertions(+), 104 deletions(-) diff --git a/docs/call reference.md b/docs/call reference.md index 98c2f2a2..dffd8746 100644 --- a/docs/call reference.md +++ b/docs/call reference.md @@ -25,9 +25,9 @@ apply coupon for discount: - 07860559FF2298EF51E7 + A2E4F6B1B75EC3D90133input. - @@ -1305,6 +1305,7 @@ Checkbox(text, background_color = None, text_color = None, checkbox_color = None, + highlight_thickness = 1, change_submits = False, enable_events = False, disabled = False, @@ -1324,28 +1325,29 @@ Parameter Descriptions: |Type|Name|Meaning| |--|--|--| -| str | text | Text to display next to checkbox | -| bool | default | Set to True if you want this checkbox initially checked | -| (int, int) or (None, None) or int | size | (w, h) w=characters-wide, h=rows-high. If an int instead of a tuple is supplied, then height is auto-set to 1 | -| (int, int) or (None, None) or int | s | Same as size parameter. It's an alias. If EITHER of them are set, then the one that's set will be used. If BOTH are set, size will be used | -| bool | auto_size_text | if True will size the element to match the length of the text | -| (str or (str, int[, str]) or None) | font | specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike | -| str | background_color | color of background | -| str | text_color | color of the text | -| str | checkbox_color | color of background of the box that has the check mark in it. The checkmark is the same color as the text | -| bool | change_submits | DO NOT USE. Only listed for backwards compat - Use enable_events instead | -| bool | enable_events | Turns on the element specific events. Checkbox events happen when an item changes | -| bool | disabled | set disable state | -| str or int or tuple or object | key | Used with window.find_element and with return values to uniquely identify this element | -| str or int or tuple or object | k | Same as the Key. You can use either k or key. Which ever is set will be used. | -| (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | pad | Amount of padding to put around element in pixels (left/right, top/bottom) or ((left, right), (top, bottom)) or an int. If an int, then it's converted into a tuple (int, int) | -| (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | p | Same as pad parameter. It's an alias. If EITHER of them are set, then the one that's set will be used. If BOTH are set, pad will be used | -| str | tooltip | text, that will appear when mouse hovers over the element | -| List[List[ List[str] or str ]] | right_click_menu | A list of lists of Menu items to show when this element is right clicked. See user docs for exact format. | -| bool | expand_x | If True the element will automatically expand in the X direction to fill available space | -| bool | expand_y | If True the element will automatically expand in the Y direction to fill available space | -| bool | visible | set visibility state of the element | -| Any | metadata | User metadata that can be set to ANYTHING | +| str | text | Text to display next to checkbox | +| bool | default | Set to True if you want this checkbox initially checked | +| (int, int) or (None, None) or int | size | (w, h) w=characters-wide, h=rows-high. If an int instead of a tuple is supplied, then height is auto-set to 1 | +| (int, int) or (None, None) or int | s | Same as size parameter. It's an alias. If EITHER of them are set, then the one that's set will be used. If BOTH are set, size will be used | +| bool | auto_size_text | if True will size the element to match the length of the text | +| (str or (str, int[, str]) or None) | font | specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike | +| str | background_color | color of background | +| str | text_color | color of the text | +| str | checkbox_color | color of background of the box that has the check mark in it. The checkmark is the same color as the text | +| int | highlight_thickness | thickness of border around checkbox when gets focus | +| bool | change_submits | DO NOT USE. Only listed for backwards compat - Use enable_events instead | +| bool | enable_events | Turns on the element specific events. Checkbox events happen when an item changes | +| bool | disabled | set disable state | +| str or int or tuple or object | key | Used with window.find_element and with return values to uniquely identify this element | +| str or int or tuple or object | k | Same as the Key. You can use either k or key. Which ever is set will be used. | +| (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | pad | Amount of padding to put around element in pixels (left/right, top/bottom) or ((left, right), (top, bottom)) or an int. If an int, then it's converted into a tuple (int, int) | +| (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | p | Same as pad parameter. It's an alias. If EITHER of them are set, then the one that's set will be used. If BOTH are set, pad will be used | +| str | tooltip | text, that will appear when mouse hovers over the element | +| List[List[ List[str] or str ]] | right_click_menu | A list of lists of Menu items to show when this element is right clicked. See user docs for exact format. | +| bool | expand_x | If True the element will automatically expand in the X direction to fill available space | +| bool | expand_y | If True the element will automatically expand in the Y direction to fill available space | +| bool | visible | set visibility state of the element | +| Any | metadata | User metadata that can be set to ANYTHING | ### bind @@ -2481,22 +2483,26 @@ update(value = None, font = None, visible = None, size = (None, None), - select = None) + select = None, + text_color = None, + background_color = None) ``` Parameter Descriptions: |Type|Name|Meaning| |--|--|--| -| Any | value | change which value is current selected based on new list of previous list of choices | -| List[Any] | values | change list of choices | -| int | set_to_index | change selection to a particular choice starting with index = 0 | -| bool | disabled | disable or enable state of the element | -| bool | readonly | if True make element readonly (user cannot change any choices). Enables the element if either choice are made. | -| (str or (str, int[, str]) or None) | font | specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike | -| bool | visible | control visibility of element | -| (int, int) | size | width, height. Width = characters-wide, height = NOTE it's the number of entries to show in the list | -| bool | select | if True, then the text will be selected, if False then selection will be cleared | +| Any | value | change which value is current selected based on new list of previous list of choices | +| List[Any] | values | change list of choices | +| int | set_to_index | change selection to a particular choice starting with index = 0 | +| bool | disabled | disable or enable state of the element | +| bool | readonly | if True make element readonly (user cannot change any choices). Enables the element if either choice are made. | +| (str or (str, int[, str]) or None) | font | specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike | +| bool | visible | control visibility of element | +| (int, int) | size | width, height. Width = characters-wide, height = NOTE it's the number of entries to show in the list | +| bool | select | if True, then the text will be selected, if False then selection will be cleared | +| str | background_color | color of background | +| str | text_color | color of the text | ### visible @@ -2586,22 +2592,26 @@ Update(value = None, font = None, visible = None, size = (None, None), - select = None) + select = None, + text_color = None, + background_color = None) ``` Parameter Descriptions: |Type|Name|Meaning| |--|--|--| -| Any | value | change which value is current selected based on new list of previous list of choices | -| List[Any] | values | change list of choices | -| int | set_to_index | change selection to a particular choice starting with index = 0 | -| bool | disabled | disable or enable state of the element | -| bool | readonly | if True make element readonly (user cannot change any choices). Enables the element if either choice are made. | -| (str or (str, int[, str]) or None) | font | specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike | -| bool | visible | control visibility of element | -| (int, int) | size | width, height. Width = characters-wide, height = NOTE it's the number of entries to show in the list | -| bool | select | if True, then the text will be selected, if False then selection will be cleared | +| Any | value | change which value is current selected based on new list of previous list of choices | +| List[Any] | values | change list of choices | +| int | set_to_index | change selection to a particular choice starting with index = 0 | +| bool | disabled | disable or enable state of the element | +| bool | readonly | if True make element readonly (user cannot change any choices). Enables the element if either choice are made. | +| (str or (str, int[, str]) or None) | font | specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike | +| bool | visible | control visibility of element | +| (int, int) | size | width, height. Width = characters-wide, height = NOTE it's the number of entries to show in the list | +| bool | select | if True, then the text will be selected, if False then selection will be cleared | +| str | background_color | color of background | +| str | text_color | color of the text | --------- @@ -5100,6 +5110,22 @@ Parameter Descriptions: |--|--|--| | bool | force | if True will call focus_force otherwise calls focus_set | +### set_ibeam_color + +Sets the color of the I-Beam that is used to "insert" characters. This is oftens called a "Cursor" by +many users. To keep from being confused with tkinter's definition of cursor (the mouse pointer), the term +ibeam is used in this case. + +``` +set_ibeam_color(ibeam_color = None) +``` + +Parameter Descriptions: + +|Type|Name|Meaning| +|--|--|--| +| str | ibeam_color | color to set the "I-Beam" used to indicate where characters will be inserted | + ### set_size Changes the size of an element to a specific size. @@ -6600,6 +6626,22 @@ Parameter Descriptions: |--|--|--| | bool | force | if True will call focus_force otherwise calls focus_set | +### set_ibeam_color + +Sets the color of the I-Beam that is used to "insert" characters. This is oftens called a "Cursor" by +many users. To keep from being confused with tkinter's definition of cursor (the mouse pointer), the term +ibeam is used in this case. + +``` +set_ibeam_color(ibeam_color = None) +``` + +Parameter Descriptions: + +|Type|Name|Meaning| +|--|--|--| +| str | ibeam_color | color to set the "I-Beam" used to indicate where characters will be inserted | + ### set_size Changes the size of an element to a specific size. @@ -9821,6 +9863,22 @@ Parameter Descriptions: |--|--|--| | bool | force | if True will call focus_force otherwise calls focus_set | +### set_ibeam_color + +Sets the color of the I-Beam that is used to "insert" characters. This is oftens called a "Cursor" by +many users. To keep from being confused with tkinter's definition of cursor (the mouse pointer), the term +ibeam is used in this case. + +``` +set_ibeam_color(ibeam_color = None) +``` + +Parameter Descriptions: + +|Type|Name|Meaning| +|--|--|--| +| str | ibeam_color | color to set the "I-Beam" used to indicate where characters will be inserted | + ### set_size Changes the size of an element to a specific size. @@ -13054,6 +13112,7 @@ Window(title, sbar_arrow_width = None, sbar_frame_color = None, sbar_relief = None, + watermark = None, metadata = None) ``` @@ -13121,6 +13180,7 @@ Parameter Descriptions: | int | sbar_arrow_width | Scrollbar width of the arrow on the scrollbar. It will potentially impact the overall width of the scrollbar | | str | sbar_frame_color | Scrollbar Color of frame around scrollbar (available only on some ttk themes) | | str | sbar_relief | Scrollbar relief that will be used for the "thumb" of the scrollbar (the thing you grab that slides). Should be a constant that is defined at starting with "RELIEF_" - RELIEF_RAISED, RELIEF_SUNKEN, RELIEF_FLAT, RELIEF_RIDGE, RELIEF_GROOVE, RELIEF_SOLID | +| bool | watermark | If True, then turns on watermarking temporarily for ALL windows created from this point forward. See global settings doc for more info | | Any | metadata | User metadata that can be set to ANYTHING | ### add_row @@ -20031,7 +20091,8 @@ set_options(icon = None, sbar_relief = None, alpha_channel = None, hide_window_when_creating = None, - use_button_shortcuts = None) + use_button_shortcuts = None, + watermark_text = None) ``` Parameter Descriptions: @@ -20104,6 +20165,7 @@ Parameter Descriptions: | float | alpha_channel | Default alpha channel to be used on all windows | | bool | hide_window_when_creating | If True then alpha will be set to 0 while a window is made and moved to location indicated | | bool | use_button_shortcuts | If True then Shortcut Char will be used with Buttons | +| str | watermark_text | Set the text that will be used if a window is watermarked | | None | **RETURN** | None ### Non PEP8 versions @@ -20187,7 +20249,8 @@ SetOptions(icon = None, sbar_relief = None, alpha_channel = None, hide_window_when_creating = None, - use_button_shortcuts = None) + use_button_shortcuts = None, + watermark_text = None) ``` Parameter Descriptions: @@ -20260,6 +20323,7 @@ Parameter Descriptions: | float | alpha_channel | Default alpha channel to be used on all windows | | bool | hide_window_when_creating | If True then alpha will be set to 0 while a window is made and moved to location indicated | | bool | use_button_shortcuts | If True then Shortcut Char will be used with Buttons | +| str | watermark_text | Set the text that will be used if a window is watermarked | | None | **RETURN** | None ## Old Themes (Look and Feel) - Replaced by theme() diff --git a/docs/cookbook.md b/docs/cookbook.md index 53b73cc3..8cae312c 100644 --- a/docs/cookbook.md +++ b/docs/cookbook.md @@ -25,9 +25,9 @@ apply coupon for discount: - 07860559FF2298EF51E7 + A2E4F6B1B75EC3D90133 - diff --git a/docs/index.md b/docs/index.md index 4121f51d..1dfb749a 100644 --- a/docs/index.md +++ b/docs/index.md @@ -25,9 +25,9 @@ apply coupon for discount: - 07860559FF2298EF51E7 + A2E4F6B1B75EC3D90133 - diff --git a/docs/readme.md b/docs/readme.md index 740737f9..181372e7 100644 --- a/docs/readme.md +++ b/docs/readme.md @@ -9,8 +9,8 @@ PySimpleGUI Udemy Course -
apply coupon for discount:
07860559FF2298EF51E7
- click here to visit course page +
apply coupon for discount:
A2E4F6B1B75EC3D90133
+ click here to visit course page diff --git a/readme_creator/markdown input files/1_HEADER_top_part.md b/readme_creator/markdown input files/1_HEADER_top_part.md index c7ba309d..e8d716ae 100644 --- a/readme_creator/markdown input files/1_HEADER_top_part.md +++ b/readme_creator/markdown input files/1_HEADER_top_part.md @@ -52,9 +52,9 @@ HOW DO I INSERT IMAGES ??? apply coupon for discount: - 07860559FF2298EF51E7 + A2E4F6B1B75EC3D90133 - diff --git a/readme_creator/markdown input files/5_call_reference.md b/readme_creator/markdown input files/5_call_reference.md index 04b093c4..2a13ca90 100644 --- a/readme_creator/markdown input files/5_call_reference.md +++ b/readme_creator/markdown input files/5_call_reference.md @@ -25,9 +25,9 @@ apply coupon for discount: - 07860559FF2298EF51E7 + A2E4F6B1B75EC3D90133input. - @@ -1111,6 +1111,9 @@ The following methods are here for backwards compatibility reference. You will ### set_focus +### set_ibeam_color + + ### set_size @@ -1421,6 +1424,9 @@ See the Column element to get a list of method calls available. The function re ### set_focus +### set_ibeam_color + + ### set_size @@ -2162,6 +2168,9 @@ The following methods are here for backwards compatibility reference. You will ### set_focus +### set_ibeam_color + + ### set_size diff --git a/readme_creator/output/call reference.md b/readme_creator/output/call reference.md index 98c2f2a2..dffd8746 100644 --- a/readme_creator/output/call reference.md +++ b/readme_creator/output/call reference.md @@ -25,9 +25,9 @@ apply coupon for discount: - 07860559FF2298EF51E7 + A2E4F6B1B75EC3D90133input. - @@ -1305,6 +1305,7 @@ Checkbox(text, background_color = None, text_color = None, checkbox_color = None, + highlight_thickness = 1, change_submits = False, enable_events = False, disabled = False, @@ -1324,28 +1325,29 @@ Parameter Descriptions: |Type|Name|Meaning| |--|--|--| -| str | text | Text to display next to checkbox | -| bool | default | Set to True if you want this checkbox initially checked | -| (int, int) or (None, None) or int | size | (w, h) w=characters-wide, h=rows-high. If an int instead of a tuple is supplied, then height is auto-set to 1 | -| (int, int) or (None, None) or int | s | Same as size parameter. It's an alias. If EITHER of them are set, then the one that's set will be used. If BOTH are set, size will be used | -| bool | auto_size_text | if True will size the element to match the length of the text | -| (str or (str, int[, str]) or None) | font | specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike | -| str | background_color | color of background | -| str | text_color | color of the text | -| str | checkbox_color | color of background of the box that has the check mark in it. The checkmark is the same color as the text | -| bool | change_submits | DO NOT USE. Only listed for backwards compat - Use enable_events instead | -| bool | enable_events | Turns on the element specific events. Checkbox events happen when an item changes | -| bool | disabled | set disable state | -| str or int or tuple or object | key | Used with window.find_element and with return values to uniquely identify this element | -| str or int or tuple or object | k | Same as the Key. You can use either k or key. Which ever is set will be used. | -| (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | pad | Amount of padding to put around element in pixels (left/right, top/bottom) or ((left, right), (top, bottom)) or an int. If an int, then it's converted into a tuple (int, int) | -| (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | p | Same as pad parameter. It's an alias. If EITHER of them are set, then the one that's set will be used. If BOTH are set, pad will be used | -| str | tooltip | text, that will appear when mouse hovers over the element | -| List[List[ List[str] or str ]] | right_click_menu | A list of lists of Menu items to show when this element is right clicked. See user docs for exact format. | -| bool | expand_x | If True the element will automatically expand in the X direction to fill available space | -| bool | expand_y | If True the element will automatically expand in the Y direction to fill available space | -| bool | visible | set visibility state of the element | -| Any | metadata | User metadata that can be set to ANYTHING | +| str | text | Text to display next to checkbox | +| bool | default | Set to True if you want this checkbox initially checked | +| (int, int) or (None, None) or int | size | (w, h) w=characters-wide, h=rows-high. If an int instead of a tuple is supplied, then height is auto-set to 1 | +| (int, int) or (None, None) or int | s | Same as size parameter. It's an alias. If EITHER of them are set, then the one that's set will be used. If BOTH are set, size will be used | +| bool | auto_size_text | if True will size the element to match the length of the text | +| (str or (str, int[, str]) or None) | font | specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike | +| str | background_color | color of background | +| str | text_color | color of the text | +| str | checkbox_color | color of background of the box that has the check mark in it. The checkmark is the same color as the text | +| int | highlight_thickness | thickness of border around checkbox when gets focus | +| bool | change_submits | DO NOT USE. Only listed for backwards compat - Use enable_events instead | +| bool | enable_events | Turns on the element specific events. Checkbox events happen when an item changes | +| bool | disabled | set disable state | +| str or int or tuple or object | key | Used with window.find_element and with return values to uniquely identify this element | +| str or int or tuple or object | k | Same as the Key. You can use either k or key. Which ever is set will be used. | +| (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | pad | Amount of padding to put around element in pixels (left/right, top/bottom) or ((left, right), (top, bottom)) or an int. If an int, then it's converted into a tuple (int, int) | +| (int, int or (int, int),(int,int) or int,(int,int)) or ((int, int),int) or int | p | Same as pad parameter. It's an alias. If EITHER of them are set, then the one that's set will be used. If BOTH are set, pad will be used | +| str | tooltip | text, that will appear when mouse hovers over the element | +| List[List[ List[str] or str ]] | right_click_menu | A list of lists of Menu items to show when this element is right clicked. See user docs for exact format. | +| bool | expand_x | If True the element will automatically expand in the X direction to fill available space | +| bool | expand_y | If True the element will automatically expand in the Y direction to fill available space | +| bool | visible | set visibility state of the element | +| Any | metadata | User metadata that can be set to ANYTHING | ### bind @@ -2481,22 +2483,26 @@ update(value = None, font = None, visible = None, size = (None, None), - select = None) + select = None, + text_color = None, + background_color = None) ``` Parameter Descriptions: |Type|Name|Meaning| |--|--|--| -| Any | value | change which value is current selected based on new list of previous list of choices | -| List[Any] | values | change list of choices | -| int | set_to_index | change selection to a particular choice starting with index = 0 | -| bool | disabled | disable or enable state of the element | -| bool | readonly | if True make element readonly (user cannot change any choices). Enables the element if either choice are made. | -| (str or (str, int[, str]) or None) | font | specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike | -| bool | visible | control visibility of element | -| (int, int) | size | width, height. Width = characters-wide, height = NOTE it's the number of entries to show in the list | -| bool | select | if True, then the text will be selected, if False then selection will be cleared | +| Any | value | change which value is current selected based on new list of previous list of choices | +| List[Any] | values | change list of choices | +| int | set_to_index | change selection to a particular choice starting with index = 0 | +| bool | disabled | disable or enable state of the element | +| bool | readonly | if True make element readonly (user cannot change any choices). Enables the element if either choice are made. | +| (str or (str, int[, str]) or None) | font | specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike | +| bool | visible | control visibility of element | +| (int, int) | size | width, height. Width = characters-wide, height = NOTE it's the number of entries to show in the list | +| bool | select | if True, then the text will be selected, if False then selection will be cleared | +| str | background_color | color of background | +| str | text_color | color of the text | ### visible @@ -2586,22 +2592,26 @@ Update(value = None, font = None, visible = None, size = (None, None), - select = None) + select = None, + text_color = None, + background_color = None) ``` Parameter Descriptions: |Type|Name|Meaning| |--|--|--| -| Any | value | change which value is current selected based on new list of previous list of choices | -| List[Any] | values | change list of choices | -| int | set_to_index | change selection to a particular choice starting with index = 0 | -| bool | disabled | disable or enable state of the element | -| bool | readonly | if True make element readonly (user cannot change any choices). Enables the element if either choice are made. | -| (str or (str, int[, str]) or None) | font | specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike | -| bool | visible | control visibility of element | -| (int, int) | size | width, height. Width = characters-wide, height = NOTE it's the number of entries to show in the list | -| bool | select | if True, then the text will be selected, if False then selection will be cleared | +| Any | value | change which value is current selected based on new list of previous list of choices | +| List[Any] | values | change list of choices | +| int | set_to_index | change selection to a particular choice starting with index = 0 | +| bool | disabled | disable or enable state of the element | +| bool | readonly | if True make element readonly (user cannot change any choices). Enables the element if either choice are made. | +| (str or (str, int[, str]) or None) | font | specifies the font family, size, etc. Tuple or Single string format 'name size styles'. Styles: italic * roman bold normal underline overstrike | +| bool | visible | control visibility of element | +| (int, int) | size | width, height. Width = characters-wide, height = NOTE it's the number of entries to show in the list | +| bool | select | if True, then the text will be selected, if False then selection will be cleared | +| str | background_color | color of background | +| str | text_color | color of the text | --------- @@ -5100,6 +5110,22 @@ Parameter Descriptions: |--|--|--| | bool | force | if True will call focus_force otherwise calls focus_set | +### set_ibeam_color + +Sets the color of the I-Beam that is used to "insert" characters. This is oftens called a "Cursor" by +many users. To keep from being confused with tkinter's definition of cursor (the mouse pointer), the term +ibeam is used in this case. + +``` +set_ibeam_color(ibeam_color = None) +``` + +Parameter Descriptions: + +|Type|Name|Meaning| +|--|--|--| +| str | ibeam_color | color to set the "I-Beam" used to indicate where characters will be inserted | + ### set_size Changes the size of an element to a specific size. @@ -6600,6 +6626,22 @@ Parameter Descriptions: |--|--|--| | bool | force | if True will call focus_force otherwise calls focus_set | +### set_ibeam_color + +Sets the color of the I-Beam that is used to "insert" characters. This is oftens called a "Cursor" by +many users. To keep from being confused with tkinter's definition of cursor (the mouse pointer), the term +ibeam is used in this case. + +``` +set_ibeam_color(ibeam_color = None) +``` + +Parameter Descriptions: + +|Type|Name|Meaning| +|--|--|--| +| str | ibeam_color | color to set the "I-Beam" used to indicate where characters will be inserted | + ### set_size Changes the size of an element to a specific size. @@ -9821,6 +9863,22 @@ Parameter Descriptions: |--|--|--| | bool | force | if True will call focus_force otherwise calls focus_set | +### set_ibeam_color + +Sets the color of the I-Beam that is used to "insert" characters. This is oftens called a "Cursor" by +many users. To keep from being confused with tkinter's definition of cursor (the mouse pointer), the term +ibeam is used in this case. + +``` +set_ibeam_color(ibeam_color = None) +``` + +Parameter Descriptions: + +|Type|Name|Meaning| +|--|--|--| +| str | ibeam_color | color to set the "I-Beam" used to indicate where characters will be inserted | + ### set_size Changes the size of an element to a specific size. @@ -13054,6 +13112,7 @@ Window(title, sbar_arrow_width = None, sbar_frame_color = None, sbar_relief = None, + watermark = None, metadata = None) ``` @@ -13121,6 +13180,7 @@ Parameter Descriptions: | int | sbar_arrow_width | Scrollbar width of the arrow on the scrollbar. It will potentially impact the overall width of the scrollbar | | str | sbar_frame_color | Scrollbar Color of frame around scrollbar (available only on some ttk themes) | | str | sbar_relief | Scrollbar relief that will be used for the "thumb" of the scrollbar (the thing you grab that slides). Should be a constant that is defined at starting with "RELIEF_" - RELIEF_RAISED, RELIEF_SUNKEN, RELIEF_FLAT, RELIEF_RIDGE, RELIEF_GROOVE, RELIEF_SOLID | +| bool | watermark | If True, then turns on watermarking temporarily for ALL windows created from this point forward. See global settings doc for more info | | Any | metadata | User metadata that can be set to ANYTHING | ### add_row @@ -20031,7 +20091,8 @@ set_options(icon = None, sbar_relief = None, alpha_channel = None, hide_window_when_creating = None, - use_button_shortcuts = None) + use_button_shortcuts = None, + watermark_text = None) ``` Parameter Descriptions: @@ -20104,6 +20165,7 @@ Parameter Descriptions: | float | alpha_channel | Default alpha channel to be used on all windows | | bool | hide_window_when_creating | If True then alpha will be set to 0 while a window is made and moved to location indicated | | bool | use_button_shortcuts | If True then Shortcut Char will be used with Buttons | +| str | watermark_text | Set the text that will be used if a window is watermarked | | None | **RETURN** | None ### Non PEP8 versions @@ -20187,7 +20249,8 @@ SetOptions(icon = None, sbar_relief = None, alpha_channel = None, hide_window_when_creating = None, - use_button_shortcuts = None) + use_button_shortcuts = None, + watermark_text = None) ``` Parameter Descriptions: @@ -20260,6 +20323,7 @@ Parameter Descriptions: | float | alpha_channel | Default alpha channel to be used on all windows | | bool | hide_window_when_creating | If True then alpha will be set to 0 while a window is made and moved to location indicated | | bool | use_button_shortcuts | If True then Shortcut Char will be used with Buttons | +| str | watermark_text | Set the text that will be used if a window is watermarked | | None | **RETURN** | None ## Old Themes (Look and Feel) - Replaced by theme() diff --git a/readme_creator/output/index.md b/readme_creator/output/index.md index 4121f51d..1dfb749a 100644 --- a/readme_creator/output/index.md +++ b/readme_creator/output/index.md @@ -25,9 +25,9 @@ apply coupon for discount: - 07860559FF2298EF51E7 + A2E4F6B1B75EC3D90133 - From d8d5227240098726a8dff88bdb42c95e9b5b44c0 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Mon, 13 Mar 2023 06:17:36 -0400 Subject: [PATCH 063/145] New Udemy Coupon added --- PySimpleGUI.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index a943780e..635a3527 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -version = __version__ = "4.61.0.165 Unreleased" +version = __version__ = "4.61.0.166 Unreleased" _change_log = """ Changelog since 4.60.0 released to PyPI on 8-May-2022 @@ -398,6 +398,8 @@ _change_log = """ 4.61.0.165 Multiline & Spin - Applied same fix for input "cursor" (I-Beam) color that was added to the Input element. Added new method - set_ibeam_color to Input, Multiline and Spin elements. Combo is a ttk element so it's not available using this call yet + 4.61.0.166 + New Udemy coupon """ __version__ = version.split()[0] # For PEP 396 and PEP 345 @@ -26376,7 +26378,7 @@ def main(): elif event == 'Get Text': popup_scrolled('Returned:', popup_get_text('Enter some text', keep_on_top=True)) elif event.startswith('-UDEMY-'): - webbrowser.open_new_tab(r'https://www.udemy.com/course/pysimplegui/?couponCode=07860559FF2298EF51E7') + webbrowser.open_new_tab(r'https://www.udemy.com/course/pysimplegui/?couponCode=A2E4F6B1B75EC3D90133') elif event.startswith('-SPONSOR-'): if webbrowser_available: webbrowser.open_new_tab(r'https://www.paypal.me/pythongui') @@ -26384,7 +26386,7 @@ def main(): if webbrowser_available: webbrowser.open_new_tab(r'https://www.buymeacoffee.com/PySimpleGUI') elif event in ('-EMOJI-HEARTS-', '-HEART-', '-PYTHON HEARTS-'): - popup_scrolled("Oh look! It's a Udemy discount coupon!", '07860559FF2298EF51E7', + popup_scrolled("Oh look! It's a Udemy discount coupon!", 'A2E4F6B1B75EC3D90133', 'A personal message from Mike -- thank you so very much for supporting PySimpleGUI!', title='Udemy Coupon', image=EMOJI_BASE64_MIKE, keep_on_top=True) elif event == 'Themes': @@ -26554,4 +26556,4 @@ if __name__ == '__main__': exit(0) main() exit(0) -#491b45b926a0f4407364c8e3fe2d56e3c83693fbdcfea2f3ebe6a10bc6cf66ec10d1ee9f0754a70ea812aed411be7b8dde143fc345648c6f24ebf88205405d66dbdbb646ee77d0a3a241f13853623acead20c030948a771c86676303f5823fdf0e59c5d20d622c589cd3ec5da0a4eb3a8b1d84f964b0e67036f534b4499f7126cf8c9b39ad46fce9ee986fadb2cf89007b79b9f8ccc897a627653414ffda66f4dc140fa798559104d01f05584d7df51bc9b5b32a5c885efd6d19f9d77278e908d36cdffe0d7e3db0bd45722913b28a61c6e3cf9826bbaf0b60fd15b98296529727f67f6bcd4cfa21aff266072bb66a778732a9263f1a81251721755b28a6383b8763b31545db380bfbf663756a9bd4ba78ae2df1c3085eae809a2adc9ee04987e3d564b06558f52645259250506b24d32109a62e33d3794d343634720d2712618d670b32d7a60b2016791d050b772df9f2a80ef7e5c2c182f06e57a207e16ccde97cc248a071f873d563caea2ff7a36e15dc5f0c8495c6ec85c37895856f3bd0138b457d62bfc83e34e1934cee2308de94fcd185c85e9611d5eac8534927accca9ac53e0aa9cea56c6b9e6f1b06eb68c8d4ca3253314332f593c6473d73017a34608393853dc5db923a8bf1a96ddd9af17127952770bb89f2e753579c0e4ace28aea294d157417f1db9b0160e3cd1bc3c4d801adca5f1a0a9b34f25f0b3ca595 \ No newline at end of file +#8191dd5d8352d3c13f89bde32cdd01d664da2f4cabeff579ec281e413131545b6aafe489020f8f73c96477dbdf9e86e0013c01759cae8c5837d9d7ea44c7fc75f9af3fb5bce6270b0254f6f6f2d966abc5257991792b3d83880d7690a85e8f4b59e4051b0ff2f7ac1a5fa27d5630c2365d70398b22cda91c1a988c4f19379c4575afb6f6c86e873e0bcda2ed4fc65879a8c4c7a297437742b1ac070de6d04019ffc5e350d6030ce97965d0414ef48ea670ba21bb359319f1c8be7e6da2ff46c727ea82f54eb30d3a74728b5aa20e1412b6812750cfb8cb6122b3e720f0a2c0106d7ddb0eba9313ed763aa3f404221e0d4ffe9bb324a56ebb410e5cd6f45f6b985db5c39369d1fe201fc2ee7c9e8017e8eb7a9e08edafa15ad8a89f6214b75b8e183e2dde4c67350975999d7f74572f0f17d422a9ca430c928f80e2ffee4dd376ce916999b7a263b39783ddf54242b1341e70240c6875832525d87100c9a733d09969465e38226d80ead49508692eb9851eaa4fba26ca5069cb2c6ee88647c79683860d9b12fa598a1d452015d80295a1b59236c38f8fb42edf1aa897db653f8c20ce79836641cc64c1e5975b8400edc98854ab5c26de57241ce8b89979173b84f9cf3e5dd455a63721545001b06af63a8b11ed7889a4e53af7a1527bbd3e14ae6e6a16eb569c79d7213d52e7f276f1a59423fb3a519adc122b73128196aec80a \ No newline at end of file From f97de3468bdf5b5f544d2663f2c0ff88c7430afe Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Mon, 13 Mar 2023 06:32:31 -0400 Subject: [PATCH 064/145] Fixed typo in coupon at top of SDK reference. Picked up the changes for GitHub's readme. --- docs/call reference.md | 2 +- readme.md | 4 ++-- readme_creator/markdown input files/5_call_reference.md | 2 +- readme_creator/output/call reference.md | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/call reference.md b/docs/call reference.md index dffd8746..d2a0d727 100644 --- a/docs/call reference.md +++ b/docs/call reference.md @@ -25,7 +25,7 @@ apply coupon for discount: - A2E4F6B1B75EC3D90133input. + A2E4F6B1B75EC3D90133. diff --git a/docs/index.md b/docs/index.md index 1dfb749a..caca6790 100644 --- a/docs/index.md +++ b/docs/index.md @@ -25,9 +25,9 @@ apply coupon for discount: - A2E4F6B1B75EC3D90133 + 65DBBEA0EC4C3B093FD1 - diff --git a/docs/readme.md b/docs/readme.md index 181372e7..56958436 100644 --- a/docs/readme.md +++ b/docs/readme.md @@ -9,8 +9,8 @@ PySimpleGUI Udemy Course -
apply coupon for discount:
A2E4F6B1B75EC3D90133
- click here to visit course page +
apply coupon for discount:
65DBBEA0EC4C3B093FD1
+ click here to visit course page diff --git a/readme.md b/readme.md index 181372e7..56958436 100644 --- a/readme.md +++ b/readme.md @@ -9,8 +9,8 @@ PySimpleGUI Udemy Course -
apply coupon for discount:
A2E4F6B1B75EC3D90133
- click here to visit course page +
apply coupon for discount:
65DBBEA0EC4C3B093FD1
+ click here to visit course page diff --git a/readme_creator/markdown input files/1_HEADER_top_part.md b/readme_creator/markdown input files/1_HEADER_top_part.md index e8d716ae..f0d043bb 100644 --- a/readme_creator/markdown input files/1_HEADER_top_part.md +++ b/readme_creator/markdown input files/1_HEADER_top_part.md @@ -52,9 +52,9 @@ HOW DO I INSERT IMAGES ??? apply coupon for discount: - A2E4F6B1B75EC3D90133 + 65DBBEA0EC4C3B093FD1 - diff --git a/readme_creator/output/index.md b/readme_creator/output/index.md index 1dfb749a..caca6790 100644 --- a/readme_creator/output/index.md +++ b/readme_creator/output/index.md @@ -25,9 +25,9 @@ apply coupon for discount: - A2E4F6B1B75EC3D90133 + 65DBBEA0EC4C3B093FD1 - From f1cd369302b54850611c9acffa595e3164693815 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Tue, 11 Apr 2023 07:23:53 -0400 Subject: [PATCH 071/145] New Udemy Coupon. Fix for bug in and better info in Watermark --- PySimpleGUI.py | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index 635a3527..b5de18b1 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -version = __version__ = "4.61.0.166 Unreleased" +version = __version__ = "4.61.0.167 Unreleased" _change_log = """ Changelog since 4.60.0 released to PyPI on 8-May-2022 @@ -159,7 +159,7 @@ _change_log = """ Use Withdraw to hide window during creation 4.61.0.63 Addition of checklist item when logging new issue to GitHub - upgraded to latest version of PySimpleGUI on PyPI - Listbox justification parameter found to not be implemented on some early verions of tkinter so had to protect this situation. This new feature crached on the Pi for example + Listbox justification parameter found to not be implemented on some early verions of tkinter so had to protect this situation. This new feature crashed on the Pi for example 4.61.0.64 Allow set_options(window_location=None) to indicate the OS should provide the window location. This will stop the Alpha channel being set to 0 when the window is created @@ -400,6 +400,9 @@ _change_log = """ Added new method - set_ibeam_color to Input, Multiline and Spin elements. Combo is a ttk element so it's not available using this call yet 4.61.0.166 New Udemy coupon + 4.61.0.167 + New Udemy coupon + Fix for bad user settings key for user watermark. Added Python version to watermark """ __version__ = version.split()[0] # For PEP 396 and PEP 345 @@ -25631,15 +25634,17 @@ def _global_settings_get_watermark_info(): return forced = Window._watermark_temp_forced prefix_text = pysimplegui_user_settings.get('-watermark text-', '') - ver_text = ' ' + version if pysimplegui_user_settings.get('-watermark ver-', False if not forced else True) or forced else '' - framework_ver_text = ' ' + framework_version if pysimplegui_user_settings.get('-watermark framework ver-', False if not forced else True) or forced else '' + + ver_text = ' ' + version.split(" ", 1)[0] if pysimplegui_user_settings.get('-watermark ver-', False if not forced else True) or forced else '' + framework_ver_text = ' Tk ' + framework_version if pysimplegui_user_settings.get('-watermark framework ver-', False if not forced else True) or forced else '' watermark_font = pysimplegui_user_settings.get('-watermark font-', '_ 9 bold') # background_color = pysimplegui_user_settings.get('-watermark bg color-', 'window.BackgroundColor') - user_text = pysimplegui_user_settings.get('-watermark user text-', '') + user_text = pysimplegui_user_settings.get('-watermark text-', '') + python_text = ' Py {}.{}.{}'.format(sys.version_info.major, sys.version_info.minor, sys.version_info.micro) if user_text: text = str(user_text) else: - text = prefix_text + ver_text + framework_ver_text + text = prefix_text + ver_text + python_text + framework_ver_text Window._watermark = lambda window: Text(text, font=watermark_font, background_color= window.BackgroundColor) @@ -26378,7 +26383,7 @@ def main(): elif event == 'Get Text': popup_scrolled('Returned:', popup_get_text('Enter some text', keep_on_top=True)) elif event.startswith('-UDEMY-'): - webbrowser.open_new_tab(r'https://www.udemy.com/course/pysimplegui/?couponCode=A2E4F6B1B75EC3D90133') + webbrowser.open_new_tab(r'https://www.udemy.com/course/pysimplegui/?couponCode=65DBBEA0EC4C3B093FD1') elif event.startswith('-SPONSOR-'): if webbrowser_available: webbrowser.open_new_tab(r'https://www.paypal.me/pythongui') @@ -26386,7 +26391,7 @@ def main(): if webbrowser_available: webbrowser.open_new_tab(r'https://www.buymeacoffee.com/PySimpleGUI') elif event in ('-EMOJI-HEARTS-', '-HEART-', '-PYTHON HEARTS-'): - popup_scrolled("Oh look! It's a Udemy discount coupon!", 'A2E4F6B1B75EC3D90133', + popup_scrolled("Oh look! It's a Udemy discount coupon!", '65DBBEA0EC4C3B093FD1', 'A personal message from Mike -- thank you so very much for supporting PySimpleGUI!', title='Udemy Coupon', image=EMOJI_BASE64_MIKE, keep_on_top=True) elif event == 'Themes': From ad3465d9ba787376f8e5ebf76565efa9ad93099c Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Tue, 18 Apr 2023 03:58:16 -0400 Subject: [PATCH 072/145] Changed Radio activeforeground to be same as text color so mouseover won't change color (previously did this for the Checkbox element) --- PySimpleGUI.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index b5de18b1..0e4ec170 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -version = __version__ = "4.61.0.167 Unreleased" +version = __version__ = "4.61.0.168 Unreleased" _change_log = """ Changelog since 4.60.0 released to PyPI on 8-May-2022 @@ -382,7 +382,7 @@ _change_log = """ 4.61.0.157 Added the _optional_window_data function that is used to help with local PySimpleGUI testing of release candidates. Not meant to be used by end-users. 4.61.0.158 - Checked checkbox activeforeground to be the same as the text so mouseover doesn't change color + Changed Checkbox activeforeground to be the same as the text so mouseover doesn't change color 4.61.0.159 New Global Settings feature - Window watermarking. Can be forced on temporarily by settings watermark=True in your Window creation 4.61.0.160 @@ -403,6 +403,9 @@ _change_log = """ 4.61.0.167 New Udemy coupon Fix for bad user settings key for user watermark. Added Python version to watermark + 4.61.0.168 + Changed Radio activeforeground to be the same as the text so mouseover doesn't change color + """ __version__ = version.split()[0] # For PEP 396 and PEP 345 @@ -17137,6 +17140,7 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form): element.TKRadio.configure(activebackground=element.BackgroundColor) if text_color is not None and text_color != COLOR_SYSTEM_DEFAULT: element.TKRadio.configure(fg=text_color) + element.TKRadio.configure(activeforeground=text_color) element.Widget.configure(highlightthickness=1) if element.BackgroundColor != COLOR_SYSTEM_DEFAULT: From 8729971855977eb6116981d860d5125c94a62427 Mon Sep 17 00:00:00 2001 From: PySimpleGUI <46163555+PySimpleGUI@users.noreply.github.com> Date: Tue, 18 Apr 2023 06:27:38 -0400 Subject: [PATCH 073/145] Update issue-form---must-fill-in-this-form-with-every-new-issue-submitted.md --- ...rm---must-fill-in-this-form-with-every-new-issue-submitted.md | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/ISSUE_TEMPLATE/issue-form---must-fill-in-this-form-with-every-new-issue-submitted.md b/.github/ISSUE_TEMPLATE/issue-form---must-fill-in-this-form-with-every-new-issue-submitted.md index eabdac93..62688945 100644 --- a/.github/ISSUE_TEMPLATE/issue-form---must-fill-in-this-form-with-every-new-issue-submitted.md +++ b/.github/ISSUE_TEMPLATE/issue-form---must-fill-in-this-form-with-every-new-issue-submitted.md @@ -61,6 +61,7 @@ These items may solve your problem. Please check those you've done by changing - - [ ] Searched main docs for your problem www.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 - [ ] 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) From 8b4e19a0cd1381bbad710bac3e01c1670bfe2090 Mon Sep 17 00:00:00 2001 From: PySimpleGUI <46163555+PySimpleGUI@users.noreply.github.com> Date: Wed, 19 Apr 2023 17:30:25 +0000 Subject: [PATCH 074/145] Automated Update! --- docs/Screens.md | 6 ++++++ docs/Screens2.md | 9 +++++++++ 2 files changed, 15 insertions(+) diff --git a/docs/Screens.md b/docs/Screens.md index 6c7f7617..491852c5 100644 --- a/docs/Screens.md +++ b/docs/Screens.md @@ -1,3 +1,9 @@ +[Kinetikal](https://github.com/Kinetikal) 2023-04-19T09:55:26Z + +![Chocolatey-GUI](https://user-images.githubusercontent.com/93329694/233038905-5a3b1f42-4794-4c6e-8411-f70f8fa79723.png) + +----------- + [PySimpleGUI](https://github.com/PySimpleGUI) 2023-03-16T18:56:49Z ![image](https://user-images.githubusercontent.com/46163555/225724235-81b435c8-84f2-48e8-9ba0-9353f6179517.png) diff --git a/docs/Screens2.md b/docs/Screens2.md index dcc46947..750b2929 100644 --- a/docs/Screens2.md +++ b/docs/Screens2.md @@ -1,3 +1,12 @@ +[Kinetikal](https://github.com/Kinetikal) 2023-04-19T09:55:26Z +I've been using PySimpleGUI to make a GUI for the Chocolatey Package Manager, thought of sending a screenshot of it here. + +![Chocolatey-GUI](https://user-images.githubusercontent.com/93329694/233038905-5a3b1f42-4794-4c6e-8411-f70f8fa79723.png) + +Thanks for this amazing module, I'm really having fun learning it! + +----------- + [andrewmk](https://github.com/andrewmk) 2023-03-24T22:40:00Z @PySimpleGUI spam comment: https://github.com/PySimpleGUI/PySimpleGUI/issues/10#issuecomment-1483457256 From 982cb755ba73d33638c67291d25f3e012840081f Mon Sep 17 00:00:00 2001 From: PySimpleGUI <46163555+PySimpleGUI@users.noreply.github.com> Date: Thu, 20 Apr 2023 17:30:22 +0000 Subject: [PATCH 075/145] Automated Update! --- docs/Screens2.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/docs/Screens2.md b/docs/Screens2.md index 750b2929..48aa8ba9 100644 --- a/docs/Screens2.md +++ b/docs/Screens2.md @@ -7,11 +7,6 @@ Thanks for this amazing module, I'm really having fun learning it! ----------- -[andrewmk](https://github.com/andrewmk) 2023-03-24T22:40:00Z -@PySimpleGUI spam comment: https://github.com/PySimpleGUI/PySimpleGUI/issues/10#issuecomment-1483457256 - ------------ - [PySimpleGUI](https://github.com/PySimpleGUI) 2023-03-16T18:56:49Z @ssweber the color scheme looks like the `GrayGrayGray` theme to me which means no colors will be added (all system defaults will be used). The important feature that's adding the images is either `Image` elements or `Button` elements. Using a Base64 version of images will enable you to drop them directly into your source code. The PySimpleGUI application `psgresizer` is very helpful in enabling you to quickly add button graphics to your application. From f06fcdc0a6eb0750150e06b00cfe211e539e48de Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Fri, 21 Apr 2023 06:59:52 -0400 Subject: [PATCH 076/145] Window threading changed so that end_key is now optional. BE CAREFUL when leaving it out as you won't be backward compatible. --- PySimpleGUI.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index 0e4ec170..a0e337c4 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -version = __version__ = "4.61.0.168 Unreleased" +version = __version__ = "4.61.0.169 Unreleased" _change_log = """ Changelog since 4.60.0 released to PyPI on 8-May-2022 @@ -405,6 +405,8 @@ _change_log = """ Fix for bad user settings key for user watermark. Added Python version to watermark 4.61.0.168 Changed Radio activeforeground to be the same as the text so mouseover doesn't change color + 4.61.0.169 + Allow no end-key to be specified for perform_long_operation/start_thread. Careful with backward compatibility! If you skip adding parm on old versions of PySimpleGUI then it'll not work. """ @@ -12621,7 +12623,7 @@ class Window: return grab - def perform_long_operation(self, func, end_key): + def perform_long_operation(self, func, end_key=None): """ Call your function that will take a long time to execute. When it's complete, send an event specified by the end_key. @@ -12638,8 +12640,8 @@ class Window: :param func: A lambda or a function name with no parms :type func: Any - :param end_key: The key that will be generated when the function returns - :type end_key: (Any) + :param end_key: Optional key that will be generated when the function returns + :type end_key: (Any | None) :return: The id of the thread :rtype: threading.Thread """ @@ -12956,14 +12958,15 @@ def _long_func_thread(window, end_key, original_func): :param window: The window that will get the event :type window: (Window) - :param end_key: The event that will be sent when function returns - :type end_key: (Any) + :param end_key: The event that will be sent when function returns. If None then no event will be sent when exiting thread + :type end_key: (Any|None) :param original_func: The user's function that is called. Can be a function with no arguments or a lambda experession :type original_func: (Any) """ return_value = original_func() - window.write_event_value(end_key, return_value) + if end_key is not None: + window.write_event_value(end_key, return_value) def _exit_mainloop(exiting_window): From 5efbff1cb8c3d65b97e029893f36982fa542b465 Mon Sep 17 00:00:00 2001 From: PySimpleGUI <46163555+PySimpleGUI@users.noreply.github.com> Date: Fri, 21 Apr 2023 17:30:19 +0000 Subject: [PATCH 077/145] Automated Update! --- docs/Screens.md | 4 ++-- docs/Screens2.md | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/Screens.md b/docs/Screens.md index 491852c5..0bd695c7 100644 --- a/docs/Screens.md +++ b/docs/Screens.md @@ -70,13 +70,13 @@ ----------- -[kubilayyalcinyt](https://github.com/kubilayyalcinyt) 2022-12-18T21:41:57Z +[gnuchanos](https://github.com/gnuchanos) 2022-12-18T21:41:57Z ![2022-12-19-003757_1280x1012_scrot](https://user-images.githubusercontent.com/117280480/208321005-c731df95-a680-4fb7-8682-5c9b86bd6afb.png) ----------- -[kubilayyalcinyt](https://github.com/kubilayyalcinyt) 2022-12-18T19:36:12Z +[gnuchanos](https://github.com/gnuchanos) 2022-12-18T19:36:12Z ![displayManager](https://user-images.githubusercontent.com/117280480/208315826-fc2172ae-349d-42ba-9cdc-3c828b7e4c26.png) ![gnuchanOS_Window_Manager](https://user-images.githubusercontent.com/117280480/208315827-1e8eb182-ea3d-4cb7-8c3f-a093ca58d8ec.png) diff --git a/docs/Screens2.md b/docs/Screens2.md index 48aa8ba9..c4f27b4a 100644 --- a/docs/Screens2.md +++ b/docs/Screens2.md @@ -181,14 +181,14 @@ https://www.youtube.com/watch?v=tPCHCc-GiHM ----------- -[kubilayyalcinyt](https://github.com/kubilayyalcinyt) 2022-12-18T21:41:57Z +[gnuchanos](https://github.com/gnuchanos) 2022-12-18T21:41:57Z ![2022-12-19-003757_1280x1012_scrot](https://user-images.githubusercontent.com/117280480/208321005-c731df95-a680-4fb7-8682-5c9b86bd6afb.png) this is what ı say ı can't do like my tiling manager ----------- -[kubilayyalcinyt](https://github.com/kubilayyalcinyt) 2022-12-18T21:05:02Z +[gnuchanos](https://github.com/gnuchanos) 2022-12-18T21:05:02Z okay ı try example finish ı ask again ----------- @@ -198,7 +198,7 @@ okay ı try example finish ı ask again ----------- -[kubilayyalcinyt](https://github.com/kubilayyalcinyt) 2022-12-18T19:36:12Z +[gnuchanos](https://github.com/gnuchanos) 2022-12-18T19:36:12Z ![displayManager](https://user-images.githubusercontent.com/117280480/208315826-fc2172ae-349d-42ba-9cdc-3c828b7e4c26.png) ![gnuchanOS_Window_Manager](https://user-images.githubusercontent.com/117280480/208315827-1e8eb182-ea3d-4cb7-8c3f-a093ca58d8ec.png) how ı create like this window first login screen second normal window ı try but ı can't do From 71c50d40b441a9d41295d62ba3ec20c15dd9c480 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Fri, 21 Apr 2023 18:25:09 -0400 Subject: [PATCH 078/145] Fix for Input Elements unresponsive on MacOS 13.2.1 Ventura when no-titlebar is enabled --- PySimpleGUI.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index a0e337c4..de1e1b2b 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -version = __version__ = "4.61.0.169 Unreleased" +version = __version__ = "4.61.0.170 Unreleased" _change_log = """ Changelog since 4.60.0 released to PyPI on 8-May-2022 @@ -407,6 +407,8 @@ _change_log = """ Changed Radio activeforeground to be the same as the text so mouseover doesn't change color 4.61.0.169 Allow no end-key to be specified for perform_long_operation/start_thread. Careful with backward compatibility! If you skip adding parm on old versions of PySimpleGUI then it'll not work. + 4.61.0.170 + Possible fix for Mac Input Element issue that's been happening with no-titlebar windows on MacOS 13.2.1 Ventura """ @@ -18234,7 +18236,10 @@ def StartupTK(window): # for the Raspberry Pi. Need to set the attributes here, prior to the building of the window # so going ahead and doing it for all platforms, in addition to doing it after the window is packed - _no_titlebar_setup(window) + # 2023-April - this call seems to be causing problems on MacOS 13.2.1 Ventura. Input elements become non-responsive + # if this call is made here and at the end of building the window + if not running_mac(): + _no_titlebar_setup(window) if not window.Resizable: root.resizable(False, False) From fb5fdbdd5ce9dc12fa4d56007a7075f445109f72 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Sat, 22 Apr 2023 10:13:36 -0400 Subject: [PATCH 079/145] 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 --- DemoPrograms/Demo_All_Elements.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/DemoPrograms/Demo_All_Elements.py b/DemoPrograms/Demo_All_Elements.py index a39c6b98..4566c226 100644 --- a/DemoPrograms/Demo_All_Elements.py +++ b/DemoPrograms/Demo_All_Elements.py @@ -11,7 +11,7 @@ Displays the values dictionary entry for each element And more! - Copyright 2021, 2022 PySimpleGUI + Copyright 2021, 2022, 2023 PySimpleGUI """ import PySimpleGUI as sg @@ -94,12 +94,11 @@ def make_window(theme): def main(): window = make_window(sg.theme()) - + # This is an Event Loop while True: event, values = window.read(timeout=100) # 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): print('============ Event = ', event, ' ==============') print('-------- Values Dictionary (key=value) --------') @@ -108,7 +107,9 @@ def main(): if event in (None, 'Exit'): print("[LOG] Clicked Exit!") 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!") sg.popup('PySimpleGUI Demo All Elements', 'Right click anywhere to see right click menu', From cb0da5887d6968a9aad3b78177fafd2e2298917f Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Wed, 26 Apr 2023 09:47:14 -0400 Subject: [PATCH 080/145] Changed enter_submits to True so that the bind_return_key works correctly. --- DemoPrograms/Demo_Chat.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/DemoPrograms/Demo_Chat.py b/DemoPrograms/Demo_Chat.py index 76b9a635..d3b81381 100644 --- a/DemoPrograms/Demo_Chat.py +++ b/DemoPrograms/Demo_Chat.py @@ -4,25 +4,28 @@ import PySimpleGUI as sg ''' 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 + +Copyright 2023 PySimpleGUI + ''' sg.theme('GreenTan') # give our window a spiffy set of colors layout = [[sg.Text('Your output will go here', size=(40, 1))], [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('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) 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 break if event == 'SEND': - query = value['-QUERY-'].rstrip() + query = values['-QUERY-'].rstrip() # EXECUTE YOUR COMMAND HERE print('The command you entered was {}'.format(query), flush=True) -window.close() \ No newline at end of file +window.close() From 7cf4c102febebcb5ea5f89e1b059b18b0136207a Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Wed, 26 Apr 2023 16:29:09 -0400 Subject: [PATCH 081/145] 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. --- PySimpleGUI.py | 241 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 236 insertions(+), 5 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index de1e1b2b..2b97ac89 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -version = __version__ = "4.61.0.170 Unreleased" +version = __version__ = "4.61.0.173 Unreleased" _change_log = """ Changelog since 4.60.0 released to PyPI on 8-May-2022 @@ -409,7 +409,13 @@ _change_log = """ Allow no end-key to be specified for perform_long_operation/start_thread. Careful with backward compatibility! If you skip adding parm on old versions of PySimpleGUI then it'll not work. 4.61.0.170 Possible fix for Mac Input Element issue that's been happening with no-titlebar windows on MacOS 13.2.1 Ventura - + 4.61.0.171 + Added formatted_datetime_now function for easy timestamps for logging + 4.61.0.172 + Added upgrade service - No notification popups should be shown yet. Don't want to SPAM users while testing + 4.61.0.173 + Made changing the "Show only critical" setting in global settings take effect immediately rather than waiting until closed settings window + Added timer_stop_usec to return timer value in microseconds """ __version__ = version.split()[0] # For PEP 396 and PEP 345 @@ -633,9 +639,9 @@ def timer_start(): def timer_stop(): """ - Time your code easily.... stop the timer and print the number of milliseconds since the timer start + Time your code easily.... stop the timer and print the number of MILLISECONDS since the timer start - :return: delta in milliseconds from timer_start was called + :return: delta in MILLISECONDS from timer_start was called :rtype: int """ global g_time_delta, g_time_end @@ -644,6 +650,19 @@ def timer_stop(): g_time_delta = g_time_end - g_time_start return int(g_time_delta * 1000) +def timer_stop_usec(): + """ + Time your code easily.... stop the timer and print the number of MICROSECONDS since the timer start + + :return: delta in MICROSECONDS from timer_start was called + :rtype: int + """ + global g_time_delta, g_time_end + + g_time_end = time.time() + g_time_delta = g_time_end - g_time_start + return int(g_time_delta * 1000000) + def _timeit(func): """ @@ -700,6 +719,19 @@ def _timeit_summary(func): return wrapper +def formatted_datetime_now(): + """ + Returns a string with current date and time formatted YYYY-MM-DD HH:MM:SS for easy logging + + :return: String with date and time formatted YYYY-MM-DD HH:MM:SS + :rtype: (str) + """ + now = datetime.datetime.now() + current_time = now.strftime("%Y-%m-%d %H:%M:%S") + return current_time + + + def running_linux(): """ Determines the OS is Linux by using sys.platform @@ -24811,6 +24843,179 @@ RED_X_BASE64 = b'iVBORw0KGgoAAAANSUhEUgAAAFoAAABaCAYAAAA4qEECAAAQ5ElEQVR4nO1ca3S GREEN_CHECK_BASE64 = b'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' + +''' +M""MMMMM""M dP +M MMMMM M 88 +M MMMMM M 88d888b. .d8888b. 88d888b. .d8888b. .d888b88 .d8888b. +M MMMMM M 88' `88 88' `88 88' `88 88' `88 88' `88 88ooood8 +M `MMM' M 88. .88 88. .88 88 88. .88 88. .88 88. ... +Mb dM 88Y888P' `8888P88 dP `88888P8 `88888P8 `88888P' +MMMMMMMMMMM 88 .88 + dP d8888P +MP""""""`MM oo +M mmmmm..M +M. `YM .d8888b. 88d888b. dP .dP dP .d8888b. .d8888b. +MMMMMMM. M 88ooood8 88' `88 88 d8' 88 88' `"" 88ooood8 +M. .MMM' M 88. ... 88 88 .88' 88 88. ... 88. ... +Mb. .dM `88888P' dP 8888P' dP `88888P' `88888P' +MMMMMMMMMMM +''' + +__upgrade_server_ip = 'upgradeapi.PySimpleGUI.com' +__upgrade_server_port = '5353' + + +def __send_dict(ip, port, dict_to_send): + """ + Send a dictionary to the upgrade server and get back a dictionary in response + :param ip: ip address of the upgrade server + :type ip: str + :param port: port number + :type port: int | str + :param dict_to_send: dictionary of items to send + :type dict_to_send: dict + :return: dictionary that is the reply + :rtype: dict + """ + + # print(f'sending dictionary to ip {ip} port {port}') + try: + # Create a socket object + s = socket.socket() + + s.settimeout(5.0) # set a 5 second timeout + + # connect to the server on local computer + s.connect((ip , int(port))) + # send a python dictionary + s.send(json.dumps(dict_to_send).encode()) + + # receive data from the server + reply_data = s.recv(1024).decode() + # close the connection + s.close() + except Exception as e: + # print(f'Error sending to server:', e) + # print(f'payload:\n', dict_to_send) + reply_data = e + try: + data_dict = json.loads(reply_data) + except Exception as e: + # print(f'UPGRADE THREAD - Error decoding reply {reply_data} as a dictionary. Error = {e}') + data_dict = {} + return data_dict + +def __show_previous_upgrade_information(): + """ + Shows information about upgrades if upgrade information is waiting to be shown + + :return: + """ + + # if nothing to show, then just return + # print('Checking for upgrade info:', pysimplegui_user_settings.get('-upgrade info available-', False), f'Seen: ', pysimplegui_user_settings.get('-upgrade info seen-', True)) + if pysimplegui_user_settings.get('-upgrade info seen-', True) and not pysimplegui_user_settings.get('-upgrade info available-', False): + return + + if pysimplegui_user_settings.get('-upgrade show only critical-', False) and pysimplegui_user_settings.get('-severity level-', '') != 'Critical': + return + + message1 = pysimplegui_user_settings.get('-upgrade message 1-', '') + message2 = pysimplegui_user_settings.get('-upgrade message 2-', '') + recommended_version = pysimplegui_user_settings.get('-upgrade recommendation-', '') + layout = [[Image(EMOJI_BASE64_HAPPY_THUMBS_UP), T('A Message from the PySimpleGUI Upgrade Service', font='_ 14')], + [T('It is recommended you upgrade to version {}'.format(recommended_version))], + [T(message1)], + [T(message2)], + [CB('Do not show this message again in the future', default=True, k='-SKIP IN FUTURE-')], + [B('Close'), T('This window auto-closes in 30 seconds')]] + + window = Window('PySimpleGUI Intelligent Upgrade', layout, disable_close=True, auto_close_duration=30, auto_close=True) + + event, values = window.read(close=True) + if values['-SKIP IN FUTURE-']: + pysimplegui_user_settings['-upgrade info available-'] = False + pysimplegui_user_settings['-upgrade info seen-'] = True + + +def __get_linux_distribution(): + with open('/etc/os-release') as f: + data = f.read() + lines = data.split('\n') + for line in lines: + if line.startswith('PRETTY_NAME'): + line_split = line.split('=')[1].strip('"') + line_tuple = tuple(line_split.split(' ')) + return line_tuple + return ('Linux Distro', 'Unknown','No lines Found in //etc//os-release') + + +def __perform_upgrade_check_thread(): + # print(f'Upgrade thread...seen = {pysimplegui_user_settings.get("-upgrade info seen-", False)}') + try: + if running_trinket(): + os_name = 'Trinket' + os_ver = __get_linux_distribution() + elif running_replit(): + os_name = 'REPL.IT' + os_ver = __get_linux_distribution() + elif running_windows(): + os_name = 'Windows' + os_ver = platform.win32_ver() + elif running_linux(): + os_name = 'Linux' + os_ver = __get_linux_distribution() + elif running_mac(): + os_name = 'Mac' + os_ver = platform.mac_ver() + else: + os_name = 'Other' + os_ver = '' + + psg_ver = version + framework_ver = framework_version + python_ver = sys.version + + upgrade_dict = { + 'OSName' : str(os_name), + 'OSVersion' : str(os_ver), + 'PythonVersion' : str(python_ver), + 'PSGVersion' : str(psg_ver), + 'FrameworkName' : 'tkinter', + 'FrameworkVersion' : str(framework_ver), + } + reply_data = __send_dict(__upgrade_server_ip, __upgrade_server_port, upgrade_dict) + + recommended_version = reply_data.get('SuggestedVersion', '') + message1 = reply_data.get('Message1', '') + message2 = reply_data.get('Message2', '') + severity_level = reply_data.get('SeverityLevel', '') + # if old information still hasn't been displayed, don't overwrite it. Only store data if there are messages that are available + if not pysimplegui_user_settings.get('-upgrade info available-', False) and (message1 or message2) and not running_trinket(): + if pysimplegui_user_settings.get('-upgrade message 1-', '') != message1 or \ + pysimplegui_user_settings.get('-upgrade message 2-', '') != message2 or \ + pysimplegui_user_settings.get('-upgrade recommendation-', '') != recommended_version or \ + pysimplegui_user_settings.get('-severity level-', '') != severity_level or \ + not pysimplegui_user_settings.get('-upgrade info seen-', False): + # Save the data to the settings file + pysimplegui_user_settings['-upgrade info seen-'] = False + pysimplegui_user_settings['-upgrade info available-'] = True + pysimplegui_user_settings['-upgrade message 1-'] = message1 + pysimplegui_user_settings['-upgrade message 2-'] = message2 + pysimplegui_user_settings['-upgrade recommendation-'] = recommended_version + pysimplegui_user_settings['-severity level-'] = severity_level + except Exception as e: + reply_data = {} + # print('Upgrade server error', e) + # print(f'Upgrade Reply = {reply_data}') + +def __perform_upgrade_check(): + # For now, do not show data returned. Still testing and do not want to "SPAM" users with any popups + # __show_previous_upgrade_information() + threading.Thread(target=lambda: __perform_upgrade_check_thread(), daemon=True).start() + + # =========================================================================# # MP""""""`MM dP dP # M mmmmm..M 88 88 @@ -25809,13 +26014,25 @@ def main_global_pysimplegui_settings(): font='_ 16', expand_x=True)]]) + upgrade_recommendation_tab_layout = [[T('Latest Recommendation and Announcements For You')], + [T('Recommendation waiting:'), T(pysimplegui_user_settings.get('-upgrade info available-',''))], + [T('Severity Level of Update:'), T(pysimplegui_user_settings.get('-severity level-',''))], + [T('Recommended Version To Upgrade To:'), T(pysimplegui_user_settings.get('-upgrade recommendation-',''))], + [T(pysimplegui_user_settings.get('-upgrade message 1-',''))], + [T(pysimplegui_user_settings.get('-upgrade message 2-',''))], + [T('Message Seen:'), T(pysimplegui_user_settings.get('-upgrade info seen-',False))], + [Checkbox('Show Only Critical Messages', default=pysimplegui_user_settings.get('-upgrade show only critical-', False), key='-UPGRADE SHOW ONLY CRITICAL-', enable_events=True)], + [Button('Show Notification Again')], + ] + upgrade_tab = Tab('Upgrade',upgrade_recommendation_tab_layout, expand_x=True) + # ------------------------- Security Tab ------------------------- security_tab = Tab('Security', [[T('PySimpleGUI hashcode')], [T(scheck_hh())]], expand_x=True) - settings_tab_group = TabGroup([[theme_tab, ttk_tab, interpreter_tab, explorer_tab, editor_tab, snapshots_tab, security_tab ]]) + settings_tab_group = TabGroup([[theme_tab, ttk_tab, interpreter_tab, explorer_tab, editor_tab, snapshots_tab, security_tab, upgrade_tab ]]) layout += [[settings_tab_group]] # [T('Buttons (Leave Unchecked To Use Default) NOT YET IMPLEMENTED!', font='_ 16')], # [Checkbox('Always use TTK buttons'), CBox('Always use TK Buttons')], @@ -25873,6 +26090,11 @@ def main_global_pysimplegui_settings(): if key[0] == '-TTK SCROLL-': pysimplegui_user_settings.set(json.dumps(('-ttk scroll-', key[1])), value) + # Upgrade Service Settings + pysimplegui_user_settings.set('-upgrade show only critical-', values['-UPGRADE SHOW ONLY CRITICAL-']) + + + theme(new_theme) _global_settings_get_ttk_scrollbar_info() @@ -25900,6 +26122,12 @@ def main_global_pysimplegui_settings(): for i in range(100): Print(i, keep_on_top=True) Print('Close this window to continue...', keep_on_top=True) + elif event == 'Show Notification Again': + pysimplegui_user_settings.set('-upgrade info seen-', False) + __show_previous_upgrade_information() + elif event == '-UPGRADE SHOW ONLY CRITICAL-': + pysimplegui_user_settings.set('-upgrade show only critical-', values['-UPGRADE SHOW ONLY CRITICAL-']) + window.close() # In case some of the settings were modified and tried out, reset the ttk info to be what's in the config file style = ttk.Style(Window.hidden_master_root) @@ -26560,6 +26788,9 @@ if _mac_should_set_alpha_to_99(): # Applyting Mac OS 12.3+ Alpha Channel fix. Sets the default Alpha Channel to 0.99 set_options(alpha_channel=0.99) + +__perform_upgrade_check() + # -------------------------------- ENTRY POINT IF RUN STANDALONE -------------------------------- # if __name__ == '__main__': From 43c49380a2d08926c2669117b16dfdc9ab25930c Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Tue, 9 May 2023 09:21:12 -0400 Subject: [PATCH 082/145] Custom Titlebar - Support for disable close, disable resizing, disable minimize. Better distro support and display of information from Upgrade Service --- PySimpleGUI.py | 147 ++++++++++++++++++++++++++++++------------------- 1 file changed, 90 insertions(+), 57 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index 2b97ac89..7798a650 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -version = __version__ = "4.61.0.173 Unreleased" +version = __version__ = "4.61.0.177 Unreleased" _change_log = """ Changelog since 4.60.0 released to PyPI on 8-May-2022 @@ -416,6 +416,14 @@ _change_log = """ 4.61.0.173 Made changing the "Show only critical" setting in global settings take effect immediately rather than waiting until closed settings window Added timer_stop_usec to return timer value in microseconds + 4.61.0.174 + Overwrite upgrade data if any portion has changed + 4.61.0.175 + Notification window - added countdown counter. Added hand cursor if message is a link and enable clicking of link to open the browser to that link + 4.61.0.176 + Improved linux distro detection + 4.61.0.177 + Custom Titlebar - Support for disabling resizing (maximizing too), support for disable minimize and disable close """ __version__ = version.split()[0] # For PEP 396 and PEP 345 @@ -12781,14 +12789,17 @@ class Window: :return: """ if key == TITLEBAR_MINIMIZE_KEY: - self._custom_titlebar_minimize() + if not self.DisableMinimize: + self._custom_titlebar_minimize() elif key == TITLEBAR_MAXIMIZE_KEY: - if self.maximized: - self.normal() - else: - self.maximize() + if self.Resizable: + if self.maximized: + self.normal() + else: + self.maximize() elif key == TITLEBAR_CLOSE_KEY: - self._OnClosingCallback() + if not self.DisableClose: + self._OnClosingCallback() def timer_start(self, frequency_ms, key=EVENT_TIMER, repeating=True): @@ -24914,41 +24925,65 @@ def __show_previous_upgrade_information(): """ # if nothing to show, then just return - # print('Checking for upgrade info:', pysimplegui_user_settings.get('-upgrade info available-', False), f'Seen: ', pysimplegui_user_settings.get('-upgrade info seen-', True)) if pysimplegui_user_settings.get('-upgrade info seen-', True) and not pysimplegui_user_settings.get('-upgrade info available-', False): return - if pysimplegui_user_settings.get('-upgrade show only critical-', False) and pysimplegui_user_settings.get('-severity level-', '') != 'Critical': return message1 = pysimplegui_user_settings.get('-upgrade message 1-', '') message2 = pysimplegui_user_settings.get('-upgrade message 2-', '') recommended_version = pysimplegui_user_settings.get('-upgrade recommendation-', '') - layout = [[Image(EMOJI_BASE64_HAPPY_THUMBS_UP), T('A Message from the PySimpleGUI Upgrade Service', font='_ 14')], + severity_level = pysimplegui_user_settings.get('-severity level-', '') + + # message2 = r'https://www.PySimpleGUI.org' + + layout = [[Image(EMOJI_BASE64_HAPPY_THUMBS_UP), T('An upgrade is available & recommended', font='_ 14')], [T('It is recommended you upgrade to version {}'.format(recommended_version))], - [T(message1)], - [T(message2)], + [T(message1, enable_events=True, k='-MESSAGE 1-')], + [T(message2, enable_events=True, k='-MESSAGE 2-')], [CB('Do not show this message again in the future', default=True, k='-SKIP IN FUTURE-')], - [B('Close'), T('This window auto-closes in 30 seconds')]] + [B('Close'), T('This window auto-closes in'), T('30', k='-CLOSE TXT-', text_color='white', background_color='red'), T('seconds')]] - window = Window('PySimpleGUI Intelligent Upgrade', layout, disable_close=True, auto_close_duration=30, auto_close=True) + window = Window('PySimpleGUI Intelligent Upgrade', layout, finalize=True) + if 'http' in message1: + window['-MESSAGE 1-'].set_cursor('hand1') + if 'http' in message2: + window['-MESSAGE 2-'].set_cursor('hand1') - event, values = window.read(close=True) - if values['-SKIP IN FUTURE-']: - pysimplegui_user_settings['-upgrade info available-'] = False - pysimplegui_user_settings['-upgrade info seen-'] = True + seconds_left=30 + while True: + event, values = window.read(timeout=1000) + if event in ('Close', WIN_CLOSED) or seconds_left < 1: + break + if values['-SKIP IN FUTURE-']: + if not running_trinket(): + pysimplegui_user_settings['-upgrade info available-'] = False + pysimplegui_user_settings['-upgrade info seen-'] = True + if event == '-MESSAGE 1-' and 'http' in message1 and webbrowser_available: + webbrowser.open_new_tab(message1) + elif event == '-MESSAGE 2-' and 'http' in message2 and webbrowser_available: + webbrowser.open_new_tab(message2) + window['-CLOSE TXT-'].update(seconds_left) + seconds_left -= 1 + + window.close() def __get_linux_distribution(): - with open('/etc/os-release') as f: - data = f.read() - lines = data.split('\n') - for line in lines: - if line.startswith('PRETTY_NAME'): - line_split = line.split('=')[1].strip('"') - line_tuple = tuple(line_split.split(' ')) - return line_tuple - return ('Linux Distro', 'Unknown','No lines Found in //etc//os-release') + line_tuple = ('Linux Distro', 'Unknown', 'No lines Found in //etc//os-release') + try: + with open('/etc/os-release') as f: + data = f.read() + lines = data.split('\n') + for line in lines: + if line.startswith('PRETTY_NAME'): + line_split = line.split('=')[1].strip('"') + line_tuple = tuple(line_split.split(' ')) + return line_tuple + except: + line_tuple = ('Linux Distro', 'Exception','Error reading//processing //etc//os-release') + + return line_tuple def __perform_upgrade_check_thread(): @@ -24991,13 +25026,12 @@ def __perform_upgrade_check_thread(): message1 = reply_data.get('Message1', '') message2 = reply_data.get('Message2', '') severity_level = reply_data.get('SeverityLevel', '') - # if old information still hasn't been displayed, don't overwrite it. Only store data if there are messages that are available - if not pysimplegui_user_settings.get('-upgrade info available-', False) and (message1 or message2) and not running_trinket(): + # If any part of the reply has changed from the last reply, overwrite the data and set flags so user will be informed + if (message1 or message2) and not running_trinket(): if pysimplegui_user_settings.get('-upgrade message 1-', '') != message1 or \ pysimplegui_user_settings.get('-upgrade message 2-', '') != message2 or \ pysimplegui_user_settings.get('-upgrade recommendation-', '') != recommended_version or \ - pysimplegui_user_settings.get('-severity level-', '') != severity_level or \ - not pysimplegui_user_settings.get('-upgrade info seen-', False): + pysimplegui_user_settings.get('-severity level-', '') != severity_level: # Save the data to the settings file pysimplegui_user_settings['-upgrade info seen-'] = False pysimplegui_user_settings['-upgrade info available-'] = True @@ -26014,25 +26048,12 @@ def main_global_pysimplegui_settings(): font='_ 16', expand_x=True)]]) - upgrade_recommendation_tab_layout = [[T('Latest Recommendation and Announcements For You')], - [T('Recommendation waiting:'), T(pysimplegui_user_settings.get('-upgrade info available-',''))], - [T('Severity Level of Update:'), T(pysimplegui_user_settings.get('-severity level-',''))], - [T('Recommended Version To Upgrade To:'), T(pysimplegui_user_settings.get('-upgrade recommendation-',''))], - [T(pysimplegui_user_settings.get('-upgrade message 1-',''))], - [T(pysimplegui_user_settings.get('-upgrade message 2-',''))], - [T('Message Seen:'), T(pysimplegui_user_settings.get('-upgrade info seen-',False))], - [Checkbox('Show Only Critical Messages', default=pysimplegui_user_settings.get('-upgrade show only critical-', False), key='-UPGRADE SHOW ONLY CRITICAL-', enable_events=True)], - [Button('Show Notification Again')], - ] - upgrade_tab = Tab('Upgrade',upgrade_recommendation_tab_layout, expand_x=True) - - # ------------------------- Security Tab ------------------------- security_tab = Tab('Security', [[T('PySimpleGUI hashcode')], [T(scheck_hh())]], expand_x=True) - settings_tab_group = TabGroup([[theme_tab, ttk_tab, interpreter_tab, explorer_tab, editor_tab, snapshots_tab, security_tab, upgrade_tab ]]) + settings_tab_group = TabGroup([[theme_tab, ttk_tab, interpreter_tab, explorer_tab, editor_tab, snapshots_tab, security_tab ]]) layout += [[settings_tab_group]] # [T('Buttons (Leave Unchecked To Use Default) NOT YET IMPLEMENTED!', font='_ 16')], # [Checkbox('Always use TTK buttons'), CBox('Always use TK Buttons')], @@ -26122,11 +26143,6 @@ def main_global_pysimplegui_settings(): for i in range(100): Print(i, keep_on_top=True) Print('Close this window to continue...', keep_on_top=True) - elif event == 'Show Notification Again': - pysimplegui_user_settings.set('-upgrade info seen-', False) - __show_previous_upgrade_information() - elif event == '-UPGRADE SHOW ONLY CRITICAL-': - pysimplegui_user_settings.set('-upgrade show only critical-', values['-UPGRADE SHOW ONLY CRITICAL-']) window.close() # In case some of the settings were modified and tried out, reset the ttk info to be what's in the config file @@ -26469,14 +26485,23 @@ def _create_main_window(): frame6 = [[VPush()],[graph_elem]] - global_settings_tab_layout = [[T('Settings Filename:'), T(pysimplegui_user_settings.full_filename, s=(50,2))], - [T('Settings Dictionary:'), MLine(pysimplegui_user_settings, size=(50,8), write_only=True)], - ] - themes_tab_layout = [[T('You can see a preview of the themes, the color swatches, or switch themes for this window')], [T('If you want to change the default theme for PySimpleGUI, use the Global Settings')], [B('Themes'), B('Theme Swatches'), B('Switch Themes')]] + + upgrade_recommendation_tab_layout = [[T('Latest Recommendation and Announcements For You', font='_ 14')], + [T('Severity Level of Update:'), T(pysimplegui_user_settings.get('-severity level-',''))], + [T('Recommended Version To Upgrade To:'), T(pysimplegui_user_settings.get('-upgrade recommendation-',''))], + [T(pysimplegui_user_settings.get('-upgrade message 1-',''))], + [T(pysimplegui_user_settings.get('-upgrade message 2-',''))], + [Checkbox('Show Only Critical Messages', default=pysimplegui_user_settings.get('-upgrade show only critical-', False), key='-UPGRADE SHOW ONLY CRITICAL-', enable_events=True)], + [Button('Show Notification Again'), B('Upgrade from GitHub', button_color='white on red', key='-UPGRADE FROM GITHUB-'), +], + ] + tab_upgrade = Tab('Upgrade\n',upgrade_recommendation_tab_layout, expand_x=True) + + tab1 = Tab('Graph\n', frame6, tooltip='Graph is in here', title_color='red') tab2 = Tab('CB, Radio\nList, Combo', [[Frame('Multiple Choice Group', frame2, title_color='#FFFFFF', tooltip='Checkboxes, radio buttons, etc', vertical_alignment='t',), @@ -26488,7 +26513,6 @@ def _create_main_window(): tab6 = Tab('Course or\nSponsor', frame7, k='-TAB SPONSOR-') tab7 = Tab('Popups\n', pop_test_tab_layout, k='-TAB POPUP-') tab8 = Tab('Themes\n', themes_tab_layout, k='-TAB THEMES-') - tab9 = Tab('Global\nSettings', global_settings_tab_layout, k='-TAB GlOBAL SETTINGS-') def VerLine(version, description, justification='r', size=(40, 1)): return [T(version, justification=justification, font='Any 12', text_color='yellow', size=size, pad=(0,0)), T(description, font='Any 12', pad=(0,0))] @@ -26507,7 +26531,7 @@ def _create_main_window(): layout_bottom = [ [B(SYMBOL_DOWN, pad=(0, 0), k='-HIDE TABS-'), - pin(Col([[TabGroup([[tab1, tab2, tab3, tab6, tab4, tab5, tab7, tab8, tab9]], key='-TAB_GROUP-')]], k='-TAB GROUP COL-'))], + pin(Col([[TabGroup([[tab1, tab2, tab3, tab6, tab4, tab5, tab7, tab8, tab_upgrade]], key='-TAB_GROUP-')]], k='-TAB GROUP COL-'))], [B('Button', highlight_colors=('yellow', 'red'),pad=(1, 0)), B('ttk Button', use_ttk_buttons=True, tooltip='This is a TTK Button',pad=(1, 0)), B('See-through Mode', tooltip='Make the background transparent',pad=(1, 0)), @@ -26610,7 +26634,7 @@ def main(): elif event.startswith('See'): window._see_through = not window._see_through window.set_transparent_color(theme_background_color() if window._see_through else '') - elif event == '-INSTALL-': + elif event in ('-INSTALL-', '-UPGRADE FROM GITHUB-'): _upgrade_gui() elif event == 'Popup': popup('This is your basic popup', keep_on_top=True) @@ -26681,6 +26705,15 @@ def main(): window.minimize() main_open_github_issue() window.normal() + elif event == 'Show Notification Again': + if not running_trinket(): + pysimplegui_user_settings.set('-upgrade info seen-', False) + __show_previous_upgrade_information() + elif event == '-UPGRADE SHOW ONLY CRITICAL-': + if not running_trinket(): + pysimplegui_user_settings.set('-upgrade show only critical-', values['-UPGRADE SHOW ONLY CRITICAL-']) + + i += 1 # _refresh_debugger() print('event = ', event) From 2e6b74f0f123afd2d502a761d9f9dd4db300f1c8 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Thu, 11 May 2023 15:37:47 -0400 Subject: [PATCH 083/145] 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 --- PySimpleGUI.py | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index 7798a650..667f6b51 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -version = __version__ = "4.61.0.177 Unreleased" +version = __version__ = "4.61.0.178 Unreleased" _change_log = """ Changelog since 4.60.0 released to PyPI on 8-May-2022 @@ -424,6 +424,8 @@ _change_log = """ Improved linux distro detection 4.61.0.177 Custom Titlebar - Support for disabling resizing (maximizing too), support for disable minimize and disable close + 4.61.0.178 + 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 """ __version__ = version.split()[0] # For PEP 396 and PEP 345 @@ -2519,11 +2521,25 @@ class Input(Element): _error_popup_with_traceback('Error in Input.update - The window was closed') return + if background_color not in (None, COLOR_SYSTEM_DEFAULT): + self.TKEntry.configure(background=background_color) + self.BackgroundColor = background_color + if text_color not in (None, COLOR_SYSTEM_DEFAULT): + self.TKEntry.configure(fg=text_color) + self.TextColor = text_color + if disabled is True: - self.TKEntry['state'] = 'readonly' if self.UseReadonlyForDisable else 'disabled' + if self.UseReadonlyForDisable: + self.TKEntry.configure(fg=self.disabled_readonly_text_color) + self.TKEntry['state'] = 'readonly' + else: + self.TKEntry.configure(fg=self.TextColor) + self.TKEntry['state'] = 'disabled' + self.Disabled = True elif disabled is False: - self.TKEntry['state'] = 'readonly' if self.ReadOnly else 'normal' - self.Disabled = disabled if disabled is not None else self.Disabled + self.TKEntry['state'] = 'normal' + self.TKEntry.configure(fg=self.TextColor) + self.Disabled = False if readonly is True: self.TKEntry['state'] = 'readonly' @@ -2532,10 +2548,7 @@ class Input(Element): - if background_color not in (None, COLOR_SYSTEM_DEFAULT): - self.TKEntry.configure(background=background_color) - if text_color not in (None, COLOR_SYSTEM_DEFAULT): - self.TKEntry.configure(fg=text_color) + if value is not None: if paste is not True: try: @@ -16730,7 +16743,7 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form): element.TKEntry.configure(selectforeground=element.selected_text_color) if element.disabled_readonly_background_color not in (None, COLOR_SYSTEM_DEFAULT): element.TKEntry.config(readonlybackground=element.disabled_readonly_background_color) - if element.disabled_readonly_text_color not in (None, COLOR_SYSTEM_DEFAULT): + if element.disabled_readonly_text_color not in (None, COLOR_SYSTEM_DEFAULT) and element.Disabled: element.TKEntry.config(fg=element.disabled_readonly_text_color) element.Widget.config(highlightthickness=0) From d7c24da2bfb6ae30f42c471b90baefe5f72d0a8f Mon Sep 17 00:00:00 2001 From: PySimpleGUI <46163555+PySimpleGUI@users.noreply.github.com> Date: Fri, 12 May 2023 17:30:17 +0000 Subject: [PATCH 084/145] Automated Update! --- docs/Screens.md | 6 ++++++ docs/Screens2.md | 13 +++++++++++++ 2 files changed, 19 insertions(+) diff --git a/docs/Screens.md b/docs/Screens.md index 0bd695c7..3c55377f 100644 --- a/docs/Screens.md +++ b/docs/Screens.md @@ -1,3 +1,9 @@ +[PySimpleGUI](https://github.com/PySimpleGUI) 2023-05-12T09:55:03Z + +![image](https://github.com/PySimpleGUI/PySimpleGUI/assets/46163555/98b78824-5286-4183-bb92-0d6fc5405270) + +----------- + [Kinetikal](https://github.com/Kinetikal) 2023-04-19T09:55:26Z ![Chocolatey-GUI](https://user-images.githubusercontent.com/93329694/233038905-5a3b1f42-4794-4c6e-8411-f70f8fa79723.png) diff --git a/docs/Screens2.md b/docs/Screens2.md index c4f27b4a..c636665e 100644 --- a/docs/Screens2.md +++ b/docs/Screens2.md @@ -1,3 +1,16 @@ +[PySimpleGUI](https://github.com/PySimpleGUI) 2023-05-12T09:55:03Z +I saw this awesome screenshot: + +![image](https://github.com/PySimpleGUI/PySimpleGUI/assets/46163555/98b78824-5286-4183-bb92-0d6fc5405270) + +posted in the readme for this project: + +https://github.com/bsanders2/FrosthavenApp + +It's got a nice design and the custom buttons look great. + +----------- + [Kinetikal](https://github.com/Kinetikal) 2023-04-19T09:55:26Z I've been using PySimpleGUI to make a GUI for the Chocolatey Package Manager, thought of sending a screenshot of it here. From fe41f3cd1f23639ad27b83e9ae965c82d60000f9 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Sun, 14 May 2023 12:22:32 -0400 Subject: [PATCH 085/145] New Udemy Coupon --- PySimpleGUI.py | 8 +++++--- docs/call reference.md | 16 ++++++++-------- docs/cookbook.md | 4 ++-- docs/index.md | 4 ++-- docs/readme.md | 4 ++-- readme.md | 4 ++-- .../markdown input files/1_HEADER_top_part.md | 4 ++-- .../markdown input files/5_call_reference.md | 4 ++-- readme_creator/output/call reference.md | 16 ++++++++-------- readme_creator/output/index.md | 4 ++-- 10 files changed, 35 insertions(+), 33 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index 667f6b51..76b95a23 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -version = __version__ = "4.61.0.178 Unreleased" +version = __version__ = "4.61.0.179 Unreleased" _change_log = """ Changelog since 4.60.0 released to PyPI on 8-May-2022 @@ -426,6 +426,8 @@ _change_log = """ Custom Titlebar - Support for disabling resizing (maximizing too), support for disable minimize and disable close 4.61.0.178 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 + 4.61.0.179 + New Udemy coupon """ __version__ = version.split()[0] # For PEP 396 and PEP 345 @@ -26660,7 +26662,7 @@ def main(): elif event == 'Get Text': popup_scrolled('Returned:', popup_get_text('Enter some text', keep_on_top=True)) elif event.startswith('-UDEMY-'): - webbrowser.open_new_tab(r'https://www.udemy.com/course/pysimplegui/?couponCode=65DBBEA0EC4C3B093FD1') + webbrowser.open_new_tab(r'https://www.udemy.com/course/pysimplegui/?couponCode=9AF99B123C49D51EB547') elif event.startswith('-SPONSOR-'): if webbrowser_available: webbrowser.open_new_tab(r'https://www.paypal.me/pythongui') @@ -26668,7 +26670,7 @@ def main(): if webbrowser_available: webbrowser.open_new_tab(r'https://www.buymeacoffee.com/PySimpleGUI') elif event in ('-EMOJI-HEARTS-', '-HEART-', '-PYTHON HEARTS-'): - popup_scrolled("Oh look! It's a Udemy discount coupon!", '65DBBEA0EC4C3B093FD1', + popup_scrolled("Oh look! It's a Udemy discount coupon!", '9AF99B123C49D51EB547', 'A personal message from Mike -- thank you so very much for supporting PySimpleGUI!', title='Udemy Coupon', image=EMOJI_BASE64_MIKE, keep_on_top=True) elif event == 'Themes': diff --git a/docs/call reference.md b/docs/call reference.md index d2a0d727..90b18ab3 100644 --- a/docs/call reference.md +++ b/docs/call reference.md @@ -25,9 +25,9 @@ apply coupon for discount: - A2E4F6B1B75EC3D90133. + 9AF99B123C49D51EB547. - @@ -13685,15 +13685,15 @@ IMPORTANT - This method uses THREADS... this means you CANNOT make any PySimpleG the function you provide with the exception of one function, Window.write_event_value. ``` -perform_long_operation(func, end_key) +perform_long_operation(func, end_key = None) ``` Parameter Descriptions: |Type|Name|Meaning| |--|--|--| -| Any | func | A lambda or a function name with no parms | -| Any | end_key | The key that will be generated when the function returns | +| Any | func | A lambda or a function name with no parms | +| (Any or None) | end_key | Optional key that will be generated when the function returns | | threading.Thread | **RETURN** | The id of the thread ### read @@ -13907,15 +13907,15 @@ IMPORTANT - This method uses THREADS... this means you CANNOT make any PySimpleG the function you provide with the exception of one function, Window.write_event_value. ``` -start_thread(func, end_key) +start_thread(func, end_key = None) ``` Parameter Descriptions: |Type|Name|Meaning| |--|--|--| -| Any | func | A lambda or a function name with no parms | -| Any | end_key | The key that will be generated when the function returns | +| Any | func | A lambda or a function name with no parms | +| (Any or None) | end_key | Optional key that will be generated when the function returns | | threading.Thread | **RETURN** | The id of the thread ### timer_get_active_timers diff --git a/docs/cookbook.md b/docs/cookbook.md index 7c8d6778..5118cafa 100644 --- a/docs/cookbook.md +++ b/docs/cookbook.md @@ -25,9 +25,9 @@ apply coupon for discount: - 65DBBEA0EC4C3B093FD1 + 9AF99B123C49D51EB547 - diff --git a/docs/index.md b/docs/index.md index caca6790..fab4bdcc 100644 --- a/docs/index.md +++ b/docs/index.md @@ -25,9 +25,9 @@ apply coupon for discount: - 65DBBEA0EC4C3B093FD1 + 9AF99B123C49D51EB547 - diff --git a/docs/readme.md b/docs/readme.md index 56958436..4922869b 100644 --- a/docs/readme.md +++ b/docs/readme.md @@ -9,8 +9,8 @@ PySimpleGUI Udemy Course -
apply coupon for discount:
65DBBEA0EC4C3B093FD1
- click here to visit course page +
apply coupon for discount:
9AF99B123C49D51EB547
+ click here to visit course page diff --git a/readme.md b/readme.md index 56958436..4922869b 100644 --- a/readme.md +++ b/readme.md @@ -9,8 +9,8 @@ PySimpleGUI Udemy Course -
apply coupon for discount:
65DBBEA0EC4C3B093FD1
- click here to visit course page +
apply coupon for discount:
9AF99B123C49D51EB547
+ click here to visit course page diff --git a/readme_creator/markdown input files/1_HEADER_top_part.md b/readme_creator/markdown input files/1_HEADER_top_part.md index f0d043bb..35b757c7 100644 --- a/readme_creator/markdown input files/1_HEADER_top_part.md +++ b/readme_creator/markdown input files/1_HEADER_top_part.md @@ -52,9 +52,9 @@ HOW DO I INSERT IMAGES ??? apply coupon for discount: - 65DBBEA0EC4C3B093FD1 + 9AF99B123C49D51EB547 - diff --git a/readme_creator/markdown input files/5_call_reference.md b/readme_creator/markdown input files/5_call_reference.md index b1afb560..1f690a41 100644 --- a/readme_creator/markdown input files/5_call_reference.md +++ b/readme_creator/markdown input files/5_call_reference.md @@ -25,9 +25,9 @@ apply coupon for discount: - A2E4F6B1B75EC3D90133. + 9AF99B123C49D51EB547. - diff --git a/readme_creator/output/call reference.md b/readme_creator/output/call reference.md index d2a0d727..90b18ab3 100644 --- a/readme_creator/output/call reference.md +++ b/readme_creator/output/call reference.md @@ -25,9 +25,9 @@ apply coupon for discount: - A2E4F6B1B75EC3D90133. + 9AF99B123C49D51EB547. - @@ -13685,15 +13685,15 @@ IMPORTANT - This method uses THREADS... this means you CANNOT make any PySimpleG the function you provide with the exception of one function, Window.write_event_value. ``` -perform_long_operation(func, end_key) +perform_long_operation(func, end_key = None) ``` Parameter Descriptions: |Type|Name|Meaning| |--|--|--| -| Any | func | A lambda or a function name with no parms | -| Any | end_key | The key that will be generated when the function returns | +| Any | func | A lambda or a function name with no parms | +| (Any or None) | end_key | Optional key that will be generated when the function returns | | threading.Thread | **RETURN** | The id of the thread ### read @@ -13907,15 +13907,15 @@ IMPORTANT - This method uses THREADS... this means you CANNOT make any PySimpleG the function you provide with the exception of one function, Window.write_event_value. ``` -start_thread(func, end_key) +start_thread(func, end_key = None) ``` Parameter Descriptions: |Type|Name|Meaning| |--|--|--| -| Any | func | A lambda or a function name with no parms | -| Any | end_key | The key that will be generated when the function returns | +| Any | func | A lambda or a function name with no parms | +| (Any or None) | end_key | Optional key that will be generated when the function returns | | threading.Thread | **RETURN** | The id of the thread ### timer_get_active_timers diff --git a/readme_creator/output/index.md b/readme_creator/output/index.md index caca6790..fab4bdcc 100644 --- a/readme_creator/output/index.md +++ b/readme_creator/output/index.md @@ -25,9 +25,9 @@ apply coupon for discount: - 65DBBEA0EC4C3B093FD1 + 9AF99B123C49D51EB547 - From f3a7e10ce0db5f6189fd1558ba2637500e1777fc Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Tue, 16 May 2023 12:52:36 -0400 Subject: [PATCH 086/145] Added check for None and COLOR_SYSTEM_DEFAULT to fix a crash problem --- PySimpleGUI.py | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index 76b95a23..0eb640ee 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -version = __version__ = "4.61.0.179 Unreleased" +version = __version__ = "4.61.0.181 Unreleased" _change_log = """ Changelog since 4.60.0 released to PyPI on 8-May-2022 @@ -428,6 +428,11 @@ _change_log = """ 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 4.61.0.179 New Udemy coupon + 4.61.0.180 + Removed Security tab from system settings + 4.61.0.181 + Added check for None and COLOR_SYSTEM_DEFAULT before any colors being set in Input.update + """ __version__ = version.split()[0] # For PEP 396 and PEP 345 @@ -2532,15 +2537,18 @@ class Input(Element): if disabled is True: if self.UseReadonlyForDisable: - self.TKEntry.configure(fg=self.disabled_readonly_text_color) + if self.disabled_readonly_text_color not in (None, COLOR_SYSTEM_DEFAULT): + self.TKEntry.configure(fg=self.disabled_readonly_text_color) self.TKEntry['state'] = 'readonly' else: - self.TKEntry.configure(fg=self.TextColor) + if self.TextColor not in (None, COLOR_SYSTEM_DEFAULT): + self.TKEntry.configure(fg=self.TextColor) self.TKEntry['state'] = 'disabled' self.Disabled = True elif disabled is False: self.TKEntry['state'] = 'normal' - self.TKEntry.configure(fg=self.TextColor) + if self.TextColor not in (None, COLOR_SYSTEM_DEFAULT): + self.TKEntry.configure(fg=self.TextColor) self.Disabled = False if readonly is True: @@ -26063,12 +26071,8 @@ def main_global_pysimplegui_settings(): font='_ 16', expand_x=True)]]) - # ------------------------- Security Tab ------------------------- - security_tab = Tab('Security', - [[T('PySimpleGUI hashcode')], [T(scheck_hh())]], - expand_x=True) - settings_tab_group = TabGroup([[theme_tab, ttk_tab, interpreter_tab, explorer_tab, editor_tab, snapshots_tab, security_tab ]]) + settings_tab_group = TabGroup([[theme_tab, ttk_tab, interpreter_tab, explorer_tab, editor_tab, snapshots_tab, ]]) layout += [[settings_tab_group]] # [T('Buttons (Leave Unchecked To Use Default) NOT YET IMPLEMENTED!', font='_ 16')], # [Checkbox('Always use TTK buttons'), CBox('Always use TK Buttons')], From 440a34888f818f4106bb76a1e74f4b93ff9b3abd Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Thu, 18 May 2023 12:05:07 -0400 Subject: [PATCH 087/145] Addition of right click menu erase, save image and display of crosshairs --- ...Demo_Graph_Drawing_And_Dragging_Figures.py | 62 +++++++++---------- 1 file changed, 28 insertions(+), 34 deletions(-) diff --git a/DemoPrograms/Demo_Graph_Drawing_And_Dragging_Figures.py b/DemoPrograms/Demo_Graph_Drawing_And_Dragging_Figures.py index b3c1affe..3afcff8e 100644 --- a/DemoPrograms/Demo_Graph_Drawing_And_Dragging_Figures.py +++ b/DemoPrograms/Demo_Graph_Drawing_And_Dragging_Figures.py @@ -1,5 +1,4 @@ import PySimpleGUI as sg -from PIL import ImageGrab """ 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 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(): sg.theme('Dark Blue 3') @@ -38,7 +24,6 @@ def main(): [sg.R('Bring to front', 1, key='-FRONT-', enable_events=True)], [sg.R('Move Everything', 1, key='-MOVEALL-', enable_events=True)], [sg.R('Move Stuff', 1, key='-MOVE-', enable_events=True)], - [sg.B('Save Image', key='-SAVE-')], ] layout = [[sg.Graph( @@ -49,20 +34,19 @@ def main(): enable_events=True, background_color='lightblue', 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.Text(key='-INFO-', size=(60, 1))]] window = sg.Window("Drawing and Moving Stuff Around", layout, finalize=True) # 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)) - dragging = False start_point = end_point = prior_rect = None - # graph.bind('', '+RIGHT+') - + crosshair_lines = [] while True: event, values = window.read() print(event, values) @@ -73,7 +57,14 @@ def main(): graph.set_cursor(cursor='fleur') # not yet released method... coming soon! elif not event.startswith('-GRAPH-'): 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 x, y = values["-GRAPH-"] if not dragging: @@ -114,25 +105,28 @@ def main(): for fig in drag_figures: graph.send_figure_to_back(fig) 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}") start_point, end_point = None, None # enable grabbing a new rect dragging = False prior_rect = None - elif event.endswith('+RIGHT+'): # Righ click - window["-INFO-"].update(value=f"Right clicked location {values['-GRAPH-']}") - elif event.endswith('+MOTION+'): # Righ click - window["-INFO-"].update(value=f"mouse freely moving {values['-GRAPH-']}") - elif event == '-SAVE-': - # filename = sg.popup_get_file('Choose file (PNG, JPG, GIF) to save to', save_as=True) - filename=r'test.jpg' - save_element_as_file(window['-GRAPH-'], filename) + # elif event.endswith('+RIGHT+'): # Right click + # window["-INFO-"].update(value=f"Right clicked location {values['-GRAPH-']}") + # elif event.endswith('+MOTION+'): # Right click + # window["-INFO-"].update(value=f"mouse freely moving {values['-GRAPH-']}") + elif event == 'Send to back': # Right clicked menu item + figures = graph.get_figures_at_location(values["-GRAPH-"]) # get items in front-to-back order + if figures: # make sure at least 1 item found + graph.send_figure_to_back(figures[-1]) # get the last item which will be the top-most elif event == 'Erase item': window["-INFO-"].update(value=f"Right click erase at {values['-GRAPH-']}") if values['-GRAPH-'] != (None, None): - drag_figures = graph.get_figures_at_location(values['-GRAPH-']) - for figure in drag_figures: - graph.delete_figure(figure) + figures = graph.get_figures_at_location(values['-GRAPH-']) + if figures: + 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() From d368af0547db188450b08e285b5583b01abdbad9 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Sat, 20 May 2023 08:30:26 -0400 Subject: [PATCH 088/145] 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 --- PySimpleGUI.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index 0eb640ee..8996ad13 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -version = __version__ = "4.61.0.181 Unreleased" +version = __version__ = "4.61.0.182 Unreleased" _change_log = """ Changelog since 4.60.0 released to PyPI on 8-May-2022 @@ -432,6 +432,8 @@ _change_log = """ Removed Security tab from system settings 4.61.0.181 Added check for None and COLOR_SYSTEM_DEFAULT before any colors being set in Input.update + 4.61.0.182 + Only enable the Mac alpha channel 0.99 patch when tkinter version is 8.6.12. Have learned this is not needed for any other tkinter version """ @@ -23918,6 +23920,10 @@ def _mac_should_set_alpha_to_99(): if not ENABLE_MAC_ALPHA_99_PATCH: return False + # ONLY enable this patch for tkinter version 8.6.12 + if framework_version != '8.6.12': + return False + # At this point, we're running a Mac and the alpha patch is enabled # Final check is to see if Mac OS version is 12.3 or later try: @@ -26843,7 +26849,7 @@ if _mac_should_set_alpha_to_99(): __perform_upgrade_check() - + # -------------------------------- ENTRY POINT IF RUN STANDALONE -------------------------------- # if __name__ == '__main__': # To execute the upgrade from command line, type: From e7b380ee7ea78f412c8a86bc7619c2a720eaa909 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Sun, 21 May 2023 19:38:07 -0400 Subject: [PATCH 089/145] Show Critical upgrade service messages. Removed the extra upgrade from github button from tab. --- PySimpleGUI.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index 8996ad13..8243b8e5 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -version = __version__ = "4.61.0.182 Unreleased" +version = __version__ = "4.61.0.183 Unreleased" _change_log = """ Changelog since 4.60.0 released to PyPI on 8-May-2022 @@ -434,7 +434,8 @@ _change_log = """ Added check for None and COLOR_SYSTEM_DEFAULT before any colors being set in Input.update 4.61.0.182 Only enable the Mac alpha channel 0.99 patch when tkinter version is 8.6.12. Have learned this is not needed for any other tkinter version - + 4.61.0.183 + Show Critical upgrade service messages. Removed the extra upgrade from github button from tab. """ __version__ = version.split()[0] # For PEP 396 and PEP 345 @@ -458,7 +459,7 @@ port = 'PySimpleGUI' """ - Copyright 2018, 2019, 2020, 2021, 2022 PySimpleGUI(tm) + Copyright 2018, 2019, 2020, 2021, 2022, 2023 PySimpleGUI(tm) Before getting into the details, let's talk about the high level goals of the PySimpleGUI project. @@ -24964,7 +24965,8 @@ def __show_previous_upgrade_information(): recommended_version = pysimplegui_user_settings.get('-upgrade recommendation-', '') severity_level = pysimplegui_user_settings.get('-severity level-', '') - # message2 = r'https://www.PySimpleGUI.org' + if severity_level != 'Critical': + return layout = [[Image(EMOJI_BASE64_HAPPY_THUMBS_UP), T('An upgrade is available & recommended', font='_ 14')], [T('It is recommended you upgrade to version {}'.format(recommended_version))], @@ -25075,7 +25077,7 @@ def __perform_upgrade_check_thread(): def __perform_upgrade_check(): # For now, do not show data returned. Still testing and do not want to "SPAM" users with any popups - # __show_previous_upgrade_information() + __show_previous_upgrade_information() threading.Thread(target=lambda: __perform_upgrade_check_thread(), daemon=True).start() @@ -26521,7 +26523,7 @@ def _create_main_window(): [T(pysimplegui_user_settings.get('-upgrade message 1-',''))], [T(pysimplegui_user_settings.get('-upgrade message 2-',''))], [Checkbox('Show Only Critical Messages', default=pysimplegui_user_settings.get('-upgrade show only critical-', False), key='-UPGRADE SHOW ONLY CRITICAL-', enable_events=True)], - [Button('Show Notification Again'), B('Upgrade from GitHub', button_color='white on red', key='-UPGRADE FROM GITHUB-'), + [Button('Show Notification Again'), ], ] tab_upgrade = Tab('Upgrade\n',upgrade_recommendation_tab_layout, expand_x=True) @@ -26682,7 +26684,6 @@ def main(): elif event in ('-EMOJI-HEARTS-', '-HEART-', '-PYTHON HEARTS-'): popup_scrolled("Oh look! It's a Udemy discount coupon!", '9AF99B123C49D51EB547', 'A personal message from Mike -- thank you so very much for supporting PySimpleGUI!', title='Udemy Coupon', image=EMOJI_BASE64_MIKE, keep_on_top=True) - elif event == 'Themes': search_string = popup_get_text('Enter a search term or leave blank for all themes', 'Show Available Themes', keep_on_top=True) if search_string is not None: From 955a7cba07c0760d1664e0420e9bbe251acc085f Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Sun, 21 May 2023 19:39:16 -0400 Subject: [PATCH 090/145] Additional of release notes for 4.60.5 dot release posted to PyPI --- docs/index.md | 16 ++++++++++++++++ .../markdown input files/4_Release_notes.md | 19 +++++++++++++++++++ readme_creator/output/index.md | 16 ++++++++++++++++ 3 files changed, 51 insertions(+) diff --git a/docs/index.md b/docs/index.md index fab4bdcc..ec2aba76 100644 --- a/docs/index.md +++ b/docs/index.md @@ -10134,6 +10134,22 @@ Test Harness and Settings Windows fit on small screens better * Emergency Patch Release for Mac OS 12.3 and greater * Fixed bug in Mac OS version check in yesterday's 4.60.2 release +## 4.60.4 PySimpleGUI 10-Oct-2022 + +* Dot release to quickly fix the Trinket detection which stopped working recently + +## 4.60.5 PySimpleGUI 21-May-2023 + +* Mac fixes + * Fix for Input Element not working in no-titlebar windows on MacOs 13.2.1 + * Change to the 0.99 Alpha fix made in 4.60.2. Now only applies patch when running on 8.6.12, regardless of Mac Control Panel setting in PySimpleGUI Global Settings. Removes the need for users to disable when upgrading tkinter. +* Added Intelligent Upgrade Service - inform users when there are releases of PySimpleGUI that fix a problem that may be unique to their combination of components +* Change to GitHub Issue GUI + * Added checkbox for checking if running latest PyPI version + * Recommended using Demo Browser to search Demo Programs + * Use platform module to fill in the OS information field +* SDK Help Window - changed all readthedocs links to use the PySimpleGUI.org hostname for better portability + ## Code Condition Make it run diff --git a/readme_creator/markdown input files/4_Release_notes.md b/readme_creator/markdown input files/4_Release_notes.md index 82200a1d..7aa73856 100644 --- a/readme_creator/markdown input files/4_Release_notes.md +++ b/readme_creator/markdown input files/4_Release_notes.md @@ -2590,6 +2590,25 @@ Test Harness and Settings Windows fit on small screens better * Emergency Patch Release for Mac OS 12.3 and greater * Fixed bug in Mac OS version check in yesterday's 4.60.2 release +## 4.60.4 PySimpleGUI 10-Oct-2022 + +* Dot release to quickly fix the Trinket detection which stopped working recently + + +## 4.60.5 PySimpleGUI 21-May-2023 + +* Mac fixes + * Fix for Input Element not working in no-titlebar windows on MacOs 13.2.1 + * Change to the 0.99 Alpha fix made in 4.60.2. Now only applies patch when running on 8.6.12, regardless of Mac Control Panel setting in PySimpleGUI Global Settings. Removes the need for users to disable when upgrading tkinter. +* Added Intelligent Upgrade Service - inform users when there are releases of PySimpleGUI that fix a problem that may be unique to their combination of components +* Change to GitHub Issue GUI + * Added checkbox for checking if running latest PyPI version + * Recommended using Demo Browser to search Demo Programs + * Use platform module to fill in the OS information field +* SDK Help Window - changed all readthedocs links to use the PySimpleGUI.org hostname for better portability + + + ## Code Condition diff --git a/readme_creator/output/index.md b/readme_creator/output/index.md index fab4bdcc..ec2aba76 100644 --- a/readme_creator/output/index.md +++ b/readme_creator/output/index.md @@ -10134,6 +10134,22 @@ Test Harness and Settings Windows fit on small screens better * Emergency Patch Release for Mac OS 12.3 and greater * Fixed bug in Mac OS version check in yesterday's 4.60.2 release +## 4.60.4 PySimpleGUI 10-Oct-2022 + +* Dot release to quickly fix the Trinket detection which stopped working recently + +## 4.60.5 PySimpleGUI 21-May-2023 + +* Mac fixes + * Fix for Input Element not working in no-titlebar windows on MacOs 13.2.1 + * Change to the 0.99 Alpha fix made in 4.60.2. Now only applies patch when running on 8.6.12, regardless of Mac Control Panel setting in PySimpleGUI Global Settings. Removes the need for users to disable when upgrading tkinter. +* Added Intelligent Upgrade Service - inform users when there are releases of PySimpleGUI that fix a problem that may be unique to their combination of components +* Change to GitHub Issue GUI + * Added checkbox for checking if running latest PyPI version + * Recommended using Demo Browser to search Demo Programs + * Use platform module to fill in the OS information field +* SDK Help Window - changed all readthedocs links to use the PySimpleGUI.org hostname for better portability + ## Code Condition Make it run From e5d0c3d4719a842bd5270bd57682eb6d8091cf2e Mon Sep 17 00:00:00 2001 From: PySimpleGUI <46163555+PySimpleGUI@users.noreply.github.com> Date: Wed, 24 May 2023 17:30:18 +0000 Subject: [PATCH 091/145] Automated Update! --- docs/Screens.md | 12 ++++++++++++ docs/Screens2.md | 14 ++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/docs/Screens.md b/docs/Screens.md index 3c55377f..6ad915a5 100644 --- a/docs/Screens.md +++ b/docs/Screens.md @@ -1,3 +1,15 @@ +[eagleEggs](https://github.com/eagleEggs) 2023-05-24T04:03:28Z + +![image](https://github.com/PySimpleGUI/PySimpleGUI/assets/29800532/5751e594-4748-431b-a1b2-76b1b7f346db) + +----------- + +[gnuchanos](https://github.com/gnuchanos) 2023-05-24T02:35:07Z + +![2023-05-24-053345_1280x1024_scrot](https://github.com/PySimpleGUI/PySimpleGUI/assets/117280480/acb7b360-af3a-4ec1-a226-a35d76676167) + +----------- + [PySimpleGUI](https://github.com/PySimpleGUI) 2023-05-12T09:55:03Z ![image](https://github.com/PySimpleGUI/PySimpleGUI/assets/46163555/98b78824-5286-4183-bb92-0d6fc5405270) diff --git a/docs/Screens2.md b/docs/Screens2.md index c636665e..5fda8a98 100644 --- a/docs/Screens2.md +++ b/docs/Screens2.md @@ -1,3 +1,17 @@ +[eagleEggs](https://github.com/eagleEggs) 2023-05-24T04:03:28Z +Started this a few days ago. Thanks to PSG it has already proven the hypothesis as valid - Streamlining novel development in a curated parameter driven manner with op3nAI API. Much more functionality to add in, but what an amazing GUI framework <3 <3 <3 And thanks to @jason990420 for all of the tkinter hacks he's posted which has always covered everything I've needed :) + +![image](https://github.com/PySimpleGUI/PySimpleGUI/assets/29800532/5751e594-4748-431b-a1b2-76b1b7f346db) + + +----------- + +[gnuchanos](https://github.com/gnuchanos) 2023-05-24T02:35:07Z +![2023-05-24-053345_1280x1024_scrot](https://github.com/PySimpleGUI/PySimpleGUI/assets/117280480/acb7b360-af3a-4ec1-a226-a35d76676167) +not finish yet + +----------- + [PySimpleGUI](https://github.com/PySimpleGUI) 2023-05-12T09:55:03Z I saw this awesome screenshot: From 79a3b85e7360a7e2b3b39b6228793c8cb7b13922 Mon Sep 17 00:00:00 2001 From: PySimpleGUI <46163555+PySimpleGUI@users.noreply.github.com> Date: Thu, 25 May 2023 17:30:21 +0000 Subject: [PATCH 092/145] Automated Update! --- docs/Screens.md | 8 ++++++++ docs/Screens2.md | 17 +++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/docs/Screens.md b/docs/Screens.md index 6ad915a5..4a3c93fc 100644 --- a/docs/Screens.md +++ b/docs/Screens.md @@ -1,3 +1,11 @@ +[mrtnbm](https://github.com/mrtnbm) 2023-05-25T16:24:22Z + +![image](https://github.com/PySimpleGUI/PySimpleGUI/assets/49289399/1a234b86-9457-4d10-8080-ea064e915397) +![image](https://github.com/PySimpleGUI/PySimpleGUI/assets/49289399/faf9adc7-6de7-42c7-b405-05e5bf081095) +![image](https://github.com/PySimpleGUI/PySimpleGUI/assets/49289399/55a72eec-56d7-4442-b660-b42e122be488) + +----------- + [eagleEggs](https://github.com/eagleEggs) 2023-05-24T04:03:28Z ![image](https://github.com/PySimpleGUI/PySimpleGUI/assets/29800532/5751e594-4748-431b-a1b2-76b1b7f346db) diff --git a/docs/Screens2.md b/docs/Screens2.md index 5fda8a98..ad705c3d 100644 --- a/docs/Screens2.md +++ b/docs/Screens2.md @@ -1,3 +1,20 @@ +[mrtnbm](https://github.com/mrtnbm) 2023-05-25T16:24:22Z +Thanks to PSG, I've created the nicest GUI I've ever made that I'm now using for my own little naive prompt lib. + +- Main window: +![image](https://github.com/PySimpleGUI/PySimpleGUI/assets/49289399/1a234b86-9457-4d10-8080-ea064e915397) + +- Edit Window: +![image](https://github.com/PySimpleGUI/PySimpleGUI/assets/49289399/faf9adc7-6de7-42c7-b405-05e5bf081095) + +The heart can be clicked and will change to outline or fill mode. + + - For reference, here is a screenshot without rescaling: + +![image](https://github.com/PySimpleGUI/PySimpleGUI/assets/49289399/55a72eec-56d7-4442-b660-b42e122be488) + +----------- + [eagleEggs](https://github.com/eagleEggs) 2023-05-24T04:03:28Z Started this a few days ago. Thanks to PSG it has already proven the hypothesis as valid - Streamlining novel development in a curated parameter driven manner with op3nAI API. Much more functionality to add in, but what an amazing GUI framework <3 <3 <3 And thanks to @jason990420 for all of the tkinter hacks he's posted which has always covered everything I've needed :) From b62648aa23ff3a5e81d5604a60ea21e86d39243d Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Mon, 29 May 2023 10:19:32 -0400 Subject: [PATCH 093/145] Expanded class wrapper demo to explain it's not a recommended design pattern. When initially released there was no explanation accompanying the code. --- DemoPrograms/Demo_Class_Wrapper.py | 66 +++++++++++++++++++++++++++++- 1 file changed, 65 insertions(+), 1 deletion(-) diff --git a/DemoPrograms/Demo_Class_Wrapper.py b/DemoPrograms/Demo_Class_Wrapper.py index 99995ee8..12201b23 100644 --- a/DemoPrograms/Demo_Class_Wrapper.py +++ b/DemoPrograms/Demo_Class_Wrapper.py @@ -4,10 +4,38 @@ import PySimpleGUI as sg Demo - Class wrapper 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 11 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(): def __init__(self): @@ -35,3 +63,39 @@ class SampleGUI(): my_gui = SampleGUI() # run the event loop 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 +''' + +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() + From eeb95398e0b4ee0e16185753c43145d2995e795c Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Mon, 29 May 2023 10:21:17 -0400 Subject: [PATCH 094/145] Added a function around the functional example --- DemoPrograms/Demo_Class_Wrapper.py | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/DemoPrograms/Demo_Class_Wrapper.py b/DemoPrograms/Demo_Class_Wrapper.py index 12201b23..4cf359c3 100644 --- a/DemoPrograms/Demo_Class_Wrapper.py +++ b/DemoPrograms/Demo_Class_Wrapper.py @@ -9,7 +9,7 @@ import PySimpleGUI as sg 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 11 lines of code. + 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 @@ -83,19 +83,21 @@ my_gui.run() MMMMMMMMMMM ''' -layout = [ [sg.Text('My layout')], - [sg.Input(key='-IN-')], - [sg.Button('Go'), sg.Button('Exit')] ] +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) + window = sg.Window('My new window', layout) -while True: # Event Loop - event, values = window.read() - if event in (sg.WIN_CLOSED, 'Exit'): - break + 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-']) + if event == 'Go': + sg.popup('Go button clicked', 'Input value:', values['-IN-']) -window.close() + window.close() +gui_function() From 0ff0efa3c6b57f92b7ec973724a3518b7ffd077c Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Mon, 29 May 2023 11:31:21 -0400 Subject: [PATCH 095/145] Fix for Combo.update background color changing incorrect widget setting. --- PySimpleGUI.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index 8243b8e5..73501cad 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -version = __version__ = "4.61.0.183 Unreleased" +version = __version__ = "4.61.0.184 Unreleased" _change_log = """ Changelog since 4.60.0 released to PyPI on 8-May-2022 @@ -436,6 +436,8 @@ _change_log = """ Only enable the Mac alpha channel 0.99 patch when tkinter version is 8.6.12. Have learned this is not needed for any other tkinter version 4.61.0.183 Show Critical upgrade service messages. Removed the extra upgrade from github button from tab. + 4.61.0.184 + Fix for Combo.update background color changing incorrect widget setting. """ __version__ = version.split()[0] # For PEP 396 and PEP 345 @@ -2839,12 +2841,12 @@ class Combo(Element): style_name = self.ttk_style_name if text_color is not None: combostyle.configure(style_name, foreground=text_color) - combostyle.configure(style_name, selectbackground=text_color) + combostyle.configure(style_name, selectforeground=text_color) combostyle.configure(style_name, insertcolor=text_color) combostyle.map(style_name, fieldforeground=[('readonly', text_color)]) self.TextColor = text_color if background_color is not None: - combostyle.configure(style_name, selectforeground=background_color) + combostyle.configure(style_name, selectbackground=background_color) combostyle.map(style_name, fieldbackground=[('readonly', background_color)]) combostyle.configure(style_name, fieldbackground=background_color) self.BackgroundColor = background_color From 4a883851e69e9dd7f0ac9aaa7b5053b145a88cbe Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Fri, 9 Jun 2023 06:31:15 -0400 Subject: [PATCH 096/145] Fix in pinning demo --- DemoPrograms/Demo_Invisible_Elements_Pinning.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/DemoPrograms/Demo_Invisible_Elements_Pinning.py b/DemoPrograms/Demo_Invisible_Elements_Pinning.py index fe9b9ce9..6216f975 100644 --- a/DemoPrograms/Demo_Invisible_Elements_Pinning.py +++ b/DemoPrograms/Demo_Invisible_Elements_Pinning.py @@ -22,9 +22,9 @@ import PySimpleGUI as sg Copyright 2020, 2022 PySimpleGUI.org """ -layout = [ [sg.Text('Hide Button or Input. Button3 hides Input. Buttons 1 & 2 hide Button 2')], +layout = [ [sg.Text('Hide Button or Multiline. Buttons 1 & 2 hide Button 2')], [sg.pin(sg.Multiline(size=(60, 10), key='-MLINE-'))], - [sg.pin(sg.Button('Button1')), sg.pin(sg.Button('Button2'), shrink=False), sg.B('Button3'), sg.B('Toggle Multiline')], + [sg.pin(sg.Button('Button1')), sg.pin(sg.Button('Button2'), shrink=False), sg.B('Toggle Multiline')], ] window = sg.Window('Visible / Invisible Element Demo', layout) @@ -39,9 +39,6 @@ while True: # Event Loop if event in ('Button1', 'Button2'): window['Button2'].update(visible=toggle) toggle = not toggle - if event == 'Button3': - window['-IN-'].update(visible=toggle_in) - toggle_in = not toggle_in elif event == 'Toggle Multiline': window['-MLINE-'].update(visible=not window['-MLINE-'].visible) window.close() From 8004b258a97bf515e665123283aef6b50c3bf9c8 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Tue, 13 Jun 2023 17:42:20 -0400 Subject: [PATCH 097/145] Fix for crash when no headings specified for a table by casting values into strings --- PySimpleGUI.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index 73501cad..d32dfba2 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -version = __version__ = "4.61.0.184 Unreleased" +version = __version__ = "4.61.0.185 Unreleased" _change_log = """ Changelog since 4.60.0 released to PyPI on 8-May-2022 @@ -438,6 +438,9 @@ _change_log = """ Show Critical upgrade service messages. Removed the extra upgrade from github button from tab. 4.61.0.184 Fix for Combo.update background color changing incorrect widget setting. + 4.61.0.185 + Fix for crash when no headings specified for a table by casting values into strings + """ __version__ = version.split()[0] # For PEP 396 and PEP 345 @@ -17677,6 +17680,7 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form): headings = element.ColumnHeadings if element.ColumnHeadings is not None else element.Values[0] for i, heading in enumerate(headings): + heading = str(heading) treeview.heading(heading, text=heading) if element.AutoSizeColumns: col_width = column_widths.get(i, len(heading)) # in case more headings than there are columns of data From 549330d0aa391f9cc1d868d6730ad9267c7b5640 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Wed, 14 Jun 2023 12:42:47 -0400 Subject: [PATCH 098/145] New Udemy Coupon --- docs/cookbook.md | 4 ++-- docs/readme.md | 4 ++-- readme.md | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/cookbook.md b/docs/cookbook.md index 5118cafa..c99da19d 100644 --- a/docs/cookbook.md +++ b/docs/cookbook.md @@ -25,9 +25,9 @@ apply coupon for discount: - 9AF99B123C49D51EB547 + F988F082A3D18483B1C5 - diff --git a/docs/readme.md b/docs/readme.md index 4922869b..046a2a64 100644 --- a/docs/readme.md +++ b/docs/readme.md @@ -9,8 +9,8 @@ PySimpleGUI Udemy Course -
apply coupon for discount:
9AF99B123C49D51EB547
- click here to visit course page +
apply coupon for discount:
F988F082A3D18483B1C5
+ click here to visit course page diff --git a/readme.md b/readme.md index 4922869b..046a2a64 100644 --- a/readme.md +++ b/readme.md @@ -9,8 +9,8 @@ PySimpleGUI Udemy Course -
apply coupon for discount:
9AF99B123C49D51EB547
- click here to visit course page +
apply coupon for discount:
F988F082A3D18483B1C5
+ click here to visit course page From 130d5492f0c3a751c961c029960baca5e7e6c22b Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Mon, 19 Jun 2023 11:23:02 -0400 Subject: [PATCH 099/145] Fix for popup_get_file when using no_window=True. Now returns None if cancelled or window closed --- PySimpleGUI.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index d32dfba2..e695c4f8 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -version = __version__ = "4.61.0.185 Unreleased" +version = __version__ = "4.61.0.186 Unreleased" _change_log = """ Changelog since 4.60.0 released to PyPI on 8-May-2022 @@ -440,6 +440,8 @@ _change_log = """ Fix for Combo.update background color changing incorrect widget setting. 4.61.0.185 Fix for crash when no headings specified for a table by casting values into strings + 4.61.0.186 + Fix for popup_get_file when using no_window=True. Now returns None if cancelled or window closed """ @@ -17680,7 +17682,7 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form): headings = element.ColumnHeadings if element.ColumnHeadings is not None else element.Values[0] for i, heading in enumerate(headings): - heading = str(heading) + # heading = str(heading) treeview.heading(heading, text=heading) if element.AutoSizeColumns: col_width = column_widths.get(i, len(heading)) # in case more headings than there are columns of data @@ -21974,6 +21976,8 @@ def popup_get_file(message, title=None, default_path='', default_extension='', s if not multiple_files and type(filename) in (tuple, list): if len(filename): # only if not 0 length, otherwise will get an error filename = filename[0] + if not filename: + return None return filename if save_as: From 891b0a5b36870677ca663976ad2c7f34f164a999 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Fri, 23 Jun 2023 10:36:02 -0400 Subject: [PATCH 100/145] Changed Python GUIs for Humans to just GUIs for Humans --- docs/readme.md | 4 ++-- readme.md | 4 ++-- readme_creator/markdown input files/1_HEADER_top_part.md | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/readme.md b/docs/readme.md index 046a2a64..3ab0cb5e 100644 --- a/docs/readme.md +++ b/docs/readme.md @@ -1,6 +1,6 @@

- Python GUIs for Humans -

Python GUIs for Humans

+ GUIs for Humans +

GUIs for HumansTM

diff --git a/readme.md b/readme.md index 046a2a64..3ab0cb5e 100644 --- a/readme.md +++ b/readme.md @@ -1,6 +1,6 @@

- Python GUIs for Humans -

Python GUIs for Humans

+ GUIs for Humans +

GUIs for HumansTM

diff --git a/readme_creator/markdown input files/1_HEADER_top_part.md b/readme_creator/markdown input files/1_HEADER_top_part.md index 35b757c7..dc06797a 100644 --- a/readme_creator/markdown input files/1_HEADER_top_part.md +++ b/readme_creator/markdown input files/1_HEADER_top_part.md @@ -27,8 +27,8 @@ HOW DO I INSERT IMAGES ???
- Python GUIs for Humans -

Python GUIs for Humans

+ GUIs for Humans +

Python GUIs for HumansTM

From 884d49a14f0a8db03e1ea092888881a3365466e9 Mon Sep 17 00:00:00 2001 From: PySimpleGUI <46163555+PySimpleGUI@users.noreply.github.com> Date: Sun, 25 Jun 2023 17:30:19 +0000 Subject: [PATCH 101/145] Automated Update! --- docs/Screens.md | 6 ++++++ docs/Screens2.md | 22 ++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/docs/Screens.md b/docs/Screens.md index 4a3c93fc..d2c5e36d 100644 --- a/docs/Screens.md +++ b/docs/Screens.md @@ -1,3 +1,9 @@ +[luisegarduno](https://github.com/luisegarduno) 2023-06-25T05:18:40Z + +![image](https://github.com/PySimpleGUI/PySimpleGUI/assets/30121656/80b10f6e-30f7-4159-8574-5f79bff705b1) + +----------- + [mrtnbm](https://github.com/mrtnbm) 2023-05-25T16:24:22Z ![image](https://github.com/PySimpleGUI/PySimpleGUI/assets/49289399/1a234b86-9457-4d10-8080-ea064e915397) diff --git a/docs/Screens2.md b/docs/Screens2.md index ad705c3d..f2b1b736 100644 --- a/docs/Screens2.md +++ b/docs/Screens2.md @@ -1,3 +1,25 @@ +[luisegarduno](https://github.com/luisegarduno) 2023-06-25T05:18:40Z +**Chess (updated!)** + +Originally added/created by @MikeTheWatchGuy, the chess demos (player vs. player & player vs. Ai) were included in PySimpleGUI ([see here](https://github.com/PySimpleGUI/PySimpleGUI/tree/8b23740fca08b7f5bad3f0d32760f42a5202d3e1/Chess)), but were removed from the main branch towards the end of 2022. + +In terms of the changes that I made to the original code (see #5052): + +I updated **requirements.txt** to include the latest versions: +``` +PySimpleGUI==4.60.5 +python-chess==1.999 +``` +I then made changes within both of the demo files to remove any outdated or deprecated code causing errors. I also added compatibility for Linux, allowing users to import files that do not end in ".exe". + +Both chess demos have only been tested on Ubuntu 20.04 but should also work on Windows since not much was changed from the original code. Lastly, for the engine, I resulted in having to use Stockfish 13, since there was several issues when trying to use Stockfish 14 or Stockfish 15. + +https://github.com/luisegarduno/ChessGUI + +![image](https://github.com/PySimpleGUI/PySimpleGUI/assets/30121656/80b10f6e-30f7-4159-8574-5f79bff705b1) + +----------- + [mrtnbm](https://github.com/mrtnbm) 2023-05-25T16:24:22Z Thanks to PSG, I've created the nicest GUI I've ever made that I'm now using for my own little naive prompt lib. From d97777b2626c0125bd596b95711d579b9da98e54 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Mon, 3 Jul 2023 18:47:04 -0400 Subject: [PATCH 102/145] Corrected the Table.get docstring to reflect that it returns a list of ints --- PySimpleGUI.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index e695c4f8..d8fd3889 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -version = __version__ = "4.61.0.186 Unreleased" +version = __version__ = "4.61.0.187 Unreleased" _change_log = """ Changelog since 4.60.0 released to PyPI on 8-May-2022 @@ -442,6 +442,8 @@ _change_log = """ Fix for crash when no headings specified for a table by casting values into strings 4.61.0.186 Fix for popup_get_file when using no_window=True. Now returns None if cancelled or window closed + 4.61.0.187 + Corrected the Table.get docstring to reflect that it returns a list of ints """ @@ -9575,11 +9577,12 @@ class Table(Element): def get(self): """ - Get the selected rows using tktiner's selection method. Experimenting with this change.... + Get the selected rows using tktiner's selection method. Returns a list of the selected rows. :return: the current table values - :rtype: List[List[Any]] + :rtype: List[int] """ + selections = self.TKTreeview.selection() selected_rows = [int(x) - 1 for x in selections] return selected_rows From 3de64e7d99ba36100bfb487472160e5e3a36d3d8 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Mon, 3 Jul 2023 18:49:55 -0400 Subject: [PATCH 103/145] Another try at correcting the Table.get docstring --- PySimpleGUI.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index d8fd3889..afa86641 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -version = __version__ = "4.61.0.187 Unreleased" +version = __version__ = "4.61.0.188 Unreleased" _change_log = """ Changelog since 4.60.0 released to PyPI on 8-May-2022 @@ -444,6 +444,8 @@ _change_log = """ Fix for popup_get_file when using no_window=True. Now returns None if cancelled or window closed 4.61.0.187 Corrected the Table.get docstring to reflect that it returns a list of ints + 4.61.0.188 + Finished correcting the Table.get docstring.... think I got it right this time.... """ @@ -9579,7 +9581,7 @@ class Table(Element): """ Get the selected rows using tktiner's selection method. Returns a list of the selected rows. - :return: the current table values + :return: a list of the index of the selected rows (a list of ints) :rtype: List[int] """ From 2ce3c7f75e6344ad13048c416ceda7b414eba6d4 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Tue, 4 Jul 2023 08:50:08 -0400 Subject: [PATCH 104/145] Changed Table click events to be generated on Button Release instead of Button (down) --- PySimpleGUI.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index afa86641..840a3e06 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -version = __version__ = "4.61.0.188 Unreleased" +version = __version__ = "4.61.0.189 Unreleased" _change_log = """ Changelog since 4.60.0 released to PyPI on 8-May-2022 @@ -446,6 +446,9 @@ _change_log = """ Corrected the Table.get docstring to reflect that it returns a list of ints 4.61.0.188 Finished correcting the Table.get docstring.... think I got it right this time.... + 4.61.0.189 + Changed Table click events to be generated on Button Release instead of Button (down). Was not getting the + correct selected rows in the values dictionary when the click event was generated using down. Now the selected rows is correct """ @@ -9566,7 +9569,7 @@ class Table(Element): self.TKTreeview.selection_set(selections) # print(selections) self.SelectedRows = [int(x) - 1 for x in selections] - # print('The new selected rows = ', self.SelectedRows) + # print('The new selected rows = ', self.SelectedRows, 'selections =', selections) if self.enable_click_events is True: if self.Key is not None: self.ParentForm.LastButtonClicked = (self.Key, TABLE_CLICKED_INDICATOR, (row, column)) @@ -17767,7 +17770,7 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form): treeview.configure(style=style_name) # scrollable_frame.pack(side=tk.LEFT, padx=elementpad[0], pady=elementpad[1], expand=True, fill='both') if element.enable_click_events is True: - treeview.bind('', element._table_clicked) + treeview.bind('', element._table_clicked) if element.right_click_selects: if running_mac(): treeview.bind('', element._table_clicked) From aaf391508ccb3fd61275bc83aa0a2ca8df30d62e Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Wed, 12 Jul 2023 17:20:56 -0400 Subject: [PATCH 105/145] New tagline. Updated call reference using newest docstrings --- docs/call reference.md | 8 ++++---- docs/cookbook.md | 4 ++-- docs/index.md | 6 +++--- docs/readme.md | 4 ++-- readme.md | 4 ++-- readme_creator/markdown input files/1_HEADER_top_part.md | 6 +++--- readme_creator/output/call reference.md | 8 ++++---- readme_creator/output/index.md | 6 +++--- 8 files changed, 23 insertions(+), 23 deletions(-) diff --git a/docs/call reference.md b/docs/call reference.md index 90b18ab3..b004ccac 100644 --- a/docs/call reference.md +++ b/docs/call reference.md @@ -11490,13 +11490,13 @@ Parameter Descriptions: ### get -Get the selected rows using tktiner's selection method. Experimenting with this change.... +Get the selected rows using tktiner's selection method. Returns a list of the selected rows. `get()` |Type|Name|Meaning| |---|---|---| -|List[List[Any]]| **return** | the current table values | +|List[int]| **return** | a list of the index of the selected rows (a list of ints) | ### get_next_focus @@ -11720,13 +11720,13 @@ The following methods are here for backwards compatibility reference. You will ### Get -Get the selected rows using tktiner's selection method. Experimenting with this change.... +Get the selected rows using tktiner's selection method. Returns a list of the selected rows. `Get()` |Type|Name|Meaning| |---|---|---| -|List[List[Any]]| **return** | the current table values | +|List[int]| **return** | a list of the index of the selected rows (a list of ints) | ### SetFocus diff --git a/docs/cookbook.md b/docs/cookbook.md index c99da19d..98473f4c 100644 --- a/docs/cookbook.md +++ b/docs/cookbook.md @@ -1,7 +1,7 @@
- Python GUIs for Humans -

Python GUIs for Humans

+ User Interfaces for Humans +

User Interfaces for HumansTM

diff --git a/docs/index.md b/docs/index.md index ec2aba76..11810190 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,7 +1,7 @@
- Python GUIs for Humans -

Python GUIs for Humans

+ User Interfaces for Humans +

User Interfaces for HumansTM

@@ -57,7 +57,7 @@ # PySimpleGUI User's Manual -## Python GUI For Humans - Transforms tkinter, Qt, Remi, WxPython into portable people-friendly Pythonic interfaces +## User Interfaces for Humans - Transforms tkinter, Qt, Remi, WxPython into portable people-friendly Pythonic interfaces ## The Call Reference Section Moved to here diff --git a/docs/readme.md b/docs/readme.md index 3ab0cb5e..03488cae 100644 --- a/docs/readme.md +++ b/docs/readme.md @@ -1,6 +1,6 @@

- GUIs for Humans -

GUIs for HumansTM

+ User Interfaces for Humans +

User Interfaces for HumansTM

diff --git a/readme.md b/readme.md index 3ab0cb5e..03488cae 100644 --- a/readme.md +++ b/readme.md @@ -1,6 +1,6 @@

- GUIs for Humans -

GUIs for HumansTM

+ User Interfaces for Humans +

User Interfaces for HumansTM

diff --git a/readme_creator/markdown input files/1_HEADER_top_part.md b/readme_creator/markdown input files/1_HEADER_top_part.md index dc06797a..320a4997 100644 --- a/readme_creator/markdown input files/1_HEADER_top_part.md +++ b/readme_creator/markdown input files/1_HEADER_top_part.md @@ -27,8 +27,8 @@ HOW DO I INSERT IMAGES ???
- GUIs for Humans -

Python GUIs for HumansTM

+ User Interfaces for Humans +

User Interfaces for HumansTM

@@ -96,7 +96,7 @@ HOW DO I INSERT IMAGES ??? # PySimpleGUI User's Manual -## Python GUI For Humans - Transforms tkinter, Qt, Remi, WxPython into portable people-friendly Pythonic interfaces +## User Interfaces for Humans - Transforms tkinter, Qt, Remi, WxPython into portable people-friendly Pythonic interfaces ## The Call Reference Section Moved to here diff --git a/readme_creator/output/call reference.md b/readme_creator/output/call reference.md index 90b18ab3..b004ccac 100644 --- a/readme_creator/output/call reference.md +++ b/readme_creator/output/call reference.md @@ -11490,13 +11490,13 @@ Parameter Descriptions: ### get -Get the selected rows using tktiner's selection method. Experimenting with this change.... +Get the selected rows using tktiner's selection method. Returns a list of the selected rows. `get()` |Type|Name|Meaning| |---|---|---| -|List[List[Any]]| **return** | the current table values | +|List[int]| **return** | a list of the index of the selected rows (a list of ints) | ### get_next_focus @@ -11720,13 +11720,13 @@ The following methods are here for backwards compatibility reference. You will ### Get -Get the selected rows using tktiner's selection method. Experimenting with this change.... +Get the selected rows using tktiner's selection method. Returns a list of the selected rows. `Get()` |Type|Name|Meaning| |---|---|---| -|List[List[Any]]| **return** | the current table values | +|List[int]| **return** | a list of the index of the selected rows (a list of ints) | ### SetFocus diff --git a/readme_creator/output/index.md b/readme_creator/output/index.md index ec2aba76..11810190 100644 --- a/readme_creator/output/index.md +++ b/readme_creator/output/index.md @@ -1,7 +1,7 @@
- Python GUIs for Humans -

Python GUIs for Humans

+ User Interfaces for Humans +

User Interfaces for HumansTM

@@ -57,7 +57,7 @@ # PySimpleGUI User's Manual -## Python GUI For Humans - Transforms tkinter, Qt, Remi, WxPython into portable people-friendly Pythonic interfaces +## User Interfaces for Humans - Transforms tkinter, Qt, Remi, WxPython into portable people-friendly Pythonic interfaces ## The Call Reference Section Moved to here From 5035d24f2c17e056e402e05fc5669cfcc323a71d Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Mon, 31 Jul 2023 12:31:59 -0400 Subject: [PATCH 106/145] Addition of black2 theme, Fix typo of text in _widget_was_created --- PySimpleGUI.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index 840a3e06..8d0107b1 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -version = __version__ = "4.61.0.189 Unreleased" +version = __version__ = "4.61.0.190 Unreleased" _change_log = """ Changelog since 4.60.0 released to PyPI on 8-May-2022 @@ -449,6 +449,9 @@ _change_log = """ 4.61.0.189 Changed Table click events to be generated on Button Release instead of Button (down). Was not getting the correct selected rows in the values dictionary when the click event was generated using down. Now the selected rows is correct + 4.61.0.190 + Addition of black2 theme + Fix typo of text in _widget_was_created """ @@ -2186,7 +2189,7 @@ class Element(): if SUPPRESS_WIDGET_NOT_FINALIZED_WARNINGS: return False - warnings.warn('You cannot Update element with key = {} until the window.read() is called or finalized=True when creating window'.format(self.Key), UserWarning) + warnings.warn('You cannot Update element with key = {} until the window.read() is called or set finalize=True when creating window'.format(self.Key), UserWarning) if not SUPPRESS_ERROR_POPUPS: _error_popup_with_traceback('Unable to complete operation on element with key {}'.format(self.Key), 'You cannot perform operations (such as calling update) on an Element until:', @@ -19713,6 +19716,8 @@ LOOK_AND_FEEL_TABLE = { "PROGRESS": DEFAULT_PROGRESS_BAR_COMPUTE, "BORDER": 1, "SLIDER_DEPTH": 0, "PROGRESS_DEPTH": 0, }, "Black": {"BACKGROUND": "#000000", "TEXT": "#FFFFFF", "INPUT": "#4D4D4D", "TEXT_INPUT": "#FFFFFF", "SCROLL": "#707070", "BUTTON": ("#000000", "#FFFFFF"), "PROGRESS": DEFAULT_PROGRESS_BAR_COMPUTE, "BORDER": 1, "SLIDER_DEPTH": 0, "PROGRESS_DEPTH": 0, }, + "Black2": {"BACKGROUND": "#000000", "TEXT": "#FFFFFF", "INPUT": "#000000", "TEXT_INPUT": "#FFFFFF", "SCROLL": "#FFFFFF", "BUTTON": ("#000000", "#FFFFFF"), + "PROGRESS": DEFAULT_PROGRESS_BAR_COMPUTE, "BORDER": 1, "SLIDER_DEPTH": 0, "PROGRESS_DEPTH": 0, }, "Tan": {"BACKGROUND": "#fdf6e3", "TEXT": "#268bd1", "INPUT": "#eee8d5", "TEXT_INPUT": "#6c71c3", "SCROLL": "#eee8d5", "BUTTON": ("#FFFFFF", "#063542"), "PROGRESS": DEFAULT_PROGRESS_BAR_COMPUTE, "BORDER": 1, "SLIDER_DEPTH": 0, "PROGRESS_DEPTH": 0, }, "TanBlue": {"BACKGROUND": "#e5dece", "TEXT": "#063289", "INPUT": "#f9f8f4", "TEXT_INPUT": "#242834", "SCROLL": "#eee8d5", "BUTTON": ("#FFFFFF", "#063289"), From 854bdccdd33a75bf6b6a57b16b2be7dee0588940 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Thu, 10 Aug 2023 12:44:33 -0400 Subject: [PATCH 107/145] Allow window resizing when in single photo mode. Updated the PIL resizing to much more recent resizing code. --- ...mo_Desktop_Widget_Digital_Picture_Frame.py | 160 ++++++++++++++---- 1 file changed, 123 insertions(+), 37 deletions(-) diff --git a/DemoPrograms/Demo_Desktop_Widget_Digital_Picture_Frame.py b/DemoPrograms/Demo_Desktop_Widget_Digital_Picture_Frame.py index 8ee2c959..8aec989c 100644 --- a/DemoPrograms/Demo_Desktop_Widget_Digital_Picture_Frame.py +++ b/DemoPrograms/Demo_Desktop_Widget_Digital_Picture_Frame.py @@ -1,8 +1,12 @@ import PySimpleGUI as sg import datetime -import PIL.Image, PIL.ImageTk +import PIL +from PIL import Image import random import os +import io +import base64 + """ 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 * Folder containing your images - Copyright 2021 PySimpleGUI + Copyright 2021, 2023 PySimpleGUI """ ALPHA = 0.9 # Initial alpha until user changes 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) - image.thumbnail(resize) - photo_img = PIL.ImageTk.PhotoImage(image) - return photo_img + +def make_square(im, fill_color=(0, 0, 0, 0)): + x, y = im.size + size = max(x, y) + 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.ANTIALIAS) 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): @@ -43,6 +106,15 @@ def choose_theme(location): else: 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): alpha = sg.user_settings_get_entry('-alpha-', ALPHA) @@ -61,7 +133,7 @@ def make_window(location): 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)))]] - 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 @@ -69,11 +141,10 @@ def make_window(location): def main(): loc = sg.user_settings_get_entry('-location-', (None, 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) 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) try: @@ -82,36 +153,26 @@ def main(): 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: - while True: - images = None - image_folder = sg.popup_get_folder('Choose location of your images', location=window.current_location(), keep_on_top=True) - if image_folder is not None: - sg.user_settings_set_entry('-image_folder-', image_folder) - 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: + image_name = single_image = sg.popup_get_file('Choose a starting image', keep_on_top=True) + if not single_image: + if sg.popup_yes_no('No folder entered','Go you want to exit the program entirely?', keep_on_top=True) == 'Yes': + exit() + if image_folder is not None and single_image is None: images = os.listdir(image_folder) 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 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 - # 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 -------------- 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) @@ -120,6 +181,28 @@ def main(): 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 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': sg.execute_editor(__file__) elif event == 'Choose Image Folder': @@ -175,12 +258,15 @@ def main(): window.close() window = make_window(loc) 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) - - - + (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() if __name__ == '__main__': + # reset_settings() # if get corrupted problems, uncomment this main() \ No newline at end of file From f292d757def83efd0432f7a250b547c8c9e898e1 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Sun, 13 Aug 2023 11:47:16 -0400 Subject: [PATCH 108/145] Fixed bug in Button.update. Was setting the activeforeground and activebackground which broke the mouseover or mouse press colors --- PySimpleGUI.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index 8d0107b1..8b5a6467 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -version = __version__ = "4.61.0.190 Unreleased" +version = __version__ = "4.61.0.191 Unreleased" _change_log = """ Changelog since 4.60.0 released to PyPI on 8-May-2022 @@ -452,6 +452,8 @@ _change_log = """ 4.61.0.190 Addition of black2 theme Fix typo of text in _widget_was_created + 4.61.0.191 + Fixed bug in Button.update. Was setting the activeforeground and activebackground which broke the mouseover or mouse press colors """ @@ -5574,9 +5576,11 @@ class Button(Element): button_style.configure(style_name, background=bc[1]) else: if bc[0] not in (None, COLOR_SYSTEM_DEFAULT): - self.TKButton.config(foreground=bc[0], activeforeground=bc[0]) + # self.TKButton.config(foreground=bc[0], activeforeground=bc[0]) # Removed 13-Aug-2023. Was causing mouseover to not work + self.TKButton.config(foreground=bc[0]) if bc[1] not in (None, COLOR_SYSTEM_DEFAULT): - self.TKButton.config(background=bc[1], activebackground=bc[1]) + # self.TKButton.config(background=bc[1], activebackground=bc[1]) # Removed 13-Aug-2023. Was causing mouseover to not work + self.TKButton.config(background=bc[1]) self.ButtonColor = bc if disabled is True: self.TKButton['state'] = 'disabled' From c51d6709563a9474663a7e6d98397b5cc9516433 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Mon, 14 Aug 2023 12:22:12 -0400 Subject: [PATCH 109/145] Fixed bug in Button.update. Corrected when activeforeground and activebackground are set. Removing them in version above was a mistake --- PySimpleGUI.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index 8b5a6467..d7b845b9 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -version = __version__ = "4.61.0.191 Unreleased" +version = __version__ = "4.61.0.192 Unreleased" _change_log = """ Changelog since 4.60.0 released to PyPI on 8-May-2022 @@ -454,6 +454,8 @@ _change_log = """ Fix typo of text in _widget_was_created 4.61.0.191 Fixed bug in Button.update. Was setting the activeforeground and activebackground which broke the mouseover or mouse press colors + 4.61.0.192 + Fixed bug in Button.update. Corrected when activeforeground and activebackground are set. Removing them in version above was a mistake """ @@ -5576,11 +5578,9 @@ class Button(Element): button_style.configure(style_name, background=bc[1]) else: if bc[0] not in (None, COLOR_SYSTEM_DEFAULT): - # self.TKButton.config(foreground=bc[0], activeforeground=bc[0]) # Removed 13-Aug-2023. Was causing mouseover to not work - self.TKButton.config(foreground=bc[0]) + self.TKButton.config(foreground=bc[0], activebackground=bc[0]) if bc[1] not in (None, COLOR_SYSTEM_DEFAULT): - # self.TKButton.config(background=bc[1], activebackground=bc[1]) # Removed 13-Aug-2023. Was causing mouseover to not work - self.TKButton.config(background=bc[1]) + self.TKButton.config(background=bc[1], activeforeground=bc[1]) self.ButtonColor = bc if disabled is True: self.TKButton['state'] = 'disabled' From 1d3126f8848e88a53e13380225efc1507eb27ab2 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Wed, 16 Aug 2023 09:34:58 -0400 Subject: [PATCH 110/145] Fixed spelling errors... resuse should have been reuse --- PySimpleGUI.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index d7b845b9..82960a7e 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -version = __version__ = "4.61.0.192 Unreleased" +version = __version__ = "4.61.0.193 Unreleased" _change_log = """ Changelog since 4.60.0 released to PyPI on 8-May-2022 @@ -456,6 +456,8 @@ _change_log = """ Fixed bug in Button.update. Was setting the activeforeground and activebackground which broke the mouseover or mouse press colors 4.61.0.192 Fixed bug in Button.update. Corrected when activeforeground and activebackground are set. Removing them in version above was a mistake + 4.61.0.193 + Fixed spelling errors... resuse should have been reuse """ @@ -7358,7 +7360,7 @@ class Frame(Element): continue if element.ParentContainer is not None: warnings.warn( - '*** YOU ARE ATTEMPTING TO RESUSE AN ELEMENT IN YOUR LAYOUT! Once placed in a layout, an element cannot be used in another layout. ***', + '*** YOU ARE ATTEMPTING TO REUSE AN ELEMENT IN YOUR LAYOUT! Once placed in a layout, an element cannot be used in another layout. ***', UserWarning) _error_popup_with_traceback('Error creating Frame layout', 'The layout specified has already been used', @@ -7694,7 +7696,7 @@ class Tab(Element): continue if element.ParentContainer is not None: warnings.warn( - '*** YOU ARE ATTEMPTING TO RESUSE AN ELEMENT IN YOUR LAYOUT! Once placed in a layout, an element cannot be used in another layout. ***', + '*** YOU ARE ATTEMPTING TO REUSE AN ELEMENT IN YOUR LAYOUT! Once placed in a layout, an element cannot be used in another layout. ***', UserWarning) popup_error_with_traceback('Error creating Tab layout', 'The layout specified has already been used', @@ -7953,7 +7955,7 @@ class TabGroup(Element): continue if element.ParentContainer is not None: warnings.warn( - '*** YOU ARE ATTEMPTING TO RESUSE AN ELEMENT IN YOUR LAYOUT! Once placed in a layout, an element cannot be used in another layout. ***', + '*** YOU ARE ATTEMPTING TO REUSE AN ELEMENT IN YOUR LAYOUT! Once placed in a layout, an element cannot be used in another layout. ***', UserWarning) PopupError('Error creating Tab layout', 'The layout specified has already been used', @@ -8614,7 +8616,7 @@ class Column(Element): continue if element.ParentContainer is not None: warnings.warn( - '*** YOU ARE ATTEMPTING TO RESUSE AN ELEMENT IN YOUR LAYOUT! Once placed in a layout, an element cannot be used in another layout. ***', + '*** YOU ARE ATTEMPTING TO REUSE AN ELEMENT IN YOUR LAYOUT! Once placed in a layout, an element cannot be used in another layout. ***', UserWarning) PopupError('Error creating Column layout', 'The layout specified has already been used', @@ -10655,10 +10657,10 @@ class Window: continue if element.ParentContainer is not None: warnings.warn( - '*** YOU ARE ATTEMPTING TO RESUSE AN ELEMENT IN YOUR LAYOUT! Once placed in a layout, an element cannot be used in another layout. ***', + '*** YOU ARE ATTEMPTING TO REUSE AN ELEMENT IN YOUR LAYOUT! Once placed in a layout, an element cannot be used in another layout. ***', UserWarning) _error_popup_with_traceback('Error detected in layout - Contains an element that has already been used.', - 'You have attempted to resuse an element in your layout.', + 'You have attempted to reuse an element in your layout.', "The layout specified has an element that's already been used.", 'You MUST start with a "clean", unused layout every time you create a window', 'The offensive Element = ', From 2ece7d4ad565bd3beb7487f644da526fccd0c6ff Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Sat, 19 Aug 2023 11:53:08 -0400 Subject: [PATCH 111/145] Added Listbox.select_index and Listbox.set_index_color --- PySimpleGUI.py | 78 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 77 insertions(+), 1 deletion(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index 82960a7e..6b00923d 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -version = __version__ = "4.61.0.193 Unreleased" +version = __version__ = "4.61.0.194 Unreleased" _change_log = """ Changelog since 4.60.0 released to PyPI on 8-May-2022 @@ -458,6 +458,8 @@ _change_log = """ Fixed bug in Button.update. Corrected when activeforeground and activebackground are set. Removing them in version above was a mistake 4.61.0.193 Fixed spelling errors... resuse should have been reuse + 4.61.0.194 + Added Listbox.select_index and Listbox.set_index_color """ @@ -3327,6 +3329,80 @@ class Listbox(Element): value = [] return value + + + def select_index(self, index, highlight_text_color=None, highlight_background_color=None): + """ + Selects an index while providing capability to setting the selected color for the index to specific text/background color + + :param index: specifies which item to change. index starts at 0 and goes to length of values list minus one + :type index: (int) + :param highlight_text_color: color of the text when this item is selected. + :type highlight_text_color: (str) + :param highlight_background_color: color of the background when this item is selected + :type highlight_background_color: (str) + """ + + if not self._widget_was_created(): # if widget hasn't been created yet, then don't allow + return + + if self._this_elements_window_closed(): + _error_popup_with_traceback('Error in Listbox.select_item - The window was closed') + return + + if index >= len(self.Values): + _error_popup_with_traceback('Index {} is out of range for Listbox.select_index. Max allowed index is {}.'.format(index, len(self.Values)-1)) + return + + self.TKListbox.selection_set(index, index) + + if highlight_text_color is not None: + text_color = highlight_text_color + else: + text_color = None + + if highlight_background_color is not None: + background_color = highlight_background_color + else: + background_color = None + + if text_color is not None: + self.widget.itemconfig(index, selectforeground=text_color) + if background_color is not None: + self.widget.itemconfig(index, selectbackground=background_color) + + + def set_index_color(self, index, text_color=None, background_color=None): + """ + Sets the color of a specific item without selecting it + + :param index: specifies which item to change. index starts at 0 and goes to length of values list minus one + :type index: (int) + :param text_color: color of the text for this item + :type text_color: (str) + :param background_color: color of the background for this item + :type background_color: (str) + """ + + if not self._widget_was_created(): # if widget hasn't been created yet, then don't allow + return + + if self._this_elements_window_closed(): + _error_popup_with_traceback('Error in Listbox.set_item_color - The window was closed') + return + + if index >= len(self.Values): + _error_popup_with_traceback('Index {} is out of range for Listbox.set_index_color. Max allowed index is {}.'.format(index, len(self.Values)-1)) + return + + + if text_color is not None: + self.widget.itemconfig(index, fg=text_color) + if background_color is not None: + self.widget.itemconfig(index, bg=background_color) + + + GetIndexes = get_indexes GetListValues = get_list_values SetValue = set_value From 393050c1ae085fa66b773410a685d4ffac8b4758 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Sun, 20 Aug 2023 17:20:05 -0400 Subject: [PATCH 112/145] New Udemy Coupon. Added Listbox.set_index_color and Listbox.select_index to the SDK Call Reference --- PySimpleGUI.py | 8 ++-- docs/call reference.md | 40 ++++++++++++++++++- docs/cookbook.md | 4 +- docs/index.md | 4 +- docs/readme.md | 4 +- .../markdown input files/1_HEADER_top_part.md | 4 +- .../markdown input files/5_call_reference.md | 10 ++++- readme_creator/output/call reference.md | 40 ++++++++++++++++++- readme_creator/output/index.md | 4 +- 9 files changed, 99 insertions(+), 19 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index 6b00923d..a91f9845 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -version = __version__ = "4.61.0.194 Unreleased" +version = __version__ = "4.61.0.195 Unreleased" _change_log = """ Changelog since 4.60.0 released to PyPI on 8-May-2022 @@ -460,6 +460,8 @@ _change_log = """ Fixed spelling errors... resuse should have been reuse 4.61.0.194 Added Listbox.select_index and Listbox.set_index_color + 4.61.0.195 + New Udemy Coupon """ @@ -26779,7 +26781,7 @@ def main(): elif event == 'Get Text': popup_scrolled('Returned:', popup_get_text('Enter some text', keep_on_top=True)) elif event.startswith('-UDEMY-'): - webbrowser.open_new_tab(r'https://www.udemy.com/course/pysimplegui/?couponCode=9AF99B123C49D51EB547') + webbrowser.open_new_tab(r'https://www.udemy.com/course/pysimplegui/?couponCode=62A4C02AB0A3DAB34388') elif event.startswith('-SPONSOR-'): if webbrowser_available: webbrowser.open_new_tab(r'https://www.paypal.me/pythongui') @@ -26787,7 +26789,7 @@ def main(): if webbrowser_available: webbrowser.open_new_tab(r'https://www.buymeacoffee.com/PySimpleGUI') elif event in ('-EMOJI-HEARTS-', '-HEART-', '-PYTHON HEARTS-'): - popup_scrolled("Oh look! It's a Udemy discount coupon!", '9AF99B123C49D51EB547', + popup_scrolled("Oh look! It's a Udemy discount coupon!", '62A4C02AB0A3DAB34388', 'A personal message from Mike -- thank you so very much for supporting PySimpleGUI!', title='Udemy Coupon', image=EMOJI_BASE64_MIKE, keep_on_top=True) elif event == 'Themes': search_string = popup_get_text('Enter a search term or leave blank for all themes', 'Show Available Themes', keep_on_top=True) diff --git a/docs/call reference.md b/docs/call reference.md index b004ccac..37b27a5b 100644 --- a/docs/call reference.md +++ b/docs/call reference.md @@ -25,9 +25,9 @@ apply coupon for discount: - 9AF99B123C49D51EB547. + 62A4C02AB0A3DAB34388.
-
@@ -5583,6 +5583,24 @@ Metadata is an Element property that you can use at any time to hold any value |---|---|---| |(Any)| **return** | the current metadata value | +### select_index + +Selects an index while providing capability to setting the selected color for the index to specific text/background color + +``` +select_index(index, + highlight_text_color = None, + highlight_background_color = None) +``` + +Parameter Descriptions: + +|Type|Name|Meaning| +|--|--|--| +| int | index | specifies which item to change. index starts at 0 and goes to length of values list minus one | +| str | highlight_text_color | color of the text when this item is selected. | +| str | highlight_background_color | color of the background when this item is selected | + ### set_cursor Sets the cursor for the current Element. @@ -5616,6 +5634,24 @@ Parameter Descriptions: |--|--|--| | bool | force | if True will call focus_force otherwise calls focus_set | +### set_index_color + +Sets the color of a specific item without selecting it + +``` +set_index_color(index, + text_color = None, + background_color = None) +``` + +Parameter Descriptions: + +|Type|Name|Meaning| +|--|--|--| +| int | index | specifies which item to change. index starts at 0 and goes to length of values list minus one | +| str | text_color | color of the text for this item | +| str | background_color | color of the background for this item | + ### set_size Changes the size of an element to a specific size. diff --git a/docs/cookbook.md b/docs/cookbook.md index 98473f4c..4281f426 100644 --- a/docs/cookbook.md +++ b/docs/cookbook.md @@ -25,9 +25,9 @@ apply coupon for discount: - F988F082A3D18483B1C5 + 62A4C02AB0A3DAB34388
-
diff --git a/docs/index.md b/docs/index.md index 11810190..a7ddf342 100644 --- a/docs/index.md +++ b/docs/index.md @@ -25,9 +25,9 @@ apply coupon for discount: - 9AF99B123C49D51EB547 + 62A4C02AB0A3DAB34388
-
diff --git a/docs/readme.md b/docs/readme.md index 03488cae..7233b9b7 100644 --- a/docs/readme.md +++ b/docs/readme.md @@ -9,8 +9,8 @@ PySimpleGUI Udemy Course
-
apply coupon for discount:
F988F082A3D18483B1C5
- click here to visit course page +
apply coupon for discount:
62A4C02AB0A3DAB34388
+ click here to visit course page
diff --git a/readme_creator/markdown input files/1_HEADER_top_part.md b/readme_creator/markdown input files/1_HEADER_top_part.md index 320a4997..926f75f5 100644 --- a/readme_creator/markdown input files/1_HEADER_top_part.md +++ b/readme_creator/markdown input files/1_HEADER_top_part.md @@ -52,9 +52,9 @@ HOW DO I INSERT IMAGES ??? apply coupon for discount: - 9AF99B123C49D51EB547 + 62A4C02AB0A3DAB34388 - diff --git a/readme_creator/markdown input files/5_call_reference.md b/readme_creator/markdown input files/5_call_reference.md index 1f690a41..07fdb13a 100644 --- a/readme_creator/markdown input files/5_call_reference.md +++ b/readme_creator/markdown input files/5_call_reference.md @@ -25,9 +25,9 @@ apply coupon for discount: - 9AF99B123C49D51EB547. + 62A4C02AB0A3DAB34388. - @@ -1207,12 +1207,18 @@ The following methods are here for backwards compatibility reference. You will ### metadata +### select_index + + ### set_cursor ### set_focus +### set_index_color + + ### set_size diff --git a/readme_creator/output/call reference.md b/readme_creator/output/call reference.md index b004ccac..37b27a5b 100644 --- a/readme_creator/output/call reference.md +++ b/readme_creator/output/call reference.md @@ -25,9 +25,9 @@ apply coupon for discount: - 9AF99B123C49D51EB547. + 62A4C02AB0A3DAB34388. - @@ -5583,6 +5583,24 @@ Metadata is an Element property that you can use at any time to hold any value |---|---|---| |(Any)| **return** | the current metadata value | +### select_index + +Selects an index while providing capability to setting the selected color for the index to specific text/background color + +``` +select_index(index, + highlight_text_color = None, + highlight_background_color = None) +``` + +Parameter Descriptions: + +|Type|Name|Meaning| +|--|--|--| +| int | index | specifies which item to change. index starts at 0 and goes to length of values list minus one | +| str | highlight_text_color | color of the text when this item is selected. | +| str | highlight_background_color | color of the background when this item is selected | + ### set_cursor Sets the cursor for the current Element. @@ -5616,6 +5634,24 @@ Parameter Descriptions: |--|--|--| | bool | force | if True will call focus_force otherwise calls focus_set | +### set_index_color + +Sets the color of a specific item without selecting it + +``` +set_index_color(index, + text_color = None, + background_color = None) +``` + +Parameter Descriptions: + +|Type|Name|Meaning| +|--|--|--| +| int | index | specifies which item to change. index starts at 0 and goes to length of values list minus one | +| str | text_color | color of the text for this item | +| str | background_color | color of the background for this item | + ### set_size Changes the size of an element to a specific size. diff --git a/readme_creator/output/index.md b/readme_creator/output/index.md index 11810190..a7ddf342 100644 --- a/readme_creator/output/index.md +++ b/readme_creator/output/index.md @@ -25,9 +25,9 @@ apply coupon for discount: - 9AF99B123C49D51EB547 + 62A4C02AB0A3DAB34388 - From 77ea65b8de11685f0c68ec662250c461af8a1c37 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Mon, 21 Aug 2023 17:31:08 -0400 Subject: [PATCH 113/145] Added highlight colors to the set_index_color method. Parms highlight_text_color & highlight_background_color control changing the highlight colors --- PySimpleGUI.py | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index a91f9845..ed42523a 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -version = __version__ = "4.61.0.195 Unreleased" +version = __version__ = "4.61.0.196 Unreleased" _change_log = """ Changelog since 4.60.0 released to PyPI on 8-May-2022 @@ -462,6 +462,9 @@ _change_log = """ Added Listbox.select_index and Listbox.set_index_color 4.61.0.195 New Udemy Coupon + 4.61.0.196 + Added highlight colors to the set_index_color method. Parms highlight_text_color & highlight_background_color control changing the highlight colors + """ @@ -3332,7 +3335,6 @@ class Listbox(Element): return value - def select_index(self, index, highlight_text_color=None, highlight_background_color=None): """ Selects an index while providing capability to setting the selected color for the index to specific text/background color @@ -3359,31 +3361,25 @@ class Listbox(Element): self.TKListbox.selection_set(index, index) if highlight_text_color is not None: - text_color = highlight_text_color - else: - text_color = None - + self.widget.itemconfig(index, selectforeground=highlight_text_color) if highlight_background_color is not None: - background_color = highlight_background_color - else: - background_color = None - - if text_color is not None: - self.widget.itemconfig(index, selectforeground=text_color) - if background_color is not None: - self.widget.itemconfig(index, selectbackground=background_color) + self.widget.itemconfig(index, selectbackground=highlight_background_color) - def set_index_color(self, index, text_color=None, background_color=None): + def set_index_color(self, index, text_color=None, background_color=None, highlight_text_color=None, highlight_background_color=None): """ Sets the color of a specific item without selecting it - :param index: specifies which item to change. index starts at 0 and goes to length of values list minus one - :type index: (int) - :param text_color: color of the text for this item - :type text_color: (str) - :param background_color: color of the background for this item - :type background_color: (str) + :param index: specifies which item to change. index starts at 0 and goes to length of values list minus one + :type index: (int) + :param text_color: color of the text for this item + :type text_color: (str) + :param background_color: color of the background for this item + :type background_color: (str) + :param highlight_text_color: color of the text when this item is selected. + :type highlight_text_color: (str) + :param highlight_background_color: color of the background when this item is selected + :type highlight_background_color: (str) """ if not self._widget_was_created(): # if widget hasn't been created yet, then don't allow @@ -3397,11 +3393,15 @@ class Listbox(Element): _error_popup_with_traceback('Index {} is out of range for Listbox.set_index_color. Max allowed index is {}.'.format(index, len(self.Values)-1)) return - if text_color is not None: self.widget.itemconfig(index, fg=text_color) if background_color is not None: self.widget.itemconfig(index, bg=background_color) + if highlight_text_color is not None: + self.widget.itemconfig(index, selectforeground=highlight_text_color) + if highlight_background_color is not None: + self.widget.itemconfig(index, selectbackground=highlight_background_color) + From 0b6eb6d5b3c5c2c9cf98c70679b79aef703507d7 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Mon, 21 Aug 2023 17:33:27 -0400 Subject: [PATCH 114/145] Rebuilt the call reference based on new set_index_color parms --- docs/call reference.md | 12 ++++++++---- readme_creator/output/call reference.md | 12 ++++++++---- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/docs/call reference.md b/docs/call reference.md index 37b27a5b..cc0bd9ef 100644 --- a/docs/call reference.md +++ b/docs/call reference.md @@ -5641,16 +5641,20 @@ Sets the color of a specific item without selecting it ``` set_index_color(index, text_color = None, - background_color = None) + background_color = None, + highlight_text_color = None, + highlight_background_color = None) ``` Parameter Descriptions: |Type|Name|Meaning| |--|--|--| -| int | index | specifies which item to change. index starts at 0 and goes to length of values list minus one | -| str | text_color | color of the text for this item | -| str | background_color | color of the background for this item | +| int | index | specifies which item to change. index starts at 0 and goes to length of values list minus one | +| str | text_color | color of the text for this item | +| str | background_color | color of the background for this item | +| str | highlight_text_color | color of the text when this item is selected. | +| str | highlight_background_color | color of the background when this item is selected | ### set_size diff --git a/readme_creator/output/call reference.md b/readme_creator/output/call reference.md index 37b27a5b..cc0bd9ef 100644 --- a/readme_creator/output/call reference.md +++ b/readme_creator/output/call reference.md @@ -5641,16 +5641,20 @@ Sets the color of a specific item without selecting it ``` set_index_color(index, text_color = None, - background_color = None) + background_color = None, + highlight_text_color = None, + highlight_background_color = None) ``` Parameter Descriptions: |Type|Name|Meaning| |--|--|--| -| int | index | specifies which item to change. index starts at 0 and goes to length of values list minus one | -| str | text_color | color of the text for this item | -| str | background_color | color of the background for this item | +| int | index | specifies which item to change. index starts at 0 and goes to length of values list minus one | +| str | text_color | color of the text for this item | +| str | background_color | color of the background for this item | +| str | highlight_text_color | color of the text when this item is selected. | +| str | highlight_background_color | color of the background when this item is selected | ### set_size From cf3345303d72360f379597ce9ca4c58123fdc88c Mon Sep 17 00:00:00 2001 From: PySimpleGUI <46163555+PySimpleGUI@users.noreply.github.com> Date: Sat, 26 Aug 2023 17:30:18 +0000 Subject: [PATCH 115/145] Automated Update! --- docs/Screens.md | 7 +++++++ docs/Screens2.md | 9 +++++++++ 2 files changed, 16 insertions(+) diff --git a/docs/Screens.md b/docs/Screens.md index d2c5e36d..6353ed9c 100644 --- a/docs/Screens.md +++ b/docs/Screens.md @@ -1,3 +1,10 @@ +[definite-d](https://github.com/definite-d) 2023-08-26T16:34:23Z + +![launcher_dark](https://github.com/PySimpleGUI/PySimpleGUI/assets/38317208/579bc2be-abaa-4fd6-a1ea-609ada3be1a9) +![editor_dark](https://github.com/PySimpleGUI/PySimpleGUI/assets/38317208/725fd3bd-4147-4b45-a034-c85b5bd3d74d) + +----------- + [luisegarduno](https://github.com/luisegarduno) 2023-06-25T05:18:40Z ![image](https://github.com/PySimpleGUI/PySimpleGUI/assets/30121656/80b10f6e-30f7-4159-8574-5f79bff705b1) diff --git a/docs/Screens2.md b/docs/Screens2.md index f2b1b736..2f5c4952 100644 --- a/docs/Screens2.md +++ b/docs/Screens2.md @@ -1,3 +1,12 @@ +[definite-d](https://github.com/definite-d) 2023-08-26T16:34:23Z +[Themera](https://github.com/definite-d/Themera) v2.1.0 has been released (available [here](https://github.com/definite-d/Themera/releases/tag/v2.1.0)). I'd like to share screenshots and point out that with Windows 11, the color of the "built-in" titlebar can be customized. I accomplished it within Themera with a bit of a non-standard solution, but it's proof of concept. + +![launcher_dark](https://github.com/PySimpleGUI/PySimpleGUI/assets/38317208/579bc2be-abaa-4fd6-a1ea-609ada3be1a9) +![editor_dark](https://github.com/PySimpleGUI/PySimpleGUI/assets/38317208/725fd3bd-4147-4b45-a034-c85b5bd3d74d) + + +----------- + [luisegarduno](https://github.com/luisegarduno) 2023-06-25T05:18:40Z **Chess (updated!)** From 0459adac698f3c0c682270a936474991622b1c75 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Mon, 28 Aug 2023 07:09:38 -0400 Subject: [PATCH 116/145] Made Table Element Header mouse-over and clicked be the inverse of the normal header colors. Makes for a much nicer experience --- PySimpleGUI.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index ed42523a..862cef08 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -version = __version__ = "4.61.0.196 Unreleased" +version = __version__ = "4.61.0.197 Unreleased" _change_log = """ Changelog since 4.60.0 released to PyPI on 8-May-2022 @@ -464,6 +464,8 @@ _change_log = """ New Udemy Coupon 4.61.0.196 Added highlight colors to the set_index_color method. Parms highlight_text_color & highlight_background_color control changing the highlight colors + 4.61.0.197 + Made Table Element Header mouse-over and clicked be the inverse of the normal header colors. Makes for a much nicer experience """ @@ -17854,6 +17856,13 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form): table_style.configure(style_name, font=font) if element.BorderWidth is not None: table_style.configure(style_name, borderwidth=element.BorderWidth) + + if element.HeaderBackgroundColor not in (None, COLOR_SYSTEM_DEFAULT) and element.HeaderTextColor not in (None, COLOR_SYSTEM_DEFAULT): + table_style.map(style_name + ".Heading", background=[('pressed', '!focus', element.HeaderBackgroundColor), + ('active', element.HeaderTextColor),]) + table_style.map(style_name + ".Heading", foreground=[('pressed', '!focus', element.HeaderTextColor), + ('active', element.HeaderBackgroundColor),]) + treeview.configure(style=style_name) # scrollable_frame.pack(side=tk.LEFT, padx=elementpad[0], pady=elementpad[1], expand=True, fill='both') if element.enable_click_events is True: From 3907e7636e199a3097c3d28671a536deea5fc676 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Thu, 31 Aug 2023 12:18:43 -0400 Subject: [PATCH 117/145] Added Added no_buffering option to popup_animated --- PySimpleGUI.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index 862cef08..dbcb1c82 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -version = __version__ = "4.61.0.197 Unreleased" +version = __version__ = "4.61.0.198 Unreleased" _change_log = """ Changelog since 4.60.0 released to PyPI on 8-May-2022 @@ -466,6 +466,8 @@ _change_log = """ Added highlight colors to the set_index_color method. Parms highlight_text_color & highlight_background_color control changing the highlight colors 4.61.0.197 Made Table Element Header mouse-over and clicked be the inverse of the normal header colors. Makes for a much nicer experience + 4.61.0.198 + Added no_buffering option to popup_animated """ @@ -22435,7 +22437,7 @@ def popup_get_date(start_mon=None, start_day=None, start_year=None, begin_at_sun # --------------------------- PopupAnimated --------------------------- def popup_animated(image_source, message=None, background_color=None, text_color=None, font=None, no_titlebar=True, grab_anywhere=True, keep_on_top=True, - location=(None, None), relative_location=(None, None), alpha_channel=None, time_between_frames=0, transparent_color=None, title='', icon=None): + location=(None, None), relative_location=(None, None), alpha_channel=None, time_between_frames=0, transparent_color=None, title='', icon=None, no_buffering=False): """ Show animation one frame at a time. This function has its own internal clocking meaning you can call it at any frequency and the rate the frames of video is shown remains constant. Maybe your frames update every 30 ms but your @@ -22472,6 +22474,8 @@ def popup_animated(image_source, message=None, background_color=None, text_color :type title: (str) :param icon: Same as Window icon parameter. Can be either a filename or Base64 byte string. For Windows if filename, it MUST be ICO format. For Linux, must NOT be ICO :type icon: str | bytes + :param no_buffering: If True then no buffering will be used for the GIF. May work better if you have a large animation + :type no_buffering: (str) :return: True if the window updated OK. False if the window was closed :rtype: bool """ @@ -22497,7 +22501,10 @@ def popup_animated(image_source, message=None, background_color=None, text_color Window._animated_popup_dict[image_source] = window else: window = Window._animated_popup_dict[image_source] - window['-IMAGE-'].update_animation(image_source, time_between_frames=time_between_frames) + if no_buffering: + window['-IMAGE-'].update_animation_no_buffering(image_source, time_between_frames=time_between_frames) + else: + window['-IMAGE-'].update_animation(image_source, time_between_frames=time_between_frames) event, values = window.read(1) if event == WIN_CLOSED: return False From ed128a36f565c8c1c2ca7113fb86d73755ec454a Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Thu, 31 Aug 2023 12:24:21 -0400 Subject: [PATCH 118/145] fixed bool instead of string in doctring --- PySimpleGUI.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index dbcb1c82..6550b58f 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -22475,7 +22475,7 @@ def popup_animated(image_source, message=None, background_color=None, text_color :param icon: Same as Window icon parameter. Can be either a filename or Base64 byte string. For Windows if filename, it MUST be ICO format. For Linux, must NOT be ICO :type icon: str | bytes :param no_buffering: If True then no buffering will be used for the GIF. May work better if you have a large animation - :type no_buffering: (str) + :type no_buffering: (bool) :return: True if the window updated OK. False if the window was closed :rtype: bool """ From 48c7b673c192e4f4a2d9236c7ecb268cc4f89746 Mon Sep 17 00:00:00 2001 From: PySimpleGUI <46163555+PySimpleGUI@users.noreply.github.com> Date: Wed, 6 Sep 2023 17:30:28 +0000 Subject: [PATCH 119/145] Automated Update! --- docs/Screens.md | 6 ++++++ docs/Screens2.md | 12 ++++++++++++ 2 files changed, 18 insertions(+) diff --git a/docs/Screens.md b/docs/Screens.md index 6353ed9c..b144cc08 100644 --- a/docs/Screens.md +++ b/docs/Screens.md @@ -1,3 +1,9 @@ +[onyx-and-iris](https://github.com/onyx-and-iris) 2023-09-06T00:00:13Z + +![image](https://github.com/PySimpleGUI/PySimpleGUI/assets/55352169/f99212f5-1870-4387-ba4c-159dd40d4c8e) + +----------- + [definite-d](https://github.com/definite-d) 2023-08-26T16:34:23Z ![launcher_dark](https://github.com/PySimpleGUI/PySimpleGUI/assets/38317208/579bc2be-abaa-4fd6-a1ea-609ada3be1a9) diff --git a/docs/Screens2.md b/docs/Screens2.md index 2f5c4952..e95633b4 100644 --- a/docs/Screens2.md +++ b/docs/Screens2.md @@ -1,3 +1,15 @@ +[onyx-and-iris](https://github.com/onyx-and-iris) 2023-09-06T00:00:13Z +A small remote utility for Voicemeeter, designed to work with the NVDA screen reader. + +![image](https://github.com/PySimpleGUI/PySimpleGUI/assets/55352169/f99212f5-1870-4387-ba4c-159dd40d4c8e) +https://github.com/onyx-and-iris/nvda-voicemeeter + +Thanks for creating PYSimpleGUI, first time using but very impressed! + + + +----------- + [definite-d](https://github.com/definite-d) 2023-08-26T16:34:23Z [Themera](https://github.com/definite-d/Themera) v2.1.0 has been released (available [here](https://github.com/definite-d/Themera/releases/tag/v2.1.0)). I'd like to share screenshots and point out that with Windows 11, the color of the "built-in" titlebar can be customized. I accomplished it within Themera with a bit of a non-standard solution, but it's proof of concept. From ce32fe3814e3850f8781ca8494404a635de89b20 Mon Sep 17 00:00:00 2001 From: PySimpleGUI <46163555+PySimpleGUI@users.noreply.github.com> Date: Sat, 9 Sep 2023 17:30:27 +0000 Subject: [PATCH 120/145] Automated Update! --- docs/Screens.md | 12 ++++++------ docs/Screens2.md | 14 +++++++------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/docs/Screens.md b/docs/Screens.md index b144cc08..b8b9d02c 100644 --- a/docs/Screens.md +++ b/docs/Screens.md @@ -695,7 +695,7 @@ ----------- -[vohe](https://github.com/vohe) 2022-01-23T13:53:09Z +[ghost](https://github.com/ghost) 2022-01-23T13:53:09Z ![AudioRecScreenshot](https://user-images.githubusercontent.com/7021635/150681690-1874c8c0-4464-46a4-ae0f-748a618fb845.png) @@ -1191,13 +1191,13 @@ ----------- -[vohe](https://github.com/vohe) 2020-08-08T11:11:29Z +[ghost](https://github.com/ghost) 2020-08-08T11:11:29Z ![Picture](https://user-images.githubusercontent.com/7021635/89708548-82ae8600-d978-11ea-8a8d-59b24e092830.png) ----------- -[vohe](https://github.com/vohe) 2020-08-05T13:31:05Z +[ghost](https://github.com/ghost) 2020-08-05T13:31:05Z ![Popup Directory](https://user-images.githubusercontent.com/7021635/89418628-9c5d8c80-d730-11ea-9f6f-42d190cfdbf5.png) ![Popup Directory2](https://user-images.githubusercontent.com/7021635/89418636-9e275000-d730-11ea-8de6-f02c4a304701.png) @@ -1210,13 +1210,13 @@ ----------- -[vohe](https://github.com/vohe) 2020-08-02T17:28:23Z +[ghost](https://github.com/ghost) 2020-08-02T17:28:23Z ![mockupall](https://user-images.githubusercontent.com/7021635/89128448-ec9cda80-d4f5-11ea-965d-05cef5844f8f.png) ----------- -[vohe](https://github.com/vohe) 2020-07-05T16:45:42Z +[ghost](https://github.com/ghost) 2020-07-05T16:45:42Z ![english](https://user-images.githubusercontent.com/7021635/86537489-b61c7180-beef-11ea-9b65-4d11b0a4d515.png) ![german](https://user-images.githubusercontent.com/7021635/86537492-b7e63500-beef-11ea-8b41-e79d1cbbc904.png) @@ -1224,7 +1224,7 @@ ----------- -[vohe](https://github.com/vohe) 2020-07-04T15:43:31Z +[ghost](https://github.com/ghost) 2020-07-04T15:43:31Z ![Audiorecorder (spotify)](https://user-images.githubusercontent.com/7021635/86515989-6a00fc80-be1d-11ea-89c9-08411c829eb7.png) diff --git a/docs/Screens2.md b/docs/Screens2.md index e95633b4..a5cc70d1 100644 --- a/docs/Screens2.md +++ b/docs/Screens2.md @@ -2384,7 +2384,7 @@ Obviously the GUI was the easy part! ----------- -[vohe](https://github.com/vohe) 2022-01-23T13:53:09Z +[ghost](https://github.com/ghost) 2022-01-23T13:53:09Z The Januar Version is ready to go. I manged it , finally, to work without lastfm. For everyone who can use this: Audiorecorder,, records (e.g.) spotify web player - with free account. @@ -4507,7 +4507,7 @@ GitHub.com/MOABdali/megaCheckers if anyone wants to try it. Please keep in mind ----------- -[vohe](https://github.com/vohe) 2020-08-08T11:11:29Z +[ghost](https://github.com/ghost) 2020-08-08T11:11:29Z Ready to go, I found that putting move than 3000 elements in a sg.treedata() structure works, but as i close that there'll be a huge garbage collection of tkinter under the hood. So my directory popup window isn't usable for a 'normal' user directory, especially if the show hidden files option is active. @@ -4521,7 +4521,7 @@ Have Fun, stay healthy. ----------- -[vohe](https://github.com/vohe) 2020-08-05T13:31:05Z +[ghost](https://github.com/ghost) 2020-08-05T13:31:05Z In addition to get a Folder Browser running , which does not - show hidden files, - throws errors on Permissions @@ -4544,7 +4544,7 @@ The bars for each color have the color of the original image and the other-color ----------- -[vohe](https://github.com/vohe) 2020-08-02T17:28:23Z +[ghost](https://github.com/ghost) 2020-08-02T17:28:23Z Hi folks, here is another one i playing with.... The TreeElement is not as flexible as i want it. But many things are possible. @@ -4554,7 +4554,7 @@ I got the functionallity i want, but the interface isn't that what i like to get ----------- -[vohe](https://github.com/vohe) 2020-07-05T16:45:42Z +[ghost](https://github.com/ghost) 2020-07-05T16:45:42Z Thank you, first of all i got it as i like (but not so elegant) First of all it works. ![english](https://user-images.githubusercontent.com/7021635/86537489-b61c7180-beef-11ea-9b65-4d11b0a4d515.png) @@ -4579,7 +4579,7 @@ https://github.com/PySimpleGUI/PySimpleGUI/issues/new?assignees=&labels=&templat ----------- -[vohe](https://github.com/vohe) 2020-07-04T21:28:44Z +[ghost](https://github.com/ghost) 2020-07-04T21:28:44Z > Very nice @vohe ! Thanks for posting it! > I like they use of tabs. Great , simple layout. I might have to use that idea for settings sometime. It's never dawned on me before to put them into a tab like that. @@ -4596,7 +4596,7 @@ I like they use of tabs. Great , simple layout. I might have to use that idea ----------- -[vohe](https://github.com/vohe) 2020-07-04T15:43:31Z +[ghost](https://github.com/ghost) 2020-07-04T15:43:31Z ![Audiorecorder (spotify)](https://user-images.githubusercontent.com/7021635/86515989-6a00fc80-be1d-11ea-89c9-08411c829eb7.png) A little Programm, that records files form a webside (actually open.spotify) store them as mp3, tag them, sort them into directorys , notify the user when a new song is beginning. From 4504ea77c3be661e1cad3dcb73febb4b1f8c3eda Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Thu, 21 Sep 2023 16:09:33 -0400 Subject: [PATCH 121/145] New Udemy Coupon --- docs/call reference.md | 12 ++++++++---- docs/cookbook.md | 4 ++-- docs/index.md | 8 +++++--- docs/readme.md | 4 ++-- readme.md | 4 ++-- .../markdown input files/1_HEADER_top_part.md | 4 ++-- .../markdown input files/5_call_reference.md | 4 ++-- readme_creator/output/call reference.md | 12 ++++++++---- readme_creator/output/index.md | 8 +++++--- 9 files changed, 36 insertions(+), 24 deletions(-) diff --git a/docs/call reference.md b/docs/call reference.md index cc0bd9ef..08ca758c 100644 --- a/docs/call reference.md +++ b/docs/call reference.md @@ -25,9 +25,9 @@ apply coupon for discount: - 62A4C02AB0A3DAB34388. + 2F6C6BE01B8940D3E457. - @@ -16903,7 +16903,8 @@ popup_animated(image_source, time_between_frames = 0, transparent_color = None, title = "", - icon = None) + icon = None, + no_buffering = False) ``` Parameter Descriptions: @@ -16925,6 +16926,7 @@ Parameter Descriptions: | str | transparent_color | This color will be completely see-through in your window. Can even click through | | str | title | Title that will be shown on the window | | str or bytes | icon | Same as Window icon parameter. Can be either a filename or Base64 byte string. For Windows if filename, it MUST be ICO format. For Linux, must NOT be ICO | +| bool | no_buffering | If True then no buffering will be used for the GIF. May work better if you have a large animation | | bool | **RETURN** | True if the window updated OK. False if the window was closed Popup that closes itself after some time period @@ -17987,7 +17989,8 @@ PopupAnimated(image_source, time_between_frames = 0, transparent_color = None, title = "", - icon = None) + icon = None, + no_buffering = False) ``` Parameter Descriptions: @@ -18009,6 +18012,7 @@ Parameter Descriptions: | str | transparent_color | This color will be completely see-through in your window. Can even click through | | str | title | Title that will be shown on the window | | str or bytes | icon | Same as Window icon parameter. Can be either a filename or Base64 byte string. For Windows if filename, it MUST be ICO format. For Linux, must NOT be ICO | +| bool | no_buffering | If True then no buffering will be used for the GIF. May work better if you have a large animation | | bool | **RETURN** | True if the window updated OK. False if the window was closed Display a Popup without a titlebar. Enables grab anywhere so you can move it diff --git a/docs/cookbook.md b/docs/cookbook.md index 4281f426..3637ddd3 100644 --- a/docs/cookbook.md +++ b/docs/cookbook.md @@ -25,9 +25,9 @@ apply coupon for discount: - 62A4C02AB0A3DAB34388 + 2F6C6BE01B8940D3E457 - diff --git a/docs/index.md b/docs/index.md index a7ddf342..6c855457 100644 --- a/docs/index.md +++ b/docs/index.md @@ -25,9 +25,9 @@ apply coupon for discount: - 62A4C02AB0A3DAB34388 + 2F6C6BE01B8940D3E457 - @@ -2028,7 +2028,8 @@ popup_animated(image_source, time_between_frames = 0, transparent_color = None, title = "", - icon = None) + icon = None, + no_buffering = False) ``` Parameter Descriptions: @@ -2050,6 +2051,7 @@ Parameter Descriptions: | str | transparent_color | This color will be completely see-through in your window. Can even click through | | str | title | Title that will be shown on the window | | str or bytes | icon | Same as Window icon parameter. Can be either a filename or Base64 byte string. For Windows if filename, it MUST be ICO format. For Linux, must NOT be ICO | +| bool | no_buffering | If True then no buffering will be used for the GIF. May work better if you have a large animation | | bool | **RETURN** | True if the window updated OK. False if the window was closed ***To close animated popups***, call PopupAnimated with `image_source=None`. This will close all of the currently open PopupAnimated windows. diff --git a/docs/readme.md b/docs/readme.md index 7233b9b7..e73b6075 100644 --- a/docs/readme.md +++ b/docs/readme.md @@ -9,8 +9,8 @@ PySimpleGUI Udemy Course -
apply coupon for discount:
62A4C02AB0A3DAB34388
- click here to visit course page +
apply coupon for discount:
2F6C6BE01B8940D3E457
+ click here to visit course page diff --git a/readme.md b/readme.md index 03488cae..e73b6075 100644 --- a/readme.md +++ b/readme.md @@ -9,8 +9,8 @@ PySimpleGUI Udemy Course -
apply coupon for discount:
F988F082A3D18483B1C5
- click here to visit course page +
apply coupon for discount:
2F6C6BE01B8940D3E457
+ click here to visit course page diff --git a/readme_creator/markdown input files/1_HEADER_top_part.md b/readme_creator/markdown input files/1_HEADER_top_part.md index 926f75f5..ca75d9e5 100644 --- a/readme_creator/markdown input files/1_HEADER_top_part.md +++ b/readme_creator/markdown input files/1_HEADER_top_part.md @@ -52,9 +52,9 @@ HOW DO I INSERT IMAGES ??? apply coupon for discount: - 62A4C02AB0A3DAB34388 + 2F6C6BE01B8940D3E457 - diff --git a/readme_creator/markdown input files/5_call_reference.md b/readme_creator/markdown input files/5_call_reference.md index 07fdb13a..7b223866 100644 --- a/readme_creator/markdown input files/5_call_reference.md +++ b/readme_creator/markdown input files/5_call_reference.md @@ -25,9 +25,9 @@ apply coupon for discount: - 62A4C02AB0A3DAB34388. + 2F6C6BE01B8940D3E457. - diff --git a/readme_creator/output/call reference.md b/readme_creator/output/call reference.md index cc0bd9ef..08ca758c 100644 --- a/readme_creator/output/call reference.md +++ b/readme_creator/output/call reference.md @@ -25,9 +25,9 @@ apply coupon for discount: - 62A4C02AB0A3DAB34388. + 2F6C6BE01B8940D3E457. - @@ -16903,7 +16903,8 @@ popup_animated(image_source, time_between_frames = 0, transparent_color = None, title = "", - icon = None) + icon = None, + no_buffering = False) ``` Parameter Descriptions: @@ -16925,6 +16926,7 @@ Parameter Descriptions: | str | transparent_color | This color will be completely see-through in your window. Can even click through | | str | title | Title that will be shown on the window | | str or bytes | icon | Same as Window icon parameter. Can be either a filename or Base64 byte string. For Windows if filename, it MUST be ICO format. For Linux, must NOT be ICO | +| bool | no_buffering | If True then no buffering will be used for the GIF. May work better if you have a large animation | | bool | **RETURN** | True if the window updated OK. False if the window was closed Popup that closes itself after some time period @@ -17987,7 +17989,8 @@ PopupAnimated(image_source, time_between_frames = 0, transparent_color = None, title = "", - icon = None) + icon = None, + no_buffering = False) ``` Parameter Descriptions: @@ -18009,6 +18012,7 @@ Parameter Descriptions: | str | transparent_color | This color will be completely see-through in your window. Can even click through | | str | title | Title that will be shown on the window | | str or bytes | icon | Same as Window icon parameter. Can be either a filename or Base64 byte string. For Windows if filename, it MUST be ICO format. For Linux, must NOT be ICO | +| bool | no_buffering | If True then no buffering will be used for the GIF. May work better if you have a large animation | | bool | **RETURN** | True if the window updated OK. False if the window was closed Display a Popup without a titlebar. Enables grab anywhere so you can move it diff --git a/readme_creator/output/index.md b/readme_creator/output/index.md index a7ddf342..6c855457 100644 --- a/readme_creator/output/index.md +++ b/readme_creator/output/index.md @@ -25,9 +25,9 @@ apply coupon for discount: - 62A4C02AB0A3DAB34388 + 2F6C6BE01B8940D3E457 - @@ -2028,7 +2028,8 @@ popup_animated(image_source, time_between_frames = 0, transparent_color = None, title = "", - icon = None) + icon = None, + no_buffering = False) ``` Parameter Descriptions: @@ -2050,6 +2051,7 @@ Parameter Descriptions: | str | transparent_color | This color will be completely see-through in your window. Can even click through | | str | title | Title that will be shown on the window | | str or bytes | icon | Same as Window icon parameter. Can be either a filename or Base64 byte string. For Windows if filename, it MUST be ICO format. For Linux, must NOT be ICO | +| bool | no_buffering | If True then no buffering will be used for the GIF. May work better if you have a large animation | | bool | **RETURN** | True if the window updated OK. False if the window was closed ***To close animated popups***, call PopupAnimated with `image_source=None`. This will close all of the currently open PopupAnimated windows. From 2470d10afc797e34688cb356c76060fa6d4c90e4 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Mon, 2 Oct 2023 09:52:10 -0400 Subject: [PATCH 122/145] New Udemy coupons... added earlier but forgot to post to GitHub --- PySimpleGUI.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index 6550b58f..97c3835c 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -version = __version__ = "4.61.0.198 Unreleased" +version = __version__ = "4.61.0.199 Unreleased" _change_log = """ Changelog since 4.60.0 released to PyPI on 8-May-2022 @@ -468,7 +468,8 @@ _change_log = """ Made Table Element Header mouse-over and clicked be the inverse of the normal header colors. Makes for a much nicer experience 4.61.0.198 Added no_buffering option to popup_animated - + 4.61.0.199 + Updated Udemy coupon code """ @@ -26797,7 +26798,7 @@ def main(): elif event == 'Get Text': popup_scrolled('Returned:', popup_get_text('Enter some text', keep_on_top=True)) elif event.startswith('-UDEMY-'): - webbrowser.open_new_tab(r'https://www.udemy.com/course/pysimplegui/?couponCode=62A4C02AB0A3DAB34388') + webbrowser.open_new_tab(r'https://www.udemy.com/course/pysimplegui/?couponCode=2F6C6BE01B8940D3E457') elif event.startswith('-SPONSOR-'): if webbrowser_available: webbrowser.open_new_tab(r'https://www.paypal.me/pythongui') @@ -26805,7 +26806,7 @@ def main(): if webbrowser_available: webbrowser.open_new_tab(r'https://www.buymeacoffee.com/PySimpleGUI') elif event in ('-EMOJI-HEARTS-', '-HEART-', '-PYTHON HEARTS-'): - popup_scrolled("Oh look! It's a Udemy discount coupon!", '62A4C02AB0A3DAB34388', + popup_scrolled("Oh look! It's a Udemy discount coupon!", '2F6C6BE01B8940D3E457', 'A personal message from Mike -- thank you so very much for supporting PySimpleGUI!', title='Udemy Coupon', image=EMOJI_BASE64_MIKE, keep_on_top=True) elif event == 'Themes': search_string = popup_get_text('Enter a search term or leave blank for all themes', 'Show Available Themes', keep_on_top=True) From 5f8735d1f3268a161e7f3b2e54d0668a1dd26e2e Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Mon, 2 Oct 2023 13:12:48 -0400 Subject: [PATCH 123/145] 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! --- PySimpleGUI.py | 78 ++++++++++++++++++++++++-------------------------- 1 file changed, 38 insertions(+), 40 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index 97c3835c..1bc733af 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -version = __version__ = "4.61.0.199 Unreleased" +version = __version__ = "4.61.0.200 Unreleased" _change_log = """ Changelog since 4.60.0 released to PyPI on 8-May-2022 @@ -470,6 +470,8 @@ _change_log = """ Added no_buffering option to popup_animated 4.61.0.199 Updated Udemy coupon code + 4.61.0.200 + 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! """ @@ -11745,8 +11747,8 @@ class Window: :param event: event information passed in by tkinter. Contains x,y position of mouse :type event: (event) """ - - self._StartMove(event) + self._start_move_save_offset(event) + return def _StartMoveGrabAnywhere(self, event): @@ -11760,31 +11762,11 @@ class Window: if (isinstance(event.widget, GRAB_ANYWHERE_IGNORE_THESE_WIDGETS) or event.widget in self._grab_anywhere_ignore_these_list) and event.widget not in self._grab_anywhere_include_these_list: # print('Found widget to ignore in grab anywhere...') return - - self._StartMove(event) - + self._start_move_save_offset(event) def _StartMove(self, event): - try: - geometry = self.TKroot.geometry() - location = geometry[geometry.find('+')+1:].split('+') - self._startx = int(location[0]) - self._starty = int(location[1]) - self._mousex = event.x + event.widget.winfo_rootx() - self._mousey = event.y + event.widget.winfo_rooty() - # print(self._startx, self._starty) - # print(self._mousex, self._mousey) - # print(self.TKroot.geometry()) - except: - pass - # print('Start move {},{} widget {}'.format(event.x,event.y, event.widget)) - - if Window._move_all_windows: - for window in Window._active_windows: - window._offsetx = event.x + event.widget.winfo_rootx() - window.TKroot.winfo_rootx() - window._offsety = event.y + event.widget.winfo_rooty() - window.TKroot.winfo_rooty() - - + self._start_move_save_offset(event) + return def _StopMove(self, event): """ @@ -11795,6 +11777,28 @@ class Window: """ return + def _start_move_save_offset(self, event): + self._mousex = event.x + event.widget.winfo_rootx() + self._mousey = event.y + event.widget.winfo_rooty() + geometry = self.TKroot.geometry() + location = geometry[geometry.find('+') + 1:].split('+') + self._startx = int(location[0]) + self._starty = int(location[1]) + self._mouse_offset_x = self._mousex - self._startx + self._mouse_offset_y = self._mousey - self._starty + # ------ Move All Windows code ------ + if Window._move_all_windows: + # print('Moving all') + for win in Window._active_windows: + if win == self: + continue + geometry = win.TKroot.geometry() + location = geometry[geometry.find('+') + 1:].split('+') + _startx = int(location[0]) + _starty = int(location[1]) + win._mouse_offset_x = event.x_root - _startx + win._mouse_offset_y = event.y_root - _starty + def _OnMotionUsingControlKey(self, event): self._OnMotion(event) @@ -11815,22 +11819,16 @@ class Window: def _OnMotion(self, event): - try: - _mousex = event.x + event.widget.winfo_rootx() - _mousey = event.y + event.widget.winfo_rooty() - deltax = _mousex - self._mousex - deltay = _mousey - self._mousey - x = self._startx + deltax - y = self._starty + deltay - self.TKroot.geometry("+%s+%s" % (x, y)) # this is what really moves the window + self.TKroot.geometry(f"+{event.x_root-self._mouse_offset_x}+{event.y_root-self._mouse_offset_y}") + # print(f"+{event.x_root}+{event.y_root}") + # ------ Move All Windows code ------ + try: if Window._move_all_windows: - for window in Window._active_windows: - deltax = window._offsetx - deltay = window._offsety - x = window.TKroot.winfo_pointerx() - deltax - y = window.TKroot.winfo_pointery() - deltay - window.TKroot.geometry("+%s+%s" % (x, y)) # this is what really moves the window + for win in Window._active_windows: + if win == self: + continue + win.TKroot.geometry(f"+{event.x_root-win._mouse_offset_x}+{event.y_root-win._mouse_offset_y}") except Exception as e: print('on motion error', e) From ddebd7a5c603a027fae70eaba20a6eff5dcedae0 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Thu, 5 Oct 2023 15:03:52 -0400 Subject: [PATCH 124/145] Added init for _mouse_offset_x and y in case tkinter doesn't call the mouse down callback --- PySimpleGUI.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index 1bc733af..c6cf892a 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -version = __version__ = "4.61.0.200 Unreleased" +version = __version__ = "4.61.0.201 Unreleased" _change_log = """ Changelog since 4.60.0 released to PyPI on 8-May-2022 @@ -472,6 +472,8 @@ _change_log = """ Updated Udemy coupon code 4.61.0.200 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! + 4.61.0.201 + Added init for _mouse_offset_x and y in case tkinter doesn't call the mouse down callback """ @@ -10618,6 +10620,7 @@ class Window: if self.use_custom_titlebar: self.Margins = (0, 0) self.NoTitleBar = True + self._mouse_offset_x = self._mouse_offset_y = 0 if watermark is True: Window._watermark_temp_forced = True @@ -26985,4 +26988,4 @@ if __name__ == '__main__': exit(0) main() exit(0) -#8191dd5d8352d3c13f89bde32cdd01d664da2f4cabeff579ec281e413131545b6aafe489020f8f73c96477dbdf9e86e0013c01759cae8c5837d9d7ea44c7fc75f9af3fb5bce6270b0254f6f6f2d966abc5257991792b3d83880d7690a85e8f4b59e4051b0ff2f7ac1a5fa27d5630c2365d70398b22cda91c1a988c4f19379c4575afb6f6c86e873e0bcda2ed4fc65879a8c4c7a297437742b1ac070de6d04019ffc5e350d6030ce97965d0414ef48ea670ba21bb359319f1c8be7e6da2ff46c727ea82f54eb30d3a74728b5aa20e1412b6812750cfb8cb6122b3e720f0a2c0106d7ddb0eba9313ed763aa3f404221e0d4ffe9bb324a56ebb410e5cd6f45f6b985db5c39369d1fe201fc2ee7c9e8017e8eb7a9e08edafa15ad8a89f6214b75b8e183e2dde4c67350975999d7f74572f0f17d422a9ca430c928f80e2ffee4dd376ce916999b7a263b39783ddf54242b1341e70240c6875832525d87100c9a733d09969465e38226d80ead49508692eb9851eaa4fba26ca5069cb2c6ee88647c79683860d9b12fa598a1d452015d80295a1b59236c38f8fb42edf1aa897db653f8c20ce79836641cc64c1e5975b8400edc98854ab5c26de57241ce8b89979173b84f9cf3e5dd455a63721545001b06af63a8b11ed7889a4e53af7a1527bbd3e14ae6e6a16eb569c79d7213d52e7f276f1a59423fb3a519adc122b73128196aec80a \ No newline at end of file +#5550034f4202b0dde48a8ff1a870d871f1759f6e59b3a92f40150e8c42204e1b06eaafbe206994c7f0ff811df9f61018269480e40a91fe781b16dac2c81dfe0c0977090f8557e435b97d4d8e7c5ec1c91f2be19033b9dc2f5a8f16e0b5d1cab1e692d998dbb4f5fc26b551befa483142430c1cadee39363aba10ed19675867ed15ef534fd40fcdf38c811e3431751de160dd6eb567091160b936a580305902387dca997ce20b90f80984644e8289882eabf1809b3f54f98a80ea80f2c5a644ebeac34413cf68b4c8cf2c7d69072abee5fddd075e7daae6f7644e4eba3deaa228cc4d4dbcb59cdc62c73c2c830f630653cc10646d314eeba1736f43a8a603c57221eb9977f2ad6a05692f87f161238e8514b317d20fcaec1e84faead09e0e8c9ecac402c38a021b490086fd3d07d3f2777627f21946f0ff1b4b0e66d28e1b0484a21b9d61f4929bfd9ca58c48ec1e7bd764cbfe21cc827ae7239d544ee324a0f4a1d9d4aa75d5e76a0fed5f8540ba275fdc3684d2d7b722028cabee2d3d7aa469ab4c9cf5c3c66cb7dbcc749b57991988e726c5191ac02224d345d87ba6eb5b209f5f755fa1318f10034de6c828aead47f333f80de385ae13e0a0be2a8c76cfa9162c24c6ff9dc55c0031af42464adaf2ccb95bebbd17f24cfd2938140c3538109491bea1f409c7358dde3a2466f4788a68cd3c3bb45cbd33589475a149617549 \ No newline at end of file From 377673070981329149108f9e088da0ed305ce835 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Thu, 5 Oct 2023 16:11:51 -0400 Subject: [PATCH 125/145] Replaced PIL's deprecated constant ANTIALIAS with LANCZOS --- DemoPrograms/Demo_Buttons_Nice_Graphics.py | 2 +- DemoPrograms/Demo_Desktop_Widget_Digital_Picture_Frame.py | 2 +- DemoPrograms/Demo_Emoji_Toolbar_PIL.py | 2 +- DemoPrograms/Demo_Graph_Elem_Image_Album.py | 2 +- DemoPrograms/Demo_Image_Elem_Image_Viewer_PIL_Based.py | 2 +- DemoPrograms/Demo_Image_Resize_and_Base64_Encode.pyw | 2 +- DemoPrograms/Demo_Image_Viewer_Thumbnails.py | 2 +- DemoPrograms/Demo_Matplotlib_Grid_of_Graphs_Using_PIL.py | 2 +- DemoPrograms/Demo_Nice_Buttons.py | 2 +- DemoPrograms/Demo_PIL_Use.py | 2 +- DemoPrograms/Demo_PNG_Thumbnail_Viewer.py | 6 +++--- DemoPrograms/Demo_System_Tray_Reminder.py | 2 +- docs/cookbook.md | 4 ++-- 13 files changed, 16 insertions(+), 16 deletions(-) diff --git a/DemoPrograms/Demo_Buttons_Nice_Graphics.py b/DemoPrograms/Demo_Buttons_Nice_Graphics.py index 3d372416..45b3c915 100644 --- a/DemoPrograms/Demo_Buttons_Nice_Graphics.py +++ b/DemoPrograms/Demo_Buttons_Nice_Graphics.py @@ -26,7 +26,7 @@ def resize_base64_image(image64, size): ''' image_file = io.BytesIO(base64.b64decode(image64)) img = Image.open(image_file) - img.thumbnail(size, Image.ANTIALIAS) + img.thumbnail(size, Image.LANCZOS) bio = io.BytesIO() img.save(bio, format='PNG') imgbytes = bio.getvalue() diff --git a/DemoPrograms/Demo_Desktop_Widget_Digital_Picture_Frame.py b/DemoPrograms/Demo_Desktop_Widget_Digital_Picture_Frame.py index 8aec989c..2e5f6bb0 100644 --- a/DemoPrograms/Demo_Desktop_Widget_Digital_Picture_Frame.py +++ b/DemoPrograms/Demo_Desktop_Widget_Digital_Picture_Frame.py @@ -81,7 +81,7 @@ def convert_to_bytes(source, size=(None, None), subsample=None, zoom=None, fill= elif zoom is not None: scale = zoom - resized_image = image.resize((int(width * scale), int(height * scale)), Image.ANTIALIAS) if scale is not None else image + 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 diff --git a/DemoPrograms/Demo_Emoji_Toolbar_PIL.py b/DemoPrograms/Demo_Emoji_Toolbar_PIL.py index 0ff22ce9..ee4b84b5 100644 --- a/DemoPrograms/Demo_Emoji_Toolbar_PIL.py +++ b/DemoPrograms/Demo_Emoji_Toolbar_PIL.py @@ -92,7 +92,7 @@ def convert_to_bytes(file_or_bytes, resize=None, fill=False): if resize: new_width, new_height = resize 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 resize is not None: img = make_square(img, resize[0]) diff --git a/DemoPrograms/Demo_Graph_Elem_Image_Album.py b/DemoPrograms/Demo_Graph_Elem_Image_Album.py index 115f72c5..90f2770e 100644 --- a/DemoPrograms/Demo_Graph_Elem_Image_Album.py +++ b/DemoPrograms/Demo_Graph_Elem_Image_Album.py @@ -44,7 +44,7 @@ def convert_to_bytes(file_or_bytes, resize=None): if resize: new_width, new_height = resize 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() img.save(bio, format="PNG") del img diff --git a/DemoPrograms/Demo_Image_Elem_Image_Viewer_PIL_Based.py b/DemoPrograms/Demo_Image_Elem_Image_Viewer_PIL_Based.py index 715bb351..9cb05b8c 100644 --- a/DemoPrograms/Demo_Image_Elem_Image_Viewer_PIL_Based.py +++ b/DemoPrograms/Demo_Image_Elem_Image_Viewer_PIL_Based.py @@ -45,7 +45,7 @@ def convert_to_bytes(file_or_bytes, resize=None): if resize: new_width, new_height = resize 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: img.save(bio, format="PNG") del img diff --git a/DemoPrograms/Demo_Image_Resize_and_Base64_Encode.pyw b/DemoPrograms/Demo_Image_Resize_and_Base64_Encode.pyw index 12e880be..f1a00789 100644 --- a/DemoPrograms/Demo_Image_Resize_and_Base64_Encode.pyw +++ b/DemoPrograms/Demo_Image_Resize_and_Base64_Encode.pyw @@ -55,7 +55,7 @@ def resize(input_file, size, output_file=None, encode_format='PNG'): new_width, new_height = 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) - 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: resized_image = image diff --git a/DemoPrograms/Demo_Image_Viewer_Thumbnails.py b/DemoPrograms/Demo_Image_Viewer_Thumbnails.py index c766fed2..43742cc8 100644 --- a/DemoPrograms/Demo_Image_Viewer_Thumbnails.py +++ b/DemoPrograms/Demo_Image_Viewer_Thumbnails.py @@ -56,7 +56,7 @@ def convert_to_bytes(file_or_bytes, resize=None, fill=False): if resize: new_width, new_height = resize 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: img = make_square(img, THUMBNAIL_SIZE[0]) with io.BytesIO() as bio: diff --git a/DemoPrograms/Demo_Matplotlib_Grid_of_Graphs_Using_PIL.py b/DemoPrograms/Demo_Matplotlib_Grid_of_Graphs_Using_PIL.py index f42f26ee..fb253de3 100644 --- a/DemoPrograms/Demo_Matplotlib_Grid_of_Graphs_Using_PIL.py +++ b/DemoPrograms/Demo_Matplotlib_Grid_of_Graphs_Using_PIL.py @@ -890,7 +890,7 @@ def convert_to_bytes(file_or_bytes, resize=None): if resize: new_width, new_height = resize 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: img.save(bio, format="PNG") del img diff --git a/DemoPrograms/Demo_Nice_Buttons.py b/DemoPrograms/Demo_Nice_Buttons.py index a1cefe13..9e782d11 100644 --- a/DemoPrograms/Demo_Nice_Buttons.py +++ b/DemoPrograms/Demo_Nice_Buttons.py @@ -15,7 +15,7 @@ button64 = 'iVBORw0KGgoAAAANSUhEUgAAAoAAAAFACAMAAAAbEz04AAAABGdBTUEAALGPC/xhBQAA def image_file_to_bytes(image64, size): image_file = io.BytesIO(base64.b64decode(image64)) img = Image.open(image_file) - img.thumbnail(size, Image.ANTIALIAS) + img.thumbnail(size, Image.LANCZOS) bio = io.BytesIO() img.save(bio, format='PNG') imgbytes = bio.getvalue() diff --git a/DemoPrograms/Demo_PIL_Use.py b/DemoPrograms/Demo_PIL_Use.py index ca7a37a4..0854e242 100644 --- a/DemoPrograms/Demo_PIL_Use.py +++ b/DemoPrograms/Demo_PIL_Use.py @@ -60,7 +60,7 @@ def convert_to_bytes(source, size=(None, None), subsample=None, zoom=None, fill= elif zoom is not None: scale = zoom - resized_image = image.resize((int(width * scale), int(height * scale)), Image.ANTIALIAS) if scale is not None else image + 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 diff --git a/DemoPrograms/Demo_PNG_Thumbnail_Viewer.py b/DemoPrograms/Demo_PNG_Thumbnail_Viewer.py index 36e1d8c6..3056c3ad 100644 --- a/DemoPrograms/Demo_PNG_Thumbnail_Viewer.py +++ b/DemoPrograms/Demo_PNG_Thumbnail_Viewer.py @@ -59,7 +59,7 @@ def convert_to_bytes(file_or_bytes, resize=None): if resize: new_width, new_height = resize 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: img.save(bio, format="PNG") del img @@ -69,7 +69,7 @@ def convert_to_bytes(file_or_bytes, resize=None): # def image_file_to_bytes(filename, size): # try: # image = Image.open(filename) -# image.thumbnail(size, Image.ANTIALIAS) +# image.thumbnail(size, Image.LANCZOS) # bio = io.BytesIO() # a binary memory resident stream # image.save(bio, format='PNG') # save image as png to it # imgbytes = bio.getvalue() @@ -80,7 +80,7 @@ def convert_to_bytes(file_or_bytes, resize=None): def set_image_to_blank(key): 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() img.save(bio, format='PNG') imgbytes = bio.getvalue() diff --git a/DemoPrograms/Demo_System_Tray_Reminder.py b/DemoPrograms/Demo_System_Tray_Reminder.py index b93d883e..94bba7cb 100644 --- a/DemoPrograms/Demo_System_Tray_Reminder.py +++ b/DemoPrograms/Demo_System_Tray_Reminder.py @@ -29,7 +29,7 @@ def resize_base64_image(image64, size): """ image_file = io.BytesIO(base64.b64decode(image64)) img = Image.open(image_file) - img.thumbnail(size, Image.ANTIALIAS) + img.thumbnail(size, Image.LANCZOS) bio = io.BytesIO() img.save(bio, format='PNG') imgbytes = bio.getvalue() diff --git a/docs/cookbook.md b/docs/cookbook.md index 3637ddd3..cc8789b6 100644 --- a/docs/cookbook.md +++ b/docs/cookbook.md @@ -2664,7 +2664,7 @@ def convert_to_bytes(file_or_bytes, resize=None): if resize: new_width, new_height = resize 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() img.save(bio, format="PNG") del img @@ -2747,7 +2747,7 @@ def convert_to_bytes(file_or_bytes, resize=None): if resize: new_width, new_height = resize 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() img.save(bio, format="PNG") del img From 7f485c5f78f29cd961cd96cff5d3fefa41c49623 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Thu, 5 Oct 2023 16:26:20 -0400 Subject: [PATCH 126/145] Remove extra space accidently added (learned you can put spaces after periods in Python?) --- DemoPrograms/Demo_Emoji_Toolbar_PIL.py | 2 +- DemoPrograms/Demo_Graph_Elem_Image_Album.py | 2 +- DemoPrograms/Demo_Image_Elem_Image_Viewer_PIL_Based.py | 2 +- DemoPrograms/Demo_Image_Viewer_Thumbnails.py | 2 +- DemoPrograms/Demo_Matplotlib_Grid_of_Graphs_Using_PIL.py | 2 +- DemoPrograms/Demo_PNG_Thumbnail_Viewer.py | 4 ++-- docs/cookbook.md | 4 ++-- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/DemoPrograms/Demo_Emoji_Toolbar_PIL.py b/DemoPrograms/Demo_Emoji_Toolbar_PIL.py index ee4b84b5..dd0cecee 100644 --- a/DemoPrograms/Demo_Emoji_Toolbar_PIL.py +++ b/DemoPrograms/Demo_Emoji_Toolbar_PIL.py @@ -92,7 +92,7 @@ def convert_to_bytes(file_or_bytes, resize=None, fill=False): if resize: new_width, new_height = resize scale = min(new_height / cur_height, new_width / cur_width) - img = img.resize((int(cur_width * scale), int(cur_height * scale)), PIL. Image.LANCZOS) + img = img.resize((int(cur_width * scale), int(cur_height * scale)), PIL.Image.LANCZOS) if fill: if resize is not None: img = make_square(img, resize[0]) diff --git a/DemoPrograms/Demo_Graph_Elem_Image_Album.py b/DemoPrograms/Demo_Graph_Elem_Image_Album.py index 90f2770e..4a38454f 100644 --- a/DemoPrograms/Demo_Graph_Elem_Image_Album.py +++ b/DemoPrograms/Demo_Graph_Elem_Image_Album.py @@ -44,7 +44,7 @@ def convert_to_bytes(file_or_bytes, resize=None): if resize: new_width, new_height = resize scale = min(new_height/cur_height, new_width/cur_width) - img = img.resize((int(cur_width*scale), int(cur_height*scale)), PIL. Image.LANCZOS) + img = img.resize((int(cur_width*scale), int(cur_height*scale)), PIL.Image.LANCZOS) bio = io.BytesIO() img.save(bio, format="PNG") del img diff --git a/DemoPrograms/Demo_Image_Elem_Image_Viewer_PIL_Based.py b/DemoPrograms/Demo_Image_Elem_Image_Viewer_PIL_Based.py index 9cb05b8c..9585b96c 100644 --- a/DemoPrograms/Demo_Image_Elem_Image_Viewer_PIL_Based.py +++ b/DemoPrograms/Demo_Image_Elem_Image_Viewer_PIL_Based.py @@ -45,7 +45,7 @@ def convert_to_bytes(file_or_bytes, resize=None): if resize: new_width, new_height = resize scale = min(new_height/cur_height, new_width/cur_width) - img = img.resize((int(cur_width*scale), int(cur_height*scale)), PIL. Image.LANCZOS) + img = img.resize((int(cur_width*scale), int(cur_height*scale)), PIL.Image.LANCZOS) with io.BytesIO() as bio: img.save(bio, format="PNG") del img diff --git a/DemoPrograms/Demo_Image_Viewer_Thumbnails.py b/DemoPrograms/Demo_Image_Viewer_Thumbnails.py index 43742cc8..d7f77498 100644 --- a/DemoPrograms/Demo_Image_Viewer_Thumbnails.py +++ b/DemoPrograms/Demo_Image_Viewer_Thumbnails.py @@ -56,7 +56,7 @@ def convert_to_bytes(file_or_bytes, resize=None, fill=False): if resize: new_width, new_height = resize scale = min(new_height / cur_height, new_width / cur_width) - img = img.resize((int(cur_width * scale), int(cur_height * scale)), PIL. Image.LANCZOS) + img = img.resize((int(cur_width * scale), int(cur_height * scale)), PIL.Image.LANCZOS) if fill: img = make_square(img, THUMBNAIL_SIZE[0]) with io.BytesIO() as bio: diff --git a/DemoPrograms/Demo_Matplotlib_Grid_of_Graphs_Using_PIL.py b/DemoPrograms/Demo_Matplotlib_Grid_of_Graphs_Using_PIL.py index fb253de3..09097450 100644 --- a/DemoPrograms/Demo_Matplotlib_Grid_of_Graphs_Using_PIL.py +++ b/DemoPrograms/Demo_Matplotlib_Grid_of_Graphs_Using_PIL.py @@ -890,7 +890,7 @@ def convert_to_bytes(file_or_bytes, resize=None): if resize: new_width, new_height = resize scale = min(new_height/cur_height, new_width/cur_width) - img = img.resize((int(cur_width*scale), int(cur_height*scale)), PIL. Image.LANCZOS) + img = img.resize((int(cur_width*scale), int(cur_height*scale)), PIL.Image.LANCZOS) with io.BytesIO() as bio: img.save(bio, format="PNG") del img diff --git a/DemoPrograms/Demo_PNG_Thumbnail_Viewer.py b/DemoPrograms/Demo_PNG_Thumbnail_Viewer.py index 3056c3ad..9b400da0 100644 --- a/DemoPrograms/Demo_PNG_Thumbnail_Viewer.py +++ b/DemoPrograms/Demo_PNG_Thumbnail_Viewer.py @@ -59,7 +59,7 @@ def convert_to_bytes(file_or_bytes, resize=None): if resize: new_width, new_height = resize scale = min(new_height / cur_height, new_width / cur_width) - img = img.resize((int(cur_width * scale), int(cur_height * scale)), PIL. Image.LANCZOS) + img = img.resize((int(cur_width * scale), int(cur_height * scale)), PIL.Image.LANCZOS) with io.BytesIO() as bio: img.save(bio, format="PNG") del img @@ -80,7 +80,7 @@ def convert_to_bytes(file_or_bytes, resize=None): def set_image_to_blank(key): img = PIL.Image.new('RGB', (100, 100), (255, 255, 255)) - img.thumbnail((1, 1), PIL. Image.LANCZOS) + img.thumbnail((1, 1), PIL.Image.LANCZOS) bio = io.BytesIO() img.save(bio, format='PNG') imgbytes = bio.getvalue() diff --git a/docs/cookbook.md b/docs/cookbook.md index cc8789b6..5a2b26a2 100644 --- a/docs/cookbook.md +++ b/docs/cookbook.md @@ -2664,7 +2664,7 @@ def convert_to_bytes(file_or_bytes, resize=None): if resize: new_width, new_height = resize scale = min(new_height/cur_height, new_width/cur_width) - img = img.resize((int(cur_width*scale), int(cur_height*scale)), PIL. Image.LANCZOS) + img = img.resize((int(cur_width*scale), int(cur_height*scale)), PIL.Image.LANCZOS) bio = io.BytesIO() img.save(bio, format="PNG") del img @@ -2747,7 +2747,7 @@ def convert_to_bytes(file_or_bytes, resize=None): if resize: new_width, new_height = resize scale = min(new_height/cur_height, new_width/cur_width) - img = img.resize((int(cur_width*scale), int(cur_height*scale)), PIL. Image.LANCZOS) + img = img.resize((int(cur_width*scale), int(cur_height*scale)), PIL.Image.LANCZOS) bio = io.BytesIO() img.save(bio, format="PNG") del img From fe31a0a7ed3dc60dfe3c59f15ec2c406335a978f Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Mon, 16 Oct 2023 08:57:47 -0400 Subject: [PATCH 127/145] Fixed numpy deprecated problems. Checking in improvement made long ago buit forgot to check in --- DemoPrograms/Demo_Sudoku.py | 87 +++++++++++++++++-------------------- 1 file changed, 40 insertions(+), 47 deletions(-) diff --git a/DemoPrograms/Demo_Sudoku.py b/DemoPrograms/Demo_Sudoku.py index 7e6ba67b..041faf96 100644 --- a/DemoPrograms/Demo_Sudoku.py +++ b/DemoPrograms/Demo_Sudoku.py @@ -2,18 +2,17 @@ import PySimpleGUI as sg, random import numpy as np from typing import List, Any, Union, Tuple, Dict - """ Sudoku Puzzle Demo - + How to easily generate a GUI for a Sudoku puzzle. The Window definition and creation is a single line of code. - + Code to generate a playable puzzle was supplied from: https://github.com/MorvanZhou/sudoku - + Copyright 2020 PySimpleGUI.com - + """ @@ -27,7 +26,7 @@ def generate_sudoku(mask_rate): """ while True: n = 9 - solution = np.zeros((n, n), np.int) + solution = np.zeros((n, n), np.int_) rg = np.arange(1, n + 1) solution[0, :] = np.random.choice(rg, n, replace=False) try: @@ -36,10 +35,11 @@ def generate_sudoku(mask_rate): col_rest = np.setdiff1d(rg, solution[:r, c]) row_rest = np.setdiff1d(rg, solution[r, :c]) avb1 = np.intersect1d(col_rest, row_rest) - 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()) + 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()) 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 except ValueError: pass @@ -48,7 +48,6 @@ def generate_sudoku(mask_rate): return puzzle, solution - def check_progress(window, solution): """ Gives you a visual hint on your progress. @@ -65,38 +64,23 @@ def check_progress(window, solution): solved = True for r, row in enumerate(solution): for c, col in enumerate(row): - value = window[r,c].get() + value = window[r, c].get() if value: try: value = int(value) except: value = 0 if value != solution[r][c]: - window[r,c].update(background_color='red') + window[r, c].update(background_color='red') solved = False else: - window[r,c].update(background_color=sg.theme_input_background_color()) + window[r, c].update(background_color=sg.theme_input_background_color()) else: solved = False window[r, c].update(background_color='yellow') 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): """" 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) """ - - + 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. # 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] # To get a better understanding, take it apart. Spread it out. You'll learn in the process. 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.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) + [[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 + 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 - puzzle, solution = create_and_show_puzzle(window) - check_showing = False - while True: # The Event Loop + puzzle, solution = create_and_show_puzzle() + + while True: # The Event Loop event, values = window.read() - if event == sg.WIN_CLOSED: + if event is None: break if event == 'Solve': @@ -131,7 +128,6 @@ def main(mask_rate=0.7): for c, col in enumerate(row): window[r, c].update(solution[r][c], background_color=sg.theme_input_background_color()) elif event == 'Check': - check_showing = True solved = check_progress(window, solution) if solved: sg.popup('Solved! You have solved the puzzle correctly.') @@ -140,17 +136,14 @@ def main(mask_rate=0.7): try: elem.update(solution[elem.Key[0]][elem.Key[1]], background_color=sg.theme_input_background_color()) 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': - puzzle, solution = create_and_show_puzzle(window) - 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()) + puzzle, solution = create_and_show_puzzle() + window.close() -if __name__ == "__main__": - DEFAULT_MASK_RATE = 0.7 # % Of cells to hide - main(DEFAULT_MASK_RATE) + +if __name__ == "__main__": + mask_rate = 0.7 # % Of cells to hide + main(mask_rate) From 5131c537f522e054c43b7b4ee39e72a6792344e9 Mon Sep 17 00:00:00 2001 From: PySimpleGUI <46163555+PySimpleGUI@users.noreply.github.com> Date: Fri, 20 Oct 2023 17:30:27 +0000 Subject: [PATCH 128/145] Automated Update! --- docs/Screens2.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/Screens2.md b/docs/Screens2.md index a5cc70d1..1171933c 100644 --- a/docs/Screens2.md +++ b/docs/Screens2.md @@ -1,3 +1,13 @@ +[maria-korosteleva](https://github.com/maria-korosteleva) 2023-10-20T11:52:13Z +I've used the framework to build a garment design configurator in my latest research paper on programmable garments =) +https://github.com/maria-korosteleva/GarmentCode +https://igl.ethz.ch/projects/garmentcode/ + +Screenshot GUI_2_mosaic + + +----------- + [onyx-and-iris](https://github.com/onyx-and-iris) 2023-09-06T00:00:13Z A small remote utility for Voicemeeter, designed to work with the NVDA screen reader. From 746b79d61a0d7be1960c7be6a0ab94d49c0bc796 Mon Sep 17 00:00:00 2001 From: PySimpleGUI <46163555+PySimpleGUI@users.noreply.github.com> Date: Sat, 21 Oct 2023 17:30:27 +0000 Subject: [PATCH 129/145] Automated Update! --- docs/Screens.md | 6 ++++++ docs/Screens2.md | 7 +++++++ 2 files changed, 13 insertions(+) diff --git a/docs/Screens.md b/docs/Screens.md index b8b9d02c..54dbbdfd 100644 --- a/docs/Screens.md +++ b/docs/Screens.md @@ -1,3 +1,9 @@ +[PySimpleGUI](https://github.com/PySimpleGUI) 2023-10-21T16:11:14Z + +![image](https://github.com/PySimpleGUI/PySimpleGUI/assets/46163555/c2881407-2cd6-43ee-86e5-10005caed189) + +----------- + [onyx-and-iris](https://github.com/onyx-and-iris) 2023-09-06T00:00:13Z ![image](https://github.com/PySimpleGUI/PySimpleGUI/assets/55352169/f99212f5-1870-4387-ba4c-159dd40d4c8e) diff --git a/docs/Screens2.md b/docs/Screens2.md index 1171933c..2df21734 100644 --- a/docs/Screens2.md +++ b/docs/Screens2.md @@ -1,3 +1,10 @@ +[PySimpleGUI](https://github.com/PySimpleGUI) 2023-10-21T16:11:14Z +Wow @maria-korosteleva what an incredible application! I love what you've created! ![image](https://github.com/PySimpleGUI/PySimpleGUI/assets/46163555/c2881407-2cd6-43ee-86e5-10005caed189) + +I've never seen anything like what you've made. There's clearly a **lot** going on with your work than just a GUI. I had never thought about the intersection of CAD and making garments. It's a fascinating use of technology. I really appreciate you taking the time to post a screenshot and letting us know about your project. + +----------- + [maria-korosteleva](https://github.com/maria-korosteleva) 2023-10-20T11:52:13Z I've used the framework to build a garment design configurator in my latest research paper on programmable garments =) https://github.com/maria-korosteleva/GarmentCode From 29127a73eef3d0288bd96a869b83f8fdb222ac14 Mon Sep 17 00:00:00 2001 From: PySimpleGUI <46163555+PySimpleGUI@users.noreply.github.com> Date: Mon, 23 Oct 2023 17:30:23 +0000 Subject: [PATCH 130/145] Automated Update! --- docs/Screens2.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/Screens2.md b/docs/Screens2.md index 2df21734..ce1f808c 100644 --- a/docs/Screens2.md +++ b/docs/Screens2.md @@ -1,3 +1,9 @@ +[maria-korosteleva](https://github.com/maria-korosteleva) 2023-10-23T09:26:11Z +@PySimpleGUI Thank you very much for your kind words! 🥰 + + +----------- + [PySimpleGUI](https://github.com/PySimpleGUI) 2023-10-21T16:11:14Z Wow @maria-korosteleva what an incredible application! I love what you've created! ![image](https://github.com/PySimpleGUI/PySimpleGUI/assets/46163555/c2881407-2cd6-43ee-86e5-10005caed189) From 9b63e2e66102ed807822d3c06cfabdd24f927b28 Mon Sep 17 00:00:00 2001 From: PySimpleGUI <46163555+PySimpleGUI@users.noreply.github.com> Date: Thu, 26 Oct 2023 17:30:26 +0000 Subject: [PATCH 131/145] Automated Update! --- docs/Screens.md | 14 ++++++++++++++ docs/Screens2.md | 29 +++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/docs/Screens.md b/docs/Screens.md index 54dbbdfd..db331dba 100644 --- a/docs/Screens.md +++ b/docs/Screens.md @@ -1,3 +1,17 @@ +[PySimpleGUI](https://github.com/PySimpleGUI) 2023-10-26T09:38:54Z + +![image](https://github.com/PySimpleGUI/PySimpleGUI/assets/46163555/c68c3fdd-3bc3-4654-9cef-7b8cf1565443) + +----------- + +[ikeman32](https://github.com/ikeman32) 2023-10-25T21:58:09Z + +![image](https://github.com/PySimpleGUI/PySimpleGUI/assets/7841462/fdddd0e4-6654-41c0-a6c7-a9262c903e8d) +![image](https://github.com/PySimpleGUI/PySimpleGUI/assets/7841462/f61d5e2b-7178-4008-8fad-6ae482aa5cfc) +![image](https://github.com/PySimpleGUI/PySimpleGUI/assets/7841462/90dac6a7-92b0-4e34-9813-aa557d4a47e7) + +----------- + [PySimpleGUI](https://github.com/PySimpleGUI) 2023-10-21T16:11:14Z ![image](https://github.com/PySimpleGUI/PySimpleGUI/assets/46163555/c2881407-2cd6-43ee-86e5-10005caed189) diff --git a/docs/Screens2.md b/docs/Screens2.md index ce1f808c..41b51850 100644 --- a/docs/Screens2.md +++ b/docs/Screens2.md @@ -1,3 +1,32 @@ +[PySimpleGUI](https://github.com/PySimpleGUI) 2023-10-26T09:38:54Z +We're on very similar wavelengths @ikeman32. It's great to see some add-on tools to help users. + +As part of the PySimpleGUI 5 release of the PySimpleGUI applications and add-on modules, I've written a GUI tool that creates all of the necessary files to upload a PySimpleGUI application to PyPI, opening up distribution of Python applications to PySimpleGUI users. We've been releasing tools via PyPI for some time. "psgresizer" is a good example. Users can pip install it and then once installed it can be run by typing "psgresizer" from the command line. There's already a tool, psgshortcut, that takes it all a start further by making shortcuts (icons) that can be pinned to the taskbar or double-clicked. + +The idea is to make distribution easy as well as the result be familiar feeling. The command line isn't a normal part of a normal Windows user's world, so getting it out of the way entirely makes a lot of sense. I've just about got the final tool finished that will make it all work end to end. + +![image](https://github.com/PySimpleGUI/PySimpleGUI/assets/46163555/c68c3fdd-3bc3-4654-9cef-7b8cf1565443) + + +----------- + +[ikeman32](https://github.com/ikeman32) 2023-10-25T21:58:09Z +I have created a simple bash script to initialize a PySimpleGUI project. It can be found here: https://github.com/ikeman32/ScriptHelpers/tree/main/devscripts + +It's very basic at the moment, but functional. For Windows users, I do have an AI-generated port, but it remains untested as I gave up my Windows addiction in 2017. I may eventually create a platform-independent version of the script using Python. + +I do accept code contributions, so if there are Windows users that want to develop a Windows batch equivalent or a Python version of this script, see the README. Or you can code your own. + +PySimpleGUI is an absolute God-sent for me. I like simplicity, and I am also lazy, so if there is an easier way to do something, I'm all for it. I'm also in the planning stages for a visual editor/IDE for PySimpleGUI applications. + +![image](https://github.com/PySimpleGUI/PySimpleGUI/assets/7841462/fdddd0e4-6654-41c0-a6c7-a9262c903e8d) +![image](https://github.com/PySimpleGUI/PySimpleGUI/assets/7841462/f61d5e2b-7178-4008-8fad-6ae482aa5cfc) +![image](https://github.com/PySimpleGUI/PySimpleGUI/assets/7841462/90dac6a7-92b0-4e34-9813-aa557d4a47e7) + + + +----------- + [maria-korosteleva](https://github.com/maria-korosteleva) 2023-10-23T09:26:11Z @PySimpleGUI Thank you very much for your kind words! 🥰 From f78e4913a275d762ffd987191c0d412b0eb12c13 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Fri, 27 Oct 2023 11:36:53 -0400 Subject: [PATCH 132/145] New Udemy Coupon Code --- docs/cookbook.md | 8 ++++---- docs/readme.md | 4 ++-- readme.md | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/cookbook.md b/docs/cookbook.md index 5a2b26a2..c31e2319 100644 --- a/docs/cookbook.md +++ b/docs/cookbook.md @@ -25,9 +25,9 @@ apply coupon for discount: - 2F6C6BE01B8940D3E457 + C967880E71496470E40E - @@ -2664,7 +2664,7 @@ def convert_to_bytes(file_or_bytes, resize=None): if resize: new_width, new_height = resize scale = min(new_height/cur_height, new_width/cur_width) - img = img.resize((int(cur_width*scale), int(cur_height*scale)), PIL.Image.LANCZOS) + img = img.resize((int(cur_width*scale), int(cur_height*scale)), PIL.Image.ANTIALIAS) bio = io.BytesIO() img.save(bio, format="PNG") del img @@ -2747,7 +2747,7 @@ def convert_to_bytes(file_or_bytes, resize=None): if resize: new_width, new_height = resize scale = min(new_height/cur_height, new_width/cur_width) - img = img.resize((int(cur_width*scale), int(cur_height*scale)), PIL.Image.LANCZOS) + img = img.resize((int(cur_width*scale), int(cur_height*scale)), PIL.Image.ANTIALIAS) bio = io.BytesIO() img.save(bio, format="PNG") del img diff --git a/docs/readme.md b/docs/readme.md index e73b6075..2f5ece73 100644 --- a/docs/readme.md +++ b/docs/readme.md @@ -9,8 +9,8 @@ PySimpleGUI Udemy Course -
apply coupon for discount:
2F6C6BE01B8940D3E457
- click here to visit course page +
apply coupon for discount:
C967880E71496470E40E
+ click here to visit course page diff --git a/readme.md b/readme.md index e73b6075..2f5ece73 100644 --- a/readme.md +++ b/readme.md @@ -9,8 +9,8 @@ PySimpleGUI Udemy Course -
apply coupon for discount:
2F6C6BE01B8940D3E457
- click here to visit course page +
apply coupon for discount:
C967880E71496470E40E
+ click here to visit course page From 0f16031512678d0c0c80c3f868ededf20f39d6a0 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Fri, 27 Oct 2023 11:47:21 -0400 Subject: [PATCH 133/145] New yaml file for readthedocs --- readthedocs.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/readthedocs.yml b/readthedocs.yml index 47eaa0a4..b3c5d278 100644 --- a/readthedocs.yml +++ b/readthedocs.yml @@ -1,7 +1,10 @@ version: 2 +version: 2 +build: + os: "ubuntu-22.04" + python: - version: 3.6 install: - requirements: docs/requirements.txt From 1ee5a7f9d2460de4f3f9d5998303af16c2b59a3c Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Fri, 27 Oct 2023 11:49:01 -0400 Subject: [PATCH 134/145] Update readthedocs.yml --- readthedocs.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/readthedocs.yml b/readthedocs.yml index b3c5d278..d05298fb 100644 --- a/readthedocs.yml +++ b/readthedocs.yml @@ -3,7 +3,9 @@ version: 2 version: 2 build: os: "ubuntu-22.04" - + tools: + python: "3.11" + python: install: - requirements: docs/requirements.txt From bed18263e619cbbfdc77aed8a9e26657bbc1a9cf Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Fri, 27 Oct 2023 12:13:19 -0400 Subject: [PATCH 135/145] New udemy coupon. --- docs/call reference.md | 4 ++-- docs/index.md | 4 ++-- readme_creator/markdown input files/1_HEADER_top_part.md | 4 ++-- readme_creator/markdown input files/5_call_reference.md | 4 ++-- readme_creator/output/call reference.md | 4 ++-- readme_creator/output/index.md | 4 ++-- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/call reference.md b/docs/call reference.md index 08ca758c..ff8d87df 100644 --- a/docs/call reference.md +++ b/docs/call reference.md @@ -25,9 +25,9 @@ apply coupon for discount: - 2F6C6BE01B8940D3E457. + C967880E71496470E40E. - diff --git a/docs/index.md b/docs/index.md index 6c855457..58767359 100644 --- a/docs/index.md +++ b/docs/index.md @@ -25,9 +25,9 @@ apply coupon for discount: - 2F6C6BE01B8940D3E457 + C967880E71496470E40E - diff --git a/readme_creator/markdown input files/1_HEADER_top_part.md b/readme_creator/markdown input files/1_HEADER_top_part.md index ca75d9e5..a9aac931 100644 --- a/readme_creator/markdown input files/1_HEADER_top_part.md +++ b/readme_creator/markdown input files/1_HEADER_top_part.md @@ -52,9 +52,9 @@ HOW DO I INSERT IMAGES ??? apply coupon for discount: - 2F6C6BE01B8940D3E457 + C967880E71496470E40E - diff --git a/readme_creator/markdown input files/5_call_reference.md b/readme_creator/markdown input files/5_call_reference.md index 7b223866..a9ebf633 100644 --- a/readme_creator/markdown input files/5_call_reference.md +++ b/readme_creator/markdown input files/5_call_reference.md @@ -25,9 +25,9 @@ apply coupon for discount: - 2F6C6BE01B8940D3E457. + C967880E71496470E40E. - diff --git a/readme_creator/output/call reference.md b/readme_creator/output/call reference.md index 08ca758c..ff8d87df 100644 --- a/readme_creator/output/call reference.md +++ b/readme_creator/output/call reference.md @@ -25,9 +25,9 @@ apply coupon for discount: - 2F6C6BE01B8940D3E457. + C967880E71496470E40E. - diff --git a/readme_creator/output/index.md b/readme_creator/output/index.md index 6c855457..58767359 100644 --- a/readme_creator/output/index.md +++ b/readme_creator/output/index.md @@ -25,9 +25,9 @@ apply coupon for discount: - 2F6C6BE01B8940D3E457 + C967880E71496470E40E - From 85f3f472f7da67510a006ee89347bb30acee4321 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Sun, 29 Oct 2023 13:10:57 -0400 Subject: [PATCH 136/145] Added doctring and destroy previous right click menu to set_right_click_menu AND Changed Sizer element to use Canvas instead of Column element --- PySimpleGUI.py | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index c6cf892a..2b1489c6 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -version = __version__ = "4.61.0.201 Unreleased" +version = __version__ = "4.61.0.203 Unreleased" _change_log = """ Changelog since 4.60.0 released to PyPI on 8-May-2022 @@ -474,6 +474,10 @@ _change_log = """ 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! 4.61.0.201 Added init for _mouse_offset_x and y in case tkinter doesn't call the mouse down callback + 4.61.0.202 + Added doctring and destroy previous right click menu to set_right_click_menu + 4.61.0.203 + Changed Sizer element to use Canvas instead of Column element """ @@ -2267,6 +2271,12 @@ class Element(): def set_right_click_menu(self, menu=None): + """ + Sets a right click menu for an element. + If a menu is already set for the element, it will call the tkinter destroy method to remove it + :param menu: A list of lists of Menu items to show when this element is right clicked. See user docs for exact format. + :type menu: List[List[ List[str] | str ]] + """ if menu == MENU_RIGHT_CLICK_DISABLED: return if menu is None: @@ -2274,6 +2284,12 @@ class Element(): if menu is None: return if menu: + # If previously had a menu destroy it + if self.TKRightClickMenu: + try: + self.TKRightClickMenu.destroy() + except: + pass top_menu = tk.Menu(self.ParentForm.TKroot, tearoff=self.ParentForm.right_click_menu_tearoff, tearoffcommand=self._tearoff_menu_callback) if self.ParentForm.right_click_menu_background_color not in (COLOR_SYSTEM_DEFAULT, None): @@ -13595,8 +13611,8 @@ def Sizer(h_pixels=0, v_pixels=0): :rtype: (Column) """ - return Column([[]], pad=((h_pixels, 0), (v_pixels, 0))) - + # return Column([[]], pad=((h_pixels, 0), (v_pixels, 0))) + return Canvas(size=(h_pixels, v_pixels), pad=(0,0)) def pin(elem, vertical_alignment=None, shrink=True, expand_x=None, expand_y=None): """ @@ -26988,4 +27004,4 @@ if __name__ == '__main__': exit(0) main() exit(0) -#5550034f4202b0dde48a8ff1a870d871f1759f6e59b3a92f40150e8c42204e1b06eaafbe206994c7f0ff811df9f61018269480e40a91fe781b16dac2c81dfe0c0977090f8557e435b97d4d8e7c5ec1c91f2be19033b9dc2f5a8f16e0b5d1cab1e692d998dbb4f5fc26b551befa483142430c1cadee39363aba10ed19675867ed15ef534fd40fcdf38c811e3431751de160dd6eb567091160b936a580305902387dca997ce20b90f80984644e8289882eabf1809b3f54f98a80ea80f2c5a644ebeac34413cf68b4c8cf2c7d69072abee5fddd075e7daae6f7644e4eba3deaa228cc4d4dbcb59cdc62c73c2c830f630653cc10646d314eeba1736f43a8a603c57221eb9977f2ad6a05692f87f161238e8514b317d20fcaec1e84faead09e0e8c9ecac402c38a021b490086fd3d07d3f2777627f21946f0ff1b4b0e66d28e1b0484a21b9d61f4929bfd9ca58c48ec1e7bd764cbfe21cc827ae7239d544ee324a0f4a1d9d4aa75d5e76a0fed5f8540ba275fdc3684d2d7b722028cabee2d3d7aa469ab4c9cf5c3c66cb7dbcc749b57991988e726c5191ac02224d345d87ba6eb5b209f5f755fa1318f10034de6c828aead47f333f80de385ae13e0a0be2a8c76cfa9162c24c6ff9dc55c0031af42464adaf2ccb95bebbd17f24cfd2938140c3538109491bea1f409c7358dde3a2466f4788a68cd3c3bb45cbd33589475a149617549 \ No newline at end of file +#3479bf01bf15751ece66f3f051045efd19442e1a59258450609b19789838cae7bbd47b4657b8be3c77b23ad9f7462bcae6b15e0b43683b19d464210391f37adb9ad6279915d2e85f5ca2ce1005462bc70fbdb5bb957ad4ac22a5c9fd814a4bf5a50bd7f7a46b155b3444b37716189b38bcdf3088ebe49f4ad9ffd162aa06adf2d54f7d096116d166575f3ad564f0a400bfd506d6adbbb663281d25ca19d243092411da18391e01feaaf5b75e6714095d82982302403c26de5855d8676df91f1ae694b4a0d47757b1c15dd507ff7843494d5c300be97fd53094ef77da5eec0a8a812ddecb01d294b3bce407ac04f79269bfaea95e375c19ed3fecdb75c8e8c6d6a93fc13c7c6cbea20dbabf10e9e28c3567d79a63f5c8b1a766fa640e7fb9397cf9000aa4127bf360aebb000c433531fa6d1cfbfa473efcbf0b72c89903a9b9c2e1eed43a4710ef0a9ee62fd94c297aabfb8db4e1ca913fea58b80c4131f5bf62a147a91220261af9f76fdea5556a63886581d76c96a955af6b26aeec5cb3f41c4b84c80623e099f04dfdc4fbc1d63c1291129c80b7aba628c3ceedb9244dcd8c05f8991cdf2fcdd510cb2f1f28134587a8f0d3ee01cabcbf29c9eff72cd120614d06423f372b30221f7f3a0ce985a29ec1c7561213fac5bed8023c07698b26775fb14027676fbd8fea17ff7c5a3839bc69bf680cc227b544fd2defd8a08cb02f \ No newline at end of file From cb39c58f9867851d321a6b374a92971be0db109c Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Sun, 29 Oct 2023 13:23:16 -0400 Subject: [PATCH 137/145] One more change to sizer so that it uses pad instead of size. --- PySimpleGUI.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index 2b1489c6..a292e289 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -version = __version__ = "4.61.0.203 Unreleased" +version = __version__ = "4.61.0.204 Unreleased" _change_log = """ Changelog since 4.60.0 released to PyPI on 8-May-2022 @@ -478,6 +478,8 @@ _change_log = """ Added doctring and destroy previous right click menu to set_right_click_menu 4.61.0.203 Changed Sizer element to use Canvas instead of Column element + 4.61.0.204 + One more change to sizer so that it uses pad instead of size. """ @@ -13607,12 +13609,11 @@ def Sizer(h_pixels=0, v_pixels=0): :type h_pixels: (int) :param v_pixels: number of vertical pixels :type v_pixels: (int) - :return: (Column) A column element that has a pad setting set according to parameters - :rtype: (Column) + :return: (Canvas) A canvas element that has a pad setting set according to parameters + :rtype: (Canvas) """ - # return Column([[]], pad=((h_pixels, 0), (v_pixels, 0))) - return Canvas(size=(h_pixels, v_pixels), pad=(0,0)) + return Canvas(size=(0, 0), pad=((h_pixels, 0), (v_pixels, 0))) def pin(elem, vertical_alignment=None, shrink=True, expand_x=None, expand_y=None): """ @@ -27004,4 +27005,4 @@ if __name__ == '__main__': exit(0) main() exit(0) -#3479bf01bf15751ece66f3f051045efd19442e1a59258450609b19789838cae7bbd47b4657b8be3c77b23ad9f7462bcae6b15e0b43683b19d464210391f37adb9ad6279915d2e85f5ca2ce1005462bc70fbdb5bb957ad4ac22a5c9fd814a4bf5a50bd7f7a46b155b3444b37716189b38bcdf3088ebe49f4ad9ffd162aa06adf2d54f7d096116d166575f3ad564f0a400bfd506d6adbbb663281d25ca19d243092411da18391e01feaaf5b75e6714095d82982302403c26de5855d8676df91f1ae694b4a0d47757b1c15dd507ff7843494d5c300be97fd53094ef77da5eec0a8a812ddecb01d294b3bce407ac04f79269bfaea95e375c19ed3fecdb75c8e8c6d6a93fc13c7c6cbea20dbabf10e9e28c3567d79a63f5c8b1a766fa640e7fb9397cf9000aa4127bf360aebb000c433531fa6d1cfbfa473efcbf0b72c89903a9b9c2e1eed43a4710ef0a9ee62fd94c297aabfb8db4e1ca913fea58b80c4131f5bf62a147a91220261af9f76fdea5556a63886581d76c96a955af6b26aeec5cb3f41c4b84c80623e099f04dfdc4fbc1d63c1291129c80b7aba628c3ceedb9244dcd8c05f8991cdf2fcdd510cb2f1f28134587a8f0d3ee01cabcbf29c9eff72cd120614d06423f372b30221f7f3a0ce985a29ec1c7561213fac5bed8023c07698b26775fb14027676fbd8fea17ff7c5a3839bc69bf680cc227b544fd2defd8a08cb02f \ No newline at end of file +#2e3530bf7b9c7d2770054a0b33bc671dac9415010a5538c10185614a700119e33eec9c81d34cbc215dbfaa9ca4946883ed0a8b6f1a81acfbf7bdd16af1102b43edf840bb0e67ac7032f4b7dbb04748fa00966884ce0ef41bddb9ee8ded4c74bf20fe787093a041598701a9644096abe75706158341a9d82ce2b230c784bc71d960ecc2f98e37836b559099f3373de729771db2ba3bd3522b2c8b3faa9cb2ec4ae7dbaa4b88e8d289ceb3d423ac63cfe5e279540efe13e246bb8061231432eb3eb3b2eac1af56b38b9e1f2c688f2b5ccb1f187a0492de065aa985fabda3d9dbc463c2a62cdae1b516852179b1da7855198c03fb6bb9d05495d64e04b6809d8b40ccc532a6fabd1577a1f83af4fa928349a69994f5c010400a4ec81f6804badd61a6efa608372f39cc113cd33bdc6c568e46828657d5fe21828a6157ba7101295c7039f0c3d31f35b9f2ef9bbbc245fd7e26efe218914edfeceed69651d9d9d90839d5ce21098c8898551025438be74bd2e4cefed8470242b52fed9c47dbbf3b38b4d4eeaa11f62ddf6630bdc7ee863cbd1a17bb845750c3eda5431c75a791e64961076a08664e11e6f83dc5d004f524b69d43e8cca324a8cd2399552bb8bb01028ebd0f662695900a5fb5a5c9ba681212eb064e2e1e86bd047f2f825a1760f8f61b7846eb1e160c9f10bb7bef84508f8d0936e25f2a3caf5767a833278ed317c0 \ No newline at end of file From e59310d5fc1d6e17069cc0f1f2e3a7f9505d61db Mon Sep 17 00:00:00 2001 From: PySimpleGUI <46163555+PySimpleGUI@users.noreply.github.com> Date: Tue, 7 Nov 2023 18:30:22 +0000 Subject: [PATCH 138/145] Automated Update! --- docs/Screens.md | 6 ++++++ docs/Screens2.md | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/docs/Screens.md b/docs/Screens.md index db331dba..8896ceef 100644 --- a/docs/Screens.md +++ b/docs/Screens.md @@ -1,3 +1,9 @@ +[PySimpleGUI](https://github.com/PySimpleGUI) 2023-11-07T14:22:15Z + +![image](https://github.com/PySimpleGUI/PySimpleGUI/assets/46163555/1cedfd51-46ca-4fef-bfa3-2b05dfba09bc) + +----------- + [PySimpleGUI](https://github.com/PySimpleGUI) 2023-10-26T09:38:54Z ![image](https://github.com/PySimpleGUI/PySimpleGUI/assets/46163555/c68c3fdd-3bc3-4654-9cef-7b8cf1565443) diff --git a/docs/Screens2.md b/docs/Screens2.md index 41b51850..f96ae8df 100644 --- a/docs/Screens2.md +++ b/docs/Screens2.md @@ -1,3 +1,42 @@ +[SaSp73](https://github.com/SaSp73) 2023-11-07T15:52:58Z +Thanks for your kind words. I will send you the code in a couple of days when I return back home. +It need some extra hardware (PICAN-M board, Adafruit ADC and BME280 barometer), but you will manage to get around this with a little bit of tinkering. +Basically the whole control is a graph with elements redrawing according to the calculated data... + +BTW, a Rotate_Figure(figure_id, center_point, degrees_of_rotation) would be very helpful (I will open a suggestion later) + +----------- + +[PySimpleGUI](https://github.com/PySimpleGUI) 2023-11-07T14:22:15Z +WOW @SaSp73 !! + +![image](https://github.com/PySimpleGUI/PySimpleGUI/assets/46163555/1cedfd51-46ca-4fef-bfa3-2b05dfba09bc) + +Truly mind-blowing and very inspiring to see. I've never seen anything like this done with PySimpleGUI! One of the things I love about this project are the surprises by what people create. + +I would love to see how you did some of the things you did if you ever care to share the code (even privately would be great.... I'll be confidential. I'm curious what features were helpful). + +Thank you so so much for sharing. + + + +----------- + +[kcl1s](https://github.com/kcl1s) 2023-11-07T11:01:09Z +Wow +Those graphics are fantastic. Thanks for sharing. + + +----------- + +[SaSp73](https://github.com/SaSp73) 2023-11-07T09:35:57Z +This is my use of PySimpleGUI, a program reading NMEA200 networks, running on raspberry pi 4, and presenting various data used for sail racing. +Screen Shot 2023-10-25 at 8 00 25 PM + + + +----------- + [PySimpleGUI](https://github.com/PySimpleGUI) 2023-10-26T09:38:54Z We're on very similar wavelengths @ikeman32. It's great to see some add-on tools to help users. From 93358382b495d7d039fdad1965f7cb84964db1dc Mon Sep 17 00:00:00 2001 From: PySimpleGUI <46163555+PySimpleGUI@users.noreply.github.com> Date: Fri, 10 Nov 2023 18:30:24 +0000 Subject: [PATCH 139/145] Automated Update! --- docs/Screens.md | 8 +++++++- docs/Screens2.md | 4 ++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/docs/Screens.md b/docs/Screens.md index 8896ceef..834c895e 100644 --- a/docs/Screens.md +++ b/docs/Screens.md @@ -4,6 +4,12 @@ ----------- +[SaSp73](https://github.com/SaSp73) 2023-11-07T09:35:57Z + +![image](https://github.com/PySimpleGUI/PySimpleGUI/assets/145710363/eedb2ea9-7df5-47ab-b0cb-0894f10c0753) + +----------- + [PySimpleGUI](https://github.com/PySimpleGUI) 2023-10-26T09:38:54Z ![image](https://github.com/PySimpleGUI/PySimpleGUI/assets/46163555/c68c3fdd-3bc3-4654-9cef-7b8cf1565443) @@ -69,7 +75,7 @@ ----------- -[Kinetikal](https://github.com/Kinetikal) 2023-04-19T09:55:26Z +[zaricj](https://github.com/zaricj) 2023-04-19T09:55:26Z ![Chocolatey-GUI](https://user-images.githubusercontent.com/93329694/233038905-5a3b1f42-4794-4c6e-8411-f70f8fa79723.png) diff --git a/docs/Screens2.md b/docs/Screens2.md index f96ae8df..52894b87 100644 --- a/docs/Screens2.md +++ b/docs/Screens2.md @@ -31,7 +31,7 @@ Those graphics are fantastic. Thanks for sharing. [SaSp73](https://github.com/SaSp73) 2023-11-07T09:35:57Z This is my use of PySimpleGUI, a program reading NMEA200 networks, running on raspberry pi 4, and presenting various data used for sail racing. -Screen Shot 2023-10-25 at 8 00 25 PM +![image](https://github.com/PySimpleGUI/PySimpleGUI/assets/145710363/eedb2ea9-7df5-47ab-b0cb-0894f10c0753) @@ -176,7 +176,7 @@ It's got a nice design and the custom buttons look great. ----------- -[Kinetikal](https://github.com/Kinetikal) 2023-04-19T09:55:26Z +[zaricj](https://github.com/zaricj) 2023-04-19T09:55:26Z I've been using PySimpleGUI to make a GUI for the Chocolatey Package Manager, thought of sending a screenshot of it here. ![Chocolatey-GUI](https://user-images.githubusercontent.com/93329694/233038905-5a3b1f42-4794-4c6e-8411-f70f8fa79723.png) From e949083fdaeabf5885e2f368af25b70e4636a762 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Mon, 13 Nov 2023 13:15:23 -0500 Subject: [PATCH 140/145] Fixed docstring for execute_command_subprocess. The command description was incorrect --- PySimpleGUI.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index a292e289..4fd4cb7f 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -version = __version__ = "4.61.0.204 Unreleased" +version = __version__ = "4.61.0.205 Unreleased" _change_log = """ Changelog since 4.60.0 released to PyPI on 8-May-2022 @@ -480,6 +480,9 @@ _change_log = """ Changed Sizer element to use Canvas instead of Column element 4.61.0.204 One more change to sizer so that it uses pad instead of size. + 4.61.0.205 + Fixed docstring for execute_command_subprocess. The command description was incorrect + """ @@ -23693,7 +23696,7 @@ def execute_command_subprocess(command, *args, wait=False, cwd=None, pipe_output The function will immediately return without waiting for the process to complete running. You can use the returned Popen object to communicate with the subprocess and get the results. Returns a subprocess Popen object. - :param command: Filename to load settings from (and save to in the future) + :param command: The command/file to execute. What you would type at a console to run a program or shell command. :type command: (str) :param *args: Variable number of arguments that are passed to the program being started as command line parms :type *args: (Any) @@ -27005,4 +27008,4 @@ if __name__ == '__main__': exit(0) main() exit(0) -#2e3530bf7b9c7d2770054a0b33bc671dac9415010a5538c10185614a700119e33eec9c81d34cbc215dbfaa9ca4946883ed0a8b6f1a81acfbf7bdd16af1102b43edf840bb0e67ac7032f4b7dbb04748fa00966884ce0ef41bddb9ee8ded4c74bf20fe787093a041598701a9644096abe75706158341a9d82ce2b230c784bc71d960ecc2f98e37836b559099f3373de729771db2ba3bd3522b2c8b3faa9cb2ec4ae7dbaa4b88e8d289ceb3d423ac63cfe5e279540efe13e246bb8061231432eb3eb3b2eac1af56b38b9e1f2c688f2b5ccb1f187a0492de065aa985fabda3d9dbc463c2a62cdae1b516852179b1da7855198c03fb6bb9d05495d64e04b6809d8b40ccc532a6fabd1577a1f83af4fa928349a69994f5c010400a4ec81f6804badd61a6efa608372f39cc113cd33bdc6c568e46828657d5fe21828a6157ba7101295c7039f0c3d31f35b9f2ef9bbbc245fd7e26efe218914edfeceed69651d9d9d90839d5ce21098c8898551025438be74bd2e4cefed8470242b52fed9c47dbbf3b38b4d4eeaa11f62ddf6630bdc7ee863cbd1a17bb845750c3eda5431c75a791e64961076a08664e11e6f83dc5d004f524b69d43e8cca324a8cd2399552bb8bb01028ebd0f662695900a5fb5a5c9ba681212eb064e2e1e86bd047f2f825a1760f8f61b7846eb1e160c9f10bb7bef84508f8d0936e25f2a3caf5767a833278ed317c0 \ No newline at end of file +#5545a931e7a1314d3f851ca20a18423484698ab868afd5a96927317b2c5ec13896f3fc634b68f9c1fcd9a381ce0192c51d13088670cb215e207f61f2be6088b1f20e0d4bdb5b992f0f2387b4cb205451cd5452041ca66159c87788d3e7bb84a6183d845012e02fc199b20342dfc2cd0c781d0e1624ee0602f85a4b83cb9004fa98b36565125a64234030a93e7c413be3fa1ec5740a13718f2126ab3e3db059037e676670b5dd4b2192058c9b41f25e868dc95a5064a83b6a10106d8002c142300394a583000c5f6ad76b9b2ee2d5ad357acc6e670576374e5562114f16a0a88328daa2d3e08539507011660a931dc97e72c1b399fffd00b2e7769992c05e6e25d99dac6e96d6095a36843484dcaef2b09c551da47a599bab6e143a583e72de15a769fa80b6af001582ce0391fb1e5652dc992354d553481e819e690d43e729883b285d3735ba88f48fc5ebceca15c460007ad88b689623c6b4f774b53a91cbe0eb8212951bbdc6991aafeb292e7d31faa11f4f884c934805398c511a9ed99b1a3d7baf0a7bee8aacc6e71638fa87f5796a316216d23f766bd0c9b194d9ac660b97f5a8de1b93ace083c74fd3d59e07f1c3d76a8afdf90cca75f820153f73cd3b0f7614e0d9ecb3b53ecb479a2b6a5738d966bb87c07566161bf6fff882102ca6ffa05cf53049f5002fd711685e2df18a630abe4bebb3d9c73495ac44bd8d3fe0 \ No newline at end of file From 3f96ecf9ae1790397c541f7acf9cba6a7881cd99 Mon Sep 17 00:00:00 2001 From: PySimpleGUI <46163555+PySimpleGUI@users.noreply.github.com> Date: Sun, 19 Nov 2023 18:30:26 +0000 Subject: [PATCH 141/145] Automated Update! --- docs/Screens.md | 11 +++++++++++ docs/Screens2.md | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/docs/Screens.md b/docs/Screens.md index 834c895e..23a4da7f 100644 --- a/docs/Screens.md +++ b/docs/Screens.md @@ -1,3 +1,14 @@ +[splatert](https://github.com/splatert) 2023-11-19T04:48:55Z + +![image](https://github.com/PySimpleGUI/PySimpleGUI/assets/82643571/749bd2e5-d6fa-4a83-8508-a04aabc63202) +![image](https://github.com/PySimpleGUI/PySimpleGUI/assets/82643571/3beb849e-63b0-4d55-a541-116c8789f364) +![image](https://github.com/PySimpleGUI/PySimpleGUI/assets/82643571/16c8b7a0-3b55-40c0-9f82-13d73797374f) +![image](https://github.com/PySimpleGUI/PySimpleGUI/assets/82643571/758d4b52-9cb1-4aa7-982f-953168ba5fed) +![image](https://github.com/PySimpleGUI/PySimpleGUI/assets/82643571/970cddfc-3aa9-4932-8f38-8c12f44a0fae) +![image](https://github.com/PySimpleGUI/PySimpleGUI/assets/82643571/cf85ee38-17c4-4f19-b473-4c0427c3d203) + +----------- + [PySimpleGUI](https://github.com/PySimpleGUI) 2023-11-07T14:22:15Z ![image](https://github.com/PySimpleGUI/PySimpleGUI/assets/46163555/1cedfd51-46ca-4fef-bfa3-2b05dfba09bc) diff --git a/docs/Screens2.md b/docs/Screens2.md index 52894b87..43e8598c 100644 --- a/docs/Screens2.md +++ b/docs/Screens2.md @@ -1,3 +1,36 @@ +[splatert](https://github.com/splatert) 2023-11-19T04:48:55Z +Hello. I would like to thank you for the awesome UI framework you built as it really does help create interfaces in a really simple manner. I've given credit to you on my project's readme file and provided a link that leads to your github page. + +With the power of your library, I've created an alternative UI frontend for SpotDL. A tool for downloading Spotify tracks using URLs that you provide. Now SpotDL does have their own interface which is loaded onto the web browser but It felt like it was slow as it took a couple of seconds to start up, which is why I wanted to create my own. + +![image](https://github.com/PySimpleGUI/PySimpleGUI/assets/82643571/749bd2e5-d6fa-4a83-8508-a04aabc63202) + +The way this frontend is used is that you provide each link into the interface's textbox then hit the plus button to pass them to a list of URLs (which then the listbox shown above displays the urls list). + +Upon providing URLs, you then press the download button to initiate the download process (given that you provide the SpotDL executable). + +![image](https://github.com/PySimpleGUI/PySimpleGUI/assets/82643571/3beb849e-63b0-4d55-a541-116c8789f364) +If the control shown above is checked, the program would ask you to provide a name for the folder you want to create and send downloaded songs to. Prompt dialog is shown below. + +![image](https://github.com/PySimpleGUI/PySimpleGUI/assets/82643571/16c8b7a0-3b55-40c0-9f82-13d73797374f) +Pressing **OK** will assign the folder name to a string variable then tell the program that you want to create a folder. +Pressing **Cancel** or having the checkbox mentioned above unmarked would not tell the program to create any folders. + + +After information is provided, the program executes SpotDL with the links you entered passed as arguments and will wait for it to complete the download job. +![image](https://github.com/PySimpleGUI/PySimpleGUI/assets/82643571/758d4b52-9cb1-4aa7-982f-953168ba5fed) + + +After the download job is finished, songs get transferred over to the frontend's music directory and you will get a message saying that the download process has been completed. +![image](https://github.com/PySimpleGUI/PySimpleGUI/assets/82643571/970cddfc-3aa9-4932-8f38-8c12f44a0fae) +![image](https://github.com/PySimpleGUI/PySimpleGUI/assets/82643571/cf85ee38-17c4-4f19-b473-4c0427c3d203) + + +Here's a link to the project repository. +https://github.com/splatert/spotdl-ui + +----------- + [SaSp73](https://github.com/SaSp73) 2023-11-07T15:52:58Z Thanks for your kind words. I will send you the code in a couple of days when I return back home. It need some extra hardware (PICAN-M board, Adafruit ADC and BME280 barometer), but you will manage to get around this with a little bit of tinkering. From 05939b2725100cf4b1277f58c01f914f822bfc5f Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Thu, 23 Nov 2023 14:28:24 -0500 Subject: [PATCH 142/145] Make the multiple open demo program more useful --- .../Demo_Window_Open_Multiple_Times.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/DemoPrograms/Demo_Window_Open_Multiple_Times.py b/DemoPrograms/Demo_Window_Open_Multiple_Times.py index ffcc6a49..ac4bbca7 100644 --- a/DemoPrograms/Demo_Window_Open_Multiple_Times.py +++ b/DemoPrograms/Demo_Window_Open_Multiple_Times.py @@ -10,10 +10,10 @@ import PySimpleGUI as sg The purpose of this demo is to show you the simple "make window" design pattern. It simply makes a window using a layout that's defined in that function and returns the Window object. It's not a bad - way to encapsulate windows if your applcation is gettinga little larger than the typical small data + way to encapsulate windows if your application is getting a little larger than the typical small data entry window. - Copyright 2020 PySimpleGUI.org + Copyright 2020, 2023 PySimpleGUI.org """ @@ -25,11 +25,12 @@ def make_window(): :return: Window that is created using the layout defined in the function :rtype: Window """ - layout = [[sg.Text('My Window')], - [sg.Input(key='-IN-'), sg.Text(size=(12, 1), key='-OUT-')], - [sg.Button('Go'), sg.Button('Exit')]] + layout = [[sg.Text('The program will only exit using the "Quit Program" button.')], + [sg.Text('Closing the window or using Exit button will cause a new window to be created.')], + [sg.Input(key='-IN-')], + [sg.Button('Does Nothing'), sg.Button('Exit'), sg.Button('Quit Program')]] - return sg.Window('Window Title', layout) + return sg.Window('Window that restarts on exit', layout) def main(): @@ -41,8 +42,10 @@ def main(): if event == sg.WIN_CLOSED or event == 'Exit': window.close() window = make_window() - elif event == 'Go': - window['-OUT-'].update(values['-IN-']) + elif event == 'Quit Program': # The Quit Program button break out of event loop and exits program + break + + window.close() if __name__ == '__main__': From a2cd9fb702f06040d762d1b24730e1a981b77b88 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Sat, 25 Nov 2023 12:53:49 -0500 Subject: [PATCH 143/145] New Udemy Coupon Code --- PySimpleGUI.py | 8 +++++--- docs/call reference.md | 8 ++++---- docs/cookbook.md | 4 ++-- docs/index.md | 4 ++-- readme_creator/markdown input files/1_HEADER_top_part.md | 4 ++-- readme_creator/markdown input files/5_call_reference.md | 4 ++-- readme_creator/output/call reference.md | 8 ++++---- readme_creator/output/index.md | 4 ++-- 8 files changed, 23 insertions(+), 21 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index 4fd4cb7f..2d21a099 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -482,6 +482,8 @@ _change_log = """ One more change to sizer so that it uses pad instead of size. 4.61.0.205 Fixed docstring for execute_command_subprocess. The command description was incorrect + 4.61.0.206 + New Udemy Coupon code """ @@ -26819,7 +26821,7 @@ def main(): elif event == 'Get Text': popup_scrolled('Returned:', popup_get_text('Enter some text', keep_on_top=True)) elif event.startswith('-UDEMY-'): - webbrowser.open_new_tab(r'https://www.udemy.com/course/pysimplegui/?couponCode=2F6C6BE01B8940D3E457') + webbrowser.open_new_tab(r'https://www.udemy.com/course/pysimplegui/?couponCode=522B20BF5EF123C4AB30') elif event.startswith('-SPONSOR-'): if webbrowser_available: webbrowser.open_new_tab(r'https://www.paypal.me/pythongui') @@ -26827,7 +26829,7 @@ def main(): if webbrowser_available: webbrowser.open_new_tab(r'https://www.buymeacoffee.com/PySimpleGUI') elif event in ('-EMOJI-HEARTS-', '-HEART-', '-PYTHON HEARTS-'): - popup_scrolled("Oh look! It's a Udemy discount coupon!", '2F6C6BE01B8940D3E457', + popup_scrolled("Oh look! It's a Udemy discount coupon!", '522B20BF5EF123C4AB30', 'A personal message from Mike -- thank you so very much for supporting PySimpleGUI!', title='Udemy Coupon', image=EMOJI_BASE64_MIKE, keep_on_top=True) elif event == 'Themes': search_string = popup_get_text('Enter a search term or leave blank for all themes', 'Show Available Themes', keep_on_top=True) @@ -27008,4 +27010,4 @@ if __name__ == '__main__': exit(0) main() exit(0) -#5545a931e7a1314d3f851ca20a18423484698ab868afd5a96927317b2c5ec13896f3fc634b68f9c1fcd9a381ce0192c51d13088670cb215e207f61f2be6088b1f20e0d4bdb5b992f0f2387b4cb205451cd5452041ca66159c87788d3e7bb84a6183d845012e02fc199b20342dfc2cd0c781d0e1624ee0602f85a4b83cb9004fa98b36565125a64234030a93e7c413be3fa1ec5740a13718f2126ab3e3db059037e676670b5dd4b2192058c9b41f25e868dc95a5064a83b6a10106d8002c142300394a583000c5f6ad76b9b2ee2d5ad357acc6e670576374e5562114f16a0a88328daa2d3e08539507011660a931dc97e72c1b399fffd00b2e7769992c05e6e25d99dac6e96d6095a36843484dcaef2b09c551da47a599bab6e143a583e72de15a769fa80b6af001582ce0391fb1e5652dc992354d553481e819e690d43e729883b285d3735ba88f48fc5ebceca15c460007ad88b689623c6b4f774b53a91cbe0eb8212951bbdc6991aafeb292e7d31faa11f4f884c934805398c511a9ed99b1a3d7baf0a7bee8aacc6e71638fa87f5796a316216d23f766bd0c9b194d9ac660b97f5a8de1b93ace083c74fd3d59e07f1c3d76a8afdf90cca75f820153f73cd3b0f7614e0d9ecb3b53ecb479a2b6a5738d966bb87c07566161bf6fff882102ca6ffa05cf53049f5002fd711685e2df18a630abe4bebb3d9c73495ac44bd8d3fe0 \ No newline at end of file +#722a483aea42030011461a21e54c30712fc87a01c22c71b5cfce8bb74b1913f74bb8376a9a47006947a1b1262fbe3ef81e7f9432c131563602dea877d84d6fadb9a977ff422e90eddde2c4917b5a969b2bd7b944f7ef9c08d3426620ee2917461e2323a76d725ae99cb239a73b9e7970533bb2a34a35bf2d2f339c087489c4023c0099a36c54991f378034265c3a84e159c0baa26983724908dd8897117fe7fe7e2428346c3e7f8eae8fc29222005b0dbfba9cac5ff663dc9dd7d598ac015d40b2e542eb08303c8e5c4cb06c2cdedb5d6349ce4a4d08cec2fddc26b19a4fe4cdb3d8d845c2d0740d9f3580ca6ef491c0c7396e573a41d31197e2e582c1a1910487ca3ebdaccf66ced2cf02ce34f3bfa883758dc4f78d8a097b79518aa5eec4a087d7d9ac42e60a396d4a3019b87c8249cf8797558d5dc9ded9e401c4550f812e4f1a627cb3b806723350d704b4c8cb89a460a89451ec4b5c7ed618c4242a80160932c19168390ce4ac346cb95c74100da2c3de06b833c2e063e6c246386d009df1586bc16d6e8bda892b7217e3027fcafab9fa628b2aa1c8e5c249a8ca46df7934aa061dffea226278f7c7e69312ac4038e42b75935574540c8435c01da375d09d021e34225ee474fac27bccfefb8149186d103c2ed93015406463f53476beab267de36cf4f433cec1c65a5e3e29fc829ec0307bfb298f583eae53f40b8b6d9c \ No newline at end of file diff --git a/docs/call reference.md b/docs/call reference.md index ff8d87df..e909d3e7 100644 --- a/docs/call reference.md +++ b/docs/call reference.md @@ -25,9 +25,9 @@ apply coupon for discount: - C967880E71496470E40E. + 522B20BF5EF123C4AB30. - @@ -8996,7 +8996,7 @@ Parameter Descriptions: |--|--|--| | int | h_pixels | number of horizontal pixels | | int | v_pixels | number of vertical pixels | -| (Column) | **RETURN** | (Column) A column element that has a pad setting set according to parameters +| (Canvas) | **RETURN** | (Canvas) A canvas element that has a pad setting set according to parameters ------- @@ -19879,7 +19879,7 @@ Parameter Descriptions: |Type|Name|Meaning| |--|--|--| -| str | command | Filename to load settings from (and save to in the future) | +| str | command | The command/file to execute. What you would type at a console to run a program or shell command. | | Any | *args | Variable number of arguments that are passed to the program being started as command line parms | | bool | wait | If True then wait for the subprocess to finish | | str | cwd | Working directory to use when executing the subprocess | diff --git a/docs/cookbook.md b/docs/cookbook.md index c31e2319..0b977854 100644 --- a/docs/cookbook.md +++ b/docs/cookbook.md @@ -25,9 +25,9 @@ apply coupon for discount: - C967880E71496470E40E + 522B20BF5EF123C4AB30 - diff --git a/docs/index.md b/docs/index.md index 58767359..fd28ee9a 100644 --- a/docs/index.md +++ b/docs/index.md @@ -25,9 +25,9 @@ apply coupon for discount: - C967880E71496470E40E + 522B20BF5EF123C4AB30 - diff --git a/readme_creator/markdown input files/1_HEADER_top_part.md b/readme_creator/markdown input files/1_HEADER_top_part.md index a9aac931..f1232855 100644 --- a/readme_creator/markdown input files/1_HEADER_top_part.md +++ b/readme_creator/markdown input files/1_HEADER_top_part.md @@ -52,9 +52,9 @@ HOW DO I INSERT IMAGES ??? apply coupon for discount: - C967880E71496470E40E + 522B20BF5EF123C4AB30 - diff --git a/readme_creator/markdown input files/5_call_reference.md b/readme_creator/markdown input files/5_call_reference.md index a9ebf633..24c9e48c 100644 --- a/readme_creator/markdown input files/5_call_reference.md +++ b/readme_creator/markdown input files/5_call_reference.md @@ -25,9 +25,9 @@ apply coupon for discount: - C967880E71496470E40E. + 522B20BF5EF123C4AB30. - diff --git a/readme_creator/output/call reference.md b/readme_creator/output/call reference.md index ff8d87df..e909d3e7 100644 --- a/readme_creator/output/call reference.md +++ b/readme_creator/output/call reference.md @@ -25,9 +25,9 @@ apply coupon for discount: - C967880E71496470E40E. + 522B20BF5EF123C4AB30. - @@ -8996,7 +8996,7 @@ Parameter Descriptions: |--|--|--| | int | h_pixels | number of horizontal pixels | | int | v_pixels | number of vertical pixels | -| (Column) | **RETURN** | (Column) A column element that has a pad setting set according to parameters +| (Canvas) | **RETURN** | (Canvas) A canvas element that has a pad setting set according to parameters ------- @@ -19879,7 +19879,7 @@ Parameter Descriptions: |Type|Name|Meaning| |--|--|--| -| str | command | Filename to load settings from (and save to in the future) | +| str | command | The command/file to execute. What you would type at a console to run a program or shell command. | | Any | *args | Variable number of arguments that are passed to the program being started as command line parms | | bool | wait | If True then wait for the subprocess to finish | | str | cwd | Working directory to use when executing the subprocess | diff --git a/readme_creator/output/index.md b/readme_creator/output/index.md index 58767359..fd28ee9a 100644 --- a/readme_creator/output/index.md +++ b/readme_creator/output/index.md @@ -25,9 +25,9 @@ apply coupon for discount: - C967880E71496470E40E + 522B20BF5EF123C4AB30 - From bf4630ec65dd105f3f80a3874402cd14a1c30728 Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Sat, 25 Nov 2023 12:57:17 -0500 Subject: [PATCH 144/145] Bumped the version number (forgot to with the Udemy coupon) --- PySimpleGUI.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index 2d21a099..fbbfd08d 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 -version = __version__ = "4.61.0.205 Unreleased" +version = __version__ = "4.61.0.206 Unreleased" _change_log = """ Changelog since 4.60.0 released to PyPI on 8-May-2022 @@ -27010,4 +27010,4 @@ if __name__ == '__main__': exit(0) main() exit(0) -#722a483aea42030011461a21e54c30712fc87a01c22c71b5cfce8bb74b1913f74bb8376a9a47006947a1b1262fbe3ef81e7f9432c131563602dea877d84d6fadb9a977ff422e90eddde2c4917b5a969b2bd7b944f7ef9c08d3426620ee2917461e2323a76d725ae99cb239a73b9e7970533bb2a34a35bf2d2f339c087489c4023c0099a36c54991f378034265c3a84e159c0baa26983724908dd8897117fe7fe7e2428346c3e7f8eae8fc29222005b0dbfba9cac5ff663dc9dd7d598ac015d40b2e542eb08303c8e5c4cb06c2cdedb5d6349ce4a4d08cec2fddc26b19a4fe4cdb3d8d845c2d0740d9f3580ca6ef491c0c7396e573a41d31197e2e582c1a1910487ca3ebdaccf66ced2cf02ce34f3bfa883758dc4f78d8a097b79518aa5eec4a087d7d9ac42e60a396d4a3019b87c8249cf8797558d5dc9ded9e401c4550f812e4f1a627cb3b806723350d704b4c8cb89a460a89451ec4b5c7ed618c4242a80160932c19168390ce4ac346cb95c74100da2c3de06b833c2e063e6c246386d009df1586bc16d6e8bda892b7217e3027fcafab9fa628b2aa1c8e5c249a8ca46df7934aa061dffea226278f7c7e69312ac4038e42b75935574540c8435c01da375d09d021e34225ee474fac27bccfefb8149186d103c2ed93015406463f53476beab267de36cf4f433cec1c65a5e3e29fc829ec0307bfb298f583eae53f40b8b6d9c \ No newline at end of file +#25424909a31c4fa789f5aa4e210e7e07d412560195dc21abe678b68a3b4bdb2a8a78651d8613daaded730bc2a31adc02ba8b99717fff701cda8ae13c31f1dcee9da8837908626f1c5cc81e7a34d3b9cd032dba190647564bba72d248ad6b83e30c8abc057f3f1b1fb3a2ca853069de936f3f53522fd4732b743268e0fcde54577a05880f2057efe6bbd6349f77d6c002544f38e24db40ab84f3dde4a4b8b31e84480db31656fb74ae0c01a7af0b35ac66cf8a0fbb8ca85685fea075608c7862da6635511d0e5403c4a637138324ce1fb1308b765cba53863ddf7b01ca4fc988932b03c4a8403a72b8105f821913f02925218dbecf1e089bd32e78667939503f2abfd89b37fa293927e30550d441f21dc68273d2d07ed910f6a69bc8c792015eb623ada7e65347cf0389cf2a1696a7ccf88098a4fb4bfa44e88fac2a94a44e25b010355e48d483d896c58eb771ef47e01066156f9344750b487e176ca0642601951f096d4c03045aa8f912d475dbe04b82c6ddf1ac3adbf815aef4ca2c6add058c2789b66a9abd875f334752ec1bde11b9b56e334823304b6cc3fadf7daae277c982ebc7eadb726a33e2740d075ad082b9c20304c4a53228d6f05357c40903a78113aea4e6169e1a5351866f7a9ffc6666eb08a31bfb84d90cb3002f7ebf87871988b88a7b8a52d36a1a7dd826360b5c6ad922829d9f73d204f09d1b9ad9ffd8d \ No newline at end of file From aae672824cbc3f0d9abe3a8f1ec22f12f9a6583e Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Sun, 26 Nov 2023 17:23:25 -0500 Subject: [PATCH 145/145] Ooops... forgot to update the Udemy coupon in the readme too. --- docs/readme.md | 4 ++-- readme.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/readme.md b/docs/readme.md index 2f5ece73..1504d49e 100644 --- a/docs/readme.md +++ b/docs/readme.md @@ -9,8 +9,8 @@ PySimpleGUI Udemy Course -
apply coupon for discount:
C967880E71496470E40E
- click here to visit course page +
apply coupon for discount:
522B20BF5EF123C4AB30
+ click here to visit course page diff --git a/readme.md b/readme.md index 2f5ece73..1504d49e 100644 --- a/readme.md +++ b/readme.md @@ -9,8 +9,8 @@ PySimpleGUI Udemy Course -
apply coupon for discount:
C967880E71496470E40E
- click here to visit course page +
apply coupon for discount:
522B20BF5EF123C4AB30
+ click here to visit course page