Merge pull request #1494 from PySimpleGUI/Dev-latest

First attempt at built-in debugger
This commit is contained in:
MikeTheWatchGuy 2019-05-30 10:30:12 -04:00 committed by GitHub
commit cebe99496f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 516 additions and 4 deletions

View File

@ -22,7 +22,9 @@ import textwrap
import pickle
import calendar
from random import randint
import textwrap
import operator
import inspect
# 888888ba .d88888b oo dP .88888. dP dP dP
@ -241,6 +243,8 @@ BUTTON_TYPE_READ_FORM = 7
BUTTON_TYPE_REALTIME = 9
BUTTON_TYPE_CALENDAR_CHOOSER = 30
BUTTON_TYPE_COLOR_CHOOSER = 40
BUTTON_TYPE_SHOW_DEBUGGER = 'show debugger'
# ------------------------- Element types ------------------------- #
# class ElementType(Enum):
@ -1648,6 +1652,8 @@ class Button(Element):
self.TKCal = TKCalendar(master=root, firstweekday=calendar.SUNDAY, target_element=target_element, close_when_chosen=self.CalendarCloseWhenChosen, default_date=self.DefaultDate_M_D_Y )
self.TKCal.pack(expand=1, fill='both')
root.update()
elif self.BType == BUTTON_TYPE_SHOW_DEBUGGER: # this is a return type button so GET RESULTS and destroy window
show_debugger_window()
if should_submit_window:
self.ParentForm.LastButtonClicked = target_element.Key
@ -3544,6 +3550,8 @@ class Window:
hidden_master_root = None
animated_popup_dict = {}
container_element_counter = 0 # used to get a number of Container Elements (Frame, Column, Tab)
read_call_from_debugger = False
def __init__(self, title, layout=None, default_element_size=DEFAULT_ELEMENT_SIZE, default_button_element_size=(None, None),
auto_size_text=None, auto_size_buttons=None, location=(None, None), size=(None, None), element_padding=None, margins=(None, None), button_color=None, font=None,
progress_bar_color=(None, None), background_color=None, border_depth=None, auto_close=False,
@ -3781,6 +3789,9 @@ class Window:
self.TKroot.quit() # kick the users out of the mainloop
def Read(self, timeout=None, timeout_key=TIMEOUT_KEY):
# ensure called only 1 time through a single read cycle
if not Window.read_call_from_debugger:
refresh_debugger()
timeout = int(timeout) if timeout is not None else None
if timeout == 0: # timeout of zero runs the old readnonblocking
event, values = self.ReadNonBlocking()
@ -4389,9 +4400,9 @@ def Help(button_text='Help', size=(None, None), auto_size_button=None, button_co
# ------------------------- NO BUTTON Element lazy function ------------------------- #
def Debugger(button_text='', size=(None, None), auto_size_button=None, button_color=None, disabled=False, font=None,
def Debug(button_text='', size=(None, None), auto_size_button=None, button_color=None, disabled=False, font=None,
tooltip=None, bind_return_key=False, focus=False, pad=None, key=None):
return Button(button_text=button_text, button_type=BUTTON_TYPE_READ_FORM, tooltip=tooltip, size=size,
return Button(button_text=button_text, button_type=BUTTON_TYPE_SHOW_DEBUGGER, tooltip=tooltip, size=size,
auto_size_button=auto_size_button, button_color=COLOR_SYSTEM_DEFAULT, font=font, disabled=disabled,
bind_return_key=bind_return_key, focus=focus, pad=pad, key=key, image_data=PSG_DEBUGGER_LOGO,image_subsample=4,border_width=0)
@ -7745,6 +7756,507 @@ def PopupAnimated(image_source, message=None, background_color=None, text_color=
#####################################################################################################
# Debugger
#####################################################################################################
PSGDebugLogo = b'R0lGODlhMgAtAPcAAAAAADD/2akK/4yz0pSxyZWyy5u3zZ24zpW30pG52J250J+60aC60KS90aDC3a3E163F2K3F2bPI2bvO3rzP3qvJ4LHN4rnR5P/zuf/zuv/0vP/0vsDS38XZ6cnb6f/xw//zwv/yxf/1w//zyP/1yf/2zP/3z//30wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAP8ALAAAAAAyAC0AAAj/AP8JHEiwoMGDCBMqXMiwoUOFAiJGXBigYoAPDxlK3CigwUGLIAOEyIiQI8cCBUOqJFnQpEkGA1XKZPlPgkuXBATK3JmRws2bB3TuXNmQw8+jQoeCbHj0qIGkSgNobNoUqlKIVJs++BfV4oiEWalaHVpyosCwJidw7Sr1YMQFBDn+y4qSbUW3AiDElXiWqoK1bPEKGLixr1jAXQ9GuGn4sN22Bl02roo4Kla+c8OOJbsQM9rNPJlORlr5asbPpTk/RP2YJGu7rjWnDm2RIQLZrSt3zgp6ZmqwmkHAng3ccWDEMe8Kpnw8JEHlkXnPdh6SxHPILaU/dp60LFUP07dfRq5aYntohAO0m+c+nvT6pVMPZ3jv8AJu8xktyNbw+ATJDtKFBx9NlA20gWU0DVQBYwZhsJMICRrkwEYJJGRCSBtEqGGCAQEAOw=='
red_x = b"R0lGODlhEAAQAPeQAIsAAI0AAI4AAI8AAJIAAJUAAJQCApkAAJoAAJ4AAJkJCaAAAKYAAKcAAKcCAKcDA6cGAKgAAKsAAKsCAKwAAK0AAK8AAK4CAK8DAqUJAKULAKwLALAAALEAALIAALMAALMDALQAALUAALYAALcEALoAALsAALsCALwAAL8AALkJAL4NAL8NAKoTAKwbAbEQALMVAL0QAL0RAKsREaodHbkQELMsALg2ALk3ALs+ALE2FbgpKbA1Nbc1Nb44N8AAAMIWAMsvAMUgDMcxAKVABb9NBbVJErFYEq1iMrtoMr5kP8BKAMFLAMxKANBBANFCANJFANFEB9JKAMFcANFZANZcANpfAMJUEMZVEc5hAM5pAMluBdRsANR8AM9YOrdERMpIQs1UVMR5WNt8X8VgYMdlZcxtYtx4YNF/btp9eraNf9qXXNCCZsyLeNSLd8SSecySf82kd9qqc9uBgdyBgd+EhN6JgtSIiNuJieGHhOGLg+GKhOKamty1ste4sNO+ueenp+inp+HHrebGrefKuOPTzejWzera1O7b1vLb2/bl4vTu7fbw7ffx7vnz8f///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAJAALAAAAAAQABAAAAjUACEJHEiwYEEABniQKfNFgQCDkATQwAMokEU+PQgUFDAjjR09e/LUmUNnh8aBCcCgUeRmzBkzie6EeQBAoAAMXuA8ciRGCaJHfXzUMCAQgYooWN48anTokR8dQk4sELggBhQrU9Q8evSHiJQgLCIIfMDCSZUjhbYuQkLFCRAMAiOQGGLE0CNBcZYmaRIDLqQFGF60eTRoSxc5jwjhACFWIAgMLtgUocJFy5orL0IQRHAiQgsbRZYswbEhBIiCCH6EiJAhAwQMKU5DjHCi9gnZEHMTDAgAOw=="
COLOR_SCHEME = 'LightGreen'
WIDTH_VARIABLES = 23
WIDTH_RESULTS = 46
WIDTH_WATCHER_VARIABLES = 20
WIDTH_WATCHER_RESULTS = 58
WIDTH_LOCALS = 80
NUM_AUTO_WATCH = 13
class Debugger():
watcher_window = None # type: Window
popout_window = None # type: Window
local_choices = {}
myrc = ''
custom_watch = ''
locals = {}
globals = {}
popout_choices = {}
# # ######
## ## ## # # # # # ###### ##### # # #### #### ###### #####
# # # # # # # ## # # # # # # # # # # # # # # #
# # # # # # # # # # # ##### ##### # # # # ##### # #
# # ###### # # # # # # # # # # # # ### # ### # #####
# # # # # # ## # # # # # # # # # # # # # #
# # # # # # # ###### ###### ##### #### #### #### ###### # #
# Includes the DUAL PANE! Don't forget REPL is there too!
def _build_main_debugger_window(self):
ChangeLookAndFeel(COLOR_SCHEME)
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_'),
B('Obj', key=key1 + 'OBJ_'), ]
return row1
variables_frame = [InVar('_VAR1_'),
InVar('_VAR2_'),
InVar('_VAR3_'), ]
interactive_frame = [[T('>>> ', size=(9, 1), justification='r'), In(size=(83, 1), key='_INTERACTIVE_'),
B('Go', bind_return_key=True, visible=False)],
[T('CODE >>> ', justification='r', size=(9, 1)), In(size=(83, 1), key='_CODE_')],
[Multiline(size=(93, 26), key='_OUTPUT_', autoscroll=True, do_not_clear=True)], ]
autowatch_frame = [[Button('Choose Variables To Auto Watch', key='_LOCALS_'),
Button('Clear All Auto Watches'),
Button('Show All Variables', key='_SHOW_ALL_'),
Button('Locals', key='_ALL_LOCALS_'),
Button('Globals', key='_GLOBALS_'),
Button('Popout', key='_POPOUT_')]] + \
[
[T('', size=(WIDTH_WATCHER_VARIABLES, 1), key='_WATCH%s_' % i),
T('', size=(WIDTH_WATCHER_RESULTS, 2), key='_WATCH%s_RESULT_' % i,
auto_size_text=True)] for i in range(1, NUM_AUTO_WATCH + 1)]
col1 = [
[Frame('Auto Watches', autowatch_frame, title_color='blue')]
]
col2 = [
[Frame('Variables or Expressions to Watch', variables_frame, title_color='blue'), ],
[Frame('REPL-Light - Press Enter To Execute Commands', interactive_frame, title_color='blue'), ]
]
layout = [[Pane([Column(col1), Column(col2)], size=(700, 640), orientation='h', background_color='red',
show_handle=True, ), ],
[Button('', image_data=red_x, key='_EXIT_', button_color=None),
Text('Pull Red Line For REPL & Object Display Screen ---> ', size=(80, 1), justification='r')]]
window = Window("I'm Watching You Debugger", layout, icon=PSGDebugLogo, margins=(0, 0)).Finalize()
window.Element('_VAR1_').SetFocus()
Debugger.watcher_window = window
ChangeLookAndFeel('SystemDefault')
return window
# # ####### #
## ## ## # # # # # # ###### # # ##### # #### #### #####
# # # # # # # ## # # # # # ## # # # # # # # # #
# # # # # # # # # ##### # # ##### # # # # # # # # # # #
# # ###### # # # # # # # # # # # # # # # # # #####
# # # # # # ## # # # # # ## # # # # # # #
# # # # # # # ####### ## ###### # # # ####### #### #### #
def _refresh_main_debugger_window(self, mylocals, myglobals):
if not Debugger.watcher_window:
return False
event, values = Debugger.watcher_window.Read(timeout=1)
if event in (None, 'Exit', '_EXIT_'): # EXIT BUTTON / X BUTTON
try:
Debugger.watcher_window.Close()
except: pass
Debugger.watcher_window = None
return False
cmd_interactive = values['_INTERACTIVE_']
cmd_code = values['_CODE_']
cmd = cmd_interactive or cmd_code
if event == 'Go': # GO BUTTON
Debugger.watcher_window.Element('_INTERACTIVE_').Update('')
Debugger.watcher_window.Element('_CODE_').Update('')
Debugger.watcher_window.Element('_OUTPUT_').Update(">>> {}\n".format(cmd), append=True, autoscroll=True)
if cmd_interactive:
expression = """ {} = {} """.format(fullname(Debugger.myrc), cmd)
try:
exec(expression, myglobals, mylocals)
Debugger.watcher_window.Element('_OUTPUT_').Update('{}\n'.format(Debugger.myrc), append=True,
autoscroll=True)
except Exception as e:
Debugger.watcher_window.Element('_OUTPUT_').Update('Exception {}\n'.format(e), append=True,
autoscroll=True)
else:
Debugger.watcher_window.Element('_CODE_').Update('')
Debugger.watcher_window.Element('_OUTPUT_').Update(">>> {}\n".format(cmd), append=True, autoscroll=True)
expression = """{}""".format(cmd)
try:
exec(expression, myglobals, mylocals)
Debugger.watcher_window.Element('_OUTPUT_').Update('{}\n'.format(cmd), append=True, autoscroll=True)
except Exception as e:
Debugger.watcher_window.Element('_OUTPUT_').Update('Exception {}\n'.format(e), append=True,
autoscroll=True)
elif event.endswith('_DETAIL_'): # DETAIL BUTTON
var = values['_VAR{}_'.format(event[4])]
expression = """ {} = {} """.format(fullname(Debugger.myrc), var)
try:
exec(expression, myglobals, mylocals)
PopupScrolled(str(values['_VAR{}_'.format(event[4])]) + '\n' + str(Debugger.myrc), title=var,
non_blocking=True)
except:
pass
elif event.endswith('_OBJ_'): # OBJECT BUTTON
var = values['_VAR{}_'.format(event[4])]
expression = """ {} = {} """.format(fullname(Debugger.myrc), cmd)
try:
exec(expression, myglobals, mylocals)
PopupScrolled(ObjToStringSingleObj(Debugger.myrc), title=var, non_blocking=True)
except:
pass
elif event == '_LOCALS_': # Show all locals BUTTON
self._choose_auto_watches(mylocals)
elif event == '_ALL_LOCALS_':
self._display_all_vars(mylocals)
elif event == '_GLOBALS_':
self._display_all_vars(myglobals)
elif event == 'Clear All Auto Watches':
if PopupYesNo('Do you really want to clear all Auto-Watches?', 'Really Clear??') == 'Yes':
Debugger.local_choices = {}
Debugger.custom_watch = ''
# Debugger.watcher_window.Element('_CUSTOM_WATCH_').Update('')
elif event == '_POPOUT_':
if not Debugger.popout_window:
self._build_floating_window()
elif event == '_SHOW_ALL_':
for key in Debugger.locals:
Debugger.local_choices[key] = True if not key.startswith('_') else False
# -------------------- Process the manual "watch list" ------------------
for i in range(1, 4):
key = '_VAR{}_'.format(i)
out_key = '_VAR{}_CHANGED_'.format(i)
Debugger.myrc = ''
if Debugger.watcher_window.Element(key):
if values[key]:
Debugger.watcher_window.Element(out_key).Update(values[key])
else:
Debugger.watcher_window.Element(out_key).Update('')
# -------------------- Process the automatic "watch list" ------------------
slot = 1
for key in Debugger.local_choices:
if Debugger.local_choices[key] is True:
Debugger.watcher_window.Element('_WATCH{}_'.format(slot)).Update(key)
Debugger.watcher_window.Element('_WATCH{}_RESULT_'.format(slot)).Update(Debugger.locals[key])
slot += 1
if slot + int(not Debugger.custom_watch in (None, '')) >= NUM_AUTO_WATCH:
break
if Debugger.custom_watch:
Debugger.watcher_window.Element('_WATCH{}_'.format(slot)).Update(Debugger.custom_watch)
try:
Debugger.myrc = eval(Debugger.custom_watch, myglobals, mylocals)
except:
Debugger.myrc = ''
Debugger.watcher_window.Element('_WATCH{}_RESULT_'.format(slot)).Update(Debugger.myrc)
slot += 1
for i in range(slot, NUM_AUTO_WATCH + 1):
Debugger.watcher_window.Element('_WATCH{}_'.format(i)).Update('')
Debugger.watcher_window.Element('_WATCH{}_RESULT_'.format(i)).Update('')
return True
###### # #
# # #### ##### # # ##### # # # # # # ##### #### # #
# # # # # # # # # # # # # # ## # # # # # # #
###### # # # # # # # # # # # # # # # # # # # # #
# # # ##### # # ##### # # # # # # # # # # # # ## #
# # # # # # # # # # # # ## # # # # ## ##
# #### # #### # ## ## # # # ##### #### # #
###### # # #
# # # # # # ##### #### # # # # # # ## ##### ####
# # # # ## ## # # # # # # # # # # # # # #
# # # # # ## # # # #### # # # # # # # # # # ####
# # # # # # ##### # ####### # # # # ###### ##### #
# # # # # # # # # # # # # # # # # # # # #
###### #### # # # #### # # ###### ###### # # # # # ####
def _display_all_vars(self, dict):
num_cols = 3
output_text = ''
num_lines = 2
cur_col = 0
out_text = 'All of your Vars'
longest_line = max([len(key) for key in dict])
line = []
sorted_dict = {}
for key in sorted(dict.keys()):
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)
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
ScrolledTextBox(out_text, non_blocking=True)
##### # #
# # # # #### #### #### ###### # # # ## ##### #### # #
# # # # # # # # # # # # # # # # # # #
# ###### # # # # #### ##### # # # # # # # ######
# # # # # # # # # # # # ###### # # # #
# # # # # # # # # # # # # # # # # # # # #
##### # # #### #### #### ###### ## ## # # # #### # #
# # # #
# # ## ##### # ## ##### # ###### #### # # # # # #
# # # # # # # # # # # # # # # # # # ## #
# # # # # # # # # ##### # ##### #### # # # # # # #
# # ###### ##### # ###### # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # ##
# # # # # # # # ##### ###### ###### #### ## ## # # #
def _choose_auto_watches(self, my_locals):
ChangeLookAndFeel(COLOR_SCHEME)
num_cols = 3
output_text = ''
num_lines = 2
cur_col = 0
layout = [[Text('Choose your "Auto Watch" variables', font='ANY 14', text_color='red')]]
longest_line = max([len(key) for key in my_locals])
line = []
sorted_dict = {}
for key in sorted(my_locals.keys()):
sorted_dict[key] = my_locals[key]
for key in sorted_dict:
line.append(CB(key, key=key, size=(longest_line, 1),
default=Debugger.local_choices[key] if key in Debugger.local_choices else False))
if cur_col + 1 == num_cols:
cur_col = 0
layout.append(line)
line = []
else:
cur_col += 1
if cur_col:
layout.append(line)
layout += [
[Text('Custom Watch'), Input(default_text=Debugger.custom_watch, size=(60, 1), key='_CUSTOM_WATCH_')]]
layout += [
[Ok(), Cancel(), Button('Clear All'), Button('Select [almost] All', key='_AUTO_SELECT_')]]
window = Window('All Locals', layout, icon=PSGDebugLogo).Finalize()
while True: # event loop
event, values = window.Read()
if event in (None, 'Cancel'):
break
elif event == 'Ok':
Debugger.local_choices = values
Debugger.custom_watch = values['_CUSTOM_WATCH_']
break
elif event == 'Clear All':
PopupQuickMessage('Cleared Auto Watches', auto_close=True, auto_close_duration=3, non_blocking=True,
text_color='red', font='ANY 18')
for key in sorted_dict:
window.Element(key).Update(False)
window.Element('_CUSTOM_WATCH_').Update('')
elif event == 'Select All':
for key in sorted_dict:
window.Element(key).Update(False)
elif event == '_AUTO_SELECT_':
for key in sorted_dict:
window.Element(key).Update(not key.startswith('_'))
# exited event loop
window.Close()
ChangeLookAndFeel('SystemDefault')
###### #######
# # # # # # ##### # # #### ## ##### # # # ####
# # # # # # # # # # # # # # # # ## # # #
###### # # # # # # ##### # # # # # # # # # # #
# # # # # # # # # # # # ###### # # # # # # ###
# # # # # # # # # # # # # # # # # ## # #
###### #### # ###### ##### # ###### #### # # # # # # ####
# #
# # # # # # ##### #### # #
# # # # ## # # # # # # #
# # # # # # # # # # # # #
# # # # # # # # # # # # ## #
# # # # # ## # # # # ## ##
## ## # # # ##### #### # #
def _build_floating_window(self):
if Debugger.popout_window:
Debugger.popout_window.Close()
ChangeLookAndFeel('Topanga')
num_cols = 2
width_var = 15
width_value = 30
layout = []
line = []
col = 0
Debugger.popout_choices = Debugger.local_choices if Debugger.local_choices != {} else {}
if Debugger.popout_choices == {}:
for key in sorted(Debugger.locals.keys()):
if not key.startswith('_'):
Debugger.popout_choices[key] = True
width_var = max([len(key) for key in Debugger.popout_choices])
for key in Debugger.popout_choices:
if Debugger.popout_choices[key] is True:
value = str(Debugger.locals.get(key))
line += [Text(key, size=(width_var, 1), font='Sans 8'), Text(' = ', font='Sans 8'),
Text(value, key=key, size=(width_value, 1 if len(value) < width_value else 2),
font='Sans 8')]
if col + 1 < num_cols:
line += [VerticalSeparator(), T(' ')]
col += 1
if col >= num_cols:
layout.append(line)
line = []
col = 0
if col != 0:
layout.append(line)
layout = [[Column(layout), Column(
[[Button('', key='_EXIT_', image_data=red_x, button_color=('#282923', '#282923'), border_width=0)]])]]
Debugger.popout_window = Window('Floating', layout, alpha_channel=0, no_titlebar=True, grab_anywhere=True,
element_padding=(0, 0), margins=(0, 0), keep_on_top=True, ).Finalize()
screen_size = Debugger.popout_window.GetScreenDimensions()
Debugger.popout_window.Move(screen_size[0] - Debugger.popout_window.Size[0], 0)
Debugger.popout_window.SetAlpha(1)
ChangeLookAndFeel('SystemDefault')
######
# # ###### ###### ##### ###### #### # #
# # # # # # # # # #
###### ##### ##### # # ##### #### ######
# # # # ##### # # # #
# # # # # # # # # # #
# # ###### # # # ###### #### # #
#######
# # #### ## ##### # # # ####
# # # # # # # # ## # # #
##### # # # # # # # # # # #
# # # # ###### # # # # # # ###
# # # # # # # # # ## # #
# ###### #### # # # # # # ####
# #
# # # # # # ##### #### # #
# # # # ## # # # # # # #
# # # # # # # # # # # # #
# # # # # # # # # # # # ## #
# # # # # ## # # # # ## ##
## ## # # # ##### #### # #
def _refresh_floating_window(self):
if not Debugger.popout_window:
return
for key in Debugger.popout_choices:
if Debugger.popout_choices[key] is True:
Debugger.popout_window.Element(key).Update(Debugger.locals.get(key))
event, values = Debugger.popout_window.Read(timeout=1)
if event in (None, '_EXIT_'):
Debugger.popout_window.Close()
Debugger.popout_window = None
# 888 888 .d8888b. d8888 888 888 888 888
# 888 888 d88P Y88b d88888 888 888 888 888
# 888 888 888 888 d88P888 888 888 888 888
# 888 888 .d8888b .d88b. 888d888 888 d88P 888 888 888 8888b. 88888b. 888 .d88b.
# 888 888 88K d8P Y8b 888P" 888 d88P 888 888 888 "88b 888 "88b 888 d8P Y8b
# 888 888 "Y8888b. 88888888 888 888 888 d88P 888 888 888 .d888888 888 888 888 88888888
# Y88b. .d88P X88 Y8b. 888 Y88b d88P d8888888888 888 888 888 888 888 d88P 888 Y8b.
# "Y88888P" 88888P' "Y8888 888 "Y8888P" d88P 888 888 888 "Y888888 88888P" 888 "Y8888
# 8888888888 888 d8b
# 888 888 Y8P
# 888 888
# 8888888 888 888 88888b. .d8888b 888888 888 .d88b. 88888b. .d8888b
# 888 888 888 888 "88b d88P" 888 888 d88""88b 888 "88b 88K
# 888 888 888 888 888 888 888 888 888 888 888 888 "Y8888b.
# 888 Y88b 888 888 888 Y88b. Y88b. 888 Y88..88P 888 888 X88
# 888 "Y88888 888 888 "Y8888P "Y888 888 "Y88P" 888 888 88888P'
def show_debugger_window():
frame, *others = inspect.stack()[1]
try:
Debugger.locals = frame.f_back.f_locals
Debugger.globals = frame.f_back.f_globals
finally:
del frame
if not Debugger.watcher_window:
Debugger.watcher_window = debugger._build_main_debugger_window()
return True
def show_debugger_popout_window():
# frame = inspect.currentframe()
# prev_frame = inspect.currentframe().f_back
# frame = inspect.getframeinfo(prev_frame)
frame, *others = inspect.stack()[1]
try:
Debugger.locals = frame.f_back.f_locals
Debugger.globals = frame.f_back.f_globals
finally:
del frame
if Debugger.popout_window:
return
if not Debugger.popout_window:
Debugger.popout_window = debugger._build_floating_window()
def refresh_debugger():
Window.read_call_from_debugger = True
# frame = inspect.currentframe()
# prev_frame = inspect.currentframe().f_back
frame, *others = inspect.stack()[1]
try:
Debugger.locals = frame.f_back.f_locals
Debugger.globals = frame.f_back.f_globals
finally:
del frame
debugger._refresh_floating_window() if Debugger.popout_window else None
rc = debugger._refresh_main_debugger_window(Debugger.locals, Debugger.globals) if Debugger.watcher_window else False
Window.read_call_from_debugger = False
return rc
def fullname(o):
# o.__module__ + "." + o.__class__.__qualname__ is an example in
# this context of H.L. Mencken's "neat, plausible, and wrong."
# Python makes no guarantees as to whether the __module__ special
# attribute is defined, so we take a more circumspect approach.
# Alas, the module name is explicitly excluded from __qualname__
# in Python 3.
module = o.__class__.__module__
if module is None or module == str.__class__.__module__:
return o.__class__.__name__ # Avoid reporting __builtin__
else:
return module + '.' + o.__class__.__name__
debugger = Debugger()
"""
d8b
Y8P
@ -7826,7 +8338,7 @@ def main():
layout1 = [
[Menu(menu_def)],
[Image(data=DEFAULT_BASE64_ICON)],
[Text('You are running the PySimpleGUI.py file itself', font='ANY 15', tooltip='My tooltip', key='_TEXT1_')],
[Text('You are running the py file itself', font='ANY 15', tooltip='My tooltip', key='_TEXT1_')],
[Text('You should be importing it rather than running it', font='ANY 15')],
[Frame('Input Text Group', frame1, title_color='red'),
Image(data=DEFAULT_BASE64_LOADING_GIF, key='_IMAGE_')],