From 5ced9df9f99a1b78423753160f6bf5e2920e7d41 Mon Sep 17 00:00:00 2001 From: MikeTheWatchGuy Date: Sat, 8 Dec 2018 17:11:24 -0500 Subject: [PATCH 1/3] Set scrollbar width for Listbox, Table to 12 px, removed global variable used to hold "master" window / app, Table.Update - Dummy num_rows parm to maintain compat with tkinter --- PySimpleGUIQt/PySimpleGUIQt.py | 296 ++++++++++++++++++++++++--------- 1 file changed, 213 insertions(+), 83 deletions(-) diff --git a/PySimpleGUIQt/PySimpleGUIQt.py b/PySimpleGUIQt/PySimpleGUIQt.py index aae9f5b4..424b0e8c 100644 --- a/PySimpleGUIQt/PySimpleGUIQt.py +++ b/PySimpleGUIQt/PySimpleGUIQt.py @@ -6,6 +6,7 @@ import textwrap import pickle import base64 import calendar +from random import randint FORCE_PYQT5 = False @@ -239,24 +240,6 @@ EVENT_SYSTEM_TRAY_MESSAGE_CLICKED = '__MESSAGE_CLICKED__' MENU_KEY_SEPARATOR = '::' MENU_DISABLED_CHARACTER = '!' -# a shameful global variable. This represents the top-level window information. Needed because opening a second window is different than opening the first. -class MyWindows(): - def __init__(self): - self.NumOpenWindows = 0 - self.user_defined_icon = None - self.hidden_master_root = None - self.QTApplication = None - self.active_popups = {} - def Decrement(self): - self.NumOpenWindows -= 1 * (self.NumOpenWindows != 0) # decrement if not 0 - # print('---- DECREMENTING Num Open Windows = {} ---'.format(self.NumOpenWindows)) - - def Increment(self): - self.NumOpenWindows += 1 - # print('++++ INCREMENTING Num Open Windows = {} ++++'.format(self.NumOpenWindows)) - - -_my_windows = MyWindows() # terrible hack using globals... means need a class for collecing windows # ====================================================================== # @@ -1330,8 +1313,6 @@ class Button(Element): # ------- Button Callback ------- # def ButtonCallBack(self): - global _my_windows - # print('Button callback') @@ -1419,7 +1400,7 @@ class Button(Element): self.ParentForm.QT_QMainWindow.close() if self.ParentForm.NonBlocking: # TODO DESTROY WIN - _my_windows.Decrement() + Window.DecrementOpenCount() elif self.BType == BUTTON_TYPE_READ_FORM: # LEAVE THE WINDOW OPEN!! DO NOT CLOSE # first, get the results table built # modify the Results table in the parent FlexForm object @@ -1435,7 +1416,7 @@ class Button(Element): self.ParentForm.QT_QMainWindow.close() if self.ParentForm.CurrentlyRunningMainloop: # if this window is running the mainloop, kick out self.ParentForm.QTApplication.exit() - _my_windows.Decrement() + Window.DecrementOpenCount() elif self.BType == BUTTON_TYPE_CALENDAR_CHOOSER: # this is a return type button so GET RESULTS and destroy window should_submit_window = False @@ -2542,17 +2523,21 @@ class Table(Element): print('Vertical Header value ', value) - def Update(self, values=None, visible=None): + def Update(self, values=None, num_rows=None, visible=None): if values is not None: self.Values = values self.SelectedRows = [] self.QT_TableWidget.clear() - self.QT_TableWidget.setRowCount(len(self.Values)) - self.QT_TableWidget.setColumnCount(len(self.Values[0])) - for rownum, rows in enumerate(self.Values): - # self.QT_TableWidget.insertRow(rownum) - for colnum, columns in enumerate(rows): - self.QT_TableWidget.setItem(rownum, colnum, QTableWidgetItem(self.Values[rownum][colnum])) + if len(values) != 0: + self.QT_TableWidget.setRowCount(len(self.Values)) + self.QT_TableWidget.setColumnCount(len(self.Values[0])) + for rownum, rows in enumerate(self.Values): + # self.QT_TableWidget.insertRow(rownum) + for colnum, columns in enumerate(rows): + self.QT_TableWidget.setItem(rownum, colnum, QTableWidgetItem(self.Values[rownum][colnum])) + # if num_rows is not None: + # self.QT_TableWidget.setFixedHeight(num_rows * 35 + 25) # convert num rows into pixels...crude but effective + super().Update(self.QT_TableWidget, visible=visible) @@ -2799,11 +2784,10 @@ class SystemTray: self.LastMessage = None self.LastTitle = None - global _my_windows - if _my_windows.QTApplication is None: - _my_windows.QTApplication = QApplication(sys.argv) - self.App = _my_windows.QTApplication + if Window.QTApplication is None: + Window.QTApplication = QApplication(sys.argv) + self.App = Window.QTApplication self.QWidget = QWidget() qicon = None @@ -2982,6 +2966,13 @@ class SystemTray: # ------------------------------------------------------------------------- # class Window: + NumOpenWindows = 0 + user_defined_icon = None + hidden_master_root = None + QTApplication = None + active_popups = {} + + def __init__(self, title, default_element_size=DEFAULT_ELEMENT_SIZE, default_button_element_size=(None, None), auto_size_text=None, auto_size_buttons=None, location=(None, None), size=(None, None), element_padding=None, button_color=None, font=None, progress_bar_color=(None, None), background_color=None, border_depth=None, auto_close=False, @@ -3032,7 +3023,7 @@ class Window: self.Font = font if font else DEFAULT_FONT self.RadioDict = {} self.BorderDepth = border_depth - self.WindowIcon = icon if icon is not None else _my_windows.user_defined_icon + self.WindowIcon = icon if icon is not None else Window.user_defined_icon self.AutoClose = auto_close self.NonBlocking = False self.TKroot = None @@ -3075,6 +3066,17 @@ class Window: self.XFound = False + @staticmethod + def IncrementOpenCount(): + Window.NumOpenWindows += 1 + # print('+++++ INCREMENTING Num Open Windows = {} ---'.format(Window.NumOpenWindows)) + + @staticmethod + def DecrementOpenCount(): + Window.NumOpenWindows -= 1 * (Window.NumOpenWindows != 0) # decrement if not 0 + # print('----- DECREMENTING Num Open Windows = {} ---'.format(Window.NumOpenWindows)) + + # ------------------------- Add ONE Row to Form ------------------------- # def AddRow(self, *args): ''' Parms are a variable number of Elements ''' @@ -3219,7 +3221,7 @@ class Window: rc = self.TKroot.update() except: self.TKrootDestroyed = True - _my_windows.Decrement() + Window.DecrementOpenCount() results = BuildResults(self, False, self) if results[0] != None and results[0] != timeout_key: return results @@ -3248,10 +3250,10 @@ class Window: if self.RootNeedsDestroying: self.LastButtonClicked = None self.QTApplication.exit() - _my_windows.Decrement() + Window.DecrementOpenCount() # if form was closed with X if self.LastButtonClicked is None and self.LastKeyboardEvent is None and self.ReturnValues[0] is None: - _my_windows.Decrement() + Window.DecrementOpenCount() # Determine return values if self.LastKeyboardEvent is not None or self.LastButtonClicked is not None: results = BuildResults(self, False, self) @@ -3292,7 +3294,7 @@ class Window: except: print('* ERROR FINALIZING *') self.TKrootDestroyed = True - _my_windows.Decrement() + Window.DecrementOpenCount() return self @@ -3346,10 +3348,10 @@ class Window: print('*** Error loading form to disk ***') def GetScreenDimensions(self): - if _my_windows.QTApplication is None: - _my_windows.QTApplication = QApplication(sys.argv) + if Window.QTApplication is None: + Window.QTApplication = QApplication(sys.argv) try: - screen = _my_windows.QTApplication.primaryScreen() + screen = Window.QTApplication.primaryScreen() except: return None, None size = screen.size() @@ -4634,8 +4636,14 @@ def PackFormIntoFrame(window, containing_frame, toplevel_win): elif element_type == ELEM_TYPE_INPUT_LISTBOX: max_line_len = max([len(str(l)) for l in element.Values]) if len(element.Values) != 0 else 0 element.QT_ListWidget = QListWidget() - style = '' - style = create_style_from_font(font) + style = element.QT_ListWidget.styleSheet() + style += """QScrollBar:vertical { + border: none; + background:lightgray; + width:12px; + margin: 0px 0px 0px 0px; + } """ + style += create_style_from_font(font) if element.TextColor is not None: style += 'color: %s;' % element.TextColor @@ -5252,6 +5260,12 @@ def PackFormIntoFrame(window, containing_frame, toplevel_win): add_treeview_data(element.TreeData.root_node, element.QT_QTreeWidget) style = '' + style += """QScrollBar:vertical { + border: none; + background:lightgray; + width:12px; + margin: 0px 0px 0px 0px; + } """ style += 'margin: {}px {}px {}px {}px;'.format(*full_element_pad) style += 'border: {}px solid gray; '.format(border_depth) element.QT_QTreeWidget.setStyleSheet(style) @@ -5351,17 +5365,16 @@ def stop_timer(timer): # ----====----====----====----====----==== STARTUP TK ====----====----====----====----====----# def StartupTK(window): - global _my_windows global using_pyqt5 - ow = _my_windows.NumOpenWindows + ow = Window.NumOpenWindows - if _my_windows.QTApplication is None: - _my_windows.QTApplication = QApplication(sys.argv) + if Window.QTApplication is None: + Window.QTApplication = QApplication(sys.argv) - window.QTApplication = _my_windows.QTApplication + window.QTApplication = Window.QTApplication - _my_windows.Increment() + Window.IncrementOpenCount() # window.QTWindow = QWidget() @@ -5479,7 +5492,7 @@ def StartupTK(window): window.TimerCancelled = True # print('..... BACK from MainLoop') if not window.FormRemainedOpen: - _my_windows.Decrement() + Window.DecrementOpenCount() if window.RootNeedsDestroying: # print('** Destroying window **') window.QT_QMainWindow.close() # destroy the window @@ -5576,7 +5589,6 @@ def _ProgressMeterUpdate(bar, value, text_elem, *args): :param value: int :return: True if not cancelled, OK....False if Error ''' - global _my_windows if bar == None: return False if bar.BarExpired: return False message, w, h = ConvertArgsToSingleString(*args) @@ -5588,7 +5600,7 @@ def _ProgressMeterUpdate(bar, value, text_elem, *args): bar.BarExpired = True bar.ParentForm._Close() if rc: # if update was OK but bar expired, decrement num windows - _my_windows.Decrement() + Window.DecrementOpenCount() if bar.ParentForm.RootNeedsDestroying: try: bar.ParentForm.QT_QMainWindow.close() @@ -5813,7 +5825,6 @@ _easy_print_data = None # global variable... I'm cheating class DebugWin(): - global _my_windows def __init__(self, size=(None, None), location=(None, None), font=None, no_titlebar=False, no_button=False, grab_anywhere=False, keep_on_top=False): # Show a form that's a running counter @@ -5830,7 +5841,7 @@ class DebugWin(): ] self.window.AddRows(self.layout) self.window.Read(timeout=0) # Show a non-blocking form, returns immediately - _my_windows.active_popups[self.window] = 'debug window' + Window.active_popups[self.window] = 'debug window' return def Print(self, *args, end=None, sep=None): @@ -5840,7 +5851,7 @@ class DebugWin(): if self.window is None: # if window was destroyed already, just print print(*args, sep=sepchar, end=endchar) return - _my_windows.active_popups[self.window] = 'debug window' + Window.active_popups[self.window] = 'debug window' event, values = self.window.Read(timeout=0) if event == 'Quit' or event is None: self.Close() @@ -5932,14 +5943,13 @@ ScrolledTextBox = PopupScrolled # Sets the icon to be used by default # # ===================================================# def SetGlobalIcon(icon): - global _my_windows try: with open(icon, 'r') as icon_file: pass except: raise FileNotFoundError - _my_windows.user_defined_icon = icon + Window.user_defined_icon = icon return True @@ -5990,7 +6000,6 @@ def SetOptions(icon=None, button_color=None, element_size=(None, None), button_e global DEFAULT_INPUT_TEXT_COLOR global DEFAULT_TOOLTIP_TIME global DEFAULT_ERROR_BUTTON_COLOR - global _my_windows if icon: try: @@ -5998,7 +6007,7 @@ def SetOptions(icon=None, button_color=None, element_size=(None, None), button_e pass except: raise FileNotFoundError - _my_windows.user_defined_icon = icon + Window.user_defined_icon = icon if button_color != None: DEFAULT_BUTTON_COLOR = button_color @@ -6471,8 +6480,6 @@ def Popup(*args, title=None, button_color=None, background_color=None, text_colo :param location: :return: """ - global _my_windows - if not args: args_to_print = [''] @@ -6540,7 +6547,7 @@ def Popup(*args, title=None, button_color=None, background_color=None, text_colo window.Layout(layout) if non_blocking: button, values = window.Read(timeout=0) - _my_windows.active_popups[window] = title + Window.active_popups[window] = title else: button, values = window.Read() @@ -6925,11 +6932,10 @@ def PopupGetFolder(message, title=None, default_path='', no_window=False, size=( :return: Contents of text field. None if closed using X or cancelled """ - global _my_windows if no_window: - if _my_windows.QTApplication is None: - _my_windows.QTApplication = QApplication(sys.argv) + if Window.QTApplication is None: + Window.QTApplication = QApplication(sys.argv) folder_name = QFileDialog.getExistingDirectory(dir=initial_folder) return folder_name @@ -6980,11 +6986,9 @@ def PopupGetFile(message, title=None, default_path='', default_extension='', sav :return: string representing the path chosen, None if cancelled or window closed with X """ - global _my_windows - if no_window: - if _my_windows.QTApplication is None: - _my_windows.QTApplication = QApplication(sys.argv) + if Window.QTApplication is None: + Window.QTApplication = QApplication(sys.argv) if save_as: qt_types = convert_tkinter_filetypes_to_qt(file_types) @@ -7059,24 +7063,150 @@ def PopupGetText(message, title=None, default_text='', password_char='', size=(N def main(): - layout = [[Text('You are running the PySimpleGUI.py file itself')], - [Text('You should be importing it rather than running it')], - [Text('Here is your sample input window....')], - [Text('Source File', size=(150, 25), justification='right'), InputText('Source', focus=True), FileBrowse()], - [Text('Destination Folder', size=(150, 25), justification='right'), InputText('Dest'), FolderBrowse()], - [Ok(bind_return_key=True), Cancel()]] + ChangeLookAndFeel('GreenTan') + # SetOptions(element_padding=(0,0)) + # ------ Menu Definition ------ # + menu_def = [['&File', ['!&Open::KeyOpen', '&Save::KeySave', '---', '&Properties::KeyProp', 'E&xit']], + ['&Edit', ['&Paste', ['Special::KeySpecial', '!Normal', ], 'Undo'], ], + ['!&Toolbar', ['Command &1', 'Command &2', 'Command &3', 'Command &4']], + ['&Help', '&About...'], ] - window = Window('Demo window..', - auto_size_buttons=False, - default_element_size=(280,22), - auto_size_text=False, - default_button_element_size=(80,22) - ).Layout(layout) - event, values = window.Read() - print(event, values) + treedata = TreeData() + + treedata.Insert("", '_A_', 'Tree Item 1', [1, 2, 3], ) + treedata.Insert("", '_B_', 'B', [4, 5, 6], ) + treedata.Insert("_A_", '_A1_', 'Sub Item 1', ['can', 'be', 'anything'], ) + treedata.Insert("", '_C_', 'C', [], ) + treedata.Insert("_C_", '_C1_', 'C1', ['or'], ) + treedata.Insert("_A_", '_A2_', 'Sub Item 2', [None, None]) + treedata.Insert("_A1_", '_A3_', 'A30', ['getting deep']) + treedata.Insert("_C_", '_C2_', 'C2', ['nothing', 'at', 'all']) + + for i in range(100): + treedata.Insert('_C_', i, i, []) + + frame1 = [ + [Input('Input Text', do_not_clear=True, size=(250, 35), tooltip='Input'), Stretch()], + [Multiline(size=(250, 75), do_not_clear=True, default_text='Multiline Input', tooltip='Multiline input'), + MultilineOutput(size=(250, 75), default_text='Multiline Output', tooltip='Multiline output')], + ] + + frame2 = [ + [Listbox(['Listbox 1', 'Listbox 2', 'Listbox 3', 'Item 4', 'Item 5'], size=(200, 85), tooltip='Listbox', + key='_LISTBOX_', font='Courier 12', text_color='red', background_color='white')], + [Combo(['Combo item 1', 'Combo item 2', 'Combo item 3'], size=(200, 35), tooltip='Combo')], + [Spin([1, 2, 3], size=(40, 30), tooltip='Spinner')], + ] + + frame3 = [ + [Checkbox('Checkbox1', True, tooltip='Checkbox'), Checkbox('Checkbox1')], + [Radio('Radio Button1', 1, tooltip='Radio'), Radio('Radio Button2', 1, default=True), Stretch()], + ] + + frame4 = [ + [Slider(range=(0, 100), orientation='v', size=(3, 30), default_value=40, tooltip='Slider'), + Dial(range=(0, 100), tick_interval=1, resolution=1, size=(150, 150), default_value=40, tooltip='Dial'), + Stretch()], + ] + matrix = [[str(x * y) for x in range(4)] for y in range(3)] + + frame5 = [ + [Table(values=matrix, max_col_width=25, + auto_size_columns=True, display_row_numbers=True, change_submits=False, bind_return_key=True, + justification='right', num_rows=8, alternating_row_color='lightblue', key='_table_', + text_color='black', tooltip='Table'), + Tree(data=treedata, headings=['col1', 'col2', 'col3'], change_submits=True, auto_size_columns=True, + num_rows=10, col0_width=10, key='_TREE_', show_expanded=True, size=(200, 150), tooltip='Tree'), + Stretch()], + ] + + graph_elem = Graph((880, 150), (0, 0), (600, 300), key='+GRAPH+', tooltip='Graph') + + frame6 = [ + [graph_elem, Stretch()], + ] + + tab1 = Tab('Graph Number 1', frame6, tooltip='Tab 1') + tab2 = Tab('Graph Number 2', [[]]) + + layout = [ + [Menu(menu_def, key='_REALMENU_')], + [Text('You are running the PySimpleGUI.py file itself', font='ANY 15')], + [Text('You should be importing it rather than running it', font='ANY 15')], + # [Image(data_base64=logo, tooltip='Image', click_submits=True, key='_IMAGE_'), + [Frame('Input Text Group', frame1, title_color='red', tooltip='Text Group'), Stretch()], + [Frame('Multiple Choice Group', frame2, title_color='green'), + Frame('Binary Choice Group', frame3, title_color='purple'), + Frame('Variable Choice Group', frame4, title_color='blue'), Stretch()], + [Frame('Structured Data Group', frame5, title_color='red'), ], + # [Frame('Graphing Group', frame6)], + [TabGroup([[tab1, tab2]])], + [ProgressBar(max_value=600, start_value=400, size=(600, 25), key='+PROGRESS+'), + Text('', key='_PROGTEXT_'), Stretch(), + ButtonMenu('&Menu', ['Menu', ['&Pause Graph', 'Menu item::optional_key']], key='_MENU_', + tooltip='Button Menu'), + Button('Button'), Button('Exit', tooltip='Exit button')], + ] + + window = Window('Window Title', + font=('Helvetica', 13), + default_button_element_size=(100, 30), + auto_size_buttons=False, + default_element_size=(200, 22), + border_depth=1, + ).Layout(layout).Finalize() + graph_elem.DrawCircle((200, 200), 50, 'blue') + i = 0 + graph_paused = False + + # window.Element('_LISTBOX_').SetValue(['Listbox 1','Listbox 3']) + while True: # Event Loop + # TimerStart() + event, values = window.Read(timeout=10) + print(event) if event != TIMEOUT_KEY else None + if event is None or event == 'Exit': + break + if values['_MENU_'] == 'Pause Graph': + graph_paused = not graph_paused + if event != TIMEOUT_KEY: + print(event, values) + if not graph_paused: + i += 1 + + if i < 600: + graph_elem.DrawLine((i, 0), (i, randint(0, 300)), width=1, + color='#{:06x}'.format(randint(0, 0xffffff))) + else: + graph_elem.Move(-1, 0) + graph_elem.DrawLine((i, 0), (i, randint(0, 300)), width=1, + color='#{:06x}'.format(randint(0, 0xffffff))) + + window.FindElement('+PROGRESS+').UpdateBar(i % 600) + window.FindElement('_PROGTEXT_').Update((i % 600) // 6) + + # TimerStop() window.Close() + + # layout = [[Text('You are running the PySimpleGUI.py file itself')], + # [Text('You should be importing it rather than running it')], + # [Text('Here is your sample input window....')], + # [Text('Source File', size=(150, 25), justification='right'), InputText('Source', focus=True), FileBrowse()], + # [Text('Destination Folder', size=(150, 25), justification='right'), InputText('Dest'), FolderBrowse()], + # [Ok(bind_return_key=True), Cancel()]] + # + # window = Window('Demo window..', + # auto_size_buttons=False, + # default_element_size=(280,22), + # auto_size_text=False, + # default_button_element_size=(80,22) + # ).Layout(layout) + # event, values = window.Read() + # print(event, values) + # window.Close() + + if __name__ == '__main__': main() exit(69) From a56691d8f535d4ba6a4168ab606b069cab5be284 Mon Sep 17 00:00:00 2001 From: MikeTheWatchGuy Date: Sun, 9 Dec 2018 13:28:38 -0500 Subject: [PATCH 2/3] Pretty big doc update --- PySimpleGUIQt/readme.md | 109 ++------------------------ docs/index.md | 168 ++++++++++++++++++++++++++++------------ readme.md | 168 ++++++++++++++++++++++++++++------------ 3 files changed, 245 insertions(+), 200 deletions(-) diff --git a/PySimpleGUIQt/readme.md b/PySimpleGUIQt/readme.md index ad3527c8..da52d251 100644 --- a/PySimpleGUIQt/readme.md +++ b/PySimpleGUIQt/readme.md @@ -26,7 +26,7 @@ "Qt without the ugly" - ## The Alpha Release Version 0.20.0 + ## The Alpha Release Version 0.18.0 [Announcements of Latest Developments](https://github.com/MikeTheWatchGuy/PySimpleGUI/issues/142) @@ -37,7 +37,7 @@ Welcome to the Alpha Release of PySimpleGUI for Qt! You can use the exact same code that you are running on the older, tkinter, version of PySimpleGUI. -PySimpleGUIQt uses **PySide2** OR **PyQt5** for access to Qt. **PyQt5 has been having a number of problems recently however so tread lightly.** +PySimpleGUIQt uses **PySide2** OR **PyQt5** for access to Qt. PyQt5 has been having a number of problems recently however so tread lightly. ## Porting your PySimpleGUI code to PySimpleGUIQt @@ -153,14 +153,13 @@ These Elements are "complete" (a relative term... more are more complete than ot Notable MISSING features at the moment include: * Graphs Element Methods - erasing, draw arc, etc -# New PySimpleGUI Features only in Qt (or first introduced in Qt) +# New PySimpleGUI Features only in Qt There are a number of new features that are only available in PySimpleGUIQt. These include: * ButtonMenu Element * Dial Element * Stretcher Element * SystemTray feature -* "Dynamic" windows that grow and shrink (uses invisible elements) ## SystemTray @@ -219,7 +218,7 @@ You will find 3 parameters used to specify these 3 options on both the initializ ## Menu Definition ```python -menu_def = ['BLANK', ['&Open', '&Save', ['1', '2', ['a', 'b']], '!&Properties', 'E&xit']] +menu_def = ['BLANK', ['&Open', '&Save', ['1', '2', ['a', 'b']], '&Properties', 'E&xit']] ``` A menu is defined using a list. A "Menu entry" is a string that specifies: @@ -227,7 +226,7 @@ A menu is defined using a list. A "Menu entry" is a string that specifies: * keyboard shortcut * key -See section on Menu Keys for more information on using keys with menus. +See section on Menu Keys for more informatoin on using keys with menus. An entry without a key and keyboard shortcut is a simple string `'Menu Item'` @@ -244,10 +243,6 @@ The first entry can be ignored.`'BLANK`' was chosen for this example. It's this **Separators** If you want a separator between 2 items, add the entry `'---'` and it will add a separator item at that place in your menu. -**Disabled menu entries** - -If you want to disable a menu entry, place a `!` before the menu entry - ## SystemTray Methods @@ -365,18 +360,6 @@ If you want to change the separator characters from :: top something else,change When a menu item has a key and it is chosen, then entire string is returned. If Hide were selected, then Hide::key would be returned from the Read. Note that the shortcut character & is NOT returned from Reads. -## Dynamic Windows (Element Visibility) - -Finally, the ability to grow and shrink has been added as of release 0.20.0 - -While the window **appears** to be dynamic, the reality is that the elements are created up front, when you define the window layout. You will create these "extra" elements with the flag `visible=False`. Then, when you wish to show those elements, call the element's `Update` method setting `visible=True`. - -After you call the `Update` method, it's important to call `window.VisibilityChanged()` so that your window can change sizes. Without that call your window will not shrink. It will grow properly, but it will not shrink. While this could have been done by PySimpleGUI on the user's behalf, the thought was that perhaps the user wants the window size to remain the same and the element simply appears and disappears, leaving a blank spot. If the window automatically grew and shrank, this would not be possible. Just buck-up and make the call to `VisibilityChanged`. - -## `enable_events` Parameter - -All elements that are capable of producing events now have a parameter `enable_events`. This is *identical* to the old parameter `change_submits` or `click_submits`. The idea is to standardize on 1 name that all elements use. The old parameters will continue to work, but the documentation and sample programs will steer you away from them and towards enable_events. - # Release Notes: ### 0.12.0 - 20-Nov-2018 @@ -503,88 +486,6 @@ Window - Get screen dimensions Slider - disable Dial - disable -### 0.20.0 6-Dec-2018 - -* Ability to change calculations between characters and pixels -* size_px added to ALL elements that have a size parameter -* General Element.Update(widget, background_color, text_color, font, visible) -* visible parameter added to ALL elements -* enable_events flag -* Input text - enable events, visibility, size_px -* Input text update added capabilities - * ability to highlight the input string - * background, text colors and font -* Combo - enable events, visibility, size_px -* Combo - auto complete feature -* Combo - added to Update - background color, text color, font, visible -* Listbox - enable events, visibility, size_px -* Listbox - better scaling from characters to pixels -* Listbox - ability to Update with set to index, text color, font, visibility -* Radio - enable events, visibility, size_px -* Radio - Update additions - background_color, text_color, font, visibility -* Checkbox - enable events, visibility, size_px -* Checkbox - Update additions - background_color, text_color, font, visibility -* Spin - enable events, visibility, size_px -* Spin - Update additions - background_color, text_color, font, visibility -* Multiline input - enable events, visibility, size_px -* Multiline input - Update additions - background_color, text_color, font, visibility -* Multiline input better character to pixel scaling -* Multiline output - enable events, visibility, size_px -* Multiline output - Update additions - background_color, text_color, visibility -* Text - enable events, size in pixels -* Text - Update addition of visibility -* Output - visible, size_px -* Output - added update capability with new value, background_color, text_color, font, visibility -* Button - enable events, visible, size_px -* Button - Color Chooser feature completed -* Button - Color Chooser can target (None, None) which will store the value to be returned with the values from Read() -* Button - fixed bug in SaveAs button code. Bad filter variable -* Button - Updated added font, visibility -* Button - new SetFocus() method will set the focus onto the button -* ButtonMenu - Update method implemented that includes menu definition changes, text, button color, font, visibility -* ProgressBar - added visibility, size_px -* ProgressBar - added Update method for changing the visibility -* Images - events, size_pix, visibility -* Images - can now get click events for images! -* Images - Update added visibility -* Graph - visibility, size_px -* Graph - Update method for changing visibility -* Frame - visibility, size_px -* Frame - Update method added that controls visibility -* ALL elements inside of a Frame that's invisible will also be invisible -* Tab - visible parameter added, however not yet functional! -* TabGroup - enable events, visibility -* TabGroup - Update for controlling visibility -* Slider - enable events, size_px -* Slider - Update method now includes visibility -* Dial - enable events, size_px, visibility -* Dial - Update method added visibilty control -* Column - visibility added -* Column - Added Update method to control visibility -* ALL elements inside of an invisible Column Element will also be invisible -* MenuBar - added visibility -* MenuBar - Update can now change menu definitions at runtime, and control visibility -* Table - enable events, size_px, visibility -* Table - Update method can control visibility -* Tree - enable events, size_px, visibility -* Tree - Update method can control visibility -* VisibilityChanged() function that must be called when using Qt so that the window will shrink or grow -* window.GetScreenDimensions can now be called prior to window creation -* window.Size property -* enable_events added to all of the shortcut buttons and browse buttons -* Ability to set a button image from a file -* Combo - ability to set a default value -* Combo - Readonly setting. Allows for user editing of value -* Menus - Ability to disable / enable any part of a menu by adding a ! before the entry name -* Tabs - ability to set tab text color, background color, background color of seletected tab -* Tabs - ability to set widget area's background color -* Sliders - paging works properly (using page-up page-down or slider slider area to advance slider) -* Tree - Setting number of visible rows implemented -* Added 5 pixels to every window. Have been having issues with text being cutoff on the right side -* SetOptions - ability to change default error button color for popups - - - # Design ## Author Mike B. diff --git a/docs/index.md b/docs/index.md index 00f3c133..a29833b0 100644 --- a/docs/index.md +++ b/docs/index.md @@ -59,20 +59,41 @@ The native GUI framework for perfectionists with deadlines #### Note regarding Python versions As of 9/25/2018 **both Python 3 and Python 2.7 are supported**! The Python 3 version is named `PySimpleGUI`. The Python 2.7 version is `PySimpleGUI27`. They are installed separately and the imports are different. See instructions in Installation section for more info. -#### Qt Version +# Qt Version -Check out the new PySimpleGUI port to the Qt GUI Framework. You can learn more on the [PySimpleGUIQt GitHub site](https://github.com/MikeTheWatchGuy/PySimpleGUI/tree/master/PySimpleGUIQt). There is a separate Readme file for the Qt version that you'll find there. Give it a shot if you're looking for something a bit more "modern". PySimpleGUIQt is currently in Alpha. All of the widgets are operational and your source code is completely portable from one platform to another by simply changing the import statement. +### Github +Check out the new PySimpleGUI port to the Qt GUI Framework. You can learn more on the [PySimpleGUIQt GitHub site](https://github.com/MikeTheWatchGuy/PySimpleGUI/tree/master/PySimpleGUIQt). **There is a separate Readme file for the Qt version** that you'll find there. +Give it a shot if you're looking for something a bit more "modern". PySimpleGUIQt is currently in Alpha. All of the widgets are operational but some may not yet be full-featured. If one is missing and your project needs it, log an Issue and you'll likely get priority support. + +Here is a summary of the Qt Elements + +![scrolling graphics](https://user-images.githubusercontent.com/13696193/48665874-8bfd0e00-ea84-11e8-880d-8e164d9fea34.gif) + +Are there enough things on there to cover your GUI solution? + + +### Source code compatibility +Your source code is completely portable from one platform to another by simply changing the import statement. + + + ### Platforms + + It's surprising that Python GUI code is completely cross platform from Windows to Mac to Linux. No source code changes. This is true for both PySimpleGUI and PySimpleGUIQt. + +However, Macs suck. They suck on tkinter in particular. I had to completely turn off the "Look and feel" calls for Macs. Colored buttons in particular are broken. Not in the PySimpleGUI code, of course. It's mostly because Macs suck. Consider using Qt instead of tkinter on the Mac. Or, if using tkinter, bring your own button images. ------------------------------------------------------------------------ -Looking for a GUI package? -* Taking your Python code from the world of command lines and into the convenience of a GUI? * -* Have a Raspberry **Pi** with a touchscreen that's going to waste because you don't have the time to learn a GUI SDK? -* Into Machine Learning and are sick of the command line? -* Would like to distribute your Python code to Windows users as a single .EXE file that launches straight into a GUI, much like a WinForms app? -* Want technical support? Looking for an actively maintained package? +Looking for a GUI package? Are you +* looking to take your Python code from the world of command lines and into the convenience of a GUI? * +* sitting on a Raspberry **Pi** with a touchscreen that's going to waste because you don't have the time to learn a GUI SDK? +* into Machine Learning and are sick of the command line? +* wanting to distribute your Python code to Windows users as a single .EXE file that launches straight into a GUI, much like a WinForms app? +* a teacher wanting to teach your students how to program using a GUI? +* a student that wants to put a GUI onto their project? +* looking for an active project? Look no further, **you've found your GUI package**. @@ -110,7 +131,9 @@ Perhaps you're looking for a way to interact with your **Raspberry Pi** in a mor ![raspberry pi everything demo](https://user-images.githubusercontent.com/13696193/44279694-5b58ce80-a220-11e8-9ab6-d6021f5a944f.jpg) - f + + + In addition to a primary GUI, you can add a Progress Meter to your code with ONE LINE of code. Slide this line into any of your `for` loops and get a nice meter: OneLineProgressMeter('My meter title', current_value, max value, 'key') @@ -1326,6 +1349,7 @@ Window( title, auto_size_buttons=None, location=(None,None), size=(None,None), + element_padding=None, button_color=None, font=None, progress_bar_color=(None,None), @@ -1352,7 +1376,9 @@ Parameter Descriptions. You will find these same parameters specified for each default_button_element_size - Size of buttons on this window auto_size_text - Bool. True if elements should size themselves according to contents. Defaults to True auto_size_buttons - Bool. True if button elements should size themselves according to their text label - location - (x,y) Location to place window in pixels + location - (x,y) Location to place window in pixels + size - (w,h) forces a window to be a paricular size + element_padding - (w,h) default padding amount for elements font - Font name and size for elements of the window button_color - Default color for buttons (foreground, background). Can be text or hex progress_bar_color - Foreground and background colors for progress bars @@ -1368,13 +1394,28 @@ Parameter Descriptions. You will find these same parameters specified for each text_justification - Justification to use for Text Elements in this window no_titlebar - Create window without a titlebar grab_anywhere - Grab any location on the window to move the window - keep_on_top - if True then window will always stop on top of other windows on the screen. Great for floating toolbars. + keep_on_top - if True then window will always stop on top of other windows on the screen. Great for floating toolbars. + resizable - if True - user can manually changge the wize of the window. Defaults to False + disable_close - if True user will not be able to close using the X. ### Window Location PySimpleGUI computes the exact center of your window and centers the window on the screen. If you want to locate your window elsewhere, such as the system default of (0,0), if you have 2 ways of doing this. The first is when the window is created. Use the `location` parameter to set where the window. The second way of doing this is to use the `SetOptions` call which will set the default window location for all windows in the future. + +### Window Size + +You can get your window's size by access the `Size`property. The window has to be Read once or Finalized in order for the value to be correct. Note that it's a property, not a call. + +`my_windows_size = window.Size` + +To finalize your window: + +```pytyhon +window = Window('My Title').Layout(layout).Finalize() +``` -### Sizes + +### Element Sizes Note several variables that deal with "size". Element sizes are measured in characters. A Text Element with a size of 20,1 has a size of 20 characters wide by 1 character tall. The default Element size for PySimpleGUI is `(45,1)`. @@ -1638,6 +1679,15 @@ Then to get the input value from the read it would be: values['mykey'] You also use the same key if you want to call Update on an element. Please see the section below on Updates to understand that usage. +#### Visible +Beginning in version 3.17 you can create Elements that are initially invisible that you can later make visible. + +To create an invisible Element, place the element in the layout like you normally would and add the parameter `visible=False`. + +Later when you want to make that Element visible you simply call the Element's `Update` method and pass in the parameter `visible=True` + +This feature works best on Qt, but does work on the tkinter version as well. The visible parameter can also be used with the Column and Frame "container" Elements. + ### Output Elements Building a window is simply making lists of Elements. Each list is a row in the overall GUI dialog box. The definition looks something like this: @@ -1645,6 +1695,10 @@ Building a window is simply making lists of Elements. Each list is a row in the layout = [ [row 1 element, row 1 element], [row 2 element, row 2 element, row 2 element] ] The code is a crude representation of the GUI, laid out in text. +## Shortcut Functions / Multiple Function Names + +Many of the main method calls and Element names have shortcuts. This enables you to code much quicker once you are used to using the SDK. The Text Element, for example, has 3 different names `Text`, `Txt` or`T`. InputText can also be written `Input` or `In` . `FindElement` was recently renamed to `Element` because it's a commonly used function. + ## Text Element @@ -1673,7 +1727,8 @@ The most basic element is the Text element. It simply displays text. Many of t Text - The text that's displayed size - Element's size - click_submits - if clicked will cause a read call to return they key value as the button + click_submits - if clicked will cause a read call to return the key value of the button + enable_events - same as click_submits relief - relief to use around the text auto_size_text - Bool. Change width to match size of text font - Font name and size to use @@ -1686,23 +1741,28 @@ The most basic element is the Text element. It simply displays text. Many of t Some commonly used elements have 'shorthand' versions of the functions to make the code more compact. The functions `T` and `Txt` are the same as calling `Text`. -**Fonts** +### Fonts Already discussed in the common parameters section. Either string or a tuple. -**Color** in PySimpleGUI are in one of two formats - color name or RGB value. +### Color in PySimpleGUI are in one of two formats - color name or RGB value. Individual colors are specified using either the color names as defined in tkinter or an RGB string of this format: "#RRGGBB" or "darkblue" -**auto_size_text** +### `auto_size_text ` A `True` value for `auto_size_text`, when placed on Text Elements, indicates that the width of the Element should be shrunk do the width of the text. The default setting is True. -**Shortcut functions** +### tcut functions The shorthand functions for `Text` are `Txt` and `T` - + +### Events `enable_events` + + If you set the parameter `enable_events` or `click_submits` then you will get an event if the user clicks on the Text. + + ### Text Methods #### Update @@ -1741,25 +1801,12 @@ Multiline( default_text='', pad=None, tooltip=None ''' -``` - - Multiline(default_text='', - enter_submits = False, - disabled=False, - autoscroll=False, - size=(None, None), - auto_size_text=None, - background_color=None, - text_color=None, - do_not_clear=False, - key=None, - focus=False, - pad=None, - tooltip=None) -. +``` default_text - Text to display in the text box - enter_submits - Bool. If True, pressing Enter key submits window + change_submits - Bool. If True, pressing Enter key submits window + anable_events - Bool. same as change_submits + autoscroll - Bool. Causes "cursor" to always be at the end of the text size - Element's size auto_size_text - Bool. Change width to match size of text @@ -1807,7 +1854,7 @@ You should be quite familiar with these parameters by now. If not, read able an ## Input Elements These make up the majority of the window definition. Optional variables at the Element level override the window level values (e.g. `size` is specified in the Element). All input Elements create an entry in the list of return values. A Text Input Element creates a string in the list of items returned. -## Text Input Element +## Text Input Element Shortcuts (Input, In) layout = [[sg.InputText('Default text')]] @@ -1850,12 +1897,15 @@ You should be quite familiar with these parameters by now. If not, read able an There are two methods that can be called: - InputText.Update(new_Value) - sets the input value - Input.Text(Get() - returns the current value of the field. + Input.Update(new_Value) - sets the input to new_value + Input.Get() - returns the current value of the field. Shorthand functions that are equivalent to `InputText` are `Input` and `In` + +#### `do_not_clear` Parameter +**Important** - This trips a lot of people up. If you do not set the `do_not_clear` parameter then the input field will clear when an event takes place. The behavior is a "forms" style window development. The assumption is that you want the field to clear. If you are writing a chat program then you're thankful. The rest of you, I'm sorry. ### TextInput Methods ```python @@ -2033,6 +2083,11 @@ Sliders have a couple of slider-specific settings as well as appearance settings key- Dictionary key to use for return values tooltip - Tooltip to display when hovered over wlement +### Qt Sliders + +There is an important difference between Qt and tkinter sliders. On Qt, the slider values must be integer, not float. If you want your slider to go from 0.1 to 1.0, then make your slider go from 1 to 10 and divide by 10. It's an easy math thing to do and not a big deal. Just deal with it.... you're writing software after all. Presumably you know how to do these things. ;-) + + ### Slider Methods ```python Update(self, value=None, range=(None, None), disabled=None): @@ -2173,6 +2228,14 @@ Parameter definitions key = Dictionary key to use for return values pad - padding around element in the window tooltip - text to show when mouse hovered over element + + +### Qt Differences - `values` is a range! + +Note that Qt does not allow arbitrary spinner values. With PySimpleGUI-tkinter you can have any values in your list. In Qt they must be integers. Yea, it kinda sucks. I'm working on it. + +On Qt values is a tuple representing a range. On plain PySimpleGUI this value is a list of items. Make sure on the plain version you specify items as a list using [] and not a generator using (). + ### Spin Methods ```python @@ -2185,24 +2248,33 @@ disabled - if True disables the element ## Image Element Images can be placed in your window provide they are in PNG, GIF, PPM/PGM format. JPGs cannot be shown because tkinter does not naively support JPGs. You can use the Python Imaging Library (PIL) package to convert your image to PNG prior to calling PySimpleGUI if your images are in JPG format. - - Image(filename=None, - data=None, - background_color=None, - size=(None, None), - pad=None, - key=None, - tooltip=None) - +```python + Image(filename=None, + data=None, + data_base64=None, + background_color=None, + size=(None,None), + pad=None, + key=None, + tooltip=None, + click_submits=False, + enable_events=False, + visible=True, + size_px=(None,None) +``` Parameter definitions filename - file name if the image is in a file - data - if image is in RAM (PIL format?) + data - if image is in RAM (PIL format?) + data_base64 - image in base64 format background_color - Color of background size - Size (Width, Height) of image in pixels pad - Padding around Element in the window key - Key used to find the element tooltip - text to show when mouse if hovered over image + click_submits, enable_events - if True returns event when image is clicked + visible - if False will create image as hidden + size_px - size of image in pixels ### Image Methods diff --git a/readme.md b/readme.md index 00f3c133..a29833b0 100644 --- a/readme.md +++ b/readme.md @@ -59,20 +59,41 @@ The native GUI framework for perfectionists with deadlines #### Note regarding Python versions As of 9/25/2018 **both Python 3 and Python 2.7 are supported**! The Python 3 version is named `PySimpleGUI`. The Python 2.7 version is `PySimpleGUI27`. They are installed separately and the imports are different. See instructions in Installation section for more info. -#### Qt Version +# Qt Version -Check out the new PySimpleGUI port to the Qt GUI Framework. You can learn more on the [PySimpleGUIQt GitHub site](https://github.com/MikeTheWatchGuy/PySimpleGUI/tree/master/PySimpleGUIQt). There is a separate Readme file for the Qt version that you'll find there. Give it a shot if you're looking for something a bit more "modern". PySimpleGUIQt is currently in Alpha. All of the widgets are operational and your source code is completely portable from one platform to another by simply changing the import statement. +### Github +Check out the new PySimpleGUI port to the Qt GUI Framework. You can learn more on the [PySimpleGUIQt GitHub site](https://github.com/MikeTheWatchGuy/PySimpleGUI/tree/master/PySimpleGUIQt). **There is a separate Readme file for the Qt version** that you'll find there. +Give it a shot if you're looking for something a bit more "modern". PySimpleGUIQt is currently in Alpha. All of the widgets are operational but some may not yet be full-featured. If one is missing and your project needs it, log an Issue and you'll likely get priority support. + +Here is a summary of the Qt Elements + +![scrolling graphics](https://user-images.githubusercontent.com/13696193/48665874-8bfd0e00-ea84-11e8-880d-8e164d9fea34.gif) + +Are there enough things on there to cover your GUI solution? + + +### Source code compatibility +Your source code is completely portable from one platform to another by simply changing the import statement. + + + ### Platforms + + It's surprising that Python GUI code is completely cross platform from Windows to Mac to Linux. No source code changes. This is true for both PySimpleGUI and PySimpleGUIQt. + +However, Macs suck. They suck on tkinter in particular. I had to completely turn off the "Look and feel" calls for Macs. Colored buttons in particular are broken. Not in the PySimpleGUI code, of course. It's mostly because Macs suck. Consider using Qt instead of tkinter on the Mac. Or, if using tkinter, bring your own button images. ------------------------------------------------------------------------ -Looking for a GUI package? -* Taking your Python code from the world of command lines and into the convenience of a GUI? * -* Have a Raspberry **Pi** with a touchscreen that's going to waste because you don't have the time to learn a GUI SDK? -* Into Machine Learning and are sick of the command line? -* Would like to distribute your Python code to Windows users as a single .EXE file that launches straight into a GUI, much like a WinForms app? -* Want technical support? Looking for an actively maintained package? +Looking for a GUI package? Are you +* looking to take your Python code from the world of command lines and into the convenience of a GUI? * +* sitting on a Raspberry **Pi** with a touchscreen that's going to waste because you don't have the time to learn a GUI SDK? +* into Machine Learning and are sick of the command line? +* wanting to distribute your Python code to Windows users as a single .EXE file that launches straight into a GUI, much like a WinForms app? +* a teacher wanting to teach your students how to program using a GUI? +* a student that wants to put a GUI onto their project? +* looking for an active project? Look no further, **you've found your GUI package**. @@ -110,7 +131,9 @@ Perhaps you're looking for a way to interact with your **Raspberry Pi** in a mor ![raspberry pi everything demo](https://user-images.githubusercontent.com/13696193/44279694-5b58ce80-a220-11e8-9ab6-d6021f5a944f.jpg) - f + + + In addition to a primary GUI, you can add a Progress Meter to your code with ONE LINE of code. Slide this line into any of your `for` loops and get a nice meter: OneLineProgressMeter('My meter title', current_value, max value, 'key') @@ -1326,6 +1349,7 @@ Window( title, auto_size_buttons=None, location=(None,None), size=(None,None), + element_padding=None, button_color=None, font=None, progress_bar_color=(None,None), @@ -1352,7 +1376,9 @@ Parameter Descriptions. You will find these same parameters specified for each default_button_element_size - Size of buttons on this window auto_size_text - Bool. True if elements should size themselves according to contents. Defaults to True auto_size_buttons - Bool. True if button elements should size themselves according to their text label - location - (x,y) Location to place window in pixels + location - (x,y) Location to place window in pixels + size - (w,h) forces a window to be a paricular size + element_padding - (w,h) default padding amount for elements font - Font name and size for elements of the window button_color - Default color for buttons (foreground, background). Can be text or hex progress_bar_color - Foreground and background colors for progress bars @@ -1368,13 +1394,28 @@ Parameter Descriptions. You will find these same parameters specified for each text_justification - Justification to use for Text Elements in this window no_titlebar - Create window without a titlebar grab_anywhere - Grab any location on the window to move the window - keep_on_top - if True then window will always stop on top of other windows on the screen. Great for floating toolbars. + keep_on_top - if True then window will always stop on top of other windows on the screen. Great for floating toolbars. + resizable - if True - user can manually changge the wize of the window. Defaults to False + disable_close - if True user will not be able to close using the X. ### Window Location PySimpleGUI computes the exact center of your window and centers the window on the screen. If you want to locate your window elsewhere, such as the system default of (0,0), if you have 2 ways of doing this. The first is when the window is created. Use the `location` parameter to set where the window. The second way of doing this is to use the `SetOptions` call which will set the default window location for all windows in the future. + +### Window Size + +You can get your window's size by access the `Size`property. The window has to be Read once or Finalized in order for the value to be correct. Note that it's a property, not a call. + +`my_windows_size = window.Size` + +To finalize your window: + +```pytyhon +window = Window('My Title').Layout(layout).Finalize() +``` -### Sizes + +### Element Sizes Note several variables that deal with "size". Element sizes are measured in characters. A Text Element with a size of 20,1 has a size of 20 characters wide by 1 character tall. The default Element size for PySimpleGUI is `(45,1)`. @@ -1638,6 +1679,15 @@ Then to get the input value from the read it would be: values['mykey'] You also use the same key if you want to call Update on an element. Please see the section below on Updates to understand that usage. +#### Visible +Beginning in version 3.17 you can create Elements that are initially invisible that you can later make visible. + +To create an invisible Element, place the element in the layout like you normally would and add the parameter `visible=False`. + +Later when you want to make that Element visible you simply call the Element's `Update` method and pass in the parameter `visible=True` + +This feature works best on Qt, but does work on the tkinter version as well. The visible parameter can also be used with the Column and Frame "container" Elements. + ### Output Elements Building a window is simply making lists of Elements. Each list is a row in the overall GUI dialog box. The definition looks something like this: @@ -1645,6 +1695,10 @@ Building a window is simply making lists of Elements. Each list is a row in the layout = [ [row 1 element, row 1 element], [row 2 element, row 2 element, row 2 element] ] The code is a crude representation of the GUI, laid out in text. +## Shortcut Functions / Multiple Function Names + +Many of the main method calls and Element names have shortcuts. This enables you to code much quicker once you are used to using the SDK. The Text Element, for example, has 3 different names `Text`, `Txt` or`T`. InputText can also be written `Input` or `In` . `FindElement` was recently renamed to `Element` because it's a commonly used function. + ## Text Element @@ -1673,7 +1727,8 @@ The most basic element is the Text element. It simply displays text. Many of t Text - The text that's displayed size - Element's size - click_submits - if clicked will cause a read call to return they key value as the button + click_submits - if clicked will cause a read call to return the key value of the button + enable_events - same as click_submits relief - relief to use around the text auto_size_text - Bool. Change width to match size of text font - Font name and size to use @@ -1686,23 +1741,28 @@ The most basic element is the Text element. It simply displays text. Many of t Some commonly used elements have 'shorthand' versions of the functions to make the code more compact. The functions `T` and `Txt` are the same as calling `Text`. -**Fonts** +### Fonts Already discussed in the common parameters section. Either string or a tuple. -**Color** in PySimpleGUI are in one of two formats - color name or RGB value. +### Color in PySimpleGUI are in one of two formats - color name or RGB value. Individual colors are specified using either the color names as defined in tkinter or an RGB string of this format: "#RRGGBB" or "darkblue" -**auto_size_text** +### `auto_size_text ` A `True` value for `auto_size_text`, when placed on Text Elements, indicates that the width of the Element should be shrunk do the width of the text. The default setting is True. -**Shortcut functions** +### tcut functions The shorthand functions for `Text` are `Txt` and `T` - + +### Events `enable_events` + + If you set the parameter `enable_events` or `click_submits` then you will get an event if the user clicks on the Text. + + ### Text Methods #### Update @@ -1741,25 +1801,12 @@ Multiline( default_text='', pad=None, tooltip=None ''' -``` - - Multiline(default_text='', - enter_submits = False, - disabled=False, - autoscroll=False, - size=(None, None), - auto_size_text=None, - background_color=None, - text_color=None, - do_not_clear=False, - key=None, - focus=False, - pad=None, - tooltip=None) -. +``` default_text - Text to display in the text box - enter_submits - Bool. If True, pressing Enter key submits window + change_submits - Bool. If True, pressing Enter key submits window + anable_events - Bool. same as change_submits + autoscroll - Bool. Causes "cursor" to always be at the end of the text size - Element's size auto_size_text - Bool. Change width to match size of text @@ -1807,7 +1854,7 @@ You should be quite familiar with these parameters by now. If not, read able an ## Input Elements These make up the majority of the window definition. Optional variables at the Element level override the window level values (e.g. `size` is specified in the Element). All input Elements create an entry in the list of return values. A Text Input Element creates a string in the list of items returned. -## Text Input Element +## Text Input Element Shortcuts (Input, In) layout = [[sg.InputText('Default text')]] @@ -1850,12 +1897,15 @@ You should be quite familiar with these parameters by now. If not, read able an There are two methods that can be called: - InputText.Update(new_Value) - sets the input value - Input.Text(Get() - returns the current value of the field. + Input.Update(new_Value) - sets the input to new_value + Input.Get() - returns the current value of the field. Shorthand functions that are equivalent to `InputText` are `Input` and `In` + +#### `do_not_clear` Parameter +**Important** - This trips a lot of people up. If you do not set the `do_not_clear` parameter then the input field will clear when an event takes place. The behavior is a "forms" style window development. The assumption is that you want the field to clear. If you are writing a chat program then you're thankful. The rest of you, I'm sorry. ### TextInput Methods ```python @@ -2033,6 +2083,11 @@ Sliders have a couple of slider-specific settings as well as appearance settings key- Dictionary key to use for return values tooltip - Tooltip to display when hovered over wlement +### Qt Sliders + +There is an important difference between Qt and tkinter sliders. On Qt, the slider values must be integer, not float. If you want your slider to go from 0.1 to 1.0, then make your slider go from 1 to 10 and divide by 10. It's an easy math thing to do and not a big deal. Just deal with it.... you're writing software after all. Presumably you know how to do these things. ;-) + + ### Slider Methods ```python Update(self, value=None, range=(None, None), disabled=None): @@ -2173,6 +2228,14 @@ Parameter definitions key = Dictionary key to use for return values pad - padding around element in the window tooltip - text to show when mouse hovered over element + + +### Qt Differences - `values` is a range! + +Note that Qt does not allow arbitrary spinner values. With PySimpleGUI-tkinter you can have any values in your list. In Qt they must be integers. Yea, it kinda sucks. I'm working on it. + +On Qt values is a tuple representing a range. On plain PySimpleGUI this value is a list of items. Make sure on the plain version you specify items as a list using [] and not a generator using (). + ### Spin Methods ```python @@ -2185,24 +2248,33 @@ disabled - if True disables the element ## Image Element Images can be placed in your window provide they are in PNG, GIF, PPM/PGM format. JPGs cannot be shown because tkinter does not naively support JPGs. You can use the Python Imaging Library (PIL) package to convert your image to PNG prior to calling PySimpleGUI if your images are in JPG format. - - Image(filename=None, - data=None, - background_color=None, - size=(None, None), - pad=None, - key=None, - tooltip=None) - +```python + Image(filename=None, + data=None, + data_base64=None, + background_color=None, + size=(None,None), + pad=None, + key=None, + tooltip=None, + click_submits=False, + enable_events=False, + visible=True, + size_px=(None,None) +``` Parameter definitions filename - file name if the image is in a file - data - if image is in RAM (PIL format?) + data - if image is in RAM (PIL format?) + data_base64 - image in base64 format background_color - Color of background size - Size (Width, Height) of image in pixels pad - Padding around Element in the window key - Key used to find the element tooltip - text to show when mouse if hovered over image + click_submits, enable_events - if True returns event when image is clicked + visible - if False will create image as hidden + size_px - size of image in pixels ### Image Methods From a9b775c1b7470cac5b19046e07165ece731ffc08 Mon Sep 17 00:00:00 2001 From: MikeTheWatchGuy Date: Sun, 9 Dec 2018 13:33:45 -0500 Subject: [PATCH 3/3] Corrected links to documents --- docs/tutorial.md | 630 +++++++++++++++++++++++------------------------ 1 file changed, 315 insertions(+), 315 deletions(-) diff --git a/docs/tutorial.md b/docs/tutorial.md index ab3a128a..b05a2c4d 100644 --- a/docs/tutorial.md +++ b/docs/tutorial.md @@ -1,82 +1,82 @@ ![pysimplegui_logo](https://user-images.githubusercontent.com/13696193/43165867-fe02e3b2-8f62-11e8-9fd0-cc7c86b11772.png) - -# Add GUIs to your programs and scripts easily with PySimpleGUI - + +# Add GUIs to your programs and scripts easily with PySimpleGUI + PySimpleGUI now supports BOTH Python 2.7 and Python 3 - -## Introduction -Few people run Python programs by double clicking the .py file as if it were a .exe file. When a typical user (non-programmer types) double clicks an exe file, they expect it to pop open with a window they can interact with. While GUIs, using tkinter, are possible using standard Python installations, it's unlikely many programs do this. - -What if it were easy so to open a Python program into a GUI that complete beginners could do it? Would anyone care? Would anyone use it? It's difficult to answer because to date it's not been "easy" to build a custom GUI. - -There seems to be a gap in the ability to add a GUI onto a Python program/script. Complete beginners are left using only the command line and many advanced programmers don't want to take the time required to code up a tkinter GUI. - - - - -## GUI Frameworks -There is no shortage of GUI frameworks for Python. tkinter, WxPython, Qt, Kivy are a few of the major packages. In addition, there are a good number of dumbed down GUI packages that wrap one of the major packages. These include EasyGUI, PyGUI, Pyforms, ... - -The problem is that beginners (those with experience of less than 6 weeks) are not capable of learning even the simplest of the major packages. That leaves the wrapper-packages. Users will likely find it difficult or impossible to build a custom GUI layout using the smaller packages. - -PySimpleGUI attempts to address these GUI challenges by providing a super-simple, easy to understand interface to GUIs that can be easily customized. Complex GUIs are often less than 20 lines of code when PySimpleGUI is used. - -## The Secret - -What makes PySimpleGUI superior for newcomers is that the package contains the majority of the code that the user is normally expected to write. Button callbacks are handled by PySimpleGUI, not the user's code. Beginners struggle to grasp the concept of a function, expecting them to understand a call-back function in the first few weeks is a stretch. - -With some GUIs arranging the GUI Widgets often requires several lines of code.... at least one or two lines per widget. PySimpleGUI uses an "auto-packer" that creates the layout for the user automatically. There is no concept of a pack nor a grid system needed to layout a GUI Window. - -Finally, PySimpleGUI leverages the Python language constructs in clever ways that shortens the amount of code and returns the GUI data in a straightforward manner. When a Widget is created in a window layout, it is configured in-place, not several lines of code away. Results are returned as a simple list or a dictionary. - -## What is a GUI? - -Most GUIs do one thing.... they collect information from the user and return it. From a programmer's viewpoint a GUI that collects information, like a window, could be summed up as a function call that looks like this: - - button, values = GUI_Display(gui_layout) - -What's expected from most GUIs is the button that was clicked (OK, cancel, save, yes, no, etc), and the values that were input by the user. The essence of a GUI can be boiled down into a single line of code. - -This is exactly how PySimpleGUI works (for these simple kinds of GUIs). When the call is made to display the GUI, execution does no return until a button is clicked that closes the window. - -There are more complex GUIs such as those that don't close after a button is clicked. These resemble a windows program and also be created with PySimpleGUI. A remote control interface for a robot and a chat window are a couple of examples where you want to keep the window open after a button is clicked. - -## The 5-Minute GUI - -When is PySimpleGUI useful? ***Immediately***, anytime you've got a GUI need. It will take under 5 minutes for you to create and try your GUI. With those kinds of times, what do you have to lose trying it? - -The best way to go about making your GUI in under 5 minutes is to copy one of the GUIs from the [PySimpleGUI Cookbook](https://pysimplegui.readthedocs.io/en/latest/cookbook/). Follow these steps: + +## Introduction +Few people run Python programs by double clicking the .py file as if it were a .exe file. When a typical user (non-programmer types) double clicks an exe file, they expect it to pop open with a window they can interact with. While GUIs, using tkinter, are possible using standard Python installations, it's unlikely many programs do this. + +What if it were easy so to open a Python program into a GUI that complete beginners could do it? Would anyone care? Would anyone use it? It's difficult to answer because to date it's not been "easy" to build a custom GUI. + +There seems to be a gap in the ability to add a GUI onto a Python program/script. Complete beginners are left using only the command line and many advanced programmers don't want to take the time required to code up a tkinter GUI. + + + + +## GUI Frameworks +There is no shortage of GUI frameworks for Python. tkinter, WxPython, Qt, Kivy are a few of the major packages. In addition, there are a good number of dumbed down GUI packages that wrap one of the major packages. These include EasyGUI, PyGUI, Pyforms, ... + +The problem is that beginners (those with experience of less than 6 weeks) are not capable of learning even the simplest of the major packages. That leaves the wrapper-packages. Users will likely find it difficult or impossible to build a custom GUI layout using the smaller packages. + +PySimpleGUI attempts to address these GUI challenges by providing a super-simple, easy to understand interface to GUIs that can be easily customized. Complex GUIs are often less than 20 lines of code when PySimpleGUI is used. + +## The Secret + +What makes PySimpleGUI superior for newcomers is that the package contains the majority of the code that the user is normally expected to write. Button callbacks are handled by PySimpleGUI, not the user's code. Beginners struggle to grasp the concept of a function, expecting them to understand a call-back function in the first few weeks is a stretch. + +With some GUIs arranging the GUI Widgets often requires several lines of code.... at least one or two lines per widget. PySimpleGUI uses an "auto-packer" that creates the layout for the user automatically. There is no concept of a pack nor a grid system needed to layout a GUI Window. + +Finally, PySimpleGUI leverages the Python language constructs in clever ways that shortens the amount of code and returns the GUI data in a straightforward manner. When a Widget is created in a window layout, it is configured in-place, not several lines of code away. Results are returned as a simple list or a dictionary. + +## What is a GUI? + +Most GUIs do one thing.... they collect information from the user and return it. From a programmer's viewpoint a GUI that collects information, like a window, could be summed up as a function call that looks like this: + + button, values = GUI_Display(gui_layout) + +What's expected from most GUIs is the button that was clicked (OK, cancel, save, yes, no, etc), and the values that were input by the user. The essence of a GUI can be boiled down into a single line of code. + +This is exactly how PySimpleGUI works (for these simple kinds of GUIs). When the call is made to display the GUI, execution does no return until a button is clicked that closes the window. + +There are more complex GUIs such as those that don't close after a button is clicked. These resemble a windows program and also be created with PySimpleGUI. A remote control interface for a robot and a chat window are a couple of examples where you want to keep the window open after a button is clicked. + +## The 5-Minute GUI + +When is PySimpleGUI useful? ***Immediately***, anytime you've got a GUI need. It will take under 5 minutes for you to create and try your GUI. With those kinds of times, what do you have to lose trying it? + +The best way to go about making your GUI in under 5 minutes is to copy one of the GUIs from the [PySimpleGUI Cookbook](https://pysimplegui.readthedocs.io/en/latest/cookbook/). Follow these steps: * Install PySimpleGUI (see short section in readme on installation) -* Find a GUI that looks similar to what you want to create -* Copy code from Cookbook -* Paste into your IDE and run +* Find a GUI that looks similar to what you want to create +* Copy code from Cookbook +* Paste into your IDE and run + +Let's look at the first recipe from the book + + import PySimpleGUI as sg + + # Very basic window. Return values as a list + + layout = [ + [sg.Text('Please enter your Name, Address, Phone')], + [sg.Text('Name', size=(15, 1)), sg.InputText('name')], + [sg.Text('Address', size=(15, 1)), sg.InputText('address')], + [sg.Text('Phone', size=(15, 1)), sg.InputText('phone')], + [sg.Submit(), sg.Cancel()] + ] -Let's look at the first recipe from the book - - import PySimpleGUI as sg - - # Very basic window. Return values as a list - - layout = [ - [sg.Text('Please enter your Name, Address, Phone')], - [sg.Text('Name', size=(15, 1)), sg.InputText('name')], - [sg.Text('Address', size=(15, 1)), sg.InputText('address')], - [sg.Text('Phone', size=(15, 1)), sg.InputText('phone')], - [sg.Submit(), sg.Cancel()] - ] - - window = sg.Window('Simple data entry window').Layout(layout) - button, values = window.Read() - - print(button, values[0], values[1], values[2]) - - -It's a reasonably sized window. - - -![super simple 2](https://user-images.githubusercontent.com/13696193/43934091-8100e29a-9c1b-11e8-8d0a-9bd2d13e6d8e.jpg) - -If you only need to collect a few values and they're all basically strings, then you would copy this recipe and modify it to suit your needs. + window = sg.Window('Simple data entry window').Layout(layout) + button, values = window.Read() + + print(button, values[0], values[1], values[2]) + + +It's a reasonably sized window. + + +![super simple 2](https://user-images.githubusercontent.com/13696193/43934091-8100e29a-9c1b-11e8-8d0a-9bd2d13e6d8e.jpg) + +If you only need to collect a few values and they're all basically strings, then you would copy this recipe and modify it to suit your needs. ### Python 2.7 Differences @@ -90,251 +90,251 @@ Python 2.7: import PySimpleGUI27 as sg - -## The 5-line GUI - -Not all GUIs take 5 minutes. Some take 5 lines of code. This is a GUI with a custom layout contained in 5 lines of code. - - import PySimpleGUI as sg - - layout = [ [sg.Text('Enter your name'), sg.InputText()], - [sg.OK()] ] - + +## The 5-line GUI + +Not all GUIs take 5 minutes. Some take 5 lines of code. This is a GUI with a custom layout contained in 5 lines of code. + + import PySimpleGUI as sg + + layout = [ [sg.Text('Enter your name'), sg.InputText()], + [sg.OK()] ] + window = sg.Window('My first GUI').Layout(layout) button, (name,) = window.Read() - - -![myfirstgui](https://user-images.githubusercontent.com/13696193/44315412-d2918c80-a3f1-11e8-9eda-0d5d9bfefb0f.jpg) - - - -## Making Your Custom GUI - -If you find a Recipe similar to your project. You may be able to modify the code within 5 minutes in order to get to *your layout*, assuming you've got a straightforward layout. - -Widgets are called Elements in PySimpleGUI. This list of Elements are spelled exactly as you would type it into your Python code. - -### Core Element list -``` - Buttons including these types: - File Browse - Folder Browse - Color chooser - Date picker - Read window - Close window - Realtime - Checkbox - Radio Button - Listbox - Slider - Multi-line Text Input - Scroll-able Output - Progress Bar - Option Menu - Image - Menu - Frame - Column - Graph - Table - Tabbed windows - Redirected Python Output/Errors to scrolling Window -``` - -You can also have short-cut Elements. There are 2 types of shortcuts. One is simply other names for the exact same element (e.g. T instead of Text). The second type configures an Element with particular setting, sparing the programmer from specifying all of the parameters (e.g. Submit is a button with the text "Submit" on it). - -### Shortcut list - - T = Text - Txt = Text - In = InputText - Input = IntputText - Combo = DropDown = Drop = InputCombo - DropDown = InputCombo - Drop = InputCombo - OptionMenu = InputOptionMenu - CB - CBox = Check = Checkbox - RButton = ReadButton - Button = SimpleButton - -A number of common buttons have been implemented as shortcuts. These include: -### Button Shortcuts - FolderBrowse - FileBrowse - FilesBrowse - FileSaveAs - Save - Open - Submit - OK - Ok - Cancel - Quit - Help - Exit - Yes - No - -The more generic button functions, that are also shortcuts -### Generic Buttons - Button - RButton (ReadButton) - RealtimeButton - -These are all of the GUI Widgets you have to choose from. If it's not in this list, it doesn't go in your window layout. (Maybe... unless there's been an update with more features and this tutorial wasn't updated) - -### GUI Design Pattern - -The stuff that tends not to change in GUIs are the calls that setup and show the Window. It's the layout of the Elements that changes from one program to another. This is the code from above with the layout removed: - - import PySimpleGUI as sg - # Define your window here (it's a list of lists) - layout = [[ your layout ]] - window = sg.Window('Simple data entry window').Layout(layout) + + +![myfirstgui](https://user-images.githubusercontent.com/13696193/44315412-d2918c80-a3f1-11e8-9eda-0d5d9bfefb0f.jpg) + + + +## Making Your Custom GUI + +If you find a Recipe similar to your project. You may be able to modify the code within 5 minutes in order to get to *your layout*, assuming you've got a straightforward layout. + +Widgets are called Elements in PySimpleGUI. This list of Elements are spelled exactly as you would type it into your Python code. + +### Core Element list +``` + Buttons including these types: + File Browse + Folder Browse + Color chooser + Date picker + Read window + Close window + Realtime + Checkbox + Radio Button + Listbox + Slider + Multi-line Text Input + Scroll-able Output + Progress Bar + Option Menu + Image + Menu + Frame + Column + Graph + Table + Tabbed windows + Redirected Python Output/Errors to scrolling Window +``` + +You can also have short-cut Elements. There are 2 types of shortcuts. One is simply other names for the exact same element (e.g. T instead of Text). The second type configures an Element with particular setting, sparing the programmer from specifying all of the parameters (e.g. Submit is a button with the text "Submit" on it). + +### Shortcut list + + T = Text + Txt = Text + In = InputText + Input = IntputText + Combo = DropDown = Drop = InputCombo + DropDown = InputCombo + Drop = InputCombo + OptionMenu = InputOptionMenu + CB - CBox = Check = Checkbox + RButton = ReadButton + Button = SimpleButton + +A number of common buttons have been implemented as shortcuts. These include: +### Button Shortcuts + FolderBrowse + FileBrowse + FilesBrowse + FileSaveAs + Save + Open + Submit + OK + Ok + Cancel + Quit + Help + Exit + Yes + No + +The more generic button functions, that are also shortcuts +### Generic Buttons + Button + RButton (ReadButton) + RealtimeButton + +These are all of the GUI Widgets you have to choose from. If it's not in this list, it doesn't go in your window layout. (Maybe... unless there's been an update with more features and this tutorial wasn't updated) + +### GUI Design Pattern + +The stuff that tends not to change in GUIs are the calls that setup and show the Window. It's the layout of the Elements that changes from one program to another. This is the code from above with the layout removed: + + import PySimpleGUI as sg + # Define your window here (it's a list of lists) + layout = [[ your layout ]] + window = sg.Window('Simple data entry window').Layout(layout) button, values = window.Read() - - - The flow for most GUIs is: - * Create the window object - * Define GUI as a list of lists - * Show the GUI and get results - -Some windows act more like Windows programs. These windows have an "Event Loop". Please see the readme for more info on these kinds of windows (Persistent windows) - -These are line for line what you see in design pattern above. - -### GUI Layout - -To create your custom GUI, first break your window down into "rows". You'll be defining your window one row at a time. Then for each for, you'll be placing one Element after another, working from left to right. - -The result is a "list of lists" that looks something like this: - - layout = [ [Text('Row 1')], - [Text('Row 2'), Checkbox('Checkbox 1', OK()), Checkbox('Checkbox 2'), OK()] ] - -The layout produced this window: - -![tutorial2](https://user-images.githubusercontent.com/13696193/44302312-e5259c00-a2f3-11e8-9c17-63e4eb130a9e.jpg) - - -## Display GUI & Get Results - -Once you have your layout complete and you've copied over the lines of code that setup and show the window, it's time to look at how to display the window and get the values from the user. - -First get a window and display it. -``` window = sg.Window('Simple data entry window').Layout(layout) ``` - -Then read the window to get the button clicked and values.: - - button, values = window.Read() - - windows return 2 values, the text of the button that was clicked and a ***list of values*** the user entered into the window. More advanced windows return the values as a **dictionary of values**, - -If the example window was displayed and the user did nothing other than click the OK button, then the results would have been: - - button == 'OK' - values == [False, False] - -Checkbox Elements return a value of True/False. Because these checkboxes defaulted to unchecked, the values returned were both False. - -## Displaying Results - -Once you have the values from the GUI it would be nice to check what values are in the variables. Rather than print them out using a `print` statement, let's stick with the GUI idea and output to a window. - -PySimpleGUI has a number of Popup Windows to choose from. The data passed to the Popup will be displayed in a window. The function takes any number of arguments, just like a print call would. Simply pass in all the variables you would like to see in the call. - -The most-commonly used display window is the `Popup`. To display the results of the previous example, one would write: - - Popup('The GUI returned:', button, values) - -## Putting It All Together - -Now that you know the basics, let's put together a window that contains as many PySimpleGUI's elements as possible. Also, just to give it a nice look, we'll change the "look and feel" to a green and tan color scheme. - - import PySimpleGUI as sg - - sg.ChangeLookAndFeel('GreenTan') - - column1 = [[sg.Text('Column 1', background_color='#d3dfda', justification='center', size=(10, 1))], - [sg.Spin(values=('Spin Box 1', '2', '3'), initial_value='Spin Box 1')], - [sg.Spin(values=('Spin Box 1', '2', '3'), initial_value='Spin Box 2')], - [sg.Spin(values=('Spin Box 1', '2', '3'), initial_value='Spin Box 3')]] - layout = [ - [sg.Text('All graphic widgets in one window!', size=(30, 1), font=("Helvetica", 25))], - [sg.Text('Here is some text.... and a place to enter text')], - [sg.InputText('This is my text')], - [sg.Checkbox('My first checkbox!'), sg.Checkbox('My second checkbox!', default=True)], - [sg.Radio('My first Radio! ', "RADIO1", default=True), sg.Radio('My second Radio!', "RADIO1")], - [sg.Multiline(default_text='This is the default Text should you decide not to type anything', size=(35, 3)), - sg.Multiline(default_text='A second multi-line', size=(35, 3))], - [sg.InputCombo(('Combobox 1', 'Combobox 2'), size=(20, 3)), - sg.Slider(range=(1, 100), orientation='h', size=(34, 20), default_value=85)], - [sg.Listbox(values=('Listbox 1', 'Listbox 2', 'Listbox 3'), size=(30, 3)), - sg.Slider(range=(1, 100), orientation='v', size=(5, 20), default_value=25), - sg.Slider(range=(1, 100), orientation='v', size=(5, 20), default_value=75), - sg.Slider(range=(1, 100), orientation='v', size=(5, 20), default_value=10), - sg.Column(column1, background_color='#d3dfda')], - [sg.Text('_' * 80)], - [sg.Text('Choose A Folder', size=(35, 1))], - [sg.Text('Your Folder', size=(15, 1), auto_size_text=False, justification='right'), - sg.InputText('Default Folder'), sg.FolderBrowse()], - [sg.Submit(), sg.Cancel()] - ] - + + + The flow for most GUIs is: + * Create the window object + * Define GUI as a list of lists + * Show the GUI and get results + +Some windows act more like Windows programs. These windows have an "Event Loop". Please see the readme for more info on these kinds of windows (Persistent windows) + +These are line for line what you see in design pattern above. + +### GUI Layout + +To create your custom GUI, first break your window down into "rows". You'll be defining your window one row at a time. Then for each for, you'll be placing one Element after another, working from left to right. + +The result is a "list of lists" that looks something like this: + + layout = [ [Text('Row 1')], + [Text('Row 2'), Checkbox('Checkbox 1', OK()), Checkbox('Checkbox 2'), OK()] ] + +The layout produced this window: + +![tutorial2](https://user-images.githubusercontent.com/13696193/44302312-e5259c00-a2f3-11e8-9c17-63e4eb130a9e.jpg) + + +## Display GUI & Get Results + +Once you have your layout complete and you've copied over the lines of code that setup and show the window, it's time to look at how to display the window and get the values from the user. + +First get a window and display it. +``` window = sg.Window('Simple data entry window').Layout(layout) ``` + +Then read the window to get the button clicked and values.: + + button, values = window.Read() + + windows return 2 values, the text of the button that was clicked and a ***list of values*** the user entered into the window. More advanced windows return the values as a **dictionary of values**, + +If the example window was displayed and the user did nothing other than click the OK button, then the results would have been: + + button == 'OK' + values == [False, False] + +Checkbox Elements return a value of True/False. Because these checkboxes defaulted to unchecked, the values returned were both False. + +## Displaying Results + +Once you have the values from the GUI it would be nice to check what values are in the variables. Rather than print them out using a `print` statement, let's stick with the GUI idea and output to a window. + +PySimpleGUI has a number of Popup Windows to choose from. The data passed to the Popup will be displayed in a window. The function takes any number of arguments, just like a print call would. Simply pass in all the variables you would like to see in the call. + +The most-commonly used display window is the `Popup`. To display the results of the previous example, one would write: + + Popup('The GUI returned:', button, values) + +## Putting It All Together + +Now that you know the basics, let's put together a window that contains as many PySimpleGUI's elements as possible. Also, just to give it a nice look, we'll change the "look and feel" to a green and tan color scheme. + + import PySimpleGUI as sg + + sg.ChangeLookAndFeel('GreenTan') + + column1 = [[sg.Text('Column 1', background_color='#d3dfda', justification='center', size=(10, 1))], + [sg.Spin(values=('Spin Box 1', '2', '3'), initial_value='Spin Box 1')], + [sg.Spin(values=('Spin Box 1', '2', '3'), initial_value='Spin Box 2')], + [sg.Spin(values=('Spin Box 1', '2', '3'), initial_value='Spin Box 3')]] + layout = [ + [sg.Text('All graphic widgets in one window!', size=(30, 1), font=("Helvetica", 25))], + [sg.Text('Here is some text.... and a place to enter text')], + [sg.InputText('This is my text')], + [sg.Checkbox('My first checkbox!'), sg.Checkbox('My second checkbox!', default=True)], + [sg.Radio('My first Radio! ', "RADIO1", default=True), sg.Radio('My second Radio!', "RADIO1")], + [sg.Multiline(default_text='This is the default Text should you decide not to type anything', size=(35, 3)), + sg.Multiline(default_text='A second multi-line', size=(35, 3))], + [sg.InputCombo(('Combobox 1', 'Combobox 2'), size=(20, 3)), + sg.Slider(range=(1, 100), orientation='h', size=(34, 20), default_value=85)], + [sg.Listbox(values=('Listbox 1', 'Listbox 2', 'Listbox 3'), size=(30, 3)), + sg.Slider(range=(1, 100), orientation='v', size=(5, 20), default_value=25), + sg.Slider(range=(1, 100), orientation='v', size=(5, 20), default_value=75), + sg.Slider(range=(1, 100), orientation='v', size=(5, 20), default_value=10), + sg.Column(column1, background_color='#d3dfda')], + [sg.Text('_' * 80)], + [sg.Text('Choose A Folder', size=(35, 1))], + [sg.Text('Your Folder', size=(15, 1), auto_size_text=False, justification='right'), + sg.InputText('Default Folder'), sg.FolderBrowse()], + [sg.Submit(), sg.Cancel()] + ] + window = sg.Window('Everything bagel', default_element_size=(40, 1)).Layout(layout) button, values = window.Read() - sg.Popup(button, values) + sg.Popup(button, values) + +That may seem like a lot of code, but try coding this same GUI layout using any other GUI framework and it will be lengthier and what you see here.... by a WIDE margin. 10's of times longer. + +![everything for tutorial](https://user-images.githubusercontent.com/13696193/44302997-38531b00-a303-11e8-8c45-698ea62590a8.jpg) + +The last line of code opens a message box. This is how it looks: + +![tutorial results](https://user-images.githubusercontent.com/13696193/44303004-79e3c600-a303-11e8-8311-2f3726d364ad.jpg) + + +Each parameter to the message box call is displayed on a new line. There are actually 2 lines of text in the message box. The second line is very long and wrapped a number of times + +Take a moment and pair up the results values with the GUI to get an understanding of how results are created and returned. + +## Adding a GUI to Your Program or Script +If you have a script that uses the command line, you don't have to abandon it in order to add a GUI. An easy solution is that if there are zero parameters given on the command line, then the GUI is run. Otherwise, execute the command line as you do today. + +This kind of logic is all that's needed: + + if len(sys.argv) == 1: + # collect arguments from GUI + else: + # collect arguements from sys.argv + +Copy one of the Recipes from the Cookbook and run it. See if it resembles something you would like to build: +[PySimpleGUI Cookbook](https://pysimplegui.readthedocs.io/en/latest/cookbook/) + +Have some fun! Spice up the scripts you're tired of running by hand. Spend 5 or 10 minutes playing with the demo scripts. You may find one already exists that does exactly what you need. If not, you will find it's 'simple' to create your own. If you really get lost, you've only invested 10 minutes. + +## Resources + +### Installation + +Requires Python 3 + + pip install PySimpleGUI + +If on a Raspberry Pi or Linux, may need to do this instead: + + sudo pip3 install --upgrade pysimplegui + +Works on all systems that run tkinter, including the Raspberry Pi + +### Documentation +[Main manual](http://www.PySimpleGUI.org) + +[Cookbook](http://cookbook.PySimpleGUI.org) -That may seem like a lot of code, but try coding this same GUI layout using any other GUI framework and it will be lengthier and what you see here.... by a WIDE margin. 10's of times longer. - -![everything for tutorial](https://user-images.githubusercontent.com/13696193/44302997-38531b00-a303-11e8-8c45-698ea62590a8.jpg) - -The last line of code opens a message box. This is how it looks: - -![tutorial results](https://user-images.githubusercontent.com/13696193/44303004-79e3c600-a303-11e8-8311-2f3726d364ad.jpg) - - -Each parameter to the message box call is displayed on a new line. There are actually 2 lines of text in the message box. The second line is very long and wrapped a number of times - -Take a moment and pair up the results values with the GUI to get an understanding of how results are created and returned. - -## Adding a GUI to Your Program or Script -If you have a script that uses the command line, you don't have to abandon it in order to add a GUI. An easy solution is that if there are zero parameters given on the command line, then the GUI is run. Otherwise, execute the command line as you do today. - -This kind of logic is all that's needed: - - if len(sys.argv) == 1: - # collect arguments from GUI - else: - # collect arguements from sys.argv - -Copy one of the Recipes from the Cookbook and run it. See if it resembles something you would like to build: -[PySimpleGUI Cookbook](https://pysimplegui.readthedocs.io/en/latest/cookbook/) - -Have some fun! Spice up the scripts you're tired of running by hand. Spend 5 or 10 minutes playing with the demo scripts. You may find one already exists that does exactly what you need. If not, you will find it's 'simple' to create your own. If you really get lost, you've only invested 10 minutes. - -## Resources - -### Installation - -Requires Python 3 - - pip install PySimpleGUI - -If on a Raspberry Pi or Linux, may need to do this instead: - - sudo pip3 install --upgrade pysimplegui - -Works on all systems that run tkinter, including the Raspberry Pi - -### Documentation -[Main manual](https://pysimplegui.readthedocs.io/en/latest/) - -[Cookbook](https://pysimplegui.readthedocs.io/en/latest/cookbook/) - -[Tutorial](http://tutorial.pysimplegui.org) - -### Home Page (GitHub) +[Tutorial](http://tutorial.pysimplegui.org) +### Home Page (GitHub) + [www.PySimpleGUI.com](www.PySimpleGUI.com) \ No newline at end of file