Merge pull request #3381 from PySimpleGUI/Dev-latest

echo_stdout_stderr parm added to multiline and output, added Dark Bro…
This commit is contained in:
PySimpleGUI 2020-09-15 07:21:25 -04:00 committed by GitHub
commit 742f1a7180
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 67 additions and 28 deletions

View File

@ -1,5 +1,5 @@
#!/usr/bin/python3
version = __version__ = "4.29.0.8 Unreleased\nAdded shink parameter to pin, added variable Window.maximized, added main_sdk_help_window function, theme DarkGrey10 added, no longer setting highlight thickness to 0 for buttons so that focus can be seen, new themes DarkGrey11 DarkGrey12 DarkGrey13 DarkGrey14, new user_settings APIs, added text parameter to Radio.update"
version = __version__ = "4.29.0.9 Unreleased\nAdded shink parameter to pin, added variable Window.maximized, added main_sdk_help_window function, theme DarkGrey10 added, no longer setting highlight thickness to 0 for buttons so that focus can be seen, new themes DarkGrey11 DarkGrey12 DarkGrey13 DarkGrey14, new user_settings APIs, added text parameter to Radio.update, echo_stdout_stderr parm added to Multiline and Output elements, added DarkBrown7 theme"
port = 'PySimpleGUI'
@ -1962,6 +1962,7 @@ class Checkbox(Element):
return
if value is not None:
value = bool(value)
try:
self.TKIntVar.set(value)
self.InitialState = value
@ -2158,7 +2159,7 @@ class Multiline(Element):
def __init__(self, default_text='', enter_submits=False, disabled=False, autoscroll=False, border_width=None,
size=(None, None), auto_size_text=None, background_color=None, text_color=None, 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, focus=False, font=None, pad=None, tooltip=None, justification=None,
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, tooltip=None, justification=None,
right_click_menu=None, visible=True, metadata=None):
"""
:param default_text: Initial text to show
@ -2199,6 +2200,8 @@ class Multiline(Element):
:type reroute_stderr: (bool)
:param reroute_cprint: If True your cprint calls will output to this element. It's the same as you calling cprint_set_output_destination
:type reroute_cprint: (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 focus: if True initial focus will go to this element
:type focus: (bool)
:param font: specifies the font family, size, etc
@ -2236,6 +2239,7 @@ class Multiline(Element):
key = key if key is not None else k
self.previous_stdout = self.previous_stderr = None
self.reroute_cprint = reroute_cprint
self.echo_stdout_stderr = echo_stdout_stderr
self.Justification = 'left' if justification is None else justification
self.justification_tag = self.just_center_tag = self.just_left_tag = self.just_right_tag = None
if reroute_stdout:
@ -2345,6 +2349,7 @@ class Multiline(Element):
except:
pass
def Get(self):
"""
Return current contents of the Multiline Element
@ -2352,7 +2357,6 @@ class Multiline(Element):
:return: current contents of the Multiline Element (used as an input type of Multiline
:rtype: (str)
"""
return self.TKText.get(1.0, tk.END)
@ -2392,6 +2396,7 @@ class Multiline(Element):
self.previous_stderr = sys.stderr
sys.stderr = self
def restore_stdout(self):
"""
Restore a previously re-reouted stdout back to the original destination
@ -2417,6 +2422,8 @@ class Multiline(Element):
"""
try:
self.update(txt, append=True)
if self.echo_stdout_stderr:
self.previous_stdout.write(txt)
except:
pass
@ -2426,7 +2433,10 @@ class Multiline(Element):
Flush parameter was passed into a print statement.
For now doing nothing. Not sure what action should be taken to ensure a flush happens regardless.
"""
return
try:
self.previous_stdout.flush()
except:
pass
def __del__(self):
@ -2472,7 +2482,7 @@ class Text(Element):
:param relief: relief style around the text. Values are same as progress meter relief values. Should be a constant that is defined at starting with "RELIEF_" - `RELIEF_RAISED, RELIEF_SUNKEN, RELIEF_FLAT, RELIEF_RIDGE, RELIEF_GROOVE, RELIEF_SOLID`
:type relief: (str/enum)
:param font: specifies the font family, size, etc
:type font: Union[str, Tuple[str, int]]
:type font: (str or Tuple[str, int] or None)
:param text_color: color of the text
:type text_color: (str)
:param background_color: color of background
@ -2784,7 +2794,7 @@ class TKOutput(tk.Frame):
to PySimpleGUI by directly manipulating tkinter.
"""
def __init__(self, parent, width, height, bd, background_color=None, text_color=None, font=None, pad=None):
def __init__(self, parent, width, height, bd, background_color=None, text_color=None, echo_stdout_stderr=False, font=None, pad=None):
"""
:param parent: The "Root" that the Widget will be in
:type parent: Union[tk.Tk, tk.Toplevel]
@ -2798,6 +2808,8 @@ class TKOutput(tk.Frame):
:type background_color: (str)
:param text_color: color of the text
:type text_color: (str)
: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
:type font: Union[str, Tuple[str, int]]
:param pad: Amount of padding to put around element (left/right, top/bottom) or ((left, right), (top, bottom))
@ -2819,6 +2831,7 @@ class TKOutput(tk.Frame):
self.previous_stdout = sys.stdout
self.previous_stderr = sys.stderr
self.parent = parent
self.echo_stdout_stderr = echo_stdout_stderr
sys.stdout = self
sys.stderr = self
@ -2839,6 +2852,12 @@ class TKOutput(tk.Frame):
except:
pass
try:
if self.echo_stdout_stderr:
self.previous_stdout.write(txt)
except:
pass
def Close(self):
"""
Called when wanting to restore the old stdout/stderr
@ -2851,7 +2870,12 @@ class TKOutput(tk.Frame):
Flush parameter was passed into a print statement.
For now doing nothing. Not sure what action should be taken to ensure a flush happens regardless.
"""
return
try:
if self.echo_stdout_stderr:
self.previous_stdout.flush()
except:
pass
def __del__(self):
@ -2871,8 +2895,7 @@ class Output(Element):
Output Element - a multi-lined text area where stdout and stderr are re-routed to.
"""
def __init__(self, size=(None, None), background_color=None, text_color=None, pad=None, font=None, tooltip=None,
key=None, k=None, right_click_menu=None, visible=True, metadata=None):
def __init__(self, size=(None, None), background_color=None, text_color=None, pad=None, echo_stdout_stderr=False, font=None, tooltip=None, key=None, k=None, right_click_menu=None, visible=True, metadata=None):
"""
:param size: (width, height) w=characters-wide, h=rows-high
:type size: (int, int)
@ -2882,6 +2905,8 @@ class Output(Element):
:type text_color: (str)
:param pad: Amount of padding to put around element (left/right, top/bottom) or ((left, right), (top, bottom))
:type pad: (int, int) or ((int, int),(int,int)) or (int,(int,int)) or ((int, int),int)
: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
:type font: Union[str, Tuple[str, int]]
:param tooltip: text, that will appear when mouse hovers over the element
@ -2903,6 +2928,7 @@ class Output(Element):
fg = text_color if text_color is not None else DEFAULT_INPUT_TEXT_COLOR
self.RightClickMenu = right_click_menu
key = key if key is not None else k
self.echo_stdout_stderr = echo_stdout_stderr
super().__init__(ELEM_TYPE_OUTPUT, size=size, background_color=bg, text_color=fg, pad=pad, font=font,
tooltip=tooltip, key=key, visible=visible, metadata=metadata)
@ -9339,7 +9365,7 @@ def Sizer(h_pixels=0, v_pixels=0):
def pin(elem, vertical_alignment=None, shrink=True):
'''
"""
Pin's an element provided into a layout so that when it's made invisible and visible again, it will
be in the correct place. Otherwise it will be placed at the end of its containing window/column.
@ -9351,7 +9377,7 @@ def pin(elem, vertical_alignment=None, shrink=True):
:type shrink: bool
:return: A column element containing the provided element
:rtype: Column
'''
"""
if shrink:
return Column([[elem, Canvas(size=(0,0), pad=(0,0))]], pad=(0,0), vertical_alignment=vertical_alignment)
else:
@ -9359,14 +9385,14 @@ def pin(elem, vertical_alignment=None, shrink=True):
def vtop(elem_or_row):
'''
"""
Align an element or a row of elements to the top of the row that contains it
:param elem_or_row: the element or row of elements
:type elem_or_row: Union[Element, List[Element], Tuple[Element]]
:return: A column element containing the provided element aligned to the top or list of elements (a row)
:rtype: Union[Column, List[Column]]
'''
"""
if isinstance(elem_or_row, list) or isinstance(elem_or_row, tuple):
return [Column([[e]], pad=(0,0), vertical_alignment='top') for e in elem_or_row]
@ -9375,14 +9401,14 @@ def vtop(elem_or_row):
def vcenter(elem_or_row):
'''
"""
Align an element or a row of elements to the center of the row that contains it
:param elem_or_row: the element or row of elements
:type elem_or_row: Union[Element, List[Element], Tuple[Element]]
:return: A column element containing the provided element aligned to the center or list of elements (a row)
:rtype: Union[Column, List[Column]]
'''
"""
if isinstance(elem_or_row, list) or isinstance(elem_or_row, tuple):
return [Column([[e]], pad=(0,0), vertical_alignment='center') for e in elem_or_row]
@ -9392,14 +9418,14 @@ def vcenter(elem_or_row):
def vbottom(elem_or_row):
'''
"""
Align an element or a row of elements to the bottom of the row that contains it
:param elem_or_row: the element or row of elements
:type elem_or_row: Union[Element, List[Element], Tuple[Element]]
:return: A column element containing the provided element aligned to the bottom or list of elements (a row)
:rtype: Union[Column, List[Column]]
'''
"""
if isinstance(elem_or_row, list) or isinstance(elem_or_row, tuple):
return [Column([[e]], pad=(0,0), vertical_alignment='bottom') for e in elem_or_row]
@ -10173,7 +10199,7 @@ CButton = CloseButton
def ReadButton(button_text, image_filename=None, image_data=None, image_size=(None, None), image_subsample=None,
border_width=None, tooltip=None, size=(None, None), auto_size_button=None, button_color=None, font=None,
bind_return_key=False, disabled=False, focus=False, pad=None, key=None, k=None, metadata=None):
'''
"""
:param button_text: text in the button
:type button_text: (str)
:param image_filename: image filename if there is a button image
@ -10212,7 +10238,7 @@ def ReadButton(button_text, image_filename=None, image_data=None, image_size=(No
:type metadata: (Any)
:return: Button created
:rtype: (Button)
'''
"""
return Button(button_text=button_text, button_type=BUTTON_TYPE_READ_FORM, image_filename=image_filename,
image_data=image_data, image_size=image_size, image_subsample=image_subsample,
@ -11968,11 +11994,12 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form):
timeout=DEFAULT_TOOLTIP_TIME)
# ------------------------- OUTPUT placement element ------------------------- #
elif element_type == ELEM_TYPE_OUTPUT:
element = element # type: Output
width, height = element_size
element._TKOut = element.Widget = TKOutput(tk_row_frame, width=width, height=height, bd=border_depth,
background_color=element.BackgroundColor,
text_color=text_color, font=font,
pad=elementpad)
pad=elementpad, echo_stdout_stderr=element.echo_stdout_stderr)
element._TKOut.output.configure(takefocus=0) # make it so that Output does not get focus
element._TKOut.pack(side=tk.LEFT, expand=False, fill=tk.NONE)
if element.Visible is False:
@ -13085,12 +13112,12 @@ def OneLineProgressMeterCancel(key='OK for 1 meter'):
def GetComplimentaryHex(color):
'''
"""
:param color: color string, like "#RRGGBB"
:type color: (str)
:return: color string, like "#RRGGBB"
:rtype: (str)
'''
"""
# strip the # from the beginning
color = color[1:]
@ -14809,7 +14836,17 @@ LOOK_AND_FEEL_TABLE = {'SystemDefault':
'SCROLL': '#1d2125',
'BUTTON': ('#fafbfc', '#155398'),
'PROGRESS': ('#155398','#1d2125'),
'BORDER': 1, 'SLIDER_DEPTH': 0, 'PROGRESS_DEPTH': 0}
'BORDER': 1, 'SLIDER_DEPTH': 0, 'PROGRESS_DEPTH': 0},
'DarkBrown7' : {'BACKGROUND': '#2c2417',
'TEXT': '#baa379',
'INPUT': '#baa379',
'TEXT_INPUT': '#000000',
'SCROLL': '#392e1c',
'BUTTON': ('#000000', '#baa379'),
'PROGRESS': ('#baa379','#453923'),
'BORDER': 1,
'SLIDER_DEPTH': 1,
'PROGRESS_DEPTH': 0}
}
@ -16844,11 +16881,13 @@ class _UserSettings:
path = dirname_from_filename
filename = os.path.basename(filename)
else:
frame = inspect.stack()[2]
module = inspect.getmodule(frame[0])
filename = module.__file__
filename = os.path.basename(filename)
filename = os.path.splitext(filename)[0] + '.json'
# frame = inspect.stack()[2]
# module = inspect.getmodule(frame[0])
filename = os.path.splitext(os.path.basename(sys.modules["__main__"].__file__))[0] + '.json'
# print(filename)
# filename = module.__file__
# filename = os.path.basename(filename)
# filename = os.path.splitext(filename)[0] + '.json'
self.filename = filename
if path is None: