From 28c7c35ac016fd3848851f96efc148f5ff5d9b09 Mon Sep 17 00:00:00 2001 From: MikeTheWatchGuy Date: Sat, 10 Aug 2019 22:44:14 -0400 Subject: [PATCH] Lots of doc updates. The recent Tab and TabGroup changes --- PySimpleGUI.py | 17 +- PySimpleGUIQt/PySimpleGUIQt.py | 55 ++-- docs/index.md | 449 +++++++++++++++++++++++++++++---- readme.md | 449 +++++++++++++++++++++++++++++---- 4 files changed, 825 insertions(+), 145 deletions(-) diff --git a/PySimpleGUI.py b/PySimpleGUI.py index aadda41a..e707652e 100644 --- a/PySimpleGUI.py +++ b/PySimpleGUI.py @@ -1,5 +1,5 @@ #!/usr/bin/python3 -version = __version__ = "4.2.0.3 Unreleased" +version = __version__ = "4.2.0.4 Unreleased" # 888888ba .d88888b oo dP .88888. dP dP dP @@ -968,21 +968,6 @@ class Combo(Element): elif visible is True: self.TKCombo.pack() - - def GetSelectedItemsIndexes(self): - """ - Get the list of chosen items and return them as a list of indexes (offsets within the list). - Do NOT use them method as an alternative from reading the values returned to you in your call to - `Window.Read()`. All input elements should have their values read using the window.Read call, not methods - like this one. - - :return: List[int] List of indexes of currently selected items - """ - if not self.TKStringVar: - return [] - return [self.TKCombo.current(),] # for tkinter this will always be just 1 item - - def Get(self): try: if self.TKCombo.current() == -1: # if the current value was not in the original list diff --git a/PySimpleGUIQt/PySimpleGUIQt.py b/PySimpleGUIQt/PySimpleGUIQt.py index bff142bb..327114c2 100644 --- a/PySimpleGUIQt/PySimpleGUIQt.py +++ b/PySimpleGUIQt/PySimpleGUIQt.py @@ -2123,7 +2123,7 @@ class Tab(Element): self.Title = title self.BorderWidth = border_width self.Disabled = disabled - self.ParentNotebook = None + self.ParentTabGroup = None # type: TabGroup self.TabID = None self.BackgroundColor = background_color if background_color is not None else DEFAULT_BACKGROUND_COLOR self.Widget = self.QT_QWidget = None # type: QWidget @@ -2170,6 +2170,18 @@ class Tab(Element): element = row[col_num] return element + + def Select(self): + """ + Selects this tab. Mimics user clicking on this tab. Must have called window.Finalize / Read first! + """ + try: + index = self.ParentTabGroup.TabList.index(self) + self.ParentTabGroup.QT_QTabWidget.setCurrentIndex(index) + except: + print('** EXCEPTION while trying to Select tab with key =', self.Key) + + def __del__(self): for row in self.Rows: for element in row: @@ -2213,6 +2225,7 @@ class TabGroup(Element): self.BackgroundColor = background_color if background_color is not None else COLOR_SYSTEM_DEFAULT self.ChangeSubmits = change_submits or enable_events self.TabLocation = tab_location + self.TabList = [] # type: List[Tab] self.Widget = self.QT_QTabWidget = None # type: QTabWidget self.Layout(layout) @@ -2229,9 +2242,11 @@ class TabGroup(Element): for i, element in enumerate(args): # Loop through list of elements and add them to the row element.Position = (CurrentRowNumber, i) element.ParentContainer = self + element.ParentTabGroup = self CurrentRow.append(element) if element.Key is not None: self.UseDictionary = True + self.TabList.append(element) # ------------------------- Append the row to list of Rows ------------------------- # self.Rows.append(CurrentRow) @@ -2261,19 +2276,23 @@ class TabGroup(Element): if self.ChangeSubmits: element_callback_quit_mainloop(self) - def SelectTab(self, index): - try: - self.QT_QTabWidget.setCurrentIndex(index) - except: - pass + def Get(self): + """ + Returns the current value for the Tab Group, which will be the currently selected tab's KEY or the text on + the tab if no key is defined. Returns None if an error occurs. + Note that this is exactly the same data that would be returned from a call to Window.Read. Are you sure you + are using this method correctly? - def GetCurrentlySelectedTabIndex(self): + :return: Union[Any, None] The key of the currently selected tab or the tab's text if it has no key + """ + value = None try: - index = self.QT_QTabWidget.currentIndex() + cur_index = self.QT_QTabWidget.currentIndex() + tab_element = self.TabList[cur_index] + value = tab_element.Key except: - index = None - return index - + value = None + return value def __del__(self): for row in self.Rows: @@ -3519,6 +3538,8 @@ class Window: if element.Key is None: # if no key has been assigned.... create one for input elements if element.Type == ELEM_TYPE_BUTTON: element.Key = element.ButtonText + elif element.Type == ELEM_TYPE_TAB: + element.Key = element.Title if element.Type in (ELEM_TYPE_MENUBAR, ELEM_TYPE_BUTTONMENU, ELEM_TYPE_CANVAS, ELEM_TYPE_INPUT_SLIDER, ELEM_TYPE_GRAPH, ELEM_TYPE_IMAGE, ELEM_TYPE_INPUT_CHECKBOX, ELEM_TYPE_INPUT_LISTBOX, ELEM_TYPE_INPUT_COMBO, @@ -4304,14 +4325,10 @@ def BuildResultsForSubform(form, initialize_only, top_level_form): if not top_level_form.NonBlocking and not element.do_not_clear and not top_level_form.ReturnKeyboardEvents: element.QT_TextEdit.setText('') elif element.Type == ELEM_TYPE_TAB_GROUP: - try: - value = element.QT_QTabWidget.getCurrentIndex() - tab_key = element.FindKeyFromTabName(value) - if tab_key is not None: - value = tab_key - except: - value = None - value = 0 + element = element # type: TabGroup + cur_index = element.QT_QTabWidget.currentIndex() + tab_element = element.TabList[cur_index] + value = tab_element.Key elif element.Type == ELEM_TYPE_TABLE: value = [] indexes = element.QT_TableWidget.selectionModel().selectedRows() diff --git a/docs/index.md b/docs/index.md index c01ca22f..81d651e9 100644 --- a/docs/index.md +++ b/docs/index.md @@ -113,7 +113,27 @@ The YouTube videos - If you like instructional videos, there are over 15 videos # About The PySimpleGUI Documentation System -This User's Manual (also the project's readme) is one ***vital*** part of the PySimpleGUI programming environment. There are 5 resources that work together to provide to you the fastest path to success. These 5 resources are: +This User's Manual (also the project's readme) is one ***vital*** part of the PySimpleGUI programming environment. + +If you are a professional or skilled in how to develop software, then you understand the role of documentation in the world of technology development. You can skip this bit.... look for the bold "**GO TO HERE**" below. + +Bluntness is required here as the subtle approach has not worked in the past: + +***It WILL be required, at times, for you to read or search this document in order to be successful.*** + +Re-read that statement. This **will** be a serious problem for you if you're the type of person that finds it "quicker and easier to post on StackOverflow rather than reading documentation". + +If you have not yet matured to the point you are able to undertand this skill or choose to not follow it, then please save ***everyone*** the pain of doing **for you** what you, as a developer, software engineer, or wanna be coder, must do on your own. It's a vital skill for you to learn. + +Want to be a "real engineer"? Then follow "real engineering practices" such as "reading". You are learning a NEW GUI package. You've not seen anything like it. Don't be so arrogant as to believe you will never need to read documentation. + +UGH, why does this need to be said? + +***GO TO HERE*** if instructed above. + +I appologize to the other 95% of you that this..... pathetic.... reminder needs to be added, but sadly there's a need for it. + +There are 5 resources that work together to provide to you the fastest path to success. They are: 1. This User's Manual 2. The Cookbook @@ -121,7 +141,17 @@ This User's Manual (also the project's readme) is one ***vital*** part of the Py 4. Docstrings enable you to access help directly from Python or your IDE 5. Searching the GitHub Issues as a last resort -Pace yourself. The intial progress is exciting. GUIs take time and thought to build. Take a deep breath and use the provided materials and you'll do fine. +Pace yourself. The intial progress is exciting and FAST PACED. However, GUIs take time and thought to build. Take a deep breath and use the provided materials and you'll do fine. Don't skip the design phase of your GUI after you run some demos and get the hang of things. + +It is not by accident that this section, about documentation, is at the TOP of this document. + +This documentation is not HUGE in length. It's not written in complex english. It is understandable by complete beginners. And pressing `Control+F` is all you need to do to search this document. USUALLY you'll find less than 6 matches. + +## Documentation and Demos Get Out of Date + +Sometimes the documenation doesn't match exactly the version of the code you're running. Sometimes demo programs haven't been updated to match a change made to the SDK. Things don't happen simultaneously generally speaking. So, it may very well be that you find an error or inconsistency or something no longer works with the latest version of an external library. + +If you've found one of these problems, and you've searched to make sure it's not a simple mistake on your part, then by ALL means log an Issue on the GitHub. Don't be afraid to report problems if you've taken the simple steps of checking out the docs first. # Platforms @@ -3382,7 +3412,10 @@ Parameter Descriptions: #### GetSelectedItemsIndexes -Get the list of chosen items and return them as a list of indexes (offsets within the list) +Get the list of chosen items and return them as a list of indexes (offsets within the list). +Do NOT use them method as an alternative from reading the values returned to you in your call to +`Window.Read()`. All input elements should have their values read using the window.Read call, not methods +like this one. `GetSelectedItemsIndexes()` @@ -4679,14 +4712,19 @@ Parameter Descriptions: |visible|(bool) set visibility state of the element| ## Output Element -The Output Element is a re-direction of Stdout. **Anything "printed" will be displayed in this element.** This is the "trivial" way to show scrolling text in your window. It's as easy as dropping an Output Element into your window and then calling print as much as you want. -Note that you will NOT see what you `print` until you call either window.Read or window.Refresh. If you want to immediately see what was printed, call window.Refresh() immediately after your print statement. +The Output Element is a re-direction of Stdout. + +If you are looking for a way to quickly add the ability to show scrolling text within your window, then adding an `Output` Element is about as quick and easy as it gets. + +**Anything "printed" will be displayed in this element.** This is the "trivial" way to show scrolling text in your window. It's as easy as dropping an Output Element into your window and then calling print as much as you want. The user will see a scrolling area of text inside their window. + +***IMPORTANT*** You will NOT see what you `print` until you call either `window.Read` or `window.Refresh`. If you want to immediately see what was printed, call `window.Refresh()` immediately after your print statement. Output Element - a multi-lined text area where stdout and stderr are re-routed to. ```python -Output(size=(None, None)) +Output(size=(80,20)) ``` ![output](https://user-images.githubusercontent.com/13696193/44959863-b72f8280-aec3-11e8-8caa-7bc743149953.jpg) @@ -5680,9 +5718,98 @@ View of second tab: First we have the Tab layout definitions. They mirror what you see in the screen shots. Tab 1 has 1 Text Element in it. Tab 2 has a Text and an Input Element. +## Tab Element + Tab Element is another "Container" element that holds a layout and displays a tab with text. Used with TabGroup only Tabs are never placed directly into a layout. They are always "Contained" in a TabGroup layout +``` +Tab(title, + layout, + title_color=None, + background_color=None, + font=None, + pad=None, + disabled=False, + border_width=None, + key=None, + tooltip=None, + right_click_menu=None, + visible=True) +``` + +Parameter Descriptions: + +|Name|Meaning| +|---|---| +|title|(str) text to show on the tab| +|layout|List[List[Element]] The element layout that will be shown in the tab| +|title_color|(str) color of the tab text (note not currently working on tkinter)| +|background_color|(str) color of background of the entire layout| +|font|Union[str, Tuple[str, int]] specifies the font family, size, etc| +|pad|(int, int) or ((int, int),(int,int)) Amount of padding to put around element (left/right, top/bottom) or ((left, right), (top, bottom))| +|disabled|(bool) If True button will be created disabled| +|border_width|(int) width of border around element in pixels| +|key|(any) Value that uniquely identifies this element from all other elements. Used when Finding an element or in return values. Must be unique to the window| +|tooltip|(str) text, that will appear when mouse hovers over the element| +|right_click_menu|List[List[Union[List[str],str]]] A list of lists of Menu items to show when this element is right clicked. See user docs for exact format.| +|visible|(bool) set visibility state of the element| + +### Methods + +#### Select + +Create a tkinter event that mimics user clicking on a tab. Must have called window.Finalize / Read first! + +```python +Select() +``` + +#### SetFocus + +Sets the current focus to be on this element + +``` +SetFocus(force=False) +``` + +Parameter Descriptions: + +|Name|Meaning| +|---|---| +|force|(bool) if True will call focus_force otherwise calls focus_set| + +#### SetTooltip + +Called by application to change the tooltip text for an Element. Normally invoked using the Element Object such as: window.Element('key').SetToolTip('New tip'). + +``` +SetTooltip(tooltip_text) +``` + +Parameter Descriptions: + +|Name|Meaning| +|---|---| +|tooltip_text|(str) the text to show in tooltip.| + +#### Update + +Changes some of the settings for the Tab Element. Must call `Window.Read` or `Window.Finalize` prior + +``` +Update(disabled=None, visible=None) +``` + +Parameter Descriptions: + +|Name|Meaning| +|---|---| +|disabled|(bool) disable or enable state of the element| +|visible|(bool) control visibility of element| + +### TabGroup Element + TabGroup Element groups together your tabs into the group of tabs you see displayed in your window ```python @@ -5751,56 +5878,52 @@ Parameter Descriptions: |tooltip|(str) text, that will appear when mouse hovers over the element| |visible|(bool) set visibility state of the element| -``` -Tab(title, - layout, - title_color=None, - background_color=None, - font=None, - pad=None, - disabled=False, - border_width=None, - key=None, - tooltip=None, - right_click_menu=None, - visible=True) -``` - -Parameter Descriptions: - -|Name|Meaning| -|---|---| -|title|(str) text to show on the tab| -|layout|List[List[Element]] The element layout that will be shown in the tab| -|title_color|(str) color of the tab text (note not currently working on tkinter)| -|background_color|(str) color of background of the entire layout| -|font|Union[str, Tuple[str, int]] specifies the font family, size, etc| -|pad|(int, int) or ((int, int),(int,int)) Amount of padding to put around element (left/right, top/bottom) or ((left, right), (top, bottom))| -|disabled|(bool) If True button will be created disabled| -|border_width|(int) width of border around element in pixels| -|key|(any) Value that uniquely identifies this element from all other elements. Used when Finding an element or in return values. Must be unique to the window| -|tooltip|(str) text, that will appear when mouse hovers over the element| -|right_click_menu|List[List[Union[List[str],str]]] A list of lists of Menu items to show when this element is right clicked. See user docs for exact format.| -|visible|(bool) set visibility state of the element| - ### Reading Tab Groups Tab Groups now return a value when a Read returns. They return which tab is currently selected. There is also a `enable_events` parameter that can be set that causes a Read to return if a Tab in that group is selected / changed. The key or title belonging to the Tab that was switched to will be returned as the value -### Methods +### Method -Changes some of the settings for the Tab Element. Must call `Window.Read` or `Window.Finalize` prior +#### Get + +Returns the current value for the Tab Group, which will be the currently selected tab's KEY or the text on +the tab if no key is defined. Returns None if an error occurs. +Note that this is exactly the same data that would be returned from a call to Window.Read. Are you sure you +are using this method correctly? + +`Get()` + +|Name|Meaning| +|---|---| +| **return** | Union[Any, None] The key of the currently selected tab or the tab's text if it has no key | + +#### SetFocus + +Sets the current focus to be on this element ``` -Update(disabled=None, visible=None) +SetFocus(force=False) ``` Parameter Descriptions: |Name|Meaning| |---|---| -|disabled|(bool) disable or enable state of the element| -|visible|(bool) control visibility of element| +|force|(bool) if True will call focus_force otherwise calls focus_set| + +#### SetTooltip + +Called by application to change the tooltip text for an Element. Normally invoked using the Element Object such as: window.Element('key').SetToolTip('New tip'). + +``` +SetTooltip(tooltip_text) +``` + +Parameter Descriptions: + +|Name|Meaning| +|---|---| +|tooltip_text|(str) the text to show in tooltip.| ## Pane Element @@ -6159,7 +6282,7 @@ while True: window.Close() ``` -## Read(timeout = t, timeout_key='timeout') +## Read(timeout = t, timeout_key=TIMEOUT_KEY) Read with a timeout is a very good thing for your GUIs to use in a read non-blocking situation, if you can use them. If your device can wait for a little while, then use this kind of read. The longer you're able to add to the timeout value, the less CPU time you'll be taking. @@ -6682,37 +6805,247 @@ while True: # The PySimpleGUI Debugger -Starting on June 1, 2019, a built-in version of the debugger `imwatchingyou` has been shipping in every copy of PySimpleGUI. It's been largely downplayed to gauge whether or not the added code and the added feature and the use of a couple of keys, would mess up any users. +Listen up if you are +* advanced programmers debugging some really hairy stuff +* programmers from another era that like to debug this way +* those that want to have "x-ray vision" into their code +* asked to use debugger to gather information +* running on a platform that lacks ANY debugger +* debugging a problem that happens only outside of a debugger environment +* finding yourself saying "but it works when running PyCharm" + +Starting on June 1, 2019, a built-in version of the debugger `imwatchingyou` has been shipping in every copy of PySimpleGUI. It's been largely downplayed to gauge whether or not the added code and the added feature and the use of a couple of keys, would mess up any users. Over 30,000 users have installed PySimpleGUI since then and there's not be a single Issue filed nor comment/complaint made, so seems safe enough to normal users... so far.... So far no one has reported anything at all about the debugger. The assumption is that it is quietly lying dormant, waiting for you to press the `BREAK` or `CONTROL` + `BREAK` keys. It's odd no one has accidently done this and freaked out, logging an Issue. The plain PySimpleGUI module has a debugger builtin. For the other ports, please use the package `imwatchingyou`. +## What is it? Why use it? What the heck? I already have an IDE. + +This debugger provides you with something unique to most typical Python developers, the ability to "see" and interact with your code, **while it is running**. You can change variable values while your code continues to run. + +Print statements are cool, but perhaps you're tired of seeing this: +``` +Push Me {0: 'Input here'} +Push Me {0: 'Input here'} +Push Me {0: 'Input here'} +``` + +And would prefer to see this window updating continuously in the upper right corner of your display: + +![image](https://user-images.githubusercontent.com/13696193/62793751-54197900-baa0-11e9-9a98-f780259062b1.png) + +Notice how easy it is, using this window alone, to get the location that your PySimpleGUI package is coming from ***for sure***, no guessing. Expect this window to be in your debugging future as it'll get asked for from time to time. + ## Preparing To Run the Debugger -If your program is running with blocking `Read` calls, then you will want to add a timeout to your reads. This is because the debugger gets it's cycles by stealing a little bit of time from these async calls. +If your program is running with blocking `Read` calls, then you will want to add a timeout to your reads. This is because the debugger gets it's cycles by stealing a little bit of time from these async calls... but only when you have one of these debugger windows open so no bitching about wasted CPU time as there is none. -Your event loop will be modified from this: +Your event loop will be modified from this blocking: ```python while True: event, values = window.Read() ``` -To this: +To this non-blocking: ```python while True: - event, values = window.Read(timeout=100) + event, values = window.Read(timeout=200) if event == sg.TIMEOUT_KEY: continue ``` -This event loop will do nothing at all if a timeout occurs and will execute your normal code (that follows the if statement) when there is any event that is not a timeout. +These 3 lines will in no way change how your application looks and performs. You can do this to any PySimpleGUI app that uses a blocking read and you'll not notice a difference. The reason this is a NOP (No-operation) is that when a timeout happens, the envent will be set to `sg.TIMEOUT_KEY`. If a timeout is returned as the event, the code simply ignores it and restarts the loop by executing a `continue` statement. -This timeout value of 100 means that your debugger GUI will be updated 10 times a second. If this adds too much "drag" to your application, you can make the timeout larger. Try using 1000 instead of 100. +This timeout value of 200 means that your debugger GUI will be updated 5 times a second if nothing is happening. If this adds too much "drag" to your application, you can make the timeout larger. Try using 500 or 1000 instead of 100. + +### What happens if you don't add a timeout + +Let's say you're in a situation where a very intermettent bug has just happened and the debugger would really help you, but you don't have a timeout on your `windows.Read()` call. It's OK. Recall that the way the debugger gets its "cycles" is to borrow from your `Read` calls. What you need to do is alternate between using the debugger and then generating another pass through your event loop. + +Maybe it's an OK button that will cause your loop to execute again (without exiting). If so, you can use it to help move the debugger along. + +Yes, this is a major pain in the ass, but it's not THAT bad and compared to nothing in a time of crisis and this is potentially your "savior tool" that's going to save your ass, pressing that OK button a few times is going to look like nothing to you. You just want to dump out the value of a variable that holds an instance of your class! + +## A Sample Program For Us To Use + +Now that you understand how to add the debugger to your program, let's make a simple little program that you can use to follow these examples: + +```python +import PySimpleGUI as sg + +window = sg.Window('Testing the Debugger', [[sg.Text('Debugger Tester'), sg.In('Input here'), sg.B('Push Me')]]) + +while True: + event, values = window.Read(timeout=500) + if event == sg.TIMEOUT_KEY: + continue + if event is None: + break + print(event, values) +window.Close() +``` ## Debugger Windows -There are 2 debugger windows. One is called a "Popout". The Popout window displays all of your variables +### "Popout Debugger Window" + +There are 2 debugger windows. One is called the "Popout" debugger window. The Popout window displays as many currently in-scope local variables as possible. This window is not interactive. It is meant to be a frequently updated "dashboard" or "snapshot" of your variables. + +One "variable" shown in the popout window that is an often asked for piece of information when debugging Issues and that variable is `sg` (or whatever you named the PySimpleGUI pacakge when you did your import). The assumption is that your import is `import PySimpleGUI as sg`. If your import is different, then you'll see a different variable. The point is that it's shown here. + +Exiting this window is done via the little red X, **or using the rickt-click menu** which is also used as one way to launch the Main Debugger Window + +#### When you are asked for the "Location of your PySimpleGUI package or PySimpleGUI.py file" do this + +If you wish to use the debugger to find the location of THIS running program's PySimpleGUI package / the PySimpleGUI.py file, then all you need to do is: +* Press the `BREAK` key on your keyboard. + * This is sometimes labelled as the `Cancel` key + * May also have `Pause` printed on key + * On some US keyboards, it is located next to `Scroll Lock` and/or above `PageUp` key +* This will open a window located in the upper right corner of your screen that looks something like this: +![image](https://user-images.githubusercontent.com/13696193/62793751-54197900-baa0-11e9-9a98-f780259062b1.png) +* The information you are seeking is shown next to the `sg` in the window +You don't need to modify your program to get this info using this technique. + +If your variable's value is too long and doesn't fit, then you'lll need to collect this information using the "Main Debugger Window" + +#### What's NOT Listed In The Popout Debugger Window + +The Popup window is a "Snapshot" of your local variables at the time the window was opened. This means **any variables that did not exist at the time the Popout was created will not be shown**. This window does **NOT** expand in size by adding new variables. Maybe in the future. + +### The "Main Debugger Window" + +Now we're talking serious Python debugging! + +Ever wish you had a `repl>>>` prompt that you could run while your program is running. Well, that's pretty much what you're getting with the PySimpleGUI debugger Main Window! Cool, huh? If you're not impressed, go get a cup of coffee and walk off that distraction in your head before carring on because we're in to some seriously cool shit here.... + +You'll find that this window has 2 tabs, one is labelled `Variables` and the other is labelled `REPL & Watches` + +#### The "Variables" Tab of Main Debugger Window + +![SNAG-0440](https://user-images.githubusercontent.com/13696193/62797391-a01ceb80-baa9-11e9-845d-3cd02ca0dbcc.jpg) + +Notice the the "frame" surrounding this window is labelled "Auto Watches" in blue. Like the Popup window, this debugger window also "Watches" variables, which means continuously updates them as often as you call `Window.Read`. + +The maximum number of "watches" you can have any any one time is 9. + +##### Choosing variables to watch + +You can simply click "Show All Variable" button and the list of watched variables will be automatically populard by the first 9 variables it finds. Or you can click the "Choose Variables to Auto Watch" button where you can individually choose what variables, **and expressions** you wish to display. + +![SNAG-0442](https://user-images.githubusercontent.com/13696193/62797520-e96d3b00-baa9-11e9-8ba0-794e479b6fc5.jpg) + +In this window we're checking checkboxes to display these variables: + +`event`, `sg`, `values`, `window`, `__file__` + +![SNAG-0443](https://user-images.githubusercontent.com/13696193/62797518-e8d4a480-baa9-11e9-8575-5256dcf6b5ab.jpg) + +Additionally, you can see at the bottom of the window a "Custom Watch" has been defined. This can be any experession you want. Let's say you have a window with a LOT of values. Rather than looking through the `values` variable and finding the entry with the key you are looking for, the values variable's entry for a specific key is displayed. + +In this example the Custom Watch entered was `values[0]`. After clicking on the "OK" button, indicating the variables are chosen that we wish to watch, this is the Main window that is shown: + +![SNAG-0444](https://user-images.githubusercontent.com/13696193/62797514-e8d4a480-baa9-11e9-9a86-cfe99342dedb.jpg) + +We can see the variables we checked as well as the defined expression `values[0]`. If you leave this window open, these values with continuously be updated, on the fly, every time we call the line in our example code `window.Read(timeout=500)`. This means that the Main Debugger Window and these variables we defined will be updated every 500 milliseconds. + +#### The REPL & Watches Tab + +![SNAG-0441](https://user-images.githubusercontent.com/13696193/62797507-e7a37780-baa9-11e9-93c4-6ff0c8acb11d.jpg) + +This tab is provided to you as a way to interact with your running program on a real-time basis. + +If you want to quickly look at the values of variables, nearly ANY variables, then type the information into one of the 3 spaces provided to "Watch" either variables or experessions. In this example, the variable window was typed into the first slow. + +***Immediately*** after typing the character 'w', the information to the right was displayed. No button needs to be clicked. You merely neeed to type in a valid experession and it will be displayed to you.... and it will be displayed on an on-going, constantly-refreshing-basis. + +![SNAG-0447](https://user-images.githubusercontent.com/13696193/62797393-a0b58200-baa9-11e9-8016-1cadca4d97e7.jpg) + +If the area to the right of the input field is too small, then you can click on the "Detail" button and you will be shown a popup, scrolled window with all of the information displayed as if it were printed. + +I'm sure you've had the lovely experience of printing an object. When clicking the "Detail" button next to the `window` variable being shown, this window is shown: + +![SNAG-0449](https://user-images.githubusercontent.com/13696193/62801423-b0d25f00-bab3-11e9-829a-aebb429521cd.jpg) + +Oh, Python, -sigh-. I just want to see my `window` object printed. + +#### `Obj` Button to the Rescue! + +PySimpleGUI has a fun and very useful function that is discussed in the docs named `ObjToString` which takes an object and converts it's **contents** it into a nicely formatted string. This function is used to create the text output when you click the `Obj` button. The result is this instead of the tiny window shown previously: + +![SNAG-0446](https://user-images.githubusercontent.com/13696193/62797508-e7a37780-baa9-11e9-96bf-b2c066e72d78.jpg) + +## The REPL Prompt + +While not **really** a Python REPL prompt, this window's `REPL >>>` prompt is meant to act as much like one as possible. Here you can enter experessions and code too. + +The uses for this prompt are so numerous and diverse that listing them all won't be attempted. + +### Your "XRay" and "Endoscope" into Your Program + +Think of this prompt as a way to get specific diagnostics information about your ***running*** program. It cannot be stressed enough that the power and the usefullness of this tool is in its ability to diagnose a running program, after you've already started it running. + +### Execute Code + +In addition to displaying information, getting paths to packages, finding version information, you can execute code from the PySimpleGUI Debugger's `REPL >>>` prompt. You can type in any expression as well as any **executable statement**. + +For example, want to see what `PopupError` looks like while you're running your program. From the REPL prompt, type: +`sg.PopupError('This is an error popup')` + +The result is that you are shown a popup window with the text you supplied. + +### KNOW Answers to Questions About Your Program + +Using this runtime tool, you can be confident in the data you collect. Right? + +***There's no better way to find what version of a package that your program is using than to ask your program.*** This is so true. Think about it. Rather than go into PyCharm, look at your project's "Virtual Environment", follow some path to get to a window that lists packages installed for that project, get the verstion and your're done, right? Well, maybe. But are you CERTAIN your program is using THAT version of the package in question? + +SO MUCH time has been wasted in the past when people KNEW, for sure, what version they were running. Or, they had NO CLUE what version, or no clue to find out. There's nothing wrong with not knowing how to do something. We ALL start there. Geeez.. + +A real world example..... + +## How To Use the Debugger to Find The Version Number of a Package + +Let's pull together everything we've learned to now and use the debugger to solve a problem that happens often and sometimes it's not at all obvious how to find the answer. + +We're using ***Matplotlib*** and want to find the "Version". + +For this example, the little 12-line program in the section "A Sample Program For Us To Use" is being used. + +That program does not import `matplotlib`. We have a couple of choices, we can change the code, we can can import the package from the debugger. Let's use the debgger. + +Pull up the Main Debugger Window by pressing `CONTROL+BREAK` keys. Then click the "REPL * Watches" tab. At the `>>>` prompt we'll first import the package by typing: +`import matplotlib as m` + +The result returned from Python calls that don't return anything is the value None. You will see the command you entered in the output area followed by "None", indicating success. + +finally, type: +`m.__version__` + +The entire set of operations is shown in this window: + +![SNAG-0448](https://user-images.githubusercontent.com/13696193/62797392-a0b58200-baa9-11e9-97f4-9ef74cbb86f7.jpg) + +By convention you'll find many modules have a variable `__version__` that has the package's version number. PySimpleGUI has one. As you can see matplotlib has one. The `requests` module has this variable. + +For maximum compatibility, PySimpleGUI not only uses `__version__`, but also has the version contained in another variable `version` which has the version number because in some situations the `__version__` is not available but the `version` variable is avaiable. + +**It is recommended that you use the variable `version` to get the PySimpleGUI version** as it's so far been the most successful method. + +tkinter, however does NOT.... of course.... follow this convention. No, to get the tkinter version, you need to look at the variable: +`TkVersion` + +Here's the output from the REPL in the debugger showing the tkinter version: + +``` +>>> import tkinter as t +None +>>> t.TkVersion +8.6 +>>> t.__version__ +Exception module 'tkinter' has no attribute '__version__' +``` # "Demo Programs" Applications @@ -7608,9 +7941,13 @@ tkinter is the "official" GUI that Python supports. It runs on Windows, Linux, From the start of the PSG project, tkinter was not meant to be the only underlying GUI framework for PySimpleGUI. It is merely a starting point. All journeys begin with one step forward and choosing tkinter was the first of many steps for PySimpleGUI. Now there are 4 ports up and running - tkinter, WxPython, Qt and Remi (web support) -## Author +## Author & Owner -***Who*** wrote PySimpleGUI is not important. What's important is that it works well and enables anyone that wants to create a GUI to do so. +The PySimpleGUI Organization + +This documentation as well as all PySimpleGUI code is Copyright 2018, 2019 by PySimpleGUI.org + +PySimpleGUI@PySimpleGUI.org ## License @@ -7618,4 +7955,6 @@ GNU Lesser General Public License (LGPL 3) + ## Acknowledgments -#### SORRY!! Will add these back. Lost due to file length limitation \ No newline at end of file +There are a number of people that have been key contributors to this project both directly and indirectly. Paid professional help has been deployed a number of critical times in the project's history. This happens in the life of software development from time to time. + +If you've helped, I sure hope that you feel like you've been properly thanked. That you have been recognized. If not, then say something.... drop an email to comments@PySimpleGUI.org. \ No newline at end of file diff --git a/readme.md b/readme.md index c01ca22f..81d651e9 100644 --- a/readme.md +++ b/readme.md @@ -113,7 +113,27 @@ The YouTube videos - If you like instructional videos, there are over 15 videos # About The PySimpleGUI Documentation System -This User's Manual (also the project's readme) is one ***vital*** part of the PySimpleGUI programming environment. There are 5 resources that work together to provide to you the fastest path to success. These 5 resources are: +This User's Manual (also the project's readme) is one ***vital*** part of the PySimpleGUI programming environment. + +If you are a professional or skilled in how to develop software, then you understand the role of documentation in the world of technology development. You can skip this bit.... look for the bold "**GO TO HERE**" below. + +Bluntness is required here as the subtle approach has not worked in the past: + +***It WILL be required, at times, for you to read or search this document in order to be successful.*** + +Re-read that statement. This **will** be a serious problem for you if you're the type of person that finds it "quicker and easier to post on StackOverflow rather than reading documentation". + +If you have not yet matured to the point you are able to undertand this skill or choose to not follow it, then please save ***everyone*** the pain of doing **for you** what you, as a developer, software engineer, or wanna be coder, must do on your own. It's a vital skill for you to learn. + +Want to be a "real engineer"? Then follow "real engineering practices" such as "reading". You are learning a NEW GUI package. You've not seen anything like it. Don't be so arrogant as to believe you will never need to read documentation. + +UGH, why does this need to be said? + +***GO TO HERE*** if instructed above. + +I appologize to the other 95% of you that this..... pathetic.... reminder needs to be added, but sadly there's a need for it. + +There are 5 resources that work together to provide to you the fastest path to success. They are: 1. This User's Manual 2. The Cookbook @@ -121,7 +141,17 @@ This User's Manual (also the project's readme) is one ***vital*** part of the Py 4. Docstrings enable you to access help directly from Python or your IDE 5. Searching the GitHub Issues as a last resort -Pace yourself. The intial progress is exciting. GUIs take time and thought to build. Take a deep breath and use the provided materials and you'll do fine. +Pace yourself. The intial progress is exciting and FAST PACED. However, GUIs take time and thought to build. Take a deep breath and use the provided materials and you'll do fine. Don't skip the design phase of your GUI after you run some demos and get the hang of things. + +It is not by accident that this section, about documentation, is at the TOP of this document. + +This documentation is not HUGE in length. It's not written in complex english. It is understandable by complete beginners. And pressing `Control+F` is all you need to do to search this document. USUALLY you'll find less than 6 matches. + +## Documentation and Demos Get Out of Date + +Sometimes the documenation doesn't match exactly the version of the code you're running. Sometimes demo programs haven't been updated to match a change made to the SDK. Things don't happen simultaneously generally speaking. So, it may very well be that you find an error or inconsistency or something no longer works with the latest version of an external library. + +If you've found one of these problems, and you've searched to make sure it's not a simple mistake on your part, then by ALL means log an Issue on the GitHub. Don't be afraid to report problems if you've taken the simple steps of checking out the docs first. # Platforms @@ -3382,7 +3412,10 @@ Parameter Descriptions: #### GetSelectedItemsIndexes -Get the list of chosen items and return them as a list of indexes (offsets within the list) +Get the list of chosen items and return them as a list of indexes (offsets within the list). +Do NOT use them method as an alternative from reading the values returned to you in your call to +`Window.Read()`. All input elements should have their values read using the window.Read call, not methods +like this one. `GetSelectedItemsIndexes()` @@ -4679,14 +4712,19 @@ Parameter Descriptions: |visible|(bool) set visibility state of the element| ## Output Element -The Output Element is a re-direction of Stdout. **Anything "printed" will be displayed in this element.** This is the "trivial" way to show scrolling text in your window. It's as easy as dropping an Output Element into your window and then calling print as much as you want. -Note that you will NOT see what you `print` until you call either window.Read or window.Refresh. If you want to immediately see what was printed, call window.Refresh() immediately after your print statement. +The Output Element is a re-direction of Stdout. + +If you are looking for a way to quickly add the ability to show scrolling text within your window, then adding an `Output` Element is about as quick and easy as it gets. + +**Anything "printed" will be displayed in this element.** This is the "trivial" way to show scrolling text in your window. It's as easy as dropping an Output Element into your window and then calling print as much as you want. The user will see a scrolling area of text inside their window. + +***IMPORTANT*** You will NOT see what you `print` until you call either `window.Read` or `window.Refresh`. If you want to immediately see what was printed, call `window.Refresh()` immediately after your print statement. Output Element - a multi-lined text area where stdout and stderr are re-routed to. ```python -Output(size=(None, None)) +Output(size=(80,20)) ``` ![output](https://user-images.githubusercontent.com/13696193/44959863-b72f8280-aec3-11e8-8caa-7bc743149953.jpg) @@ -5680,9 +5718,98 @@ View of second tab: First we have the Tab layout definitions. They mirror what you see in the screen shots. Tab 1 has 1 Text Element in it. Tab 2 has a Text and an Input Element. +## Tab Element + Tab Element is another "Container" element that holds a layout and displays a tab with text. Used with TabGroup only Tabs are never placed directly into a layout. They are always "Contained" in a TabGroup layout +``` +Tab(title, + layout, + title_color=None, + background_color=None, + font=None, + pad=None, + disabled=False, + border_width=None, + key=None, + tooltip=None, + right_click_menu=None, + visible=True) +``` + +Parameter Descriptions: + +|Name|Meaning| +|---|---| +|title|(str) text to show on the tab| +|layout|List[List[Element]] The element layout that will be shown in the tab| +|title_color|(str) color of the tab text (note not currently working on tkinter)| +|background_color|(str) color of background of the entire layout| +|font|Union[str, Tuple[str, int]] specifies the font family, size, etc| +|pad|(int, int) or ((int, int),(int,int)) Amount of padding to put around element (left/right, top/bottom) or ((left, right), (top, bottom))| +|disabled|(bool) If True button will be created disabled| +|border_width|(int) width of border around element in pixels| +|key|(any) Value that uniquely identifies this element from all other elements. Used when Finding an element or in return values. Must be unique to the window| +|tooltip|(str) text, that will appear when mouse hovers over the element| +|right_click_menu|List[List[Union[List[str],str]]] A list of lists of Menu items to show when this element is right clicked. See user docs for exact format.| +|visible|(bool) set visibility state of the element| + +### Methods + +#### Select + +Create a tkinter event that mimics user clicking on a tab. Must have called window.Finalize / Read first! + +```python +Select() +``` + +#### SetFocus + +Sets the current focus to be on this element + +``` +SetFocus(force=False) +``` + +Parameter Descriptions: + +|Name|Meaning| +|---|---| +|force|(bool) if True will call focus_force otherwise calls focus_set| + +#### SetTooltip + +Called by application to change the tooltip text for an Element. Normally invoked using the Element Object such as: window.Element('key').SetToolTip('New tip'). + +``` +SetTooltip(tooltip_text) +``` + +Parameter Descriptions: + +|Name|Meaning| +|---|---| +|tooltip_text|(str) the text to show in tooltip.| + +#### Update + +Changes some of the settings for the Tab Element. Must call `Window.Read` or `Window.Finalize` prior + +``` +Update(disabled=None, visible=None) +``` + +Parameter Descriptions: + +|Name|Meaning| +|---|---| +|disabled|(bool) disable or enable state of the element| +|visible|(bool) control visibility of element| + +### TabGroup Element + TabGroup Element groups together your tabs into the group of tabs you see displayed in your window ```python @@ -5751,56 +5878,52 @@ Parameter Descriptions: |tooltip|(str) text, that will appear when mouse hovers over the element| |visible|(bool) set visibility state of the element| -``` -Tab(title, - layout, - title_color=None, - background_color=None, - font=None, - pad=None, - disabled=False, - border_width=None, - key=None, - tooltip=None, - right_click_menu=None, - visible=True) -``` - -Parameter Descriptions: - -|Name|Meaning| -|---|---| -|title|(str) text to show on the tab| -|layout|List[List[Element]] The element layout that will be shown in the tab| -|title_color|(str) color of the tab text (note not currently working on tkinter)| -|background_color|(str) color of background of the entire layout| -|font|Union[str, Tuple[str, int]] specifies the font family, size, etc| -|pad|(int, int) or ((int, int),(int,int)) Amount of padding to put around element (left/right, top/bottom) or ((left, right), (top, bottom))| -|disabled|(bool) If True button will be created disabled| -|border_width|(int) width of border around element in pixels| -|key|(any) Value that uniquely identifies this element from all other elements. Used when Finding an element or in return values. Must be unique to the window| -|tooltip|(str) text, that will appear when mouse hovers over the element| -|right_click_menu|List[List[Union[List[str],str]]] A list of lists of Menu items to show when this element is right clicked. See user docs for exact format.| -|visible|(bool) set visibility state of the element| - ### Reading Tab Groups Tab Groups now return a value when a Read returns. They return which tab is currently selected. There is also a `enable_events` parameter that can be set that causes a Read to return if a Tab in that group is selected / changed. The key or title belonging to the Tab that was switched to will be returned as the value -### Methods +### Method -Changes some of the settings for the Tab Element. Must call `Window.Read` or `Window.Finalize` prior +#### Get + +Returns the current value for the Tab Group, which will be the currently selected tab's KEY or the text on +the tab if no key is defined. Returns None if an error occurs. +Note that this is exactly the same data that would be returned from a call to Window.Read. Are you sure you +are using this method correctly? + +`Get()` + +|Name|Meaning| +|---|---| +| **return** | Union[Any, None] The key of the currently selected tab or the tab's text if it has no key | + +#### SetFocus + +Sets the current focus to be on this element ``` -Update(disabled=None, visible=None) +SetFocus(force=False) ``` Parameter Descriptions: |Name|Meaning| |---|---| -|disabled|(bool) disable or enable state of the element| -|visible|(bool) control visibility of element| +|force|(bool) if True will call focus_force otherwise calls focus_set| + +#### SetTooltip + +Called by application to change the tooltip text for an Element. Normally invoked using the Element Object such as: window.Element('key').SetToolTip('New tip'). + +``` +SetTooltip(tooltip_text) +``` + +Parameter Descriptions: + +|Name|Meaning| +|---|---| +|tooltip_text|(str) the text to show in tooltip.| ## Pane Element @@ -6159,7 +6282,7 @@ while True: window.Close() ``` -## Read(timeout = t, timeout_key='timeout') +## Read(timeout = t, timeout_key=TIMEOUT_KEY) Read with a timeout is a very good thing for your GUIs to use in a read non-blocking situation, if you can use them. If your device can wait for a little while, then use this kind of read. The longer you're able to add to the timeout value, the less CPU time you'll be taking. @@ -6682,37 +6805,247 @@ while True: # The PySimpleGUI Debugger -Starting on June 1, 2019, a built-in version of the debugger `imwatchingyou` has been shipping in every copy of PySimpleGUI. It's been largely downplayed to gauge whether or not the added code and the added feature and the use of a couple of keys, would mess up any users. +Listen up if you are +* advanced programmers debugging some really hairy stuff +* programmers from another era that like to debug this way +* those that want to have "x-ray vision" into their code +* asked to use debugger to gather information +* running on a platform that lacks ANY debugger +* debugging a problem that happens only outside of a debugger environment +* finding yourself saying "but it works when running PyCharm" + +Starting on June 1, 2019, a built-in version of the debugger `imwatchingyou` has been shipping in every copy of PySimpleGUI. It's been largely downplayed to gauge whether or not the added code and the added feature and the use of a couple of keys, would mess up any users. Over 30,000 users have installed PySimpleGUI since then and there's not be a single Issue filed nor comment/complaint made, so seems safe enough to normal users... so far.... So far no one has reported anything at all about the debugger. The assumption is that it is quietly lying dormant, waiting for you to press the `BREAK` or `CONTROL` + `BREAK` keys. It's odd no one has accidently done this and freaked out, logging an Issue. The plain PySimpleGUI module has a debugger builtin. For the other ports, please use the package `imwatchingyou`. +## What is it? Why use it? What the heck? I already have an IDE. + +This debugger provides you with something unique to most typical Python developers, the ability to "see" and interact with your code, **while it is running**. You can change variable values while your code continues to run. + +Print statements are cool, but perhaps you're tired of seeing this: +``` +Push Me {0: 'Input here'} +Push Me {0: 'Input here'} +Push Me {0: 'Input here'} +``` + +And would prefer to see this window updating continuously in the upper right corner of your display: + +![image](https://user-images.githubusercontent.com/13696193/62793751-54197900-baa0-11e9-9a98-f780259062b1.png) + +Notice how easy it is, using this window alone, to get the location that your PySimpleGUI package is coming from ***for sure***, no guessing. Expect this window to be in your debugging future as it'll get asked for from time to time. + ## Preparing To Run the Debugger -If your program is running with blocking `Read` calls, then you will want to add a timeout to your reads. This is because the debugger gets it's cycles by stealing a little bit of time from these async calls. +If your program is running with blocking `Read` calls, then you will want to add a timeout to your reads. This is because the debugger gets it's cycles by stealing a little bit of time from these async calls... but only when you have one of these debugger windows open so no bitching about wasted CPU time as there is none. -Your event loop will be modified from this: +Your event loop will be modified from this blocking: ```python while True: event, values = window.Read() ``` -To this: +To this non-blocking: ```python while True: - event, values = window.Read(timeout=100) + event, values = window.Read(timeout=200) if event == sg.TIMEOUT_KEY: continue ``` -This event loop will do nothing at all if a timeout occurs and will execute your normal code (that follows the if statement) when there is any event that is not a timeout. +These 3 lines will in no way change how your application looks and performs. You can do this to any PySimpleGUI app that uses a blocking read and you'll not notice a difference. The reason this is a NOP (No-operation) is that when a timeout happens, the envent will be set to `sg.TIMEOUT_KEY`. If a timeout is returned as the event, the code simply ignores it and restarts the loop by executing a `continue` statement. -This timeout value of 100 means that your debugger GUI will be updated 10 times a second. If this adds too much "drag" to your application, you can make the timeout larger. Try using 1000 instead of 100. +This timeout value of 200 means that your debugger GUI will be updated 5 times a second if nothing is happening. If this adds too much "drag" to your application, you can make the timeout larger. Try using 500 or 1000 instead of 100. + +### What happens if you don't add a timeout + +Let's say you're in a situation where a very intermettent bug has just happened and the debugger would really help you, but you don't have a timeout on your `windows.Read()` call. It's OK. Recall that the way the debugger gets its "cycles" is to borrow from your `Read` calls. What you need to do is alternate between using the debugger and then generating another pass through your event loop. + +Maybe it's an OK button that will cause your loop to execute again (without exiting). If so, you can use it to help move the debugger along. + +Yes, this is a major pain in the ass, but it's not THAT bad and compared to nothing in a time of crisis and this is potentially your "savior tool" that's going to save your ass, pressing that OK button a few times is going to look like nothing to you. You just want to dump out the value of a variable that holds an instance of your class! + +## A Sample Program For Us To Use + +Now that you understand how to add the debugger to your program, let's make a simple little program that you can use to follow these examples: + +```python +import PySimpleGUI as sg + +window = sg.Window('Testing the Debugger', [[sg.Text('Debugger Tester'), sg.In('Input here'), sg.B('Push Me')]]) + +while True: + event, values = window.Read(timeout=500) + if event == sg.TIMEOUT_KEY: + continue + if event is None: + break + print(event, values) +window.Close() +``` ## Debugger Windows -There are 2 debugger windows. One is called a "Popout". The Popout window displays all of your variables +### "Popout Debugger Window" + +There are 2 debugger windows. One is called the "Popout" debugger window. The Popout window displays as many currently in-scope local variables as possible. This window is not interactive. It is meant to be a frequently updated "dashboard" or "snapshot" of your variables. + +One "variable" shown in the popout window that is an often asked for piece of information when debugging Issues and that variable is `sg` (or whatever you named the PySimpleGUI pacakge when you did your import). The assumption is that your import is `import PySimpleGUI as sg`. If your import is different, then you'll see a different variable. The point is that it's shown here. + +Exiting this window is done via the little red X, **or using the rickt-click menu** which is also used as one way to launch the Main Debugger Window + +#### When you are asked for the "Location of your PySimpleGUI package or PySimpleGUI.py file" do this + +If you wish to use the debugger to find the location of THIS running program's PySimpleGUI package / the PySimpleGUI.py file, then all you need to do is: +* Press the `BREAK` key on your keyboard. + * This is sometimes labelled as the `Cancel` key + * May also have `Pause` printed on key + * On some US keyboards, it is located next to `Scroll Lock` and/or above `PageUp` key +* This will open a window located in the upper right corner of your screen that looks something like this: +![image](https://user-images.githubusercontent.com/13696193/62793751-54197900-baa0-11e9-9a98-f780259062b1.png) +* The information you are seeking is shown next to the `sg` in the window +You don't need to modify your program to get this info using this technique. + +If your variable's value is too long and doesn't fit, then you'lll need to collect this information using the "Main Debugger Window" + +#### What's NOT Listed In The Popout Debugger Window + +The Popup window is a "Snapshot" of your local variables at the time the window was opened. This means **any variables that did not exist at the time the Popout was created will not be shown**. This window does **NOT** expand in size by adding new variables. Maybe in the future. + +### The "Main Debugger Window" + +Now we're talking serious Python debugging! + +Ever wish you had a `repl>>>` prompt that you could run while your program is running. Well, that's pretty much what you're getting with the PySimpleGUI debugger Main Window! Cool, huh? If you're not impressed, go get a cup of coffee and walk off that distraction in your head before carring on because we're in to some seriously cool shit here.... + +You'll find that this window has 2 tabs, one is labelled `Variables` and the other is labelled `REPL & Watches` + +#### The "Variables" Tab of Main Debugger Window + +![SNAG-0440](https://user-images.githubusercontent.com/13696193/62797391-a01ceb80-baa9-11e9-845d-3cd02ca0dbcc.jpg) + +Notice the the "frame" surrounding this window is labelled "Auto Watches" in blue. Like the Popup window, this debugger window also "Watches" variables, which means continuously updates them as often as you call `Window.Read`. + +The maximum number of "watches" you can have any any one time is 9. + +##### Choosing variables to watch + +You can simply click "Show All Variable" button and the list of watched variables will be automatically populard by the first 9 variables it finds. Or you can click the "Choose Variables to Auto Watch" button where you can individually choose what variables, **and expressions** you wish to display. + +![SNAG-0442](https://user-images.githubusercontent.com/13696193/62797520-e96d3b00-baa9-11e9-8ba0-794e479b6fc5.jpg) + +In this window we're checking checkboxes to display these variables: + +`event`, `sg`, `values`, `window`, `__file__` + +![SNAG-0443](https://user-images.githubusercontent.com/13696193/62797518-e8d4a480-baa9-11e9-8575-5256dcf6b5ab.jpg) + +Additionally, you can see at the bottom of the window a "Custom Watch" has been defined. This can be any experession you want. Let's say you have a window with a LOT of values. Rather than looking through the `values` variable and finding the entry with the key you are looking for, the values variable's entry for a specific key is displayed. + +In this example the Custom Watch entered was `values[0]`. After clicking on the "OK" button, indicating the variables are chosen that we wish to watch, this is the Main window that is shown: + +![SNAG-0444](https://user-images.githubusercontent.com/13696193/62797514-e8d4a480-baa9-11e9-9a86-cfe99342dedb.jpg) + +We can see the variables we checked as well as the defined expression `values[0]`. If you leave this window open, these values with continuously be updated, on the fly, every time we call the line in our example code `window.Read(timeout=500)`. This means that the Main Debugger Window and these variables we defined will be updated every 500 milliseconds. + +#### The REPL & Watches Tab + +![SNAG-0441](https://user-images.githubusercontent.com/13696193/62797507-e7a37780-baa9-11e9-93c4-6ff0c8acb11d.jpg) + +This tab is provided to you as a way to interact with your running program on a real-time basis. + +If you want to quickly look at the values of variables, nearly ANY variables, then type the information into one of the 3 spaces provided to "Watch" either variables or experessions. In this example, the variable window was typed into the first slow. + +***Immediately*** after typing the character 'w', the information to the right was displayed. No button needs to be clicked. You merely neeed to type in a valid experession and it will be displayed to you.... and it will be displayed on an on-going, constantly-refreshing-basis. + +![SNAG-0447](https://user-images.githubusercontent.com/13696193/62797393-a0b58200-baa9-11e9-8016-1cadca4d97e7.jpg) + +If the area to the right of the input field is too small, then you can click on the "Detail" button and you will be shown a popup, scrolled window with all of the information displayed as if it were printed. + +I'm sure you've had the lovely experience of printing an object. When clicking the "Detail" button next to the `window` variable being shown, this window is shown: + +![SNAG-0449](https://user-images.githubusercontent.com/13696193/62801423-b0d25f00-bab3-11e9-829a-aebb429521cd.jpg) + +Oh, Python, -sigh-. I just want to see my `window` object printed. + +#### `Obj` Button to the Rescue! + +PySimpleGUI has a fun and very useful function that is discussed in the docs named `ObjToString` which takes an object and converts it's **contents** it into a nicely formatted string. This function is used to create the text output when you click the `Obj` button. The result is this instead of the tiny window shown previously: + +![SNAG-0446](https://user-images.githubusercontent.com/13696193/62797508-e7a37780-baa9-11e9-96bf-b2c066e72d78.jpg) + +## The REPL Prompt + +While not **really** a Python REPL prompt, this window's `REPL >>>` prompt is meant to act as much like one as possible. Here you can enter experessions and code too. + +The uses for this prompt are so numerous and diverse that listing them all won't be attempted. + +### Your "XRay" and "Endoscope" into Your Program + +Think of this prompt as a way to get specific diagnostics information about your ***running*** program. It cannot be stressed enough that the power and the usefullness of this tool is in its ability to diagnose a running program, after you've already started it running. + +### Execute Code + +In addition to displaying information, getting paths to packages, finding version information, you can execute code from the PySimpleGUI Debugger's `REPL >>>` prompt. You can type in any expression as well as any **executable statement**. + +For example, want to see what `PopupError` looks like while you're running your program. From the REPL prompt, type: +`sg.PopupError('This is an error popup')` + +The result is that you are shown a popup window with the text you supplied. + +### KNOW Answers to Questions About Your Program + +Using this runtime tool, you can be confident in the data you collect. Right? + +***There's no better way to find what version of a package that your program is using than to ask your program.*** This is so true. Think about it. Rather than go into PyCharm, look at your project's "Virtual Environment", follow some path to get to a window that lists packages installed for that project, get the verstion and your're done, right? Well, maybe. But are you CERTAIN your program is using THAT version of the package in question? + +SO MUCH time has been wasted in the past when people KNEW, for sure, what version they were running. Or, they had NO CLUE what version, or no clue to find out. There's nothing wrong with not knowing how to do something. We ALL start there. Geeez.. + +A real world example..... + +## How To Use the Debugger to Find The Version Number of a Package + +Let's pull together everything we've learned to now and use the debugger to solve a problem that happens often and sometimes it's not at all obvious how to find the answer. + +We're using ***Matplotlib*** and want to find the "Version". + +For this example, the little 12-line program in the section "A Sample Program For Us To Use" is being used. + +That program does not import `matplotlib`. We have a couple of choices, we can change the code, we can can import the package from the debugger. Let's use the debgger. + +Pull up the Main Debugger Window by pressing `CONTROL+BREAK` keys. Then click the "REPL * Watches" tab. At the `>>>` prompt we'll first import the package by typing: +`import matplotlib as m` + +The result returned from Python calls that don't return anything is the value None. You will see the command you entered in the output area followed by "None", indicating success. + +finally, type: +`m.__version__` + +The entire set of operations is shown in this window: + +![SNAG-0448](https://user-images.githubusercontent.com/13696193/62797392-a0b58200-baa9-11e9-97f4-9ef74cbb86f7.jpg) + +By convention you'll find many modules have a variable `__version__` that has the package's version number. PySimpleGUI has one. As you can see matplotlib has one. The `requests` module has this variable. + +For maximum compatibility, PySimpleGUI not only uses `__version__`, but also has the version contained in another variable `version` which has the version number because in some situations the `__version__` is not available but the `version` variable is avaiable. + +**It is recommended that you use the variable `version` to get the PySimpleGUI version** as it's so far been the most successful method. + +tkinter, however does NOT.... of course.... follow this convention. No, to get the tkinter version, you need to look at the variable: +`TkVersion` + +Here's the output from the REPL in the debugger showing the tkinter version: + +``` +>>> import tkinter as t +None +>>> t.TkVersion +8.6 +>>> t.__version__ +Exception module 'tkinter' has no attribute '__version__' +``` # "Demo Programs" Applications @@ -7608,9 +7941,13 @@ tkinter is the "official" GUI that Python supports. It runs on Windows, Linux, From the start of the PSG project, tkinter was not meant to be the only underlying GUI framework for PySimpleGUI. It is merely a starting point. All journeys begin with one step forward and choosing tkinter was the first of many steps for PySimpleGUI. Now there are 4 ports up and running - tkinter, WxPython, Qt and Remi (web support) -## Author +## Author & Owner -***Who*** wrote PySimpleGUI is not important. What's important is that it works well and enables anyone that wants to create a GUI to do so. +The PySimpleGUI Organization + +This documentation as well as all PySimpleGUI code is Copyright 2018, 2019 by PySimpleGUI.org + +PySimpleGUI@PySimpleGUI.org ## License @@ -7618,4 +7955,6 @@ GNU Lesser General Public License (LGPL 3) + ## Acknowledgments -#### SORRY!! Will add these back. Lost due to file length limitation \ No newline at end of file +There are a number of people that have been key contributors to this project both directly and indirectly. Paid professional help has been deployed a number of critical times in the project's history. This happens in the life of software development from time to time. + +If you've helped, I sure hope that you feel like you've been properly thanked. That you have been recognized. If not, then say something.... drop an email to comments@PySimpleGUI.org. \ No newline at end of file