Merge pull request #1675 from PySimpleGUI/Dev-latest

More docstrings, renamed functions
This commit is contained in:
MikeTheWatchGuy 2019-07-10 15:12:34 -04:00 committed by GitHub
commit 69342202b2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 130 additions and 165 deletions

View File

@ -35,7 +35,7 @@ OK, let's get the bullshit out of the way
This software is available for your use under a MODIFIED LGPL3+ license
This notice, these first 83 lines of code shall remain unchanged
This notice, these first 100 lines of code shall remain unchanged
# #
## ## #### ##### # ###### # ###### #####
@ -60,12 +60,13 @@ And just what the fuck is that? Well, it's LPGL3+ and these FOUR simple stipula
1. These and all comments are to remain in this document
2. You will not post this software in a repository or a location for others to download from:
A. Unless you have made 10 lines of changes
B. A notice is posted with the code that it is not the original code but instead derived from an original
3. Forking is OK and does NOT require any changes as long as it is obvious forked and stated on the page
where your software is being hosted. For example, GitHub does a fantastic job of indicating if a repository
is the result of a fork.
4. The "Official" version of PySimpleGUI and the associated documentation lives on two (and only two) places:
4. The "Official" version of PySimpleGUI and the associated documentation lives on two (and **only** two) places:
1. GitHub - (http://www.PySimpleGUI.com) currently pointing at:
# https://github.com/PySimpleGUI/PySimpleGUI
https://github.com/PySimpleGUI/PySimpleGUI
2. Read the Docs (via http://www.PySimpleGUI.org). Currently is pointed at:
https://pysimplegui.readthedocs.io/en/latest/
If you've obtained this software in any other way, then those listed here, then SUPPORT WILL NOT BE PROVIDED.
@ -73,7 +74,7 @@ And just what the fuck is that? Well, it's LPGL3+ and these FOUR simple stipula
-----------------------------------------------------------------------------------------------------------------
I absolutely hate having to include that nonsense, but every word is there for solid reasons.
I absolutely hate having to include this kind of nonsense, but every word is here for solid reasons.
How about having FUN with this package?? Terrible note to begin this journey of actually having fun making
GUI based applications so I'll try to make it up to you.
@ -96,6 +97,7 @@ The User Manual and the Cookbook are both designed to paint some nice looking GU
# do the Python 2 or 3 check so the right tkinter stuff can get pulled in
import sys
if sys.version_info[0] >= 3:
@ -119,7 +121,7 @@ import pickle
import calendar
import textwrap
import inspect
from typing import List, Any, Union, Tuple, Dict
from typing import List, Any, Union, Tuple, Dict # because this code has to run on 2.7 can't use real type hints. Must do typing only in comments
from random import randint
import warnings
@ -1713,12 +1715,12 @@ class StatusBar(Element):
key=None, tooltip=None, visible=True):
"""
:param text: Text that is to be displayed in the widget
:param size: (w,h) w=characters-wide, h=rows-high
:param auto_size_text: True if size should fit the text length
:param text: (str) Text that is to be displayed in the widget
:param size: Tuple[(int), (int)] (w,h) w=characters-wide, h=rows-high
:param auto_size_text: (bool) True if size should fit the text length
:param click_submits: (bool) DO NOT USE. Only listed for backwards compat - Use enable_events instead
:param enable_events: (bool) Turns on the element specific events. StatusBar events occur when the bar is clicked
:param relief: relief style. Values are same as progress meter relief values. Can be a constant or a string: `RELIEF_RAISED RELIEF_SUNKEN RELIEF_FLAT RELIEF_RIDGE RELIEF_GROOVE RELIEF_SOLID`
:param relief: (enum) relief style. Values are same as progress meter relief values. Can be a constant or a string: `RELIEF_RAISED RELIEF_SUNKEN RELIEF_FLAT RELIEF_RIDGE RELIEF_GROOVE RELIEF_SOLID`
:param font: Union[str, tuple] specifies the font family, size, etc
:param text_color: (str) color of the text
:param background_color: (str) color of background
@ -1748,7 +1750,6 @@ class StatusBar(Element):
def Update(self, value=None, background_color=None, text_color=None, font=None, visible=None):
"""
Changes some of the settings for the Status Bar Element. Must call `Window.Read` or `Window.Finalize` prior
:param value: (str) new text to show
:param background_color: (str) color of background
:param text_color: (str) color of the text
@ -1871,7 +1872,9 @@ class TKProgressBar():
# Scroll bar will span the length of the frame #
# ---------------------------------------------------------------------- #
class TKOutput(tk.Frame):
""" """
"""
tkinter style class. Inherits Frame class from tkinter. Adds a tk.Text and a scrollbar together
"""
def __init__(self, parent, width, height, bd, background_color=None, text_color=None, font=None, pad=None):
"""
@ -1938,25 +1941,24 @@ class TKOutput(tk.Frame):
# Routes stdout, stderr to a scrolled window #
# ---------------------------------------------------------------------- #
class Output(Element):
""" """
"""
Output Element - a multi-lined text area where stdout and stderr are re-routed to.
"""
def __init__(self, size=(None, None), background_color=None, text_color=None, pad=None, font=None, tooltip=None,
key=None, right_click_menu=None, visible=True):
"""
:param size: (w,h) w=characters-wide, h=rows-high
:param background_color: color of background
:param text_color: color of the text
:param pad: Amount of padding to put around element
:param font: specifies the font family, size, etc
:param size: Tuple[(int), (int)] (w,h) w=characters-wide, h=rows-high
:param background_color: (str) color of background
:param text_color: (str) color of the text
:param pad: (int, int) or ((int, int),(int,int)) Amount of padding to put around element (left/right, top/bottom) or ((left, right), (top, bottom))
:param font: Union[str, tuple] specifies the font family, size, etc
:param tooltip: (str) text, that will appear when mouse hovers over the element
:param key: Used with window.FindElement and with return values to uniquely identify this element to uniquely identify this element
:param right_click_menu: List[List[str]] see "Right Click Menus" for format
:param visible: set visibility state of the element (Default = True)
:param key: (Any) Used with window.FindElement and with return values to uniquely identify this element to uniquely identify this element
:param right_click_menu: List[List[str]] see "Right Click Menus"
:param visible: (bool) set visibility state of the element
"""
self._TKOut = None
self._TKOut = self.Widget = None # type: TKOutput
bg = background_color if background_color else DEFAULT_INPUT_ELEMENTS_COLOR
fg = text_color if text_color is not None else DEFAULT_INPUT_TEXT_COLOR
self.RightClickMenu = right_click_menu
@ -1976,7 +1978,7 @@ class Output(Element):
"""
Changes some of the settings for the Output Element. Must call `Window.Read` or `Window.Finalize` prior
:param value:
:param value: (str) string that will replace current contents of the output area
:param visible: (bool) control visibility of element
"""
@ -4809,19 +4811,27 @@ class Window:
@classmethod
def GetAContainerNumber(cls):
""" """
"""
Not user callable!
:return: A simple counter that makes each container element unique
"""
cls.container_element_counter += 1
return cls.container_element_counter
@classmethod
def IncrementOpenCount(self):
""" """
"""
Not user callable! Increments the number of open windows
Note - there is a bug where this count easily gets out of sync. Issue has been opened already. No ill effects
"""
self.NumOpenWindows += 1
# print('+++++ INCREMENTING Num Open Windows = {} ---'.format(Window.NumOpenWindows))
@classmethod
def DecrementOpenCount(self):
""" """
"""
Not user callable! Decrements the number of open windows
"""
self.NumOpenWindows -= 1 * (self.NumOpenWindows != 0) # decrement if not 0
# print('----- DECREMENTING Num Open Windows = {} ---'.format(Window.NumOpenWindows))
@ -4867,7 +4877,9 @@ class Window:
# ------------------------- Add Multiple Rows to Form ------------------------- #
def AddRows(self, rows):
"""
Loops through a list of lists of elements and adds each row, list, to the layout
Loops through a list of lists of elements and adds each row, list, to the layout.
This is NOT the best way to go about creating a window. Sending the entire layout at one time and passing
it as a parameter to the Window call is better.
:param rows: List[List[Elements]] A list of a list of elements
@ -4878,22 +4890,24 @@ class Window:
def Layout(self, rows):
"""
Second of two preferred ways of telling a Window what its layout is. The other way is to pass the layout as
a parameter to Window object. The parameter method is the currently preferred method. This call to Layout
has been removed from examples contained in documents and in the Demo Programs. Trying to remove this call
a parameter to Window object. The parameter method is the currently preferred method. This call to Layout
has been removed from examples contained in documents and in the Demo Programs. Trying to remove this call
from history and replace with sending as a parameter to Window.
:param rows: List[List[Elements]] Your entire layout
:return: (Window} self so that you can chain method calls
"""
self.AddRows(rows)
self.BuildKeyDict()
self._BuildKeyDict()
return self
def LayoutAndRead(self, rows, non_blocking=False):
"""
Deprecated. Now you layout your window's rows (layout) and then separately call Read.
:param rows:
:param non_blocking: (Default = False)
Deprecated!! Now your layout your window's rows (layout) and then separately call Read.
:param rows: (List[List[Element]]) The layout of the window
:param non_blocking: (bool) if True the Read call will not block
"""
raise DeprecationWarning(
'LayoutAndRead is no longer supported... change your call window.Layout(layout).Read()\nor window(title, layout).Read()')
@ -4913,9 +4927,10 @@ class Window:
def _Show(self, non_blocking=False):
"""
NOT TO BE CALLED BY USERS. INTERNAL ONLY!
It's this
It's this method that first shows the window to the user, collects results
:param non_blocking: (bool) if True, this is a non-blocking call
:return: Tuple[Any, Dict] The event, values turple that is returned from Read calls
"""
self.Shown = True
# Compute num rows & num cols (it'll come in handy debugging)
@ -4947,7 +4962,7 @@ class Window:
StartupTK(self)
# If a button or keyboard event happened but no results have been built, build the results
if self.LastKeyboardEvent is not None or self.LastButtonClicked is not None:
return BuildResults(self, False, self)
return _BuildResults(self, False, self)
return self.ReturnValues
# ------------------------- SetIcon - set the window's fav icon ------------------------- #
@ -4960,7 +4975,6 @@ class Window:
:param icon: (str) Filename or bytes object
:param pngbase64: (str) Base64 encoded GIF or PNG file
"""
if type(icon) is bytes:
wicon = tkinter.PhotoImage(data=icon)
@ -4984,6 +4998,7 @@ class Window:
except:
pass
def _GetElementAtLocation(self, location):
"""
Given a (row, col) location in a layout, return the element located at that position
@ -5010,7 +5025,6 @@ class Window:
"""
Function that's called by tkinter when autoclode timer expires. Closes the window
:return: None
"""
try:
window = self
@ -5027,8 +5041,6 @@ class Window:
def _TimeoutAlarmCallback(self):
"""
Read Timeout Alarm callback. Will kick a mainloop call out of the tkinter event loop and cause it to return
:return: None
"""
# first, get the results table built
# modify the Results table in the parent FlexForm object
@ -5040,7 +5052,9 @@ class Window:
self.FormRemainedOpen = True
self.TKroot.quit() # kick the users out of the mainloop
def Read(self, timeout=None, timeout_key=TIMEOUT_KEY):
# type: (int, Any) -> Tuple[Any, Union[Dict, List]]
"""
THE biggest deal method in the Window class! This is how you get all of your data from your Window.
Pass in a timeout (in milliseconds) to wait for a maximum of timeout milliseconds. Will return timeout_key
@ -5074,7 +5088,7 @@ class Window:
# if already have a button waiting, the return previously built results
if self.LastButtonClicked is not None and not self.LastButtonClickedWasRealtime:
# print(f'*** Found previous clicked saved {self.LastButtonClicked}')
results = BuildResults(self, False, self)
results = _BuildResults(self, False, self)
self.LastButtonClicked = None
return results
InitializeResults(self)
@ -5091,7 +5105,7 @@ class Window:
Window.DecrementOpenCount()
# _my_windows.Decrement()
# print('ROOT Destroyed')
results = BuildResults(self, False, self)
results = _BuildResults(self, False, self)
if results[0] != None and results[0] != timeout_key:
return results
else:
@ -5145,7 +5159,7 @@ class Window:
# _my_windows.Decrement()
# Determine return values
if self.LastKeyboardEvent is not None or self.LastButtonClicked is not None:
results = BuildResults(self, False, self)
results = _BuildResults(self, False, self)
if not self.LastButtonClickedWasRealtime:
self.LastButtonClicked = None
return results
@ -5159,9 +5173,10 @@ class Window:
self.ReturnValues = self.TimeoutKey, self.ReturnValues[1] # fake a timeout
return self.ReturnValues
def _ReadNonBlocking(self):
"""
Should be never called directly by the user. The user can call Window.Read(timeout=0) to get same effect
Should be NEVER called directly by the user. The user can call Window.Read(timeout=0) to get same effect
:return: Tuple[(Any), Union[Dict[Any:Any], List[Any], None] (event, values)
(event or timeout_key or None, Dictionary of values or List of values from all elements in the Window
@ -5192,7 +5207,8 @@ class Window:
self.Values = None
self.LastButtonClicked = None
return None, None
return BuildResults(self, False, self)
return _BuildResults(self, False, self)
def Finalize(self):
"""
@ -5223,8 +5239,7 @@ class Window:
Use this call when you want something to appear in your Window immediately (as soon as this function is called).
Without this call your changes to a Window will not be visible to the user until the next Read call
:return: Tuple[(Any), Union[Dict[Any:Any], List[Any], None] (event, values)
(event or timeout_key or None, Dictionary of values or List of values from all elements in the Window
:return: (Window) `self` so that method calls can be easily "chained"
"""
if self.TKrootDestroyed:
@ -5235,23 +5250,34 @@ class Window:
pass
return self
def Fill(self, values_dict):
"""
Fill in elements that are input fields with data based on a 'values dictionary'
:param values_dict: ?????????????????
:param values_dict: (Dict[Any:Any]) {Element key : value} pairs
:return: (Window) returns self so can be chained with other methods
"""
FillFormWithValues(self, values_dict)
return self
def FindElement(self, key, silent_on_error=False):
"""
Find element object associated with the provided key
:returns Found element object, an Error Element, or None
Find element object associated with the provided key. This call can be abbreviated to any of these:
FindElement == Element == Find
So take your pick as to how much typing you want to do.
Rememeber that this call will return None if no match is found which may cause your code to crash if not
checked for.
:param key: Used with window.FindElement and with return values to uniquely identify this element
:param silent_on_error: (Default = False)
:param key: (Any) Used with window.FindElement and with return values to uniquely identify this element
:param silent_on_error: (bool) If True do not display popup nor print warning of key errors
:return: Union[Element, Error Element, None] Return value can be:
* the Element that matches the supplied key if found
* an Error Element if silent_on_error is False
* None if silent_on_error True
"""
try:
element = self.AllKeysDict[key]
@ -5270,24 +5296,33 @@ class Window:
Element = FindElement # Shortcut function
Find = FindElement
def FindElementWithFocus(self):
""" """
"""
Returns the Element that currently has focus as reported by tkinter. If no element is found None is returned!
:return: Union[Element, None] An Element if one has been found with focus or None if no element found
"""
element = _FindElementWithFocusInSubForm(self)
return element
def BuildKeyDict(self):
""" """
def _BuildKeyDict(self):
"""
Used internally only! Not user callable
Builds a dictionary containing all elements with keys for this window.
"""
dict = {}
self.AllKeysDict = self._BuildKeyDictForWindow(self, self, dict)
# print(f'keys built = {self.AllKeysDict}')
def _BuildKeyDictForWindow(self, top_window, window, key_dict):
"""
Loop through all Rows and all Container Elements for this window and create the keys for all of them.
Note that the calls are recursive as all pathes must be walked
:param top_window:
:param window:
:param key_dict:
:param top_window: (Window) The highest level of the window
:param window: Union[Column, Frame, TabGroup, Pane, Tab] The "sub-window" (container element) to be searched
:param key_dict: The dictionary as it currently stands.... used as part of recursive call
:return: (dict) Dictionary filled with all keys in the window
"""
for row_num, row in enumerate(window.Rows):
for col_num, element in enumerate(row):
@ -5324,12 +5359,13 @@ class Window:
def SaveToDisk(self, filename):
"""
Saves the values contained in each of the input areas of the form. Basically saves what would be returned from
a call to Read
:param filename: ?????????????????
"""
try:
results = BuildResults(self, False, self)
results = _BuildResults(self, False, self)
with open(filename, 'wb') as sf:
pickle.dump(results[1], sf)
except:
@ -5442,7 +5478,7 @@ class Window:
else:
self.LastKeyboardEvent = str(event.keysym) + ':' + str(event.keycode)
if not self.NonBlocking:
BuildResults(self, False, self)
_BuildResults(self, False, self)
if self.CurrentlyRunningMainloop: # quit if this is the current mainloop, otherwise don't quit!
self.TKroot.quit()
@ -5456,7 +5492,7 @@ class Window:
self.FormRemainedOpen = True
self.LastKeyboardEvent = 'MouseWheel:Down' if event.delta < 0 else 'MouseWheel:Up'
if not self.NonBlocking:
BuildResults(self, False, self)
_BuildResults(self, False, self)
if self.CurrentlyRunningMainloop: # quit if this is the current mainloop, otherwise don't quit!
self.TKroot.quit()
@ -5467,7 +5503,7 @@ class Window:
except:
pass
if not self.NonBlocking:
BuildResults(self, False, self)
_BuildResults(self, False, self)
if self.TKrootDestroyed:
return None
self.TKrootDestroyed = True
@ -6395,7 +6431,7 @@ def InitializeResults(form):
:param form:
"""
BuildResults(form, True, form)
_BuildResults(form, True, form)
return
@ -6428,7 +6464,7 @@ def EncodeRadioRowCol(container, row, col):
# ------- FUNCTION BuildResults. Form exiting so build the results to pass back ------- #
# format of return values is
# (Button Pressed, input_values)
def BuildResults(form, initialize_only, top_level_form):
def _BuildResults(form, initialize_only, top_level_form):
"""
:param form:
@ -6445,13 +6481,13 @@ def BuildResults(form, initialize_only, top_level_form):
form.DictionaryKeyCounter = 0
form.ReturnValuesDictionary = {}
form.ReturnValuesList = []
BuildResultsForSubform(form, initialize_only, top_level_form)
_BuildResultsForSubform(form, initialize_only, top_level_form)
if not top_level_form.LastButtonClickedWasRealtime:
top_level_form.LastButtonClicked = None
return form.ReturnValues
def BuildResultsForSubform(form, initialize_only, top_level_form):
def _BuildResultsForSubform(form, initialize_only, top_level_form):
"""
:param form:
@ -6469,7 +6505,7 @@ def BuildResultsForSubform(form, initialize_only, top_level_form):
element.DictionaryKeyCounter = top_level_form.DictionaryKeyCounter
element.ReturnValuesList = []
element.ReturnValuesDictionary = {}
BuildResultsForSubform(element, initialize_only, top_level_form)
_BuildResultsForSubform(element, initialize_only, top_level_form)
for item in element.ReturnValuesList:
AddToReturnList(top_level_form, item)
if element.UseDictionary:
@ -6481,7 +6517,7 @@ def BuildResultsForSubform(form, initialize_only, top_level_form):
element.DictionaryKeyCounter = top_level_form.DictionaryKeyCounter
element.ReturnValuesList = []
element.ReturnValuesDictionary = {}
BuildResultsForSubform(element, initialize_only, top_level_form)
_BuildResultsForSubform(element, initialize_only, top_level_form)
for item in element.ReturnValuesList:
AddToReturnList(top_level_form, item)
if element.UseDictionary:
@ -6493,7 +6529,7 @@ def BuildResultsForSubform(form, initialize_only, top_level_form):
element.DictionaryKeyCounter = top_level_form.DictionaryKeyCounter
element.ReturnValuesList = []
element.ReturnValuesDictionary = {}
BuildResultsForSubform(element, initialize_only, top_level_form)
_BuildResultsForSubform(element, initialize_only, top_level_form)
for item in element.ReturnValuesList:
AddToReturnList(top_level_form, item)
if element.UseDictionary:
@ -6505,7 +6541,7 @@ def BuildResultsForSubform(form, initialize_only, top_level_form):
element.DictionaryKeyCounter = top_level_form.DictionaryKeyCounter
element.ReturnValuesList = []
element.ReturnValuesDictionary = {}
BuildResultsForSubform(element, initialize_only, top_level_form)
_BuildResultsForSubform(element, initialize_only, top_level_form)
for item in element.ReturnValuesList:
AddToReturnList(top_level_form, item)
if element.UseDictionary:
@ -6517,7 +6553,7 @@ def BuildResultsForSubform(form, initialize_only, top_level_form):
element.DictionaryKeyCounter = top_level_form.DictionaryKeyCounter
element.ReturnValuesList = []
element.ReturnValuesDictionary = {}
BuildResultsForSubform(element, initialize_only, top_level_form)
_BuildResultsForSubform(element, initialize_only, top_level_form)
for item in element.ReturnValuesList:
AddToReturnList(top_level_form, item)
if element.UseDictionary:
@ -6670,99 +6706,27 @@ def BuildResultsForSubform(form, initialize_only, top_level_form):
return form.ReturnValues
def FillFormWithValues(form, values_dict):
def FillFormWithValues(window, values_dict):
"""
Fills a window with values provided in a values dictionary { element_key : new_value }
:param window: (Window) The window object to fill
:param values_dict: (Dict[Any:Any]) A dictionary with element keys as key and value is values parm for Update call
"""
:param form:
:param values_dict:
"""
FillSubformWithValues(form, values_dict)
def FillSubformWithValues(form, values_dict):
"""
:param form:
:param values_dict:
"""
for row_num, row in enumerate(form.Rows):
for col_num, element in enumerate(row):
value = None
if element.Type == ELEM_TYPE_COLUMN:
FillSubformWithValues(element, values_dict)
if element.Type == ELEM_TYPE_FRAME:
FillSubformWithValues(element, values_dict)
if element.Type == ELEM_TYPE_TAB_GROUP:
FillSubformWithValues(element, values_dict)
if element.Type == ELEM_TYPE_TAB:
FillSubformWithValues(element, values_dict)
try:
value = values_dict[element.Key]
except:
continue
if element.Type == ELEM_TYPE_INPUT_TEXT:
element.Update(value)
elif element.Type == ELEM_TYPE_INPUT_CHECKBOX:
element.Update(value)
elif element.Type == ELEM_TYPE_INPUT_RADIO:
element.Update(value)
elif element.Type == ELEM_TYPE_INPUT_COMBO:
element.Update(value)
elif element.Type == ELEM_TYPE_INPUT_OPTION_MENU:
element.Update(value)
elif element.Type == ELEM_TYPE_INPUT_LISTBOX:
element.SetValue(value)
elif element.Type == ELEM_TYPE_INPUT_SLIDER:
element.Update(value)
elif element.Type == ELEM_TYPE_INPUT_MULTILINE:
element.Update(value)
elif element.Type == ELEM_TYPE_INPUT_SPIN:
element.Update(value)
elif element.Type == ELEM_TYPE_BUTTON:
element.Update(value)
def _FindElementFromKeyInSubForm(form, key):
"""
:param form:
:param key: Used with window.FindElement and with return values to uniquely identify this element
"""
for row_num, row in enumerate(form.Rows):
for col_num, element in enumerate(row):
if element.Type == ELEM_TYPE_COLUMN:
matching_elem = _FindElementFromKeyInSubForm(element, key)
if matching_elem is not None:
return matching_elem
if element.Type == ELEM_TYPE_FRAME:
matching_elem = _FindElementFromKeyInSubForm(element, key)
if matching_elem is not None:
return matching_elem
if element.Type == ELEM_TYPE_TAB_GROUP:
matching_elem = _FindElementFromKeyInSubForm(element, key)
if matching_elem is not None:
return matching_elem
if element.Type == ELEM_TYPE_PANE:
matching_elem = _FindElementFromKeyInSubForm(element, key)
if matching_elem is not None:
return matching_elem
if element.Type == ELEM_TYPE_TAB:
matching_elem = _FindElementFromKeyInSubForm(element, key)
if matching_elem is not None:
return matching_elem
if element.Key == key:
return element
for element_key in values_dict:
try:
window.AllKeysDict[element_key].Update(values_dict[element_key])
except Exception as e:
print('Problem filling form. Perhaps bad key? This is a suspected bad key: {}'.format(element_key))
def _FindElementWithFocusInSubForm(form):
# type: (...) -> Element or None
"""
Searches through a "sub-form" (can be a window or container) for the current element with focus
:param form: a Window, Column, Frame, or TabGroup (container elements)
:param form: a Window, Column, Frame, or TabGroup (container elements)
:return: Union[Element, None]
"""
for row_num, row in enumerate(form.Rows):
for col_num, element in enumerate(row):
@ -6799,7 +6763,7 @@ def _FindElementWithFocusInSubForm(form):
if sys.version_info[0] >= 3:
def AddMenuItem(top_menu, sub_menu_info, element, is_sub_menu=False, skip=False):
"""
Only to be used internally. Not user callable
:param top_menu:
:param sub_menu_info:
:param element:
@ -10736,7 +10700,7 @@ def main():
frame2 = [
[Listbox(['Listbox 1', 'Listbox 2', 'Listbox 3'], select_mode=SELECT_MODE_EXTENDED, size=(20, 5))],
[Combo(['Combo item 1',2,3,4 ], size=(20, 3),readonly=True, text_color='red', background_color='red', key='_COMBO1_')],
[Combo(['Combo item 1', 2,3,4], size=(20, 3), readonly=False, text_color='red', background_color='red', key='_COMBO2_')],
# [Combo(['Combo item 1', 2,3,4], size=(20, 3), readonly=False, text_color='red', background_color='red', key='_COMBO2_')],
[Spin([1, 2, 3, 'a','b','c'], size=(4, 3))],
]
@ -10767,8 +10731,8 @@ def main():
[graph_elem],
]
tab1 = Tab('Graph Number 1', frame6, tooltip='tab 1')
tab2 = Tab('Graph Number 2', [[]])
tab1 = Tab('Graph Number 1', frame6, tooltip='tab 1', )
tab2 = Tab('Graph Number 2', [[]],)
layout1 = [
[Image(data=DEFAULT_BASE64_ICON)],
@ -10783,7 +10747,7 @@ def main():
Frame('Variable Choice Group', frame4, title_color='blue')],
[Frame('Structured Data Group', frame5, title_color='red'), ],
# [Frame('Graphing Group', frame6)],
[TabGroup([[tab1, tab2]])],
[TabGroup([[tab1, tab2]], )],
[ProgressBar(max_value=800, size=(60, 25), key='+PROGRESS+'), Button('Button'), B('Normal'),
Button('Exit', tooltip='Exit button')],
]
@ -10796,6 +10760,7 @@ def main():
right_click_menu=['&Right', ['Right', '!&Click', '&Menu', 'E&xit', 'Properties']],
# transparent_color= '#9FB8AD',
resizable=True,
debugger_enabled=False,
# icon=r'X:\VMWare Virtual Machines\SHARED FOLDER\kingb.ico'
).Finalize()
graph_elem.DrawCircle((200, 200), 50, 'blue')