Merge pull request #1555 from PySimpleGUI/Dev-latest
Release 3.39, 1.39
This commit is contained in:
commit
4b1f7a0fe5
|
@ -631,7 +631,7 @@ class Combo(Element):
|
|||
tooltip=None, readonly=False, font=None, visible=True):
|
||||
'''
|
||||
Combo
|
||||
:param values: list of values
|
||||
:param values:
|
||||
:param default_value:
|
||||
:param size:
|
||||
:param auto_size_text:
|
||||
|
@ -1682,7 +1682,7 @@ class Button(Element):
|
|||
pass
|
||||
elif self.BType == BUTTON_TYPE_SHOW_DEBUGGER:
|
||||
if self.ParentForm.DebuggerEnabled:
|
||||
Debugger._build_floating_window('self normally goes here')
|
||||
Debugger.debugger._build_floating_window()
|
||||
# show_debugger_window()
|
||||
|
||||
if should_submit_window:
|
||||
|
|
562
PySimpleGUI27.py
562
PySimpleGUI27.py
|
@ -32,7 +32,6 @@ else:
|
|||
import types
|
||||
import datetime
|
||||
import time
|
||||
import textwrap
|
||||
import pickle
|
||||
import calendar
|
||||
from random import randint
|
||||
|
@ -66,7 +65,7 @@ def TimerStop():
|
|||
|
||||
g_time_end = time.time()
|
||||
g_time_delta = g_time_end - g_time_start
|
||||
print(int(g_time_delta * 1000))
|
||||
print((g_time_delta * 1000))
|
||||
|
||||
|
||||
"""
|
||||
|
@ -410,7 +409,7 @@ class Element(object):
|
|||
self.TKRightClickMenu = None
|
||||
self.Widget = None # Set when creating window. Has the main tkinter widget for element
|
||||
|
||||
def RightClickMenuCallback(self, event):
|
||||
def _RightClickMenuCallback(self, event):
|
||||
self.TKRightClickMenu.tk_popup(event.x_root, event.y_root, 0)
|
||||
self.TKRightClickMenu.grab_release()
|
||||
|
||||
|
@ -514,7 +513,7 @@ class Element(object):
|
|||
if self.ParentForm.CurrentlyRunningMainloop:
|
||||
self.ParentForm.TKroot.quit()
|
||||
|
||||
def KeyboardHandler(self, event):
|
||||
def _KeyboardHandler(self, event):
|
||||
if self.Key is not None:
|
||||
self.ParentForm.LastButtonClicked = self.Key
|
||||
else:
|
||||
|
@ -523,7 +522,7 @@ class Element(object):
|
|||
if self.ParentForm.CurrentlyRunningMainloop:
|
||||
self.ParentForm.TKroot.quit()
|
||||
|
||||
def ClickHandler(self, event):
|
||||
def _ClickHandler(self, event):
|
||||
if self.Key is not None:
|
||||
self.ParentForm.LastButtonClicked = self.Key
|
||||
else:
|
||||
|
@ -1696,7 +1695,7 @@ class Button(Element):
|
|||
pass
|
||||
elif self.BType == BUTTON_TYPE_SHOW_DEBUGGER:
|
||||
if self.ParentForm.DebuggerEnabled:
|
||||
Debugger._build_floating_window('self normally goes here')
|
||||
Debugger.debugger._build_floating_window()
|
||||
# show_debugger_window()
|
||||
|
||||
if should_submit_window:
|
||||
|
@ -2260,10 +2259,12 @@ class Graph(Element):
|
|||
|
||||
def DeleteFigure(self, id):
|
||||
try:
|
||||
del self.Images[id]
|
||||
self._TKCanvas2.delete(id)
|
||||
except:
|
||||
print('DeleteFigure - bad ID {}'.format(id))
|
||||
try:
|
||||
del self.Images[id] # in case was an image. If wasn't an image, then will get exception
|
||||
except: pass
|
||||
|
||||
def Update(self, background_color, visible=None):
|
||||
if self._TKCanvas2 is None:
|
||||
|
@ -2589,7 +2590,8 @@ class TabGroup(Element):
|
|||
self.ParentWindow = None
|
||||
self.SelectedTitleColor = selected_title_color
|
||||
self.Rows = []
|
||||
self.TKNotebook = None
|
||||
self.TKNotebook = None # type: ttk.Notebook
|
||||
self.Widget = None # type: ttk.Notebook
|
||||
self.TabCount = 0
|
||||
self.BorderWidth = border_width
|
||||
self.Theme = theme
|
||||
|
@ -2635,6 +2637,12 @@ class TabGroup(Element):
|
|||
return element.Key
|
||||
return None
|
||||
|
||||
def SelectTab(self, index):
|
||||
try:
|
||||
self.TKNotebook.select(index)
|
||||
except Exception as e:
|
||||
print('Exception Selecting Tab {}'.format(e))
|
||||
|
||||
def __del__(self):
|
||||
for row in self.Rows:
|
||||
for element in row:
|
||||
|
@ -3303,7 +3311,7 @@ class Table(Element):
|
|||
self.DisplayRowNumbers = display_row_numbers
|
||||
self.NumRows = num_rows if num_rows is not None else size[1]
|
||||
self.RowHeight = row_height
|
||||
self.TKTreeview = None
|
||||
self.TKTreeview = None # type: ttk.Treeview
|
||||
self.AlternatingRowColor = alternating_row_color
|
||||
self.VerticalScrollOnly = vertical_scroll_only
|
||||
self.HideVerticalScroll = hide_vertical_scroll
|
||||
|
@ -3319,7 +3327,7 @@ class Table(Element):
|
|||
size=size, pad=pad, key=key, tooltip=tooltip, visible=visible)
|
||||
return
|
||||
|
||||
def Update(self, values=None, num_rows=None, visible=None):
|
||||
def Update(self, values=None, num_rows=None, visible=None, select_rows=None):
|
||||
if values is not None:
|
||||
children = self.TKTreeview.get_children()
|
||||
for i in children:
|
||||
|
@ -3341,6 +3349,9 @@ class Table(Element):
|
|||
self.TKTreeview.pack()
|
||||
if num_rows is not None:
|
||||
self.TKTreeview.config(height=num_rows)
|
||||
if select_rows is not None:
|
||||
rows_to_select = [i+1 for i in select_rows]
|
||||
self.TKTreeview.selection_set(rows_to_select)
|
||||
|
||||
def treeview_selected(self, event):
|
||||
selections = self.TKTreeview.selection()
|
||||
|
@ -3712,6 +3723,25 @@ class Window(object):
|
|||
CurrentRow = [] # start with a blank row and build up
|
||||
# ------------------------- Add the elements to a row ------------------------- #
|
||||
for i, element in enumerate(args): # Loop through list of elements and add them to the row
|
||||
if type(element) == list:
|
||||
PopupError('Error creating layout',
|
||||
'Layout has a LIST instead of an ELEMENT',
|
||||
'This means you have a badly placed ]',
|
||||
'The offensive list is:',
|
||||
element,
|
||||
'This list will be stripped from your layout'
|
||||
)
|
||||
continue
|
||||
elif callable(element):
|
||||
PopupError('Error creating layout',
|
||||
'Layout has a FUNCTION instead of an ELEMENT',
|
||||
'This means you are missing () from your layout',
|
||||
'The offensive list is:',
|
||||
element,
|
||||
'This item will be stripped from your layout'
|
||||
)
|
||||
continue
|
||||
|
||||
element.Position = (CurrentRowNumber, i)
|
||||
element.ParentContainer = self
|
||||
CurrentRow.append(element)
|
||||
|
@ -4196,10 +4226,12 @@ class Window(object):
|
|||
return
|
||||
|
||||
def Disable(self):
|
||||
self.TKroot.grab_set_global()
|
||||
self.TKroot.attributes('-disabled', 1)
|
||||
# self.TKroot.grab_set_global()
|
||||
|
||||
def Enable(self):
|
||||
self.TKroot.grab_release()
|
||||
self.TKroot.attributes('-disabled', 0)
|
||||
# self.TKroot.grab_release()
|
||||
|
||||
def Hide(self):
|
||||
self._Hidden = True
|
||||
|
@ -4277,12 +4309,18 @@ class Window(object):
|
|||
self.TKroot.unbind("<ButtonRelease-1>")
|
||||
self.TKroot.unbind("<B1-Motion>")
|
||||
|
||||
def _callback_main_debugger_window_create_keystroke(self, event):
|
||||
Debugger.debugger._build_main_debugger_window()
|
||||
|
||||
def _callback_popout_window_create_keystroke(self, event):
|
||||
Debugger.debugger._build_floating_window()
|
||||
|
||||
def EnableDebugger(self):
|
||||
self.TKroot.bind('<Cancel>', Debugger._build_main_debugger_window)
|
||||
# root.bind('<Pause>', show_debugger_popout_window)
|
||||
self.TKroot.bind('<Pause>', Debugger._build_floating_window)
|
||||
self.TKroot.bind('<Cancel>', self._callback_main_debugger_window_create_keystroke)
|
||||
self.TKroot.bind('<Pause>', self._callback_popout_window_create_keystroke)
|
||||
self.DebuggerEnabled = True
|
||||
|
||||
|
||||
def DisableDebugger(self):
|
||||
self.TKroot.unbind("<Cancel>")
|
||||
self.TKroot.unbind("<Pause>")
|
||||
|
@ -5134,7 +5172,7 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form):
|
|||
top_menu = tk.Menu(toplevel_form.TKroot, tearoff=False)
|
||||
AddMenuItem(top_menu, menu[1], element)
|
||||
element.TKRightClickMenu = top_menu
|
||||
element.TKColFrame.bind('<Button-3>', element.RightClickMenuCallback)
|
||||
element.TKColFrame.bind('<Button-3>', element._RightClickMenuCallback)
|
||||
# ------------------------- Pane element ------------------------- #
|
||||
if element_type == ELEM_TYPE_PANE:
|
||||
bd = element.BorderDepth if element.BorderDepth is not None else border_depth
|
||||
|
@ -5213,7 +5251,7 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form):
|
|||
tktext_label.configure(background=element.BackgroundColor)
|
||||
if element.TextColor != COLOR_SYSTEM_DEFAULT and element.TextColor is not None:
|
||||
tktext_label.configure(fg=element.TextColor)
|
||||
tktext_label.pack(side=tk.LEFT, padx=elementpad[0], pady=elementpad[1], expand=True)
|
||||
tktext_label.pack(side=tk.LEFT, padx=elementpad[0], pady=elementpad[1])
|
||||
if element.Visible is False:
|
||||
tktext_label.pack_forget()
|
||||
element.TKText = tktext_label
|
||||
|
@ -5226,7 +5264,7 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form):
|
|||
top_menu = tk.Menu(toplevel_form.TKroot, tearoff=False)
|
||||
AddMenuItem(top_menu, menu[1], element)
|
||||
element.TKRightClickMenu = top_menu
|
||||
tktext_label.bind('<Button-3>', element.RightClickMenuCallback)
|
||||
tktext_label.bind('<Button-3>', element._RightClickMenuCallback)
|
||||
# ------------------------- BUTTON element ------------------------- #
|
||||
elif element_type == ELEM_TYPE_BUTTON:
|
||||
element = element # type: Button
|
||||
|
@ -5400,7 +5438,7 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form):
|
|||
textvariable=element.TKStringVar, bd=border_depth,
|
||||
font=font, show=show, justify=justify)
|
||||
if element.ChangeSubmits:
|
||||
element.TKEntry.bind('<Key>', element.KeyboardHandler)
|
||||
element.TKEntry.bind('<Key>', element._KeyboardHandler)
|
||||
element.TKEntry.bind('<Return>', element.ReturnKeyHandler)
|
||||
if element.BackgroundColor is not None and element.BackgroundColor != COLOR_SYSTEM_DEFAULT:
|
||||
element.TKEntry.configure(background=element.BackgroundColor)
|
||||
|
@ -5421,10 +5459,10 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form):
|
|||
top_menu = tk.Menu(toplevel_form.TKroot, tearoff=False)
|
||||
AddMenuItem(top_menu, menu[1], element)
|
||||
element.TKRightClickMenu = top_menu
|
||||
element.TKEntry.bind('<Button-3>', element.RightClickMenuCallback)
|
||||
element.TKEntry.bind('<Button-3>', element._RightClickMenuCallback)
|
||||
# ------------------------- COMBOBOX element ------------------------- #
|
||||
elif element_type == ELEM_TYPE_INPUT_COMBO:
|
||||
max_line_len = max([len(str(l)) for l in element.Values])
|
||||
max_line_len = max([len(str(l)) for l in element.Values]) if len(element.Values) else 0
|
||||
if auto_size_text is False:
|
||||
width = element_size[0]
|
||||
else:
|
||||
|
@ -5490,7 +5528,7 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form):
|
|||
if v == element.DefaultValue:
|
||||
element.TKCombo.current(i)
|
||||
break
|
||||
else:
|
||||
elif element.Values:
|
||||
element.TKCombo.current(0)
|
||||
if element.ChangeSubmits:
|
||||
element.TKCombo.bind('<<ComboboxSelected>>', element.ComboboxSelectHandler)
|
||||
|
@ -5570,7 +5608,7 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form):
|
|||
top_menu = tk.Menu(toplevel_form.TKroot, tearoff=False)
|
||||
AddMenuItem(top_menu, menu[1], element)
|
||||
element.TKRightClickMenu = top_menu
|
||||
element.TKListbox.bind('<Button-3>', element.RightClickMenuCallback)
|
||||
element.TKListbox.bind('<Button-3>', element._RightClickMenuCallback)
|
||||
# ------------------------- MULTILINE element ------------------------- #
|
||||
elif element_type == ELEM_TYPE_INPUT_MULTILINE:
|
||||
element = element # type: Multiline
|
||||
|
@ -5589,7 +5627,7 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form):
|
|||
if element.Visible is False:
|
||||
element.TKText.pack_forget()
|
||||
if element.ChangeSubmits:
|
||||
element.TKText.bind('<Key>', element.KeyboardHandler)
|
||||
element.TKText.bind('<Key>', element._KeyboardHandler)
|
||||
if element.EnterSubmits:
|
||||
element.TKText.bind('<Return>', element.ReturnKeyHandler)
|
||||
if element.Focus is True or (toplevel_form.UseDefaultFocus and not focus_set):
|
||||
|
@ -5606,7 +5644,7 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form):
|
|||
top_menu = tk.Menu(toplevel_form.TKroot, tearoff=False)
|
||||
AddMenuItem(top_menu, menu[1], element)
|
||||
element.TKRightClickMenu = top_menu
|
||||
element.TKText.bind('<Button-3>', element.RightClickMenuCallback)
|
||||
element.TKText.bind('<Button-3>', element._RightClickMenuCallback)
|
||||
row_should_expand = True
|
||||
# ------------------------- CHECKBOX element ------------------------- #
|
||||
elif element_type == ELEM_TYPE_INPUT_CHECKBOX:
|
||||
|
@ -5743,7 +5781,7 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form):
|
|||
top_menu = tk.Menu(toplevel_form.TKroot, tearoff=False)
|
||||
AddMenuItem(top_menu, menu[1], element)
|
||||
element.TKRightClickMenu = top_menu
|
||||
element._TKOut.bind('<Button-3>', element.RightClickMenuCallback)
|
||||
element._TKOut.bind('<Button-3>', element._RightClickMenuCallback)
|
||||
row_should_expand = True
|
||||
# ------------------------- IMAGE element ------------------------- #
|
||||
elif element_type == ELEM_TYPE_IMAGE:
|
||||
|
@ -5781,13 +5819,13 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form):
|
|||
element.TooltipObject = ToolTip(element.tktext_label, text=element.Tooltip,
|
||||
timeout=DEFAULT_TOOLTIP_TIME)
|
||||
if element.EnableEvents:
|
||||
element.tktext_label.bind('<ButtonPress-1>', element.ClickHandler)
|
||||
element.tktext_label.bind('<ButtonPress-1>', element._ClickHandler)
|
||||
if element.RightClickMenu or toplevel_form.RightClickMenu:
|
||||
menu = element.RightClickMenu or toplevel_form.RightClickMenu
|
||||
top_menu = tk.Menu(toplevel_form.TKroot, tearoff=False)
|
||||
AddMenuItem(top_menu, menu[1], element)
|
||||
element.TKRightClickMenu = top_menu
|
||||
element.tktext_label.bind('<Button-3>', element.RightClickMenuCallback)
|
||||
element.tktext_label.bind('<Button-3>', element._RightClickMenuCallback)
|
||||
# ------------------------- Canvas element ------------------------- #
|
||||
elif element_type == ELEM_TYPE_CANVAS:
|
||||
width, height = element_size
|
||||
|
@ -5809,7 +5847,7 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form):
|
|||
top_menu = tk.Menu(toplevel_form.TKroot, tearoff=False)
|
||||
AddMenuItem(top_menu, menu[1], element)
|
||||
element.TKRightClickMenu = top_menu
|
||||
element._TKCanvas.bind('<Button-3>', element.RightClickMenuCallback)
|
||||
element._TKCanvas.bind('<Button-3>', element._RightClickMenuCallback)
|
||||
# ------------------------- Graph element ------------------------- #
|
||||
elif element_type == ELEM_TYPE_GRAPH:
|
||||
element = element # type: Graph
|
||||
|
@ -5843,7 +5881,7 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form):
|
|||
top_menu = tk.Menu(toplevel_form.TKroot, tearoff=False)
|
||||
AddMenuItem(top_menu, menu[1], element)
|
||||
element.TKRightClickMenu = top_menu
|
||||
element._TKCanvas2.bind('<Button-3>', element.RightClickMenuCallback)
|
||||
element._TKCanvas2.bind('<Button-3>', element._RightClickMenuCallback)
|
||||
# ------------------------- MENUBAR element ------------------------- #
|
||||
elif element_type == ELEM_TYPE_MENUBAR:
|
||||
element = element # type: MenuBar
|
||||
|
@ -5896,7 +5934,7 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form):
|
|||
top_menu = tk.Menu(toplevel_form.TKroot, tearoff=False)
|
||||
AddMenuItem(top_menu, menu[1], element)
|
||||
element.TKRightClickMenu = top_menu
|
||||
labeled_frame.bind('<Button-3>', element.RightClickMenuCallback)
|
||||
labeled_frame.bind('<Button-3>', element._RightClickMenuCallback)
|
||||
# ------------------------- Tab element ------------------------- #
|
||||
elif element_type == ELEM_TYPE_TAB:
|
||||
element.TKFrame = element.Widget = tk.Frame(form.TKNotebook)
|
||||
|
@ -5931,10 +5969,10 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form):
|
|||
top_menu = tk.Menu(toplevel_form.TKroot, tearoff=False)
|
||||
AddMenuItem(top_menu, menu[1], element)
|
||||
element.TKRightClickMenu = top_menu
|
||||
element.TKFrame.bind('<Button-3>', element.RightClickMenuCallback)
|
||||
element.TKFrame.bind('<Button-3>', element._RightClickMenuCallback)
|
||||
# ------------------------- TabGroup element ------------------------- #
|
||||
elif element_type == ELEM_TYPE_TAB_GROUP:
|
||||
|
||||
element=element # type: TabGroup
|
||||
custom_style = str(element.Key) + 'customtab.TNotebook'
|
||||
style = tkinter.ttk.Style(tk_row_frame)
|
||||
if element.Theme is not None:
|
||||
|
@ -6130,7 +6168,7 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form):
|
|||
top_menu = tk.Menu(toplevel_form.TKroot, tearoff=False)
|
||||
AddMenuItem(top_menu, menu[1], element)
|
||||
element.TKRightClickMenu = top_menu
|
||||
element.TKTreeview.bind('<Button-3>', element.RightClickMenuCallback)
|
||||
element.TKTreeview.bind('<Button-3>', element._RightClickMenuCallback)
|
||||
# ------------------------- Tree element ------------------------- #
|
||||
elif element_type == ELEM_TYPE_TREE:
|
||||
element = element # type: Tree
|
||||
|
@ -6216,7 +6254,7 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form):
|
|||
top_menu = tk.Menu(toplevel_form.TKroot, tearoff=False)
|
||||
AddMenuItem(top_menu, menu[1], element)
|
||||
element.TKRightClickMenu = top_menu
|
||||
element.TKTreeview.bind('<Button-3>', element.RightClickMenuCallback)
|
||||
element.TKTreeview.bind('<Button-3>', element._RightClickMenuCallback)
|
||||
# ------------------------- Separator element ------------------------- #
|
||||
elif element_type == ELEM_TYPE_SEPARATOR:
|
||||
element = element # type: VerticalSeparator
|
||||
|
@ -6350,9 +6388,11 @@ def StartupTK(my_flex_form):
|
|||
root = tk.Toplevel()
|
||||
|
||||
if my_flex_form.DebuggerEnabled:
|
||||
root.bind('<Cancel>', Debugger._build_main_debugger_window)
|
||||
# root.bind('<Pause>', show_debugger_popout_window)
|
||||
root.bind('<Pause>', Debugger._build_floating_window)
|
||||
root.bind('<Cancel>', my_flex_form._callback_main_debugger_window_create_keystroke)
|
||||
root.bind('<Pause>', my_flex_form._callback_popout_window_create_keystroke)
|
||||
|
||||
# root.bind('<Cancel>', Debugger._build_main_debugger_window)
|
||||
# root.bind('<Pause>', Debugger._build_floating_window)
|
||||
try:
|
||||
root.attributes('-alpha', 0) # hide window while building it. makes for smoother 'paint'
|
||||
except:
|
||||
|
@ -8330,21 +8370,19 @@ WIDTH_VARIABLES = 23
|
|||
WIDTH_RESULTS = 46
|
||||
|
||||
WIDTH_WATCHER_VARIABLES = 20
|
||||
WIDTH_WATCHER_RESULTS = 58
|
||||
WIDTH_WATCHER_RESULTS = 60
|
||||
|
||||
WIDTH_LOCALS = 80
|
||||
NUM_AUTO_WATCH = 13
|
||||
NUM_AUTO_WATCH = 9
|
||||
|
||||
MAX_LINES_PER_RESULT_FLOATING = 4
|
||||
MAX_LINES_PER_RESULT_MAIN = 3
|
||||
|
||||
POPOUT_WINDOW_FONT = 'Sans 8'
|
||||
|
||||
class Debugger(object):
|
||||
watcher_window = None # type: Window
|
||||
popout_window = None # type: Window
|
||||
local_choices = {}
|
||||
myrc = ''
|
||||
custom_watch = ''
|
||||
locals = {}
|
||||
globals = {}
|
||||
popout_choices = {}
|
||||
|
||||
debugger = None
|
||||
|
||||
# # ######
|
||||
## ## ## # # # # # ###### ##### # # #### #### ###### #####
|
||||
|
@ -8354,11 +8392,23 @@ class Debugger(object):
|
|||
# # # # # # ## # # # # # # # # # # # # # #
|
||||
# # # # # # # ###### ###### ##### #### #### #### ###### # #
|
||||
|
||||
# Includes the DUAL PANE! Don't forget REPL is there too!
|
||||
def _build_main_debugger_window(self):
|
||||
if Debugger.watcher_window:
|
||||
return
|
||||
def __init__(self):
|
||||
self.watcher_window = None # type: Window
|
||||
self.popout_window = None # type: Window
|
||||
self.local_choices = {}
|
||||
self.myrc = ''
|
||||
self.custom_watch = ''
|
||||
self.locals = {}
|
||||
self.globals = {}
|
||||
self.popout_choices = {}
|
||||
|
||||
|
||||
|
||||
def _build_main_debugger_window_callback(self, events):
|
||||
self._build_main_debugger_window()
|
||||
|
||||
# Includes the DUAL PANE (now 2 tabs)! Don't forget REPL is there too!
|
||||
def _build_main_debugger_window(self, location=(None, None)):
|
||||
ChangeLookAndFeel(COLOR_SCHEME)
|
||||
|
||||
def InVar(key1):
|
||||
|
@ -8368,13 +8418,13 @@ class Debugger(object):
|
|||
B('Obj', key=key1 + 'OBJ_'), ]
|
||||
return row1
|
||||
|
||||
variables_frame = [InVar('_VAR1_'),
|
||||
InVar('_VAR2_'),
|
||||
InVar('_VAR3_'), ]
|
||||
variables_frame = [InVar('_VAR0_'),
|
||||
InVar('_VAR1_'),
|
||||
InVar('_VAR2_'), ]
|
||||
|
||||
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_')],
|
||||
interactive_frame = [[T('>>> '), In(size=(83, 1), key='_REPL_',
|
||||
tooltip='Type in any "expression" or "statement"\n and it will be disaplayed below.\nPress RETURN KEY instead of "Go"\nbutton for faster use'),
|
||||
B('Go', bind_return_key=True, visible=True)],
|
||||
[Multiline(size=(93, 26), key='_OUTPUT_', autoscroll=True, do_not_clear=True)], ]
|
||||
|
||||
autowatch_frame = [[Button('Choose Variables To Auto Watch', key='_LOCALS_'),
|
||||
|
@ -8382,14 +8432,17 @@ class Debugger(object):
|
|||
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)]
|
||||
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,
|
||||
)])
|
||||
|
||||
col1 = [
|
||||
[Frame('Auto Watches', autowatch_frame, title_color='blue')]
|
||||
# [Frame('Auto Watches', autowatch_frame+variable_values, title_color='blue')]
|
||||
[Frame('Auto Watches', autowatch_frame+var_layout, title_color='blue')]
|
||||
]
|
||||
|
||||
col2 = [
|
||||
|
@ -8397,15 +8450,15 @@ class Debugger(object):
|
|||
[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')]]
|
||||
# Tab based layout
|
||||
layout = [[TabGroup([[Tab('Variables', col1), Tab('REPL & Watches', col2)]])],
|
||||
[Button('', image_data=red_x, key='_EXIT_', button_color=None),]]
|
||||
|
||||
window = Window("I'm Watching You Debugger", layout, icon=PSGDebugLogo, margins=(0, 0)).Finalize()
|
||||
# ------------------------------- Create main window -------------------------------
|
||||
window = Window("PySimpleGUI Debugger", layout, icon=PSGDebugLogo, margins=(0, 0), location=location).Finalize()
|
||||
window.Element('_VAR1_').SetFocus()
|
||||
Debugger.watcher_window = window
|
||||
ChangeLookAndFeel('SystemDefault')
|
||||
self.watcher_window = window
|
||||
ChangeLookAndFeel('SystemDefault') # set look and feel to default before exiting
|
||||
return window
|
||||
|
||||
# # ####### #
|
||||
|
@ -8417,122 +8470,119 @@ class Debugger(object):
|
|||
# # # # # # # ####### ## ###### # # # ####### #### #### #
|
||||
|
||||
def _refresh_main_debugger_window(self, mylocals, myglobals):
|
||||
if not Debugger.watcher_window:
|
||||
if not self.watcher_window: # if there is no window setup, nothing to do
|
||||
return False
|
||||
event, values = Debugger.watcher_window.Read(timeout=1)
|
||||
event, values = self.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
|
||||
self.watcher_window.Close()
|
||||
except: pass
|
||||
self.watcher_window = None
|
||||
return False
|
||||
|
||||
cmd_interactive = values['_INTERACTIVE_']
|
||||
cmd_code = values['_CODE_']
|
||||
cmd = cmd_interactive or cmd_code
|
||||
|
||||
# ------------------------------- Process events from REPL Tab -------------------------------
|
||||
cmd = values['_REPL_'] # get the REPL entered
|
||||
# BUTTON - GO (NOTE - This button is invisible!!)
|
||||
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)
|
||||
|
||||
self.watcher_window.Element('_REPL_').Update('')
|
||||
self.watcher_window.Element('_OUTPUT_').Update(">>> {}\n".format(cmd), append=True, autoscroll=True)
|
||||
# REMOVED ONLY IN 2.7 version!!! HAND EDITED!
|
||||
|
||||
# if sys.version_info[0] >= 3:
|
||||
# try:
|
||||
# result = eval('{}'.format(cmd), myglobals, mylocals)
|
||||
# except Exception as e:
|
||||
# try:
|
||||
# result = exec('{}'.format(cmd), myglobals, mylocals)
|
||||
# except Exception as e:
|
||||
# result = 'Exception {}\n'.format(e)
|
||||
# else:
|
||||
result = ''
|
||||
self.watcher_window.Element('_OUTPUT_').Update('{}\n'.format(result), append=True, autoscroll=True)
|
||||
# BUTTON - DETAIL
|
||||
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)
|
||||
result = str(eval(str(var), myglobals, mylocals))
|
||||
except:
|
||||
pass
|
||||
result = ''
|
||||
PopupScrolled(str(values['_VAR{}_'.format(event[4])]) + '\n' + result, title=var, non_blocking=True)
|
||||
# BUTTON - OBJ
|
||||
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
|
||||
result = ObjToStringSingleObj(mylocals[var])
|
||||
except Exception as e:
|
||||
result = '{}\nError showing object {}'.format(e, var)
|
||||
PopupScrolled(str(var) + '\n' + str(result), title=var, non_blocking=True)
|
||||
# ------------------------------- 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)
|
||||
# BUTTON - Globals (quick popup)
|
||||
elif event == '_GLOBALS_':
|
||||
self._display_all_vars(myglobals)
|
||||
# BUTTON - clear all
|
||||
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('')
|
||||
self.local_choices = {}
|
||||
self.custom_watch = ''
|
||||
# BUTTON - Popout
|
||||
elif event == '_POPOUT_':
|
||||
if not Debugger.popout_window:
|
||||
if not self.popout_window:
|
||||
self._build_floating_window()
|
||||
# BUTTON - Show All
|
||||
elif event == '_SHOW_ALL_':
|
||||
for key in Debugger.locals:
|
||||
Debugger.local_choices[key] = True if not key.startswith('_') else False
|
||||
for key in self.locals:
|
||||
self.local_choices[key] = not key.startswith('_')
|
||||
|
||||
# -------------------- Process the manual "watch list" ------------------
|
||||
for i in range(1, 4):
|
||||
for i in range(3):
|
||||
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('')
|
||||
self.myrc = ''
|
||||
if self.watcher_window.Element(key):
|
||||
var = values[key]
|
||||
try:
|
||||
result = eval(str(var), myglobals, mylocals)
|
||||
except:
|
||||
result = ''
|
||||
self.watcher_window.Element(out_key).Update(str(result))
|
||||
else:
|
||||
self.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)
|
||||
slot = 0
|
||||
for key in self.local_choices:
|
||||
if key == '_CUSTOM_WATCH_':
|
||||
continue
|
||||
if self.local_choices[key]:
|
||||
self.watcher_window.Element('_WATCH{}_'.format(slot)).Update(key)
|
||||
try:
|
||||
Debugger.watcher_window.Element('_WATCH{}_RESULT_'.format(slot)).Update(mylocals[key])
|
||||
self.watcher_window.Element('_WATCH{}_RESULT_'.format(slot), silent_on_error=True).Update(mylocals[key])
|
||||
except:
|
||||
pass
|
||||
# Debugger.watcher_window.Element('_WATCH{}_RESULT_'.format(slot)).Update('')
|
||||
self.watcher_window.Element('_WATCH{}_RESULT_'.format(slot)).Update('')
|
||||
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)
|
||||
if slot + int(not self.custom_watch in (None, '')) >= NUM_AUTO_WATCH:
|
||||
break
|
||||
# If a custom watch was set, display that value in the window
|
||||
if self.custom_watch:
|
||||
self.watcher_window.Element('_WATCH{}_'.format(slot)).Update(self.custom_watch)
|
||||
try:
|
||||
Debugger.myrc = eval(Debugger.custom_watch, myglobals, mylocals)
|
||||
self.myrc = eval(self.custom_watch, myglobals, mylocals)
|
||||
except:
|
||||
Debugger.myrc = ''
|
||||
Debugger.watcher_window.Element('_WATCH{}_RESULT_'.format(slot)).Update(Debugger.myrc)
|
||||
self.myrc = ''
|
||||
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):
|
||||
self.watcher_window.Element('_WATCH{}_'.format(i)).Update('')
|
||||
self.watcher_window.Element('_WATCH{}_RESULT_'.format(i)).Update('')
|
||||
|
||||
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
|
||||
return True # return indicating the window stayed open
|
||||
|
||||
###### # #
|
||||
# # #### ##### # # ##### # # # # # # ##### #### # #
|
||||
|
@ -8549,6 +8599,7 @@ class Debugger(object):
|
|||
# # # # # # ##### # ####### # # # # ###### ##### #
|
||||
# # # # # # # # # # # # # # # # # # # # #
|
||||
###### #### # # # #### # # ###### ###### # # # # # ####
|
||||
# displays them into a single text box
|
||||
|
||||
def _display_all_vars(self, dict):
|
||||
num_cols = 3
|
||||
|
@ -8573,21 +8624,21 @@ class Debugger(object):
|
|||
cur_col += 1
|
||||
ScrolledTextBox(out_text, non_blocking=True)
|
||||
|
||||
##### # #
|
||||
# # # # #### #### #### ###### # # # ## ##### #### # #
|
||||
# # # # # # # # # # # # # # # # # # #
|
||||
# ###### # # # # #### ##### # # # # # # # ######
|
||||
# # # # # # # # # # # # ###### # # # #
|
||||
# # # # # # # # # # # # # # # # # # # # #
|
||||
##### # # #### #### #### ###### ## ## # # # #### # #
|
||||
##### # #
|
||||
# # # # #### #### #### ###### # # # ## ##### #### # #
|
||||
# # # # # # # # # # # # # # # # # # #
|
||||
# ###### # # # # #### ##### # # # # # # # ######
|
||||
# # # # # # # # # # # # ###### # # # #
|
||||
# # # # # # # # # # # # # # # # # # # # #
|
||||
##### # # #### #### #### ###### ## ## # # # #### # #
|
||||
|
||||
# # # #
|
||||
# # ## ##### # ## ##### # ###### #### # # # # # #
|
||||
# # # # # # # # # # # # # # # # # # ## #
|
||||
# # # # # # # # # ##### # ##### #### # # # # # # #
|
||||
# # ###### ##### # ###### # # # # # # # # # # # #
|
||||
# # # # # # # # # # # # # # # # # # # # ##
|
||||
# # # # # # # # ##### ###### ###### #### ## ## # # #
|
||||
# # # #
|
||||
# # ## ##### # ## ##### # ###### #### # # # # # #
|
||||
# # # # # # # # # # # # # # # # # # ## #
|
||||
# # # # # # # # # ##### # ##### #### # # # # # # #
|
||||
# # ###### ##### # ###### # # # # # # # # # # # #
|
||||
# # # # # # # # # # # # # # # # # # # # ##
|
||||
# # # # # # # # ##### ###### ###### #### ## ## # # #
|
||||
|
||||
def _choose_auto_watches(self, my_locals):
|
||||
ChangeLookAndFeel(COLOR_SCHEME)
|
||||
|
@ -8603,7 +8654,7 @@ class Debugger(object):
|
|||
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))
|
||||
default=self.local_choices[key] if key in self.local_choices else False))
|
||||
if cur_col + 1 == num_cols:
|
||||
cur_col = 0
|
||||
layout.append(line)
|
||||
|
@ -8614,7 +8665,7 @@ class Debugger(object):
|
|||
layout.append(line)
|
||||
|
||||
layout += [
|
||||
[Text('Custom Watch'), Input(default_text=Debugger.custom_watch, size=(60, 1), key='_CUSTOM_WATCH_')]]
|
||||
[Text('Custom Watch (any expression)'), Input(default_text=self.custom_watch, size=(40, 1), key='_CUSTOM_WATCH_')]]
|
||||
layout += [
|
||||
[Ok(), Cancel(), Button('Clear All'), Button('Select [almost] All', key='_AUTO_SELECT_')]]
|
||||
|
||||
|
@ -8625,12 +8676,12 @@ class Debugger(object):
|
|||
if event in (None, 'Cancel'):
|
||||
break
|
||||
elif event == 'Ok':
|
||||
Debugger.local_choices = values
|
||||
Debugger.custom_watch = values['_CUSTOM_WATCH_']
|
||||
self.local_choices = values
|
||||
self.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')
|
||||
text_color='red', font='ANY 18')
|
||||
for key in sorted_dict:
|
||||
window.Element(key).Update(False)
|
||||
window.Element('_CUSTOM_WATCH_').Update('')
|
||||
|
@ -8659,11 +8710,11 @@ class Debugger(object):
|
|||
# # # # # # # # # # # # #
|
||||
# # # # # # # # # # # # ## #
|
||||
# # # # # ## # # # # ## ##
|
||||
## ## # # # ##### #### # #
|
||||
## ## # # # ##### #### # #
|
||||
|
||||
def _build_floating_window(self):
|
||||
if Debugger.popout_window:
|
||||
Debugger.popout_window.Close()
|
||||
def _build_floating_window(self, location=(None, None)):
|
||||
if self.popout_window: # if floating window already exists, close it first
|
||||
self.popout_window.Close()
|
||||
ChangeLookAndFeel('Topanga')
|
||||
num_cols = 2
|
||||
width_var = 15
|
||||
|
@ -8671,19 +8722,19 @@ class Debugger(object):
|
|||
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
|
||||
self.popout_choices = self.local_choices
|
||||
if self.popout_choices == {}: # if nothing chosen, then choose all non-_ variables
|
||||
for key in sorted(self.locals.keys()):
|
||||
self.popout_choices[key] = not key.startswith('_')
|
||||
|
||||
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')]
|
||||
width_var = max([len(key) for key in self.popout_choices])
|
||||
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)]
|
||||
if col + 1 < num_cols:
|
||||
line += [VerticalSeparator(), T(' ')]
|
||||
col += 1
|
||||
|
@ -8696,13 +8747,16 @@ class Debugger(object):
|
|||
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)
|
||||
self.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,
|
||||
right_click_menu=['&Right', ['Debugger::RightClick', 'Exit::RightClick']], location=location ).Finalize()
|
||||
if location == (None, None):
|
||||
screen_size = self.popout_window.GetScreenDimensions()
|
||||
self.popout_window.Move(screen_size[0] - self.popout_window.Size[0], 0)
|
||||
self.popout_window.SetAlpha(1)
|
||||
|
||||
ChangeLookAndFeel('SystemDefault')
|
||||
return True
|
||||
|
||||
######
|
||||
# # ###### ###### ##### ###### #### # #
|
||||
|
@ -8726,18 +8780,21 @@ class Debugger(object):
|
|||
# # # # # # # # # # # # #
|
||||
# # # # # # # # # # # # ## #
|
||||
# # # # # ## # # # # ## ##
|
||||
## ## # # # ##### #### # #
|
||||
## ## # # # ##### #### # #
|
||||
|
||||
def _refresh_floating_window():
|
||||
if not Debugger.popout_window:
|
||||
def _refresh_floating_window(self):
|
||||
if not self.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
|
||||
for key in self.popout_choices:
|
||||
if self.popout_choices[key] is True and key in self.locals:
|
||||
if key is not None:
|
||||
self.popout_window.Element(key, silent_on_error=True).Update(self.locals.get(key))
|
||||
event, values = self.popout_window.Read(timeout=1)
|
||||
if event in (None, '_EXIT_', 'Exit::RightClick'):
|
||||
self.popout_window.Close()
|
||||
self.popout_window = None
|
||||
elif event == 'Debugger::RightClick':
|
||||
show_debugger_window()
|
||||
|
||||
|
||||
# 888 888 .d8888b. d8888 888 888 888 888
|
||||
|
@ -8759,123 +8816,68 @@ class Debugger(object):
|
|||
# 888 "Y88888 888 888 "Y8888P "Y888 888 "Y88P" 888 888 88888P'
|
||||
|
||||
|
||||
# The *args are needed because sometimes this is called by tkinter and it sends in some parms of something
|
||||
# Due to the BIND that happens to the key
|
||||
''
|
||||
|
||||
|
||||
def show_debugger_window(*args):
|
||||
def show_debugger_window(location=(None, None), *args):
|
||||
if Debugger.debugger is None:
|
||||
Debugger.debugger = Debugger()
|
||||
debugger = Debugger.debugger
|
||||
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
|
||||
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()
|
||||
if not debugger.watcher_window:
|
||||
debugger.watcher_window = debugger._build_main_debugger_window(location=location)
|
||||
return True
|
||||
|
||||
|
||||
#
|
||||
#
|
||||
# def show_debugger_window(*args):
|
||||
# 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(*args):
|
||||
def show_debugger_popout_window(location=(None, None), *args):
|
||||
if Debugger.debugger is None:
|
||||
Debugger.debugger = Debugger()
|
||||
debugger = Debugger.debugger
|
||||
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
|
||||
debugger.locals = frame.f_back.f_locals
|
||||
debugger.globals = frame.f_back.f_globals
|
||||
finally:
|
||||
del frame
|
||||
if Debugger.popout_window:
|
||||
return
|
||||
debugger._build_floating_window()
|
||||
|
||||
|
||||
#
|
||||
# def show_debugger_popout_window(*args):
|
||||
#
|
||||
# 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()
|
||||
if debugger.popout_window:
|
||||
debugger.popout_window.Close()
|
||||
debugger.popout_window = None
|
||||
debugger._build_floating_window(location=location)
|
||||
|
||||
|
||||
def refresh_debugger():
|
||||
if Debugger.debugger is None:
|
||||
Debugger.debugger = Debugger()
|
||||
debugger = Debugger.debugger
|
||||
Window.read_call_from_debugger = True
|
||||
frame = inspect.currentframe()
|
||||
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
|
||||
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
|
||||
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 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
|
||||
|
|
|
@ -2,10 +2,16 @@
|
|||
![pysimplegui_logo](https://user-images.githubusercontent.com/13696193/43165867-fe02e3b2-8f62-11e8-9fd0-cc7c86b11772.png)
|
||||
|
||||
[![Downloads](http://pepy.tech/badge/pysimplegui)](http://pepy.tech/project/pysimplegui) tkinter
|
||||
|
||||
[![Downloads ](https://pepy.tech/badge/pysimplegui27)](https://pepy.tech/project/pysimplegui27) tkinter 2.7
|
||||
|
||||
[![Downloads](https://pepy.tech/badge/pysimpleguiqt)](https://pepy.tech/project/pysimpleguiqt) Qt
|
||||
|
||||
[![Downloads](https://pepy.tech/badge/pysimpleguiwx)](https://pepy.tech/project/pysimpleguiWx) WxPython
|
||||
|
||||
[![Downloads](https://pepy.tech/badge/pysimpleguiweb)](https://pepy.tech/project/pysimpleguiWeb) Web (Remi)
|
||||
|
||||
|
||||
![Documentation Status](https://readthedocs.org/projects/pysimplegui/badge/?version=latest)
|
||||
![Awesome Meter](https://img.shields.io/badge/Awesome_meter-100-yellow.svg)
|
||||
![Python Version](https://img.shields.io/badge/Python-2.7_3.x-yellow.svg)
|
||||
|
@ -14,7 +20,11 @@
|
|||
|
||||
# PySimpleGUI
|
||||
|
||||
|
||||
* Create windows that look and operate _identically_ to those created directly with tkinter, Qt, WxPython, and Remi.
|
||||
* Requires 1/2 to 1/5th the amount of code as underlying frameworks.
|
||||
* For exampl, develop a working Qt application in 1/2 to 1/5th the number lines of code.
|
||||
* The savings can be even greater depending on your application.
|
||||
* One afternoon is all that is required to learn the PySimpleGUI concepts and APIs.
|
||||
|
||||
## Supports both Python 2.7 & 3 when using tkinter
|
||||
|
||||
|
@ -25,9 +35,9 @@
|
|||
## The *only* way to write both desktop and web based GUIs at the same time
|
||||
|
||||
|
||||
![Python Version](https://img.shields.io/badge/PySimpleGUI_For_Python_3.x_Version-3.38.0-red.svg?longCache=true&style=for-the-badge)
|
||||
![Python Version](https://img.shields.io/badge/PySimpleGUI_For_Python_3.x_Version-3.39.0-red.svg?longCache=true&style=for-the-badge)
|
||||
|
||||
![Python Version](https://img.shields.io/badge/PySimpleGUI_For_Python_2.7_Version-1.37.0-blue.svg?longCache=true&style=for-the-badge)
|
||||
![Python Version](https://img.shields.io/badge/PySimpleGUI_For_Python_2.7_Version-1.39.0-blue.svg?longCache=true&style=for-the-badge)
|
||||
|
||||
![Python Version](https://img.shields.io/badge/PySimpleGUIQt_Version-0.31.0-orange.svg?longCache=true&style=for-the-badge)
|
||||
|
||||
|
@ -5011,6 +5021,33 @@ A combination of user requests, and needs of new `imwatchingyou` debugger
|
|||
* Option to "launch built-in debugger" from the test harness
|
||||
* Rememeber that the Debugger is still in this code! It may or may not be operational as it's one version back from the latest release of the `imwatchingyou` debugger code. This code needs to be integrated back in
|
||||
|
||||
## 3.39 PySimpleGUI & 1.39 PySimpleGUI27 13-June-2019
|
||||
|
||||
* Ported the imwatchingyou debugger code into PySimpleGUI code
|
||||
* Replaced old debugger built-in code with the newer imwatchingyou version
|
||||
* Required removing all of the 'sg.' before PySimpleGUI calls since not importing
|
||||
* Dynamically create the debugger object when first call to `refresh` or `show` is made
|
||||
* Started the procecss of renaming Class Methods that are private to start with _
|
||||
* Needed for the automatic documentation generation that's being worked on
|
||||
* Fixed crash when clicking the Debug button
|
||||
* Fixed bug in DeleteFigure. Needed to delete image separately
|
||||
* Added more type hints
|
||||
* New `TabGroup` method `SelectTab(index)` selects a `Tab` within a `TabGroup`
|
||||
* New `Table.Update` parameter - `select_rows`. List of rows to select (0 is first)
|
||||
* Error checking in `Window.Layout` provides error "hints" to the user
|
||||
* Looks for badly placed ']'
|
||||
* Looks for functions missing '()'
|
||||
* Pops up a window warning user instead of crashing
|
||||
* May have to revisit if the popups start getting in the way
|
||||
* New implementations of `Window.Disable()` and `Window.Enable()`
|
||||
* Previously did not work correctly at all
|
||||
* Now using the "-disabled" attribute
|
||||
* Allow Comboboxes to have empty starting values
|
||||
* Was crashing
|
||||
* Enables application to fill these in later
|
||||
|
||||
|
||||
|
||||
### Upcoming
|
||||
Make suggestions people! Future release features
|
||||
|
||||
|
|
43
readme.md
43
readme.md
|
@ -2,10 +2,16 @@
|
|||
![pysimplegui_logo](https://user-images.githubusercontent.com/13696193/43165867-fe02e3b2-8f62-11e8-9fd0-cc7c86b11772.png)
|
||||
|
||||
[![Downloads](http://pepy.tech/badge/pysimplegui)](http://pepy.tech/project/pysimplegui) tkinter
|
||||
|
||||
[![Downloads ](https://pepy.tech/badge/pysimplegui27)](https://pepy.tech/project/pysimplegui27) tkinter 2.7
|
||||
|
||||
[![Downloads](https://pepy.tech/badge/pysimpleguiqt)](https://pepy.tech/project/pysimpleguiqt) Qt
|
||||
|
||||
[![Downloads](https://pepy.tech/badge/pysimpleguiwx)](https://pepy.tech/project/pysimpleguiWx) WxPython
|
||||
|
||||
[![Downloads](https://pepy.tech/badge/pysimpleguiweb)](https://pepy.tech/project/pysimpleguiWeb) Web (Remi)
|
||||
|
||||
|
||||
![Documentation Status](https://readthedocs.org/projects/pysimplegui/badge/?version=latest)
|
||||
![Awesome Meter](https://img.shields.io/badge/Awesome_meter-100-yellow.svg)
|
||||
![Python Version](https://img.shields.io/badge/Python-2.7_3.x-yellow.svg)
|
||||
|
@ -14,7 +20,11 @@
|
|||
|
||||
# PySimpleGUI
|
||||
|
||||
|
||||
* Create windows that look and operate _identically_ to those created directly with tkinter, Qt, WxPython, and Remi.
|
||||
* Requires 1/2 to 1/5th the amount of code as underlying frameworks.
|
||||
* For exampl, develop a working Qt application in 1/2 to 1/5th the number lines of code.
|
||||
* The savings can be even greater depending on your application.
|
||||
* One afternoon is all that is required to learn the PySimpleGUI concepts and APIs.
|
||||
|
||||
## Supports both Python 2.7 & 3 when using tkinter
|
||||
|
||||
|
@ -25,9 +35,9 @@
|
|||
## The *only* way to write both desktop and web based GUIs at the same time
|
||||
|
||||
|
||||
![Python Version](https://img.shields.io/badge/PySimpleGUI_For_Python_3.x_Version-3.38.0-red.svg?longCache=true&style=for-the-badge)
|
||||
![Python Version](https://img.shields.io/badge/PySimpleGUI_For_Python_3.x_Version-3.39.0-red.svg?longCache=true&style=for-the-badge)
|
||||
|
||||
![Python Version](https://img.shields.io/badge/PySimpleGUI_For_Python_2.7_Version-1.37.0-blue.svg?longCache=true&style=for-the-badge)
|
||||
![Python Version](https://img.shields.io/badge/PySimpleGUI_For_Python_2.7_Version-1.39.0-blue.svg?longCache=true&style=for-the-badge)
|
||||
|
||||
![Python Version](https://img.shields.io/badge/PySimpleGUIQt_Version-0.31.0-orange.svg?longCache=true&style=for-the-badge)
|
||||
|
||||
|
@ -5011,6 +5021,33 @@ A combination of user requests, and needs of new `imwatchingyou` debugger
|
|||
* Option to "launch built-in debugger" from the test harness
|
||||
* Rememeber that the Debugger is still in this code! It may or may not be operational as it's one version back from the latest release of the `imwatchingyou` debugger code. This code needs to be integrated back in
|
||||
|
||||
## 3.39 PySimpleGUI & 1.39 PySimpleGUI27 13-June-2019
|
||||
|
||||
* Ported the imwatchingyou debugger code into PySimpleGUI code
|
||||
* Replaced old debugger built-in code with the newer imwatchingyou version
|
||||
* Required removing all of the 'sg.' before PySimpleGUI calls since not importing
|
||||
* Dynamically create the debugger object when first call to `refresh` or `show` is made
|
||||
* Started the procecss of renaming Class Methods that are private to start with _
|
||||
* Needed for the automatic documentation generation that's being worked on
|
||||
* Fixed crash when clicking the Debug button
|
||||
* Fixed bug in DeleteFigure. Needed to delete image separately
|
||||
* Added more type hints
|
||||
* New `TabGroup` method `SelectTab(index)` selects a `Tab` within a `TabGroup`
|
||||
* New `Table.Update` parameter - `select_rows`. List of rows to select (0 is first)
|
||||
* Error checking in `Window.Layout` provides error "hints" to the user
|
||||
* Looks for badly placed ']'
|
||||
* Looks for functions missing '()'
|
||||
* Pops up a window warning user instead of crashing
|
||||
* May have to revisit if the popups start getting in the way
|
||||
* New implementations of `Window.Disable()` and `Window.Enable()`
|
||||
* Previously did not work correctly at all
|
||||
* Now using the "-disabled" attribute
|
||||
* Allow Comboboxes to have empty starting values
|
||||
* Was crashing
|
||||
* Enables application to fill these in later
|
||||
|
||||
|
||||
|
||||
### Upcoming
|
||||
Make suggestions people! Future release features
|
||||
|
||||
|
|
Loading…
Reference in New Issue