Merge pull request #1104 from PySimpleGUI/Dev-latest

Dev latest
This commit is contained in:
MikeTheWatchGuy 2019-01-23 16:21:35 -05:00 committed by GitHub
commit 434bd9ffcb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 146 additions and 49 deletions

View File

@ -48,7 +48,7 @@ DEFAULT_BASE64_ICON = b'iVBORw0KGgoAAAANSUhEUgAAACEAAAAgCAMAAACrZuH4AAAABGdBTUEA
# ----====----====----==== Constants the user CAN safely change ====----====----====----#
DEFAULT_WINDOW_ICON = 'default_icon.ico'
DEFAULT_ELEMENT_SIZE = (45, 1) # In CHARACTERS
DEFAULT_ELEMENT_SIZE = (250, 26) # In pixels
DEFAULT_BUTTON_ELEMENT_SIZE = (10, 1) # In CHARACTERS
DEFAULT_MARGINS = (10, 5) # Margins for each LEFT/RIGHT margin is first term
DEFAULT_ELEMENT_PADDING = (5, 3) # Padding between elements (row, col) in pixels
@ -464,6 +464,7 @@ class Element():
def Update(self, widget, background_color=None, text_color=None, font=None, visible=None, disabled=None, tooltip=None):
return
if font:
widget.SetFont(font_to_wx_font(font))
if text_color not in (None, COLOR_SYSTEM_DEFAULT):
@ -1024,49 +1025,56 @@ class Multiline(Element):
# Text #
# ---------------------------------------------------------------------- #
class Text(Element):
def __init__(self, text, size=(None, None), auto_size_text=None, click_submits=None, relief=None, font=None,
text_color=None, background_color=None, justification=None, pad=None, key=None, tooltip=None):
'''
Text Element
def __init__(self, text, size=(None, None), auto_size_text=None, click_submits=None, enable_events=False, relief=None, border_width=None, font=None, text_color=None, background_color=None, justification=None, pad=None, margins=None, key=None, tooltip=None, visible=True, size_px=(None,None)):
"""
Text
:param text:
:param size:
:param auto_size_text:
:param click_submits:
:param enable_events:
:param relief:
:param font:
:param text_color:
:param background_color:
:param justification:
:param pad:
:param margins:
:param key:
:param tooltip:
'''
:param visible:
:param size_px:
"""
self.DisplayText = text
self.TextColor = text_color if text_color else DEFAULT_TEXT_COLOR
self.Justification = justification
self.Relief = relief
self.ClickSubmits = click_submits
self.ClickSubmits = click_submits or enable_events
self.Margins = margins
self.size_px = size_px
if background_color is None:
bg = DEFAULT_TEXT_ELEMENT_BACKGROUND_COLOR
else:
bg = background_color
self.Widget = None # type: remi.gui.Label
pixelsize = size
if size[1] is not None and size[1] < 10:
pixelsize = size[0]*10, size[1]*20
self.WxStaticText:wx.StaticText = None # wx.StaticText(form.MasterPanel, -1, element.DisplayText)
self.BorderWidth = border_width if border_width is not None else DEFAULT_BORDER_WIDTH
super().__init__(ELEM_TYPE_TEXT, size, auto_size_text, background_color=bg, font=font if font else DEFAULT_FONT,
text_color=self.TextColor, pad=pad, key=key, tooltip=tooltip)
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)
return
def Update(self, value=None, background_color=None, text_color=None, font=None):
def Update(self, value=None, background_color=None, text_color=None, font=None, visible=None):
if value is not None:
self.DisplayText = value
stringvar = self.TKStringVar
stringvar.set(value)
if background_color is not None:
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)
self.Widget.set_text(value)
# if background_color is not None:
# 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):
super().__del__()
@ -1442,8 +1450,7 @@ class Button(Element):
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:
self.QT_QPushButton.setText(str(text))
self.ButtonText = 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:
@ -1465,11 +1472,11 @@ class Button(Element):
self.QT_QPushButton.setDisabled(False)
# fg, bg = self.ButtonColor
# print(f'Button update fg, bg {fg}, {bg}')
super().Update(self.WxButton, background_color=bg, text_color=fg, font=font, visible=visible)
super().Update(self.Widget, background_color=bg, text_color=fg, font=font, visible=visible)
def GetText(self):
return self.ButtonText
return self.Widget.get_text()
def SetFocus(self):
self.QT_QPushButton.setFocus()
@ -2632,10 +2639,11 @@ class Window:
self.BackgroundImage = background_image
self.XFound = False
self.DisableMinimize = disable_minimize
self.App = None # type: wx.App
self.MasterFrame = None # type: wx.Frame
self.MasterPanel = None # type wx.Panel
self.IgnoreClose = False
self.thread_id = None
self.App = None # type: Window.MyApp
self.MessageQueue = Queue()
@classmethod
@ -2760,7 +2768,10 @@ class Window:
except: # timeout
self.LastButtonClicked = timeout_key
elif timeout == 0:
self.LastButtonClicked = self.MessageQueue.get_nowait()
try:
self.LastButtonClicked = self.MessageQueue.get_nowait()
except:
self.LastButtonClicked = timeout_key
else:
self.LastButtonClicked = self.MessageQueue.get()
# print('--------------------- BACK FROM MESSAGE QUEUE GET ----------------------')
@ -2988,6 +2999,7 @@ class Window:
return None
def Close(self):
self.App.close()
if self.TKrootDestroyed:
return
# try:
@ -2995,6 +3007,7 @@ class Window:
# except:
# print('error closing window')
CloseNonBlockingForm = Close
CloseNonBlocking = Close
@ -3096,13 +3109,12 @@ class Window:
element.__del__()
def remi_thread(self, window):
# print('In Remi Thread....', window)
def remi_thread(self):
logging.getLogger('remi').setLevel(level=logging.CRITICAL)
logging.getLogger('remi').disabled = True
logging.disable(logging.CRITICAL)
remi.start(window.MyApp, debug=False, address='0.0.0.0', port=0, start_browser=True, userdata=(window,)) # standalone=True)
window.MessageQueue.put(None)
remi.start(self.MyApp, title=self.Title ,debug=False, address='0.0.0.0', port=0, start_browser=True, userdata=(self,)) # standalone=True)
self.MessageQueue.put(None)
class MyApp(remi.App):
def __init__(self,*args):
@ -3110,6 +3122,7 @@ class Window:
# print(args[-1])
userdata = args[-1].userdata
self.window = userdata[0] # type: Window
self.window.App = self
super(Window.MyApp, self).__init__(*args)
def main(self, name='world'):
@ -3117,6 +3130,8 @@ class Window:
wid = remi.gui.VBox()
wid.style['justify-content'] = 'flex-start'
wid.style['align-items'] = 'baseline'
wid.style['background-color'] = self.window.BackgroundColor
PackFormIntoFrame(self.window, wid, self.window)
#
# lbl = remi.gui.Label("Close or reload the page, the console thread will stop automatically.")
@ -3182,7 +3197,7 @@ def convert_tkinter_size_to_Wx(size):
return qtsize
def font_to_wx_font(font):
def font_parse_string(font):
"""
Convert from font string/tyuple into a Qt style sheet string
:param font: "Arial 10 Bold" or ('Arial', 10, 'Bold)
@ -3196,23 +3211,15 @@ def font_to_wx_font(font):
_font = font.split(' ')
else:
_font = font
name = _font[0]
family = _font[0]
point_size = int(_font[1])
# style = _font[2]
style = _font[2:] if len(_font) > 1 else None
underline = 'underline' in _font[2:]
bold = 'bold' in _font
# underline = 'underline' in _font[2:]
# bold = 'bold' in _font
wxfont = wx.Font(point_size,
wx.FONTFAMILY_DEFAULT,
wx.FONTSTYLE_NORMAL,
wx.FONTWEIGHT_BOLD if bold else wx.FONTWEIGHT_NORMAL,
underline,
faceName=family)
return wxfont
return family, point_size, style
@ -3860,6 +3867,50 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form):
def CharWidthInPixels():
return tkinter.font.Font().measure('A') # single character width
def pad_widget(widget):
lrsizer = wx.BoxSizer(wx.HORIZONTAL)
if full_element_pad[1] == full_element_pad[3]: # if right = left
lrsizer.Add(widget, 0, wx.LEFT | wx.RIGHT, border=full_element_pad[1])
else:
sizer = wx.BoxSizer(wx.HORIZONTAL)
sizer.Add(widget, 0, wx.LEFT, border=full_element_pad[3])
lrsizer.Add(sizer, 0, wx.RIGHT, border=full_element_pad[1])
top_bottom_sizer = wx.BoxSizer(wx.HORIZONTAL)
if full_element_pad[0] == full_element_pad[2]: # if top = bottom
top_bottom_sizer.Add(lrsizer, 0, wx.TOP | wx.BOTTOM, border=full_element_pad[0])
else:
sizer = wx.BoxSizer(wx.HORIZONTAL)
sizer.Add(lrsizer, 0, wx.TOP, border=full_element_pad[0])
top_bottom_sizer.Add(sizer, 0, wx.BOTTOM, border=full_element_pad[2])
return top_bottom_sizer
#
# font, text color, background color, size, disabled, visible, tooltip
#
def do_font_and_color(widget):
font_info = font_parse_string(font) # family, point size, other
widget.style['font-family'] = font_info[0]
if element.BackgroundColor not in (None, COLOR_SYSTEM_DEFAULT):
widget.style['background-color'] = element.BackgroundColor
if element.TextColor not in (None, COLOR_SYSTEM_DEFAULT):
widget.style['color'] = element.TextColor
widget.style['font-size'] = '{}px'.format(font_info[1])
size = convert_tkinter_size_to_Wx(element_size)
widget.style['height'] = '{}px'.format(size[1])
widget.style['width'] = '{}px'.format(size[0])
#
# widget.SetMinSize(element_size)
# if element.Disabled:
# widget.Enable(False)
# if not element.Visible:
# widget.Hide()
# if element.Tooltip:
# widget.SetToolTip(element.Tooltip)
border_depth = toplevel_form.BorderDepth if toplevel_form.BorderDepth is not None else DEFAULT_BORDER_WIDTH
# --------------------------------------------------------------------------- #
# **************** Use FlexForm to build the tkinter window ********** ----- #
@ -3875,6 +3926,8 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form):
tk_row_frame = remi.gui.HBox() # TODO Get horizontal ROW widget to put others into
tk_row_frame.style['justify-content'] = 'flex-start'
tk_row_frame.style['align-items'] = 'baseline'
tk_row_frame.style['background-color'] = toplevel_form.BackgroundColor
for col_num, element in enumerate(flex_row):
element.ParentForm = toplevel_form # save the button's parent form object
if toplevel_form.Font and (element.Font == DEFAULT_FONT or not element.Font):
@ -3933,6 +3986,13 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form):
element = element # type: Text
element.Widget = remi.gui.Label(element.DisplayText)
element.Widget.set_layout_orientation(True)
do_font_and_color(element.Widget)
if element.Justification:
if element.Justification.startswith('c'):
element.Widget.style['text-align'] = 'center'
elif element.Justification.startswith('r'):
element.Widget.style['text-align'] = 'right'
tk_row_frame.append(element.Widget)
# auto_size_text = element.AutoSizeText
@ -3986,8 +4046,10 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form):
elif element_type == ELEM_TYPE_BUTTON:
element = element # type: Button
size = convert_tkinter_size_to_Wx(element_size)
print(size)
element.Widget = remi.gui.Button(element.ButtonText, width=size[0], height=size[1], margin='10px')
element.Widget.onclick.connect(element.ButtonCallBack)
do_font_and_color(element.Widget)
tk_row_frame.append(element.Widget)
# stringvar = tk.StringVar()
@ -4069,6 +4131,7 @@ def PackFormIntoFrame(form, containing_frame, toplevel_form):
element.Widget = remi.gui.TextInput()
if element.DefaultText:
element.Widget.set_value(element.DefaultText)
do_font_and_color(element.Widget)
tk_row_frame.append(element.Widget)
# default_text = element.DefaultText
@ -4795,8 +4858,9 @@ def StartupTK(window:Window):
# master.update_idletasks() # don't forget
thread = threading.Thread(target=window.remi_thread, args=(window,), daemon=True)
thread.start()
window.thread_id = threading.Thread(target=window.remi_thread, daemon=True)
window.thread_id.daemon = True
window.thread_id.start()
item = window.MessageQueue.get() # Get the layout complete message
@ -6393,7 +6457,8 @@ def PopupGetText(message, default_text='', password_char='', size=(None, None),
def main():
layout = [[Text('You are running the PySimpleGUI.py file itself')],
SetOptions(background_color='blue', text_element_background_color='blue', text_color='white')
layout = [[Text('You are running the PySimpleGUI.py file itself', background_color='blue', font='Courier 20')],
[Text('You should be importing it rather than running it', size=(50, 2))],
[Text('Here is your sample input window....')],
[Text('Source Folder',justification='right'), InputText('Source', focus=True),
@ -6401,7 +6466,7 @@ def main():
[Text('Destination Folder', justification='right'), InputText('Dest'), FolderBrowse()],
[Ok(), Cancel()]]
window = Window('Demo window..').Layout(layout)
window = Window('Demo window..', background_color='blue', font='Courier 18').Layout(layout)
while True:
event, values = window.Read()
print(event, values)

View File

@ -28,13 +28,45 @@ PySimpleGUIWeb enables you to run your PySimpleGUI programs in your web browser.
At the moment (22-Jan-2019) the port has barely begun but it's far enough along to see that it's going to work. The Text, Input Text and Button elements are "functional". You can run simple PySimpleGUI programs and they actually WORK correctly.
## Engineering Pre-Release Version 0.1.0
## Engineering Pre-Release Version 0.1.0
[Announcements of Latest Developments](https://github.com/MikeTheWatchGuy/PySimpleGUI/issues/142)
Having trouble? Visit the [GitHub site ](http://www.PySimpleGUI.com) and log an Issue.
## Installation
Installation is quite simple:
`pip install pysimpleguiweb`
Should this not work, you can copy and paste the file PySimpleGUIWeb.py into your application folder.
## Using
There are a lot of examples in the PySimpleGUI Cookbook as well as on the GitHub site. At the moment very few will work due to the limited number of features of the 0.1.0 release. It shouldn't be too long before they'll work.
To use PySimpleGUIWeb you need to import it:
`import PySimpleGUIWeb as sg`
From there follow the code examples in the Coookbook and the Demo Programs. The only difference in those programs is the import statement. The remainder of the code should work without modification.
## Requirements
PySimpleGUIWeb is based on the Remi project. You will need to install Remi prior to running PySimpleGUIWeb:
`pip install remi`
You can learn more about Remi on its homepage.
https://github.com/dddomodossola/remi
PySimpleGUIWeb runs only on Python 3. Legacy Python is not supported.
## What Works
Text Element