Merge pull request #1167 from PySimpleGUI/Dev-latest

Dev latest
This commit is contained in:
MikeTheWatchGuy 2019-02-18 20:12:30 -05:00 committed by GitHub
commit bc1a852ee6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 235 additions and 128 deletions

View File

@ -6170,7 +6170,7 @@ class QuickMeter(object):
layout = [] layout = []
if self.orientation.lower().startswith('h'): if self.orientation.lower().startswith('h'):
col = [] col = []
col += [[T(arg)] for arg in args] col += [[T(''.join(map(lambda x: str(x)+'\n',args)),key='_OPTMSG_')]] ### convert all *args into one string that can be updated
col += [[T('', size=(30,10), key='_STATS_')], col += [[T('', size=(30,10), key='_STATS_')],
[ProgressBar(max_value=self.max_value, orientation='h', key='_PROG_', size=self.size, bar_color=self.bar_color)], [ProgressBar(max_value=self.max_value, orientation='h', key='_PROG_', size=self.size, bar_color=self.bar_color)],
[Cancel(button_color=self.button_color), Stretch()]] [Cancel(button_color=self.button_color), Stretch()]]
@ -6178,7 +6178,7 @@ class QuickMeter(object):
else: else:
col = [[ProgressBar(max_value=self.max_value, orientation='v', key='_PROG_', size=self.size, bar_color=self.bar_color)]] col = [[ProgressBar(max_value=self.max_value, orientation='v', key='_PROG_', size=self.size, bar_color=self.bar_color)]]
col2 = [] col2 = []
col2 += [[T(arg)] for arg in args] col2 += [[T(''.join(map(lambda x: str(x)+'\n',args)),key='_OPTMSG_')]] ### convert all *args into one string that can be updated
col2 += [[T('', size=(30,10), key='_STATS_')], col2 += [[T('', size=(30,10), key='_STATS_')],
[Cancel(button_color=self.button_color), Stretch()]] [Cancel(button_color=self.button_color), Stretch()]]
layout = [Column(col), Column(col2)] layout = [Column(col), Column(col2)]
@ -6187,11 +6187,12 @@ class QuickMeter(object):
return self.window return self.window
def UpdateMeter(self, current_value, max_value): def UpdateMeter(self, current_value, max_value,*args): ### support for *args when updating
self.current_value = current_value self.current_value = current_value
self.max_value = max_value self.max_value = max_value
self.window.Element('_PROG_').UpdateBar(self.current_value, self.max_value) self.window.Element('_PROG_').UpdateBar(self.current_value, self.max_value)
self.window.Element('_STATS_').Update('\n'.join(self.ComputeProgressStats())) self.window.Element('_STATS_').Update('\n'.join(self.ComputeProgressStats()))
self.window.Element('_OPTMSG_').Update(value=''.join(map(lambda x: str(x)+'\n',args))) ### update the string with the args
event, values = self.window.Read(timeout=0) event, values = self.window.Read(timeout=0)
if event in('Cancel', None) or current_value >= max_value: if event in('Cancel', None) or current_value >= max_value:
self.window.Close() self.window.Close()
@ -6239,10 +6240,11 @@ def OneLineProgressMeter(title, current_value, max_value, key, *args, orientatio
else: else:
meter = QuickMeter.active_meters[key] meter = QuickMeter.active_meters[key]
rc = meter.UpdateMeter(current_value, max_value) rc = meter.UpdateMeter(current_value, max_value,*args) ### pass the *args to to UpdateMeter function
OneLineProgressMeter.exit_reasons = getattr(OneLineProgressMeter,'exit_reasons', QuickMeter.exit_reasons) OneLineProgressMeter.exit_reasons = getattr(OneLineProgressMeter,'exit_reasons', QuickMeter.exit_reasons)
return rc == METER_OK return rc == METER_OK
def OneLineProgressMeterCancel(key): def OneLineProgressMeterCancel(key):
try: try:
meter = QuickMeter.active_meters[key] meter = QuickMeter.active_meters[key]

View File

@ -8,6 +8,16 @@ import base64
import calendar import calendar
from random import randint from random import randint
###### ##### ##### # # ### #####
# # # # # # # # # ##### # ###### # # # # # # # #####
# # # # # # ## ## # # # # # # # # # # #
###### # ##### # # ## # # # # ##### # #### # # # # # #
# # # # # # ##### # # # # # # # # # # #
# # # # # # # # # # # # # # # # # #
# # ##### # # # # ###### ###### ##### ##### ### #### # #
FORCE_PYQT5 = False FORCE_PYQT5 = False
if not FORCE_PYQT5: if not FORCE_PYQT5:
@ -4404,9 +4414,48 @@ def AddMenuItem(top_menu, sub_menu_info, element, is_sub_menu=False, skip=False)
AddMenuItem(top_menu, item, element) AddMenuItem(top_menu, item, element)
i += 1 i += 1
"""
QQQQQQQQQ tttt
QQ:::::::::QQ ttt:::t
QQ:::::::::::::QQ t:::::t
Q:::::::QQQ:::::::Q t:::::t
Q::::::O Q::::::Qttttttt:::::ttttttt
Q:::::O Q:::::Qt:::::::::::::::::t
Q:::::O Q:::::Qt:::::::::::::::::t
Q:::::O Q:::::Qtttttt:::::::tttttt
Q:::::O Q:::::Q t:::::t
Q:::::O Q:::::Q t:::::t
Q:::::O QQQQ:::::Q t:::::t
Q::::::O Q::::::::Q t:::::t tttttt
Q:::::::QQ::::::::Q t::::::tttt:::::t
QQ::::::::::::::Q tt::::::::::::::t
QQ:::::::::::Q tt:::::::::::tt
QQQQQQQQ::::QQ ttttttttttt
Q:::::Q
QQQQQQ
"""
# My crappy Qt code starts here
# ░░░░░░░░░░░█▀▀░░█░░░░░░
# ░░░░░░▄▀▀▀▀░░░░░█▄▄░░░░
# ░░░░░░█░█░░░░░░░░░░▐░░░
# ░░░░░░▐▐░░░░░░░░░▄░▐░░░
# ░░░░░░█░░░░░░░░▄▀▀░▐░░░
# ░░░░▄▀░░░░░░░░▐░▄▄▀░░░░
# ░░▄▀░░░▐░░░░░█▄▀░▐░░░░░
# ░░█░░░▐░░░░░░░░▄░█░░░░░
# ░░░█▄░░▀▄░░░░▄▀▐░█░░░░░
# ░░░█▐▀▀▀░▀▀▀▀░░▐░█░░░░░
# ░░▐█▐▄░░▀░░░░░░▐░█▄▄░░░
# ░░░▀▀▄░░░░░░░░▄▐▄▄▄▀░░░
# ░░░░░░░░░░░░░░░░░░░░░░░
# ------------------------------------------------------------------------------------------------------------------ # # ------------------------------------------------------------------------------------------------------------------ #
# ------------------------------------------------------------------------------------------------------------------ # # ------------------------------------------------------------------------------------------------------------------ #
# ===================================== TK CODE STARTS HERE ====================================================== # # ===================================== Qt CODE STARTS HERE ====================================================== #
# ------------------------------------------------------------------------------------------------------------------ # # ------------------------------------------------------------------------------------------------------------------ #
# ------------------------------------------------------------------------------------------------------------------ # # ------------------------------------------------------------------------------------------------------------------ #
def style_entry(**kwargs): def style_entry(**kwargs):
@ -5735,27 +5784,28 @@ class QuickMeter(object):
def BuildWindow(self, *args): def BuildWindow(self, *args):
layout = [] layout = []
if self.orientation.lower().startswith('h'): if self.orientation.lower().startswith('h'):
col = [*[[T(arg)] for arg in args], col = [[T(''.join(map(lambda x: str(x)+'\n',args)),key='_OPTMSG_')]] ### convert all *args into one string that can be updated
[T('', size=(25,8), key='_STATS_')], col += [[T('', size=(25,5), key='_STATS_')],
[ProgressBar(max_value=self.max_value, orientation='h', key='_PROG_', size=self.size, [ProgressBar(max_value=self.max_value, orientation='h', key='_PROG_', size=self.size,
bar_color=self.bar_color)], bar_color=self.bar_color)],
[Cancel(button_color=self.button_color), Stretch()]] [Cancel(button_color=self.button_color), Stretch()]]
layout += [Column(col)] layout += [Column(col)]
else: else:
col = [[ProgressBar(max_value=self.max_value, orientation='v', key='_PROG_', size=self.size, bar_color=self.bar_color)]] col = [[ProgressBar(max_value=self.max_value, orientation='v', key='_PROG_', size=self.size, bar_color=self.bar_color)]]
col2 = [*[[T(arg)] for arg in args], col2 = [[T(''.join(map(lambda x: str(x)+'\n',args)),key='_OPTMSG_')]] ### convert all *args into one string that can be updated
[T('', size=(25, 8), key='_STATS_')],[Cancel(button_color=self.button_color), Stretch()] ] col2 += [[T('', size=(25,5), key='_STATS_')],[Cancel(button_color=self.button_color), Stretch()]]
layout += [Column(col), Column(col2)] layout += [Column(col), Column(col2)]
self.window = Window(self.title, grab_anywhere=self.grab_anywhere, border_depth=self.border_width) self.window = Window(self.title, grab_anywhere=self.grab_anywhere, border_depth=self.border_width)
self.window.Layout([layout]).Finalize() self.window.Layout([layout]).Finalize()
return self.window return self.window
def UpdateMeter(self, current_value, max_value): def UpdateMeter(self, current_value, max_value, *args):
self.current_value = current_value self.current_value = current_value
self.max_value = max_value self.max_value = max_value
self.window.Element('_PROG_').UpdateBar(self.current_value, self.max_value) self.window.Element('_PROG_').UpdateBar(self.current_value, self.max_value)
self.window.Element('_STATS_').Update('\n'.join(self.ComputeProgressStats())) self.window.Element('_STATS_').Update('\n'.join(self.ComputeProgressStats()))
self.window.Element('_OPTMSG_').Update(value=''.join(map(lambda x: str(x)+'\n',args))) ### update the string with the args
event, values = self.window.Read(timeout=0) event, values = self.window.Read(timeout=0)
if event in('Cancel', None) or current_value >= max_value: if event in('Cancel', None) or current_value >= max_value:
self.window.Close() self.window.Close()
@ -5803,7 +5853,7 @@ def OneLineProgressMeter(title, current_value, max_value, key, *args, orientatio
else: else:
meter = QuickMeter.active_meters[key] meter = QuickMeter.active_meters[key]
rc = meter.UpdateMeter(current_value, max_value) rc = meter.UpdateMeter(current_value, max_value, *args)
OneLineProgressMeter.exit_reasons = getattr(OneLineProgressMeter,'exit_reasons', QuickMeter.exit_reasons) OneLineProgressMeter.exit_reasons = getattr(OneLineProgressMeter,'exit_reasons', QuickMeter.exit_reasons)
return rc == METER_OK return rc == METER_OK

View File

@ -11,7 +11,7 @@ from queue import Queue
import remi import remi
import logging import logging
import traceback import traceback
import os
g_time_start = 0 g_time_start = 0
g_time_end = 0 g_time_end = 0
@ -143,7 +143,7 @@ DEFAULT_PROGRESS_BAR_BORDER_WIDTH = 1
DEFAULT_PROGRESS_BAR_RELIEF = RELIEF_GROOVE DEFAULT_PROGRESS_BAR_RELIEF = RELIEF_GROOVE
PROGRESS_BAR_STYLES = ('default', 'winnative', 'clam', 'alt', 'classic', 'vista', 'xpnative') PROGRESS_BAR_STYLES = ('default', 'winnative', 'clam', 'alt', 'classic', 'vista', 'xpnative')
DEFAULT_PROGRESS_BAR_STYLE = 'default' DEFAULT_PROGRESS_BAR_STYLE = 'default'
DEFAULT_METER_ORIENTATION = 'Horizontal' DEFAULT_METER_ORIENTATION = 'horizontal'
DEFAULT_SLIDER_ORIENTATION = 'vertical' DEFAULT_SLIDER_ORIENTATION = 'vertical'
DEFAULT_SLIDER_BORDER_WIDTH = 1 DEFAULT_SLIDER_BORDER_WIDTH = 1
DEFAULT_SLIDER_RELIEF = 00000 DEFAULT_SLIDER_RELIEF = 00000
@ -439,6 +439,28 @@ class Element():
def Update(self, widget, background_color=None, text_color=None, font=None, visible=None, disabled=None, tooltip=None): def Update(self, widget, background_color=None, text_color=None, font=None, visible=None, disabled=None, tooltip=None):
if font is not None:
font_info = font_parse_string(font) # family, point size, other
widget.style['font-family'] = font_info[0]
widget.style['font-size'] = '{}px'.format(font_info[1])
if background_color not in (None, COLOR_SYSTEM_DEFAULT):
widget.style['background-color'] = background_color
if text_color not in (None, COLOR_SYSTEM_DEFAULT):
widget.style['color'] = text_color
if disabled:
widget.set_enabled(False)
elif disabled is False:
widget.set_enabled(True)
if visible is False:
widget.attributes['hidden'] = 'true'
elif visible is True:
del(widget.attributes['hidden'])
if tooltip is not None:
widget.attributes['title'] = tooltip
# if font: # if font:
# widget.SetFont(font_to_wx_font(font)) # widget.SetFont(font_to_wx_font(font))
# if text_color not in (None, COLOR_SYSTEM_DEFAULT): # if text_color not in (None, COLOR_SYSTEM_DEFAULT):
@ -912,22 +934,9 @@ class Spin(Element):
def Update(self, value=None, values=None, disabled=None, background_color=None, text_color=None, font=None, visible=None): def Update(self, value=None, values=None, disabled=None, background_color=None, text_color=None, font=None, visible=None):
if values != None:
self.Values = values
self.QT_Spinner.setStrings(values)
# self.QT_Spinner.setRange(self.Values[0], self.Values[1])
if value is not None: if value is not None:
# self.QT_Spinner.setValue(value) self.Widget.set_value(value)
try: super().Update(self.Widget, background_color=background_color, text_color=text_color, font=font,visible=visible)
self.QT_Spinner.setValue(self.QT_Spinner.valueFromText(value))
self.DefaultValue = value
except:
pass
if disabled == True:
self.QT_Spinner.setDisabled(True)
elif disabled == False:
self.QT_Spinner.setDisabled(False)
super().Update(self.QT_Spinner, background_color=background_color, text_color=text_color, font=font, visible=visible)
def Get(self): def Get(self):
return self.Widget.get_value() return self.Widget.get_value()
@ -1076,7 +1085,7 @@ class MultilineOutput(Element):
self.CurrentValue = self.CurrentValue + '\n' + str(value) self.CurrentValue = self.CurrentValue + '\n' + str(value)
self.Widget.set_value(self.CurrentValue) self.Widget.set_value(self.CurrentValue)
app = self.ParentForm.App app = self.ParentForm.App
app.execute_javascript("document.getElementById('%s').scrollTop=%s;" % (self.Widget.identifier, 9999)) # 9999 number of pixel to scroll # app.execute_javascript("document.getElementById('%s').scrollTop=%s;" % (self.Widget.identifier, 9999)) # 9999 number of pixel to scroll
super().Update(self.Widget, background_color=background_color, text_color=text_color, font=font, visible=visible) super().Update(self.Widget, background_color=background_color, text_color=text_color, font=font, visible=visible)
@ -1134,6 +1143,7 @@ class Text(Element):
pixelsize = size[0]*10, size[1]*20 pixelsize = size[0]*10, size[1]*20
self.BorderWidth = border_width if border_width is not None else DEFAULT_BORDER_WIDTH self.BorderWidth = border_width if border_width is not None else DEFAULT_BORDER_WIDTH
self.Disabled = False self.Disabled = False
self.Widget = None #type: remi.gui.Label
super().__init__(ELEM_TYPE_TEXT, pixelsize, auto_size_text, background_color=bg, font=font if font else DEFAULT_FONT, super().__init__(ELEM_TYPE_TEXT, pixelsize, auto_size_text, background_color=bg, font=font if font else DEFAULT_FONT,
text_color=self.TextColor, pad=pad, key=key, tooltip=tooltip, size_px=size_px, visible=visible) text_color=self.TextColor, pad=pad, key=key, tooltip=tooltip, size_px=size_px, visible=visible)
@ -1142,12 +1152,7 @@ class Text(Element):
def Update(self, value=None, background_color=None, text_color=None, font=None, visible=None): def Update(self, value=None, background_color=None, text_color=None, font=None, visible=None):
if value is not None: if value is not None:
self.Widget.set_text(str(value)) self.Widget.set_text(str(value))
# if background_color is not None: super().Update(self.Widget, background_color=background_color, text_color=text_color, font=font, visible=visible)
# self.TKText.configure(background=background_color)
# if text_color is not None:
# self.TKText.configure(fg=text_color)
# if font is not None:
# self.TKText.configure(font=font)
def __del__(self): def __del__(self):
super().__del__() super().__del__()
@ -1517,28 +1522,8 @@ class Button(Element):
def Update(self, text=None, button_color=(None, None), disabled=None, image_data=None, image_filename=None, font=None, visible=None): def Update(self, text=None, button_color=(None, None), disabled=None, image_data=None, image_filename=None, font=None, visible=None):
if text is not None: if text is not None:
self.Widget.set_text(text) self.Widget.set_text(text)
if self.ParentForm.Font and (self.Font == DEFAULT_FONT or not self.Font):
font = self.ParentForm.Font
elif self.Font is not None:
font = self.Font
else:
font = DEFAULT_FONT
fg = bg = None
if button_color != (None, None):
self.ButtonColor = button_color
fg, bg = button_color fg, bg = button_color
if self.Disabled != disabled and disabled is not None: super().Update(self.Widget, background_color=bg, text_color=fg, disabled=disabled, font=font, visible=visible)
if not disabled: # if enabling buttons, set the color
fg, bg = self.ButtonColor
self.Disabled = disabled
if disabled:
self.QT_QPushButton.setDisabled(True)
else:
self.QT_QPushButton.setDisabled(False)
# fg, bg = self.ButtonColor
# print(f'Button update fg, bg {fg}, {bg}')
super().Update(self.Widget, background_color=bg, text_color=fg, font=font, visible=visible)
def GetText(self): def GetText(self):
@ -1615,7 +1600,7 @@ class ProgressBar(Element):
# ---------------------------------------------------------------------- # # ---------------------------------------------------------------------- #
class Image(Element): class Image(Element):
def __init__(self, filename=None, data=None, background_color=None, size=(None, None), pad=None, key=None, def __init__(self, filename=None, data=None, background_color=None, size=(None, None), pad=None, key=None,
tooltip=None): tooltip=None, right_click_menu=None, visible=True, enable_events=False):
''' '''
Image Element Image Element
:param filename: :param filename:
@ -1626,32 +1611,27 @@ class Image(Element):
:param key: :param key:
:param tooltip: :param tooltip:
''' '''
self.Filename = filename self.Filename = '/'+filename if filename else None # note that Remi expects a / at the front of resource files
self.Data = data self.Data = data
self.tktext_label = None self.tktext_label = None
self.BackgroundColor = background_color self.BackgroundColor = background_color
self.Disabled = False
self.EnableEvents = enable_events
sz = (0,0) if size == (None, None) else size
self.Widget = None #type: remi.gui.Image
if data is None and filename is None: if data is None and filename is None:
print('* Warning... no image specified in Image Element! *') print('* Warning... no image specified in Image Element! *')
super().__init__(ELEM_TYPE_IMAGE, size=size, background_color=background_color, pad=pad, key=key, super().__init__(ELEM_TYPE_IMAGE, size=sz, background_color=background_color, pad=pad, key=key,
tooltip=tooltip) tooltip=tooltip, visible=visible)
return return
def Update(self, filename=None, data=None, size=(None, None)): def Update(self, filename=None, data=None, size=(None,None), visible=None):
if filename is not None: if filename is not None:
image = tk.PhotoImage(file=filename) self.Widget.set_image(filename=filename)
elif data is not None: if size != (None, None):
# if type(data) is bytes: self.Widget.style['height'] = '{}px'.format(size[1])
try: self.Widget.style['width'] = '{}px'.format(size[0])
image = tk.PhotoImage(data=data) super().Update(self.Widget, visible=visible)
except:
return # an error likely means the window has closed so exit
# else:
# image = data
else:
return
width, height = size[0] or image.width(), size[1] or image.height()
self.tktext_label.configure(image=image, width=width, height=height)
self.tktext_label.image = image
def __del__(self): def __del__(self):
super().__del__() super().__del__()
@ -2205,19 +2185,14 @@ class Slider(Element):
text_color=text_color, key=key, pad=pad, tooltip=tooltip, visible=visible, size_px=size_px) text_color=text_color, key=key, pad=pad, tooltip=tooltip, visible=visible, size_px=size_px)
return return
def Update(self, value=None, range=(None, None), disabled=None): def Update(self, value=None, range=(None, None), disabled=None, visible=None):
if value is not None: if value is not None:
try: self.Widget.set_value(value)
self.TKIntVar.set(value)
if range != (None, None):
self.TKScale.config(from_=range[0], to_=range[1])
except:
pass
self.DefaultValue = value self.DefaultValue = value
if disabled == True: if range != (None, None):
self.TKScale['state'] = 'disabled' self.Widget.style['min'] = '{}'.format(range[0])
elif disabled == False: self.Widget.style['max'] = '{}'.format(range[1])
self.TKScale['state'] = 'normal' super().Update(self.Widget, disabled=disabled, visible=visible)
def SliderCallback(self, widget:remi.Widget, value): def SliderCallback(self, widget:remi.Widget, value):
self.ParentForm.LastButtonClicked = self.Key if self.Key is not None else '' self.ParentForm.LastButtonClicked = self.Key if self.Key is not None else ''
@ -3207,11 +3182,13 @@ class Window:
userdata = args[-1].userdata userdata = args[-1].userdata
self.window = userdata[0] # type: Window self.window = userdata[0] # type: Window
else: else:
self.window = userdata2 self.window = userdata2 # type: Window
self.window.App = self self.window.App = self
self.master_widget = None self.master_widget = None
if userdata2 is None: if userdata2 is None:
super(Window.MyApp, self).__init__(*args) res_path = os.path.dirname(os.path.abspath(__file__))
# print('res path', res_path)
super(Window.MyApp, self).__init__(*args, static_file_path={'C':'c:','c':'c:','D':'d:', 'd':'d:', 'E':'e:', 'e':'e:', 'dot':'.', '.':'.'})
def main(self, name='world'): def main(self, name='world'):
# margin 0px auto allows to center the app to the screen # margin 0px auto allows to center the app to the screen
@ -3226,6 +3203,10 @@ class Window:
print('* ERROR PACKING FORM *') print('* ERROR PACKING FORM *')
print(traceback.format_exc()) print(traceback.format_exc())
if self.window.BackgroundImage:
self.master_widget.attributes['background-image'] = "url('{}')".format(self.window.BackgroundImage)
# print(f'background info',self.master_widget.attributes['background-image'] )
# add the following 3 lines to your app and the on_window_close method to make the console close automatically # add the following 3 lines to your app and the on_window_close method to make the console close automatically
tag = remi.gui.Tag(_type='script') tag = remi.gui.Tag(_type='script')
tag.add_child("javascript", """window.onunload=function(e){sendCallback('%s','%s');return "close?";};""" % ( tag.add_child("javascript", """window.onunload=function(e){sendCallback('%s','%s');return "close?";};""" % (
@ -3982,8 +3963,8 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form):
if element.TextColor not in (None, COLOR_SYSTEM_DEFAULT): if element.TextColor not in (None, COLOR_SYSTEM_DEFAULT):
widget.style['color'] = element.TextColor widget.style['color'] = element.TextColor
widget.style['font-size'] = '{}px'.format(font_info[1]) widget.style['font-size'] = '{}px'.format(font_info[1])
if element_size[0]: # if size is zero, don't set any sizes
size = convert_tkinter_size_to_Wx(element_size) size = convert_tkinter_size_to_Wx(element_size)
# if not auto_size_text:
widget.style['height'] = '{}px'.format(size[1]) widget.style['height'] = '{}px'.format(size[1])
widget.style['width'] = '{}px'.format(size[0]) widget.style['width'] = '{}px'.format(size[0])
widget.style['margin'] = '{}px {}px {}px {}px'.format(*full_element_pad) widget.style['margin'] = '{}px {}px {}px {}px'.format(*full_element_pad)
@ -4428,10 +4409,10 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form):
# ------------------------- IMAGE element ------------------------- # # ------------------------- IMAGE element ------------------------- #
elif element_type == ELEM_TYPE_IMAGE: elif element_type == ELEM_TYPE_IMAGE:
element = element # type: Image element = element # type: Image
element.Widget = remi.gui.Image(filename=element.Filename) element.Widget = remi.gui.Image(element.Filename)
do_font_and_color(element.Widget) do_font_and_color(element.Widget)
if element.ChangeSubmits: if element.EnableEvents:
element.Widget.onchange.connect(element.ChangedCallback) element.Widget.onclick.connect(element.ChangedCallback)
tk_row_frame.append(element.Widget) tk_row_frame.append(element.Widget)
# if element.Filename is not None: # if element.Filename is not None:
# photo = tk.PhotoImage(file=element.Filename) # photo = tk.PhotoImage(file=element.Filename)
@ -4616,7 +4597,8 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form):
# ------------------------- SLIDER element ------------------------- # # ------------------------- SLIDER element ------------------------- #
elif element_type == ELEM_TYPE_INPUT_SLIDER: elif element_type == ELEM_TYPE_INPUT_SLIDER:
element = element # type: Slider element = element # type: Slider
element.Widget = remi.gui.Slider(layout_orientation = remi.gui.Widget.LAYOUT_HORIZONTAL, default_value=element.DefaultValue, min=element.Range[0], max=element.Range[1],step=element.Resolution) orient = remi.gui.Widget.LAYOUT_HORIZONTAL if element.Orientation.lower().startswith('h') else remi.gui.Widget.LAYOUT_VERTICAL
element.Widget = remi.gui.Slider(layout_orientation = orient, default_value=element.DefaultValue, min=element.Range[0], max=element.Range[1],step=element.Resolution)
if element.DefaultValue: if element.DefaultValue:
element.Widget.set_value(element.DefaultValue) element.Widget.set_value(element.DefaultValue)
# if element.Orientation.startswith('v'): # if element.Orientation.startswith('v'):
@ -6453,7 +6435,7 @@ def main():
[Combo(values=['Combo 1', 'Combo 2', 'Combo 3'], default_value='Combo 2', key='_COMBO_', enable_events=True, [Combo(values=['Combo 1', 'Combo 2', 'Combo 3'], default_value='Combo 2', key='_COMBO_', enable_events=True,
readonly=False, tooltip='Combo box', disabled=False, size=(12, 1))], readonly=False, tooltip='Combo box', disabled=False, size=(12, 1))],
[Listbox(values=('Listbox 1', 'Listbox 2', 'Listbox 3'), enable_events =True, size=(10, 3), key='_LIST_')], [Listbox(values=('Listbox 1', 'Listbox 2', 'Listbox 3'), enable_events =True, size=(10, 3), key='_LIST_')],
[Slider((1, 100), default_value=80, key='_SLIDER_', visible=True, enable_events=True)], [Slider((1, 100), default_value=80, key='_SLIDER_', visible=True, enable_events=True, orientation='v')],
[Spin(values=(1, 2, 3), initial_value='2', size=(4, 1), key='_SPIN_', enable_events=True)], [Spin(values=(1, 2, 3), initial_value='2', size=(4, 1), key='_SPIN_', enable_events=True)],
[OK(), Button('Hidden', visible=False, key='_HIDDEN_'), Button('Values'), Button('Exit', button_color=('white', 'red')), Button('UnHide')] [OK(), Button('Hidden', visible=False, key='_HIDDEN_'), Button('Values'), Button('Exit', button_color=('white', 'red')), Button('UnHide')]
] ]

View File

@ -8,7 +8,7 @@
![Python Version](https://img.shields.io/badge/Python-3.x-yellow.svg) ![Python Version](https://img.shields.io/badge/Python-3.x-yellow.svg)
![Python Version](https://img.shields.io/badge/PySimpleGUIWeb_-0.9.0-orange.svg?longCache=true&style=for-the-badge) ![Python Version](https://img.shields.io/badge/PySimpleGUIWeb_-0.10.0-orange.svg?longCache=true&style=for-the-badge)
@ -31,7 +31,7 @@ This Readme is for information ***specific to*** the Web port of PySimpleGUI.
PySimpleGUIWeb enables you to run your PySimpleGUI programs in your web browser. It utilizes a package called Remi to achieve this amazing package. PySimpleGUIWeb enables you to run your PySimpleGUI programs in your web browser. It utilizes a package called Remi to achieve this amazing package.
## Engineering Pre-Release Version 0.9.0 ## Engineering Pre-Release Version 0.10.0
[Announcements of Latest Developments](https://github.com/MikeTheWatchGuy/PySimpleGUI/issues/142) [Announcements of Latest Developments](https://github.com/MikeTheWatchGuy/PySimpleGUI/issues/142)
@ -79,13 +79,14 @@ PySimpleGUIWeb runs only on Python 3. Legacy Python (2.7) is not supported.
* Listbox Element * Listbox Element
* Spinner Element (sorta... numbers 0 to 100 only now) * Spinner Element (sorta... numbers 0 to 100 only now)
* Column Element * Column Element
* Image Element
* Window background color * Window background color
* Element padding * Element padding
* Read with timeout * Read with timeout
* Read with timeout = 0 * Read with timeout = 0
* Popup Windows * Popup Windows
* Multiple windows * Multiple windows
* Update methods for many of the elements (Text is 100% complete), others have some of their parameters working.
# Running online using repl.it # Running online using repl.it
@ -186,6 +187,26 @@ New features
* Support for Window.Hide, Window.UnHide (better multi-window support) * Support for Window.Hide, Window.UnHide (better multi-window support)
## 0.9.1 PySimpleGUIWeb
* Emergency release due to some code to do scrolling of multiline not being right and sometimes crashed programs
## 0.10.0 PySimpleGUIWeb 16-Feb-2019
* Completed Text.Update method. Can now change:
* Text
* Font family & size
* Background color
* Text Color
* Visibility
* Completed Button.Update with exception of images
* Completed Spin.Update with except of range. This element still pretty crippled
* Completed Slider.Update - Can update value, visibility, disabled, but not the range
* Image Element!
* Events for Image Element
* Image.Update to change image
# Design # Design
# Author # Author
@ -197,6 +218,6 @@ New features
# Acknowledgments # Acknowledgments
<!--stackedit_data: <!--stackedit_data:
eyJoaXN0b3J5IjpbNDc1ODY1Njc2LC0xMDU3MTAzNjQzLDEyMT eyJoaXN0b3J5IjpbLTExNjY3MTk5MTcsNDc1ODY1Njc2LC0xMD
MzNTI2MzYsLTExNjA2ODQzMzldfQ== U3MTAzNjQzLDEyMTMzNTI2MzYsLTExNjA2ODQzMzldfQ==
--> -->

View File

@ -1,6 +1,4 @@
#!/usr/bin/python3 #!/usr/bin/python3
#!/usr/bin/python3
#!/usr/bin/python3
import sys import sys
import wx import wx
@ -15,12 +13,30 @@ import pickle
import os import os
import time import time
###### ##### ##### # # ### # #
# # # # # # # # # ##### # ###### # # # # # # # # # #
# # # # # # ## ## # # # # # # # # # # # # #
###### # ##### # # ## # # # # ##### # #### # # # # # # ##
# # # # # # ##### # # # # # # # # # # ##
# # # # # # # # # # # # # # # # # # # #
# # ##### # # # # ###### ###### ##### ##### ### ## ## # #
""" """
21-Dec-2018 21-Dec-2018
Welcome to the "core" PySimpleGUIWx port! Welcome to the "core" PySimpleGUIWx port!
'##:::::'##:'##::::'##:'########::'##:::'##:'########:'##::::'##::'#######::'##::: ##:
##:'##: ##:. ##::'##:: ##.... ##:. ##:'##::... ##..:: ##:::: ##:'##.... ##: ###:: ##:
##: ##: ##::. ##'##::: ##:::: ##::. ####:::::: ##:::: ##:::: ##: ##:::: ##: ####: ##:
##: ##: ##:::. ###:::: ########::::. ##::::::: ##:::: #########: ##:::: ##: ## ## ##:
##: ##: ##::: ## ##::: ##.....:::::: ##::::::: ##:::: ##.... ##: ##:::: ##: ##. ####:
##: ##: ##:: ##:. ##:: ##::::::::::: ##::::::: ##:::: ##:::: ##: ##:::: ##: ##:. ###:
. ###. ###:: ##:::. ##: ##::::::::::: ##::::::: ##:::: ##:::: ##:. #######:: ##::. ##:
:...::...:::..:::::..::..::::::::::::..::::::::..:::::..:::::..:::.......:::..::::..::
This marks the 3rd port of the PySimpleGUI GUI SDK. Each port gets a little better than This marks the 3rd port of the PySimpleGUI GUI SDK. Each port gets a little better than
the previous. the previous, in theory.
It will take a while for this Wx port to be completed, but should be running with a fully selection It will take a while for this Wx port to be completed, but should be running with a fully selection
of widgets fairly quickly. The Qt port required 1 week to get to "Alpha" condition of widgets fairly quickly. The Qt port required 1 week to get to "Alpha" condition
@ -1186,8 +1202,8 @@ class Text(Element):
if self.ParentForm.TKrootDestroyed: if self.ParentForm.TKrootDestroyed:
return return
if value is not None: if value is not None:
self.WxStaticText.SetLabel(value) self.WxStaticText.SetLabel(str(value))
self.DisplayText = value self.DisplayText = str(value)
if background_color is not None: if background_color is not None:
self.WxStaticText.SetBackgroundColour(background_color) self.WxStaticText.SetBackgroundColour(background_color)
if text_color is not None: if text_color is not None:
@ -4254,9 +4270,18 @@ else:
i += 1 i += 1
# # ######
# # # # # # # # # ##### # # #### # #
# # # # # # # # # # # # # # ## #
# # # ## ###### # # ###### # # # # #
# # # ## # # # # # # # # # #
# # # # # # # # # # # # # ##
## ## # # # # # # # #### # #
# ------------------------------------------------------------------------------------------------------------------ # # ------------------------------------------------------------------------------------------------------------------ #
# ------------------------------------------------------------------------------------------------------------------ # # ------------------------------------------------------------------------------------------------------------------ #
# ===================================== TK CODE STARTS HERE ====================================================== # # ===================================== WxPython CODE STARTS HERE ================================================ #
# ------------------------------------------------------------------------------------------------------------------ # # ------------------------------------------------------------------------------------------------------------------ #
# ------------------------------------------------------------------------------------------------------------------ # # ------------------------------------------------------------------------------------------------------------------ #
@ -5479,7 +5504,7 @@ class QuickMeter(object):
layout = [] layout = []
if self.orientation.lower().startswith('h'): if self.orientation.lower().startswith('h'):
col = [] col = []
col += [[T(arg)] for arg in args] col += [[T(''.join(map(lambda x: str(x)+'\n',args)),key='_OPTMSG_')]] ### convert all *args into one string that can be updated
col += [[T('', size=(25,8), key='_STATS_')], col += [[T('', size=(25,8), key='_STATS_')],
[ProgressBar(max_value=self.max_value, orientation='h', key='_PROG_', size=self.size)], [ProgressBar(max_value=self.max_value, orientation='h', key='_PROG_', size=self.size)],
[Cancel(button_color=self.button_color), Stretch()]] [Cancel(button_color=self.button_color), Stretch()]]
@ -5487,7 +5512,7 @@ class QuickMeter(object):
else: else:
col = [[ProgressBar(max_value=self.max_value, orientation='v', key='_PROG_', size=self.size)]] col = [[ProgressBar(max_value=self.max_value, orientation='v', key='_PROG_', size=self.size)]]
col2 = [] col2 = []
col2 += [[T(arg)] for arg in args] col2 += [[T(''.join(map(lambda x: str(x)+'\n',args)),key='_OPTMSG_')]] ### convert all *args into one string that can be updated
col2 += [[T('', size=(25,8), key='_STATS_')], col2 += [[T('', size=(25,8), key='_STATS_')],
[Cancel(button_color=self.button_color), Stretch()]] [Cancel(button_color=self.button_color), Stretch()]]
layout = [Column(col), Column(col2)] layout = [Column(col), Column(col2)]
@ -5496,11 +5521,12 @@ class QuickMeter(object):
return self.window return self.window
def UpdateMeter(self, current_value, max_value): def UpdateMeter(self, current_value, max_value, *args):
self.current_value = current_value self.current_value = current_value
self.max_value = max_value self.max_value = max_value
self.window.Element('_PROG_').UpdateBar(self.current_value, self.max_value) self.window.Element('_PROG_').UpdateBar(self.current_value, self.max_value)
self.window.Element('_STATS_').Update('\n'.join(self.ComputeProgressStats())) self.window.Element('_STATS_').Update('\n'.join(self.ComputeProgressStats()))
self.window.Element('_OPTMSG_').Update(value=''.join(map(lambda x: str(x)+'\n',args))) ### update the string with the args
event, values = self.window.Read(timeout=0) event, values = self.window.Read(timeout=0)
if event in('Cancel', None) or current_value >= max_value: if event in('Cancel', None) or current_value >= max_value:
self.window.Close() self.window.Close()
@ -5548,7 +5574,7 @@ def OneLineProgressMeter(title, current_value, max_value, key, *args, orientatio
else: else:
meter = QuickMeter.active_meters[key] meter = QuickMeter.active_meters[key]
rc = meter.UpdateMeter(current_value, max_value) rc = meter.UpdateMeter(current_value, max_value, *args)
OneLineProgressMeter.exit_reasons = getattr(OneLineProgressMeter,'exit_reasons', QuickMeter.exit_reasons) OneLineProgressMeter.exit_reasons = getattr(OneLineProgressMeter,'exit_reasons', QuickMeter.exit_reasons)
return rc == METER_OK return rc == METER_OK
@ -6219,6 +6245,16 @@ def ObjToString(obj, extra=' '):
# Pre-built dialog boxes for all your needs These are the "high level API calls # # Pre-built dialog boxes for all your needs These are the "high level API calls #
# ------------------------------------------------------------------------------------------------------------------ # # ------------------------------------------------------------------------------------------------------------------ #
######
# # #### ##### # # ##### ####
# # # # # # # # # # #
###### # # # # # # # # ####
# # # ##### # # ##### #
# # # # # # # # #
# #### # #### # ####
# ----------------------------------- The mighty Popup! ------------------------------------------------------------ # # ----------------------------------- The mighty Popup! ------------------------------------------------------------ #
@ -6827,6 +6863,19 @@ def PopupGetText(message, title=None, default_text='', password_char='', size=(N
return input_values[0] return input_values[0]
"""
d8b
Y8P
88888b.d88b. 8888b. 888 88888b.
888 "888 "88b "88b 888 888 "88b
888 888 888 .d888888 888 888 888
888 888 888 888 888 888 888 888
888 888 888 "Y888888 888 888 888
"""
def main(): def main():
ChangeLookAndFeel('GreenTan') ChangeLookAndFeel('GreenTan')
layout = [ layout = [

View File

@ -8,11 +8,11 @@
![pysimplegui_logo](https://user-images.githubusercontent.com/13696193/43165867-fe02e3b2-8f62-11e8-9fd0-cc7c86b11772.png) ![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) [![Downloads](http://pepy.tech/badge/pysimplegui)](http://pepy.tech/project/pysimplegui) tkinter
[![Downloads ](https://pepy.tech/badge/pysimplegui27)](https://pepy.tech/project/pysimplegui27) [![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) [![Downloads](https://pepy.tech/badge/pysimpleguiqt)](https://pepy.tech/project/pysimpleguiqt) Qt
[![Downloads](https://pepy.tech/badge/pysimpleguiwx)](https://pepy.tech/project/pysimpleguiWx) [![Downloads](https://pepy.tech/badge/pysimpleguiwx)](https://pepy.tech/project/pysimpleguiWx) WxPython
[![Downloads](https://pepy.tech/badge/pysimpleguiweb)](https://pepy.tech/project/pysimpleguiWeb) [![Downloads](https://pepy.tech/badge/pysimpleguiweb)](https://pepy.tech/project/pysimpleguiWeb) Web (Remi)
![Documentation Status](https://readthedocs.org/projects/pysimplegui/badge/?version=latest) ![Documentation Status](https://readthedocs.org/projects/pysimplegui/badge/?version=latest)
![Awesome Meter](https://img.shields.io/badge/Awesome_meter-100-yellow.svg) ![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) ![Python Version](https://img.shields.io/badge/Python-2.7_3.x-yellow.svg)
@ -24,9 +24,12 @@
## Supports both Python 2.7 & 3 when using tkinter ## Supports both Python 2.7 & 3 when using tkinter
## Supports both PySide2 and PyQt5 (limited support)
## PySimpleGUI source code can run either on Qt, tkinter, WxPython, Web (Remi) by changing only the import statement
## Supports both PySide2 and PyQt5 (limited support)
## Effortlessly move across tkinter, Qt, WxPython, and the Web (Remi) by changing only the import statement
## The *only* way to write both desktop and web based GUIs at the same time
@ -38,7 +41,7 @@
![Python Version](https://img.shields.io/badge/PySimpleGUIWx_version-0.3.0-orange.svg?longCache=true&style=for-the-badge) ![Python Version](https://img.shields.io/badge/PySimpleGUIWx_version-0.3.0-orange.svg?longCache=true&style=for-the-badge)
![Python Version](https://img.shields.io/badge/PySimpleGUIWeb_Version-0.2.2-orange.svg?longCache=true&style=for-the-badge) ![Python Version](https://img.shields.io/badge/PySimpleGUIWeb_Version-0.10.0-orange.svg?longCache=true&style=for-the-badge)
[Announcements of Latest Developments](https://github.com/MikeTheWatchGuy/PySimpleGUI/issues/142) [Announcements of Latest Developments](https://github.com/MikeTheWatchGuy/PySimpleGUI/issues/142)
@ -52,7 +55,7 @@
[Docs in PDF Format](https://github.com/MikeTheWatchGuy/PySimpleGUI/tree/master/docs) [Docs in PDF Format](https://github.com/MikeTheWatchGuy/PySimpleGUI/tree/master/docs)
[Run live in a web browser using repl.it!](https://repl.it/@PySimpleGUI/PySimpleGUIWeb-Demos) [Repl.it Home for PySimpleGUI](https://repl.it/@PySimpleGUI)
Super-simple GUI to use... Powerfully customizable Super-simple GUI to use... Powerfully customizable
@ -4973,9 +4976,9 @@ GNU Lesser General Public License (LGPL 3) +
* [GRADESK](https://github.com/sidbmw/ICS4U) - Created by a couple of young talented programmers, this classroom management software combines SQL and a GUI to provide a much improved interface for Ottawa teachers. * [GRADESK](https://github.com/sidbmw/ICS4U) - Created by a couple of young talented programmers, this classroom management software combines SQL and a GUI to provide a much improved interface for Ottawa teachers.
<!--stackedit_data: <!--stackedit_data:
eyJoaXN0b3J5IjpbLTE1Nzg3NDY1ODgsMjYwNTg0ODE0LDExMD eyJoaXN0b3J5IjpbMjA1MzEyNTE0OSwtMTU3ODc0NjU4OCwyNj
IwODgzMzMsMTY3OTg1MDk5MiwtMTQ2MTQyODEsLTYwNjM3MTE4 A1ODQ4MTQsMTEwMjA4ODMzMywxNjc5ODUwOTkyLC0xNDYxNDI4
LC01MDkzNTkxMjMsLTI0ODk3NjI5LDEzMDc2OTI1OSwtMjk2Nz MSwtNjA2MzcxMTgsLTUwOTM1OTEyMywtMjQ4OTc2MjksMTMwNz
gzNTUsLTc3NDA3NDIzMCwyNjYzNjQ0MTcsNDQ5NDMzMjQzLC0x Y5MjU5LC0yOTY3ODM1NSwtNzc0MDc0MjMwLDI2NjM2NDQxNyw0
MTQ4NDkwNjIzXX0= NDk0MzMyNDMsLTExNDg0OTA2MjNdfQ==
--> -->