#!/usr/bin/python3 #!/usr/bin/python3 #!/usr/bin/python3 import sys import wx import wx.adv import wx.lib.inspection from wx.lib.embeddedimage import PyEmbeddedImage import wx.lib.scrolledpanel import types import datetime import textwrap import pickle import os import time """ 21-Dec-2018 Welcome to the "core" PySimpleGUIWx port! This marks the 3rd port of the PySimpleGUI GUI SDK. Each port gets a little better than the previous. It will take a while for this Wx port to be completed, but should be running with a fully selection of widgets fairly quickly. The Qt port required 1 week to get to "Alpha" condition Enjoy! """ g_time_start = 0 g_time_end = 0 g_time_delta = 0 RUN_INSPECTION_TOOL = False # Because looks matter... DEFAULT_BASE64_ICON = b'iVBORw0KGgoAAAANSUhEUgAAACEAAAAgCAMAAACrZuH4AAAABGdBTUEAALGPC/xhBQAAAwBQTFRFAAAAMGmYMGqZMWqaMmubMmycM22dNGuZNm2bNm6bNG2dN26cNG6dNG6eNW+fN3CfOHCeOXGfNXCgNnGhN3KiOHOjOXSjOHSkOnWmOnamOnanPHSiPXakPnalO3eoPnimO3ioPHioPHmpPHmqPXqqPnurPnusPnytP3yuQHimQnurQn2sQH2uQX6uQH6vR32qRn+sSXujSHynTH2mTn+nSX6pQH6wTIGsTYKuTYSvQoCxQoCyRIK0R4S1RYS2Roa4SIe4SIe6SIi7Soq7SYm8SYq8Sou+TY2/UYStUYWvVIWtUYeyVoewUIi0VIizUI6+Vo+8WImxXJG5YI2xZI+xZ5CzZJC0ZpG1b5a3apW4aZm/cZi4dJ2/eJ69fJ+9XZfEZZnCZJzHaZ/Jdp/AeKTI/tM8/9Q7/9Q8/9Q9/9Q+/tQ//9VA/9ZA/9ZB/9ZC/9dD/9ZE/tdJ/9dK/9hF/9hG/9hH/9hI/9hJ/9hK/9lL/9pK/9pL/thO/9pM/9pN/9tO/9tP/9xP/tpR/9xQ/9xR/9xS/9xT/91U/91V/t1W/95W/95X/95Y/95Z/99a/99b/txf/txh/txk/t5l/t1q/t5v/+Bb/+Bc/+Bd/+Be/+Bf/+Bg/+Fh/+Fi/+Jh/+Ji/uJk/uJl/+Jm/+Rm/uJo/+Ro/+Rr/+Zr/+Vs/+Vu/+Zs/+Zu/uF0/uVw/+dw/+dz/+d2/uB5/uB6/uJ9/uR7/uR+/uV//+hx/+hy/+h0/+h2/+l4/+l7/+h8gKXDg6vLgazOhKzMiqrEj6/KhK/Qka/Hk7HJlLHJlLPMmLTLmbbOkLXSmLvXn77XoLrPpr/Tn8DaocLdpcHYrcjdssfZus/g/uOC/uOH/uaB/uWE/uaF/uWK/+qA/uqH/uqI/uuN/uyM/ueS/ueW/ueY/umQ/uqQ/uuS/uuW/uyU/uyX/uqa/uue/uye/uyf/u6f/uyq/u+r/u+t/vCm/vCp/vCu/vCy/vC2/vK2/vO8/vO/wtTjwtXlzdrl/vTA/vPQAAAAiNpY5gAAAQB0Uk5T////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////AFP3ByUAAAAJcEhZcwAAFw8AABcPASe7rwsAAAAYdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjEuMWMqnEsAAAKUSURBVDhPhdB3WE1xHMdxt5JV0dANoUiyd8kqkey996xclUuTlEKidO3qVnTbhIyMW/bee5NskjJLmR/f3++cK/94vP76Ps/n/Zx7z6mE/6koJowcK154vvHOL/GsKCZXkUgkWlf4vWGWq5tsDz+JWIzSokAiqXGe7nWu3HxhEYof7fhOqp1GtptQuMruVhQdxZ05U5G47tYUHbQ4oah6Fg9Z4ubm7i57JhQjdHS0RSzUPoG17u6zZTKZh8c8XlytqW9YWUOH1LqFOZ6enl5ec+XybFb0rweM1tPTM6yuq6vLs0lYJJfLvb19fHwDWGF0jh5lYNAe4/QFemOwxtfXz8/fPyBgwVMqzAcCF4ybAZ2MRCexJGBhYGBQUHDw4u1UHDG1G2ZqB/Q1MTHmzAE+kpCwL1RghlTaBt/6SaXS2kx9YH1IaOjSZST8vfA9JtoDnSngGgL7wkg4WVkofA9mcF1Sx8zMzBK4v3wFiYiMVLxlEy9u21syFhYNmgN7IyJXEYViNZvEYoCVVWOmUVvgQVSUQqGIjolRFvOAFd8HWVs34VoA+6OjY2JjY5Vxm4BC1UuhGG5jY9OUaQXci1MqlfHx8YmqjyhOViW9ZsUN29akJRmPFwkJCZsTSXIpilJffXiTzorLXYgtcxRJKpUqKTklJQ0oSt9FP/EonxVdNY4jla1kK4q2ZB6mIr+AipvduzFUzMSOtLT09IyMzMxtJKug/F0u/6dTexAWDcXXLGEjapKjfsILOLKEuYiSnTQeYCt3UHhbwEHjGMrETfBJU5zq5dSTcXC8hLJccSWP2cgLXHPu7cQNAcpyxF1dyjehAKb0cSYUAOXCUw6V8OFPgevTXFymC+fPPLU677Nw/1X8A/AbfAKGulaqFlIAAAAASUVORK5CYII=' def TimerStart(): global g_time_start g_time_start = time.time() def TimerStop(): global g_time_delta, g_time_end g_time_end = time.time() g_time_delta = g_time_end - g_time_start print(g_time_delta) # ----====----====----==== Constants the user CAN safely change ====----====----====----# DEFAULT_WINDOW_ICON = 'default_icon.ico' DEFAULT_ELEMENT_SIZE = (250, 26) # In pixels DEFAULT_BUTTON_ELEMENT_SIZE = (10, 1) # In CHARACTERS DEFAULT_MARGINS = (10, 5) # Margins for each LEFT/RIGHT margin is first term DEFAULT_ELEMENT_PADDING = (3, 2) # Padding between elements (row, col) in pixels DEFAULT_AUTOSIZE_TEXT = True DEFAULT_AUTOSIZE_BUTTONS = True DEFAULT_FONT = ("Helvetica", 10) DEFAULT_TEXT_JUSTIFICATION = 'left' DEFAULT_BORDER_WIDTH = 1 DEFAULT_AUTOCLOSE_TIME = 3 # time in seconds to show an autoclose form DEFAULT_DEBUG_WINDOW_SIZE = (80, 20) DEFAULT_WINDOW_LOCATION = (None, None) MAX_SCROLLED_TEXT_BOX_HEIGHT = 50 DEFAULT_TOOLTIP_TIME = 400 DEFAULT_PIXELS_TO_CHARS_SCALING = (10,26) # 1 character represents x by y pixels DEFAULT_PIXEL_TO_CHARS_CUTOFF = 20 # number of chars that triggers using pixels instead of chars MENU_DISABLED_CHARACTER = '!' MENU_KEY_SEPARATOR = '::' #################### COLOR STUFF #################### BLUES = ("#082567", "#0A37A3", "#00345B") PURPLES = ("#480656", "#4F2398", "#380474") GREENS = ("#01826B", "#40A860", "#96D2AB", "#00A949", "#003532") YELLOWS = ("#F3FB62", "#F0F595") TANS = ("#FFF9D5", "#F4EFCF", "#DDD8BA") NICE_BUTTON_COLORS = ((GREENS[3], TANS[0]), ('#000000', '#FFFFFF'), ('#FFFFFF', '#000000'), (YELLOWS[0], PURPLES[1]), (YELLOWS[0], GREENS[3]), (YELLOWS[0], BLUES[2])) COLOR_SYSTEM_DEFAULT = '1234567890' # Colors should never be this long if sys.platform == 'darwin': DEFAULT_BUTTON_COLOR = COLOR_SYSTEM_DEFAULT # Foreground, Background (None, None) == System Default OFFICIAL_PYSIMPLEGUI_BUTTON_COLOR = COLOR_SYSTEM_DEFAULT # Colors should never be this long else: DEFAULT_BUTTON_COLOR = ('white', BLUES[0]) # Foreground, Background (None, None) == System Default OFFICIAL_PYSIMPLEGUI_BUTTON_COLOR = ('white', BLUES[0]) # Colors should never be this long DEFAULT_ERROR_BUTTON_COLOR = ("#FFFFFF", "#FF0000") DEFAULT_BACKGROUND_COLOR = None DEFAULT_ELEMENT_BACKGROUND_COLOR = None DEFAULT_ELEMENT_TEXT_COLOR = COLOR_SYSTEM_DEFAULT DEFAULT_TEXT_ELEMENT_BACKGROUND_COLOR = None DEFAULT_TEXT_COLOR = COLOR_SYSTEM_DEFAULT DEFAULT_INPUT_ELEMENTS_COLOR = COLOR_SYSTEM_DEFAULT DEFAULT_INPUT_TEXT_COLOR = COLOR_SYSTEM_DEFAULT DEFAULT_SCROLLBAR_COLOR = None # DEFAULT_BUTTON_COLOR = (YELLOWS[0], PURPLES[0]) # (Text, Background) or (Color "on", Color) as a way to remember # DEFAULT_BUTTON_COLOR = (GREENS[3], TANS[0]) # Foreground, Background (None, None) == System Default # DEFAULT_BUTTON_COLOR = (YELLOWS[0], GREENS[4]) # Foreground, Background (None, None) == System Default # DEFAULT_BUTTON_COLOR = ('white', 'black') # Foreground, Background (None, None) == System Default # DEFAULT_BUTTON_COLOR = (YELLOWS[0], PURPLES[2]) # Foreground, Background (None, None) == System Default # DEFAULT_PROGRESS_BAR_COLOR = (GREENS[2], GREENS[0]) # a nice green progress bar # DEFAULT_PROGRESS_BAR_COLOR = (BLUES[1], BLUES[1]) # a nice green progress bar # DEFAULT_PROGRESS_BAR_COLOR = (BLUES[0], BLUES[0]) # a nice green progress bar # DEFAULT_PROGRESS_BAR_COLOR = (PURPLES[1],PURPLES[0]) # a nice purple progress bar # A transparent button is simply one that matches the background TRANSPARENT_BUTTON = ('#F0F0F0', '#F0F0F0') # -------------------------------------------------------------------------------- # Progress Bar Relief Choices RELIEF_RAISED = 'raised' RELIEF_SUNKEN = 'sunken' RELIEF_FLAT = 'flat' RELIEF_RIDGE = 'ridge' RELIEF_GROOVE = 'groove' RELIEF_SOLID = 'solid' DEFAULT_PROGRESS_BAR_COLOR = (GREENS[0], '#D0D0D0') # a nice green progress bar DEFAULT_PROGRESS_BAR_SIZE = (20, 20) # Size of Progress Bar (characters for length, pixels for width) DEFAULT_PROGRESS_BAR_BORDER_WIDTH = 1 DEFAULT_PROGRESS_BAR_RELIEF = RELIEF_GROOVE PROGRESS_BAR_STYLES = ('default', 'winnative', 'clam', 'alt', 'classic', 'vista', 'xpnative') DEFAULT_PROGRESS_BAR_STYLE = 'default' DEFAULT_METER_ORIENTATION = 'Horizontal' DEFAULT_SLIDER_ORIENTATION = 'vertical' DEFAULT_SLIDER_BORDER_WIDTH = 1 DEFAULT_SLIDER_RELIEF = 00000 DEFAULT_FRAME_RELIEF = 00000 DEFAULT_LISTBOX_SELECT_MODE = 00000 SELECT_MODE_MULTIPLE = 00000 LISTBOX_SELECT_MODE_MULTIPLE = 'multiple' SELECT_MODE_BROWSE = 00000 LISTBOX_SELECT_MODE_BROWSE = 'browse' SELECT_MODE_EXTENDED =00000 LISTBOX_SELECT_MODE_EXTENDED = 'extended' SELECT_MODE_SINGLE = 00000 LISTBOX_SELECT_MODE_SINGLE = 'single' TABLE_SELECT_MODE_NONE = 00000 TABLE_SELECT_MODE_BROWSE = 00000 TABLE_SELECT_MODE_EXTENDED = 00000 DEFAULT_TABLE_SECECT_MODE = TABLE_SELECT_MODE_EXTENDED TITLE_LOCATION_TOP = 00000 TITLE_LOCATION_BOTTOM = 00000 TITLE_LOCATION_LEFT = 00000 TITLE_LOCATION_RIGHT = 00000 TITLE_LOCATION_TOP_LEFT = 00000 TITLE_LOCATION_TOP_RIGHT = 00000 TITLE_LOCATION_BOTTOM_LEFT = 00000 TITLE_LOCATION_BOTTOM_RIGHT = 00000 THEME_DEFAULT = 'default' THEME_WINNATIVE = 'winnative' THEME_CLAM = 'clam' THEME_ALT = 'alt' THEME_CLASSIC = 'classic' THEME_VISTA = 'vista' THEME_XPNATIVE = 'xpnative' # DEFAULT_METER_ORIENTATION = 'Vertical' # ----====----====----==== Constants the user should NOT f-with ====----====----====----# ThisRow = 555666777 # magic number # DEFAULT_WINDOW_ICON = '' MESSAGE_BOX_LINE_WIDTH = 60 # "Special" Key Values.. reserved # Key representing a Read timeout TIMEOUT_KEY = '__TIMEOUT__' # Key indicating should not create any return values for element WRITE_ONLY_KEY = '__WRITE ONLY__' EVENT_SYSTEM_TRAY_ICON_DOUBLE_CLICKED = '__DOUBLE_CLICKED__' EVENT_SYSTEM_TRAY_ICON_ACTIVATED = '__ACTIVATED__' EVENT_SYSTEM_TRAY_ICON_RIGHT_CLICK = '__RIGHT_CLICK__' EVENT_SYSTEM_TRAY_MESSAGE_CLICKED = '__MESSAGE_CLICKED__' # Icons for displaying system tray messages SYSTEM_TRAY_MESSAGE_ICON_INFORMATION = wx.ICON_INFORMATION SYSTEM_TRAY_MESSAGE_ICON_WARNING = wx.ICON_WARNING SYSTEM_TRAY_MESSAGE_ICON_CRITICAL = wx.ICON_ERROR SYSTEM_TRAY_MESSAGE_ICON_NOICON = None ICON_SCREEN_DEPTH = -1 ICON_STOP = 512 # a shameful global variable. This represents the top-level window information. Needed because opening a second window is different than opening the first. class MyWindows(): def __init__(self): self.NumOpenWindows = 0 self.user_defined_icon = None self.hidden_master_root = None def Decrement(self): self.NumOpenWindows -= 1 * (self.NumOpenWindows != 0) # decrement if not 0 # print('---- DECREMENTING Num Open Windows = {} ---'.format(self.NumOpenWindows)) def Increment(self): self.NumOpenWindows += 1 # print('++++ INCREMENTING Num Open Windows = {} ++++'.format(self.NumOpenWindows)) _my_windows = MyWindows() # terrible hack using globals... means need a class for collecing windows # ====================================================================== # # One-liner functions that are handy as f_ck # # ====================================================================== # def RGB(red, green, blue): return '#%02x%02x%02x' % (red, green, blue) # ====================================================================== # # Enums for types # # ====================================================================== # # ------------------------- Button types ------------------------- # # todo Consider removing the Submit, Cancel types... they are just 'RETURN' type in reality # uncomment this line and indent to go back to using Enums # class ButtonType(Enum): BUTTON_TYPE_BROWSE_FOLDER = 1 BUTTON_TYPE_BROWSE_FILE = 2 BUTTON_TYPE_BROWSE_FILES = 21 BUTTON_TYPE_SAVEAS_FILE = 3 BUTTON_TYPE_CLOSES_WIN = 5 BUTTON_TYPE_CLOSES_WIN_ONLY = 6 BUTTON_TYPE_READ_FORM = 7 BUTTON_TYPE_REALTIME = 9 BUTTON_TYPE_CALENDAR_CHOOSER = 30 BUTTON_TYPE_COLOR_CHOOSER = 40 # ------------------------- Element types ------------------------- # # class ElementType(Enum): ELEM_TYPE_TEXT = 'text' ELEM_TYPE_INPUT_TEXT = 'input' ELEM_TYPE_INPUT_COMBO = 'combo' ELEM_TYPE_INPUT_OPTION_MENU = 'option menu' ELEM_TYPE_INPUT_RADIO = 'radio' ELEM_TYPE_INPUT_MULTILINE = 'multiline' ELEM_TYPE_MULTILINE_OUTPUT = 'multioutput' ELEM_TYPE_INPUT_CHECKBOX = 'checkbox' ELEM_TYPE_INPUT_SPIN = 'spin' ELEM_TYPE_BUTTON = 'button' ELEM_TYPE_BUTTONMENU = 'buttonmenu' ELEM_TYPE_IMAGE = 'image' ELEM_TYPE_CANVAS = 'canvas' ELEM_TYPE_FRAME = 'frame' ELEM_TYPE_GRAPH = 'graph' ELEM_TYPE_TAB = 'tab' ELEM_TYPE_TAB_GROUP = 'tabgroup' ELEM_TYPE_INPUT_SLIDER = 'slider' ELEM_TYPE_INPUT_LISTBOX = 'listbox' ELEM_TYPE_OUTPUT = 'output' ELEM_TYPE_COLUMN = 'column' ELEM_TYPE_MENUBAR = 'menubar' ELEM_TYPE_PROGRESS_BAR = 'progressbar' ELEM_TYPE_BLANK = 'blank' ELEM_TYPE_TABLE = 'table' ELEM_TYPE_TREE = 'tree' ELEM_TYPE_ERROR = 'error' ELEM_TYPE_SEPARATOR = 'separator' # ------------------------- Popup Buttons Types ------------------------- # POPUP_BUTTONS_YES_NO = 1 POPUP_BUTTONS_CANCELLED = 2 POPUP_BUTTONS_ERROR = 3 POPUP_BUTTONS_OK_CANCEL = 4 POPUP_BUTTONS_OK = 0 POPUP_BUTTONS_NO_BUTTONS = 5 # ------------------------------------------------------------------------- # # ToolTip used by the Elements # # ------------------------------------------------------------------------- # class ToolTip: """ Create a tooltip for a given widget (inspired by https://stackoverflow.com/a/36221216) """ def __init__(self, widget, text, timeout=DEFAULT_TOOLTIP_TIME): self.widget = widget self.text = text self.timeout = timeout # self.wraplength = wraplength if wraplength else widget.winfo_screenwidth() // 2 self.tipwindow = None self.id = None self.x = self.y = 0 self.widget.bind("", self.enter) self.widget.bind("", self.leave) self.widget.bind("", self.leave) def enter(self, event=None): self.schedule() def leave(self, event=None): self.unschedule() self.hidetip() def schedule(self): self.unschedule() self.id = self.widget.after(self.timeout, self.showtip) def unschedule(self): if self.id: self.widget.after_cancel(self.id) self.id = None def showtip(self): if self.tipwindow: return x = self.widget.winfo_rootx() + 20 y = self.widget.winfo_rooty() + self.widget.winfo_height() - 20 self.tipwindow = tk.Toplevel(self.widget) self.tipwindow.wm_overrideredirect(True) self.tipwindow.wm_geometry("+%d+%d" % (x, y)) label = ttk.Label(self.tipwindow, text=self.text, justify=tk.LEFT, background="#ffffe0", relief=tk.SOLID, borderwidth=1) label.pack() def hidetip(self): if self.tipwindow: self.tipwindow.destroy() self.tipwindow = None # ---------------------------------------------------------------------- # # Cascading structure.... Objects get larger # # Button # # Element # # Row # # Form # # ---------------------------------------------------------------------- # # ---------------------------------------------------------------------- # # Element CLASS # # ---------------------------------------------------------------------- # class Element(): def __init__(self, elem_type, size=(None, None), auto_size_text=None, font=None, background_color=None, text_color=None, key=None, pad=None, tooltip=None, visible=True, size_px=(None, None)): if elem_type != ELEM_TYPE_GRAPH: self.Size = convert_tkinter_size_to_Wx(size) else: self.Size = size if size_px != (None, None): self.Size = size_px self.Type = elem_type self.AutoSizeText = auto_size_text # self.Pad = DEFAULT_ELEMENT_PADDING if pad is None else pad self.Pad = pad if font is not None and type(font) is not str: self.Font = font elif font is not None: self.Font = font.split(' ') else: self.Font = font self.TKStringVar = None self.TKIntVar = None self.TKText = None self.TKEntry = None self.TKImage = None self.ParentForm = None # type: Window self.ParentContainer = None # will be a Form, Column, or Frame element self.TextInputDefault = None self.Position = (0, 0) # Default position Row 0, Col 0 self.BackgroundColor = background_color if background_color is not None else DEFAULT_ELEMENT_BACKGROUND_COLOR self.TextColor = text_color if text_color is not None else DEFAULT_ELEMENT_TEXT_COLOR self.Key = key # dictionary key for return values self.Tooltip = tooltip self.TooltipObject = None self.Visible = visible def FindReturnKeyBoundButton(self, form): for row in form.Rows: for element in row: if element.Type == ELEM_TYPE_BUTTON: if element.BindReturnKey: return element if element.Type == ELEM_TYPE_COLUMN: rc = self.FindReturnKeyBoundButton(element) if rc is not None: return rc if element.Type == ELEM_TYPE_FRAME: rc = self.FindReturnKeyBoundButton(element) if rc is not None: return rc if element.Type == ELEM_TYPE_TAB_GROUP: rc = self.FindReturnKeyBoundButton(element) if rc is not None: return rc if element.Type == ELEM_TYPE_TAB: rc = self.FindReturnKeyBoundButton(element) if rc is not None: return rc return None def TextClickedHandler(self, event): if self.Key is not None: self.ParentForm.LastButtonClicked = self.Key else: self.ParentForm.LastButtonClicked = self.DisplayText self.ParentForm.FormRemainedOpen = True if self.ParentForm.CurrentlyRunningMainloop: self.ParentForm.TKroot.quit() # kick the users out of the mainloop def ReturnKeyHandler(self, event): MyForm = self.ParentForm button_element = self.FindReturnKeyBoundButton(MyForm) if button_element is not None: button_element.ButtonCallBack(event) def ListboxSelectHandler(self, event): # first, get the results table built # modify the Results table in the parent FlexForm object if self.Key is not None: self.ParentForm.LastButtonClicked = self.Key else: self.ParentForm.LastButtonClicked = '' self.ParentForm.FormRemainedOpen = True if self.ParentForm.CurrentlyRunningMainloop: self.ParentForm.TKroot.quit() # kick the users out of the mainloop def ComboboxSelectHandler(self, event): # first, get the results table built # modify the Results table in the parent FlexForm object if self.Key is not None: self.ParentForm.LastButtonClicked = self.Key else: self.ParentForm.LastButtonClicked = '' self.ParentForm.FormRemainedOpen = True if self.ParentForm.CurrentlyRunningMainloop: self.ParentForm.TKroot.quit() # kick the users out of the mainloop def RadioHandler(self): if self.Key is not None: self.ParentForm.LastButtonClicked = self.Key else: self.ParentForm.LastButtonClicked = '' self.ParentForm.FormRemainedOpen = True if self.ParentForm.CurrentlyRunningMainloop: self.ParentForm.TKroot.quit() def CheckboxHandler(self): if self.Key is not None: self.ParentForm.LastButtonClicked = self.Key else: self.ParentForm.LastButtonClicked = '' self.ParentForm.FormRemainedOpen = True if self.ParentForm.CurrentlyRunningMainloop: self.ParentForm.TKroot.quit() def TabGroupSelectHandler(self, event): if self.Key is not None: self.ParentForm.LastButtonClicked = self.Key else: self.ParentForm.LastButtonClicked = '' self.ParentForm.FormRemainedOpen = True if self.ParentForm.CurrentlyRunningMainloop: self.ParentForm.TKroot.quit() def KeyboardHandler(self, event): if self.Key is not None: self.ParentForm.LastButtonClicked = self.Key else: self.ParentForm.LastButtonClicked = '' self.ParentForm.FormRemainedOpen = True if self.ParentForm.CurrentlyRunningMainloop: self.ParentForm.TKroot.quit() def WxCallbackKeyboard(self, value): element_callback_quit_mainloop(self) def Update(self, widget, background_color=None, text_color=None, font=None, visible=None, disabled=None, tooltip=None): if font: widget.SetFont(font_to_wx_font(font)) if text_color not in (None, COLOR_SYSTEM_DEFAULT): widget.SetForegroundColour(text_color) if background_color not in (None, COLOR_SYSTEM_DEFAULT): widget.SetBackgroundColour(background_color) if visible is True: widget.Show() self.ParentForm.VisibilityChanged() elif visible is False: widget.Hide() self.ParentForm.VisibilityChanged() if disabled: widget.Enable(False) elif disabled is False: widget.Enable(True) if tooltip is not None: widget.SetToolTip(tooltip) def __del__(self): pass # ---------------------------------------------------------------------- # # Input Class # # ---------------------------------------------------------------------- # class InputText(Element): def __init__(self, default_text='', size=(None,None), disabled=False, password_char='', justification=None, background_color=None, text_color=None, font=None, tooltip=None, change_submits=False, enable_events=False, do_not_clear=False, key=None, focus=False, pad=None, visible=True, size_px=(None,None)): ''' Input a line of text Element :param default_text: Default value to display :param size: Size of field in characters :param password_char: If non-blank, will display this character for every character typed :param background_color: Color for Element. Text or RGB Hex ''' self.DefaultText = default_text self.PasswordCharacter = password_char bg = background_color if background_color is not None else DEFAULT_INPUT_ELEMENTS_COLOR fg = text_color if text_color is not None else DEFAULT_INPUT_TEXT_COLOR self.Focus = focus self.do_not_clear = do_not_clear self.Justification = justification or 'left' self.Disabled = disabled self.ChangeSubmits = change_submits or enable_events self.QT_QLineEdit = None self.ValueWasChanged = False self.WxTextCtrl = None super().__init__(ELEM_TYPE_INPUT_TEXT, size=size, background_color=bg, text_color=fg, key=key, pad=pad, font=font, tooltip=tooltip, visible=visible, size_px=size_px) def dragEnterEvent(self, e): if e.mimeData().hasText(): e.accept() else: e.ignore() def dropEvent(self, e): self.QT_QLineEdit.setText(e.mimeData().text()) def QtCallbackFocusInEvent(self,value): return # def WxCallbackKeyboard(self, value): # if not self.ChangeSubmits: # return # element_callback_quit_mainloop(self) def QtCallbackReturnPressed(self): self.ReturnKeyHandler(None) return def Update(self, value=None, disabled=None, select=None, background_color=None, text_color=None, font=None, visible=None): if disabled is True: self.WxTextCtrl.Enable(True) elif disabled is False: self.WxTextCtrl.Enable(False) if value is not None: self.WxTextCtrl.SetValue(str(value)) self.DefaultText = value if select: self.WxTextCtrl.SelectAll() # if visible: # self.WxTextCtrl.Show() # self.ParentForm.VisibilityChanged() # elif visible is False: # self.WxTextCtrl.Hide() super().Update(self.WxTextCtrl, background_color=background_color, text_color=text_color, font=font, visible=visible) def Get(self): return self.WxTextCtrl.GetValue() def SetFocus(self): self.WxTextCtrl.SetFocus() def __del__(self): super().__del__() # ------------------------- INPUT TEXT Element lazy functions ------------------------- # In = InputText Input = InputText # ---------------------------------------------------------------------- # # Combo # # ---------------------------------------------------------------------- # class Combo(Element): def __init__(self, values, default_value=None, size=(None, None), auto_size_text=None, background_color=None, text_color=None, change_submits=False, enable_events=False, disabled=False, key=None, pad=None, tooltip=None, readonly=False, visible_items=10, font=None, auto_complete=True, visible=True, size_px=(None,None)): ''' Input Combo Box Element (also called Dropdown box) :param values: :param size: Size of field in characters :param auto_size_text: True if should shrink field to fit the default text :param background_color: Color for Element. Text or RGB Hex ''' self.Values = values self.DefaultValue = default_value self.ChangeSubmits = change_submits or enable_events # self.InitializeAsDisabled = disabled self.Disabled = disabled self.Readonly = readonly 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.VisibleItems = visible_items self.AutoComplete = auto_complete self.WxComboBox = None # type: wx.ComboBox super().__init__(ELEM_TYPE_INPUT_COMBO, size=size, auto_size_text=auto_size_text, background_color=bg, text_color=fg, key=key, pad=pad, tooltip=tooltip, font=font or DEFAULT_FONT, visible=visible, size_px=size_px) def QtCurrentItemChanged(self, state): if self.ChangeSubmits: element_callback_quit_mainloop(self) def Update(self, value=None, values=None, set_to_index=None, disabled=None, readonly=None, background_color=None, text_color=None, font=None, visible=None): if values is not None: self.WxComboBox.Set(values) if value: self.WxComboBox.SetSelection(self.WxComboBox.FindString(value)) if set_to_index is not None: self.WxComboBox.SetSelection(set_to_index) if disabled is True: self.WxComboBox.Enable(False) elif disabled is False: self.WxComboBox.Enable(True) if readonly is not None: self.WxComboBox.SetWindowStyle(wx.CB_READONLY) super().Update(self.WxComboBox, background_color=background_color, text_color=text_color, font=font, visible=visible) def __del__(self): super().__del__() # ------------------------- INPUT COMBO Element lazy functions ------------------------- # InputCombo = Combo DropDown = InputCombo Drop = InputCombo # ---------------------------------------------------------------------- # # Option Menu # # ---------------------------------------------------------------------- # class OptionMenu(Element): def __init__(self, values, default_value=None, size=(None, None), disabled=False, auto_size_text=None, background_color=None, text_color=None, key=None, pad=None, tooltip=None): ''' InputOptionMenu :param values: :param default_value: :param size: :param disabled: :param auto_size_text: :param background_color: :param text_color: :param key: :param pad: :param tooltip: ''' self.Values = values self.DefaultValue = default_value self.TKOptionMenu = None self.Disabled = disabled 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 super().__init__(ELEM_TYPE_INPUT_OPTION_MENU, size=size, auto_size_text=auto_size_text, background_color=bg, text_color=fg, key=key, pad=pad, tooltip=tooltip) def Update(self, value=None, values=None, disabled=None): if values is not None: self.Values = values if self.Values is not None: for index, v in enumerate(self.Values): if v == value: try: self.TKStringVar.set(value) except: pass self.DefaultValue = value break if disabled == True: self.TKOptionMenu['state'] = 'disabled' elif disabled == False: self.TKOptionMenu['state'] = 'normal' def __del__(self): try: self.TKOptionMenu.__del__() except: pass super().__del__() # ------------------------- OPTION MENU Element lazy functions ------------------------- # InputOptionMenu = OptionMenu # ---------------------------------------------------------------------- # # Listbox # # ---------------------------------------------------------------------- # class Listbox(Element): def __init__(self, values, default_values=None, select_mode=None, change_submits=False, bind_return_key=False, size=(None, None), disabled=False, auto_size_text=None, font=None, background_color=None, text_color=None, key=None, pad=None, tooltip=None): ''' Listbox Element :param values: :param default_values: :param select_mode: :param change_submits: :param bind_return_key: :param size: :param disabled: :param auto_size_text: :param font: :param background_color: :param text_color: :param key: :param pad: :param tooltip: ''' self.Values = values self.DefaultValues = default_values self.TKListbox = None self.ChangeSubmits = change_submits self.BindReturnKey = bind_return_key self.Disabled = disabled if select_mode == LISTBOX_SELECT_MODE_BROWSE: self.SelectMode = SELECT_MODE_BROWSE elif select_mode == LISTBOX_SELECT_MODE_EXTENDED: self.SelectMode = SELECT_MODE_EXTENDED elif select_mode == LISTBOX_SELECT_MODE_MULTIPLE: self.SelectMode = SELECT_MODE_MULTIPLE elif select_mode == LISTBOX_SELECT_MODE_SINGLE: self.SelectMode = SELECT_MODE_SINGLE else: self.SelectMode = DEFAULT_LISTBOX_SELECT_MODE 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 super().__init__(ELEM_TYPE_INPUT_LISTBOX, size=size, auto_size_text=auto_size_text, font=font, background_color=bg, text_color=fg, key=key, pad=pad, tooltip=tooltip) def Update(self, values=None, disabled=None): if disabled == True: self.TKListbox.configure(state='disabled') elif disabled == False: self.TKListbox.configure(state='normal') if values is not None: self.TKListbox.delete(0, 'end') for item in values: self.TKListbox.insert(tk.END, item) self.TKListbox.selection_set(0, 0) self.Values = values def SetValue(self, values): for index, item in enumerate(self.Values): try: if item in values: self.TKListbox.selection_set(index) else: self.TKListbox.selection_clear(index) except: pass self.DefaultValues = values def GetListValues(self): return self.Values def __del__(self): try: self.TKListBox.__del__() except: pass super().__del__() # ---------------------------------------------------------------------- # # Radio # # ---------------------------------------------------------------------- # class Radio(Element): def __init__(self, text, group_id, default=False, disabled=False, size=(None, None), auto_size_text=None, background_color=None, text_color=None, font=None, key=None, pad=None, tooltip=None, change_submits=False, enable_events=False, visible=True, size_px=(None, None)): """ :param text: :param group_id: :param default: :param disabled: :param size: :param auto_size_text: :param background_color: :param text_color: :param font: :param key: :param pad: :param tooltip: :param change_submits: :param enable_events: :param visible: :param size_px: """ self.InitialState = default self.Text = text self.GroupID = group_id self.Value = None self.Disabled = disabled self.TextColor = text_color or DEFAULT_TEXT_COLOR self.ChangeSubmits = change_submits or enable_events self.WxRadioButton = None # type: wx.RadioButton super().__init__(ELEM_TYPE_INPUT_RADIO, size=size, auto_size_text=auto_size_text, font=font, background_color=background_color, text_color=self.TextColor, key=key, pad=pad, tooltip=tooltip, visible=visible, size_px=size_px) def Update(self, value=None, disabled=None, background_color=None, text_color=None, font=None, visible=None): if value: self.WxRadioButton.SetValue(True) elif value is False: self.WxRadioButton.SetValue(False) super().Update(self.WxRadioButton, background_color=background_color, text_color=text_color, font=font, visible=visible) def __del__(self): super().__del__() # ---------------------------------------------------------------------- # # Checkbox # # ---------------------------------------------------------------------- # class Checkbox(Element): def __init__(self, text, default=False, size=(None, None), auto_size_text=None, font=None, background_color=None, text_color=None, change_submits=False, enable_events=False, disabled=False, key=None, pad=None, tooltip=None, visible=True, size_px=(None,None)): ''' Checkbox Element :param text: :param default: :param size: :param auto_size_text: :param font: :param background_color: :param text_color: :param change_submits: :param disabled: :param key: :param pad: :param tooltip: ''' self.Text = text self.InitialState = default self.WxCheckbox:wx.CheckBox = None self.Disabled = disabled self.TextColor = text_color if text_color else DEFAULT_TEXT_COLOR self.ChangeSubmits = change_submits or enable_events super().__init__(ELEM_TYPE_INPUT_CHECKBOX, size=size, auto_size_text=auto_size_text, font=font, background_color=background_color, text_color=self.TextColor, key=key, pad=pad, tooltip=tooltip, visible=visible, size_px=size_px) def Get(self): return self.WxCheckbox.GetValue() def Update(self, value=None, disabled=None): if value is not None: try: self.WxCheckbox.SetValue(value) self.InitialState = value except: pass if disabled == True: self.WxCheckbox.Disable() elif disabled == False: self.WxCheckbox.Enable() def __del__(self): super().__del__() # ------------------------- CHECKBOX Element lazy functions ------------------------- # CB = Checkbox CBox = Checkbox Check = Checkbox # ---------------------------------------------------------------------- # # Spin # # ---------------------------------------------------------------------- # class Spin(Element): # Values = None # TKSpinBox = None def __init__(self, values, initial_value=None, disabled=False, change_submits=False, enable_events=False, size=(None, None), readonly=True, auto_size_text=None, font=None, background_color=None, text_color=None, key=None, pad=None, tooltip=None, visible=True, size_px=(None,None)): ''' Spinner Element :param values: :param initial_value: :param disabled: :param change_submits: :param size: :param auto_size_text: :param font: :param background_color: :param text_color: :param key: :param pad: :param tooltip: ''' self.Values = values self.DefaultValue = initial_value or values[0] self.ChangeSubmits = change_submits or enable_events self.Disabled = disabled 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.WxSpinCtrl : wx.SpinCtrl = None self.WxTextCtrl = None # type : wx.TextCtrl self.CurrentValue = self.DefaultValue self.ReadOnly = readonly super().__init__(ELEM_TYPE_INPUT_SPIN, size, auto_size_text, font=font, background_color=bg, text_color=fg, key=key, pad=pad, tooltip=tooltip, visible=visible, size_px=size_px) return def WxSpinCallback(self, event:wx.SpinEvent): print(f'spin event {event.GetInt()} {self.WxSpinCtrl.GetValue()}') offset = event.GetInt() self.WxTextCtrl.SetValue(self.Values[offset]) self.CurrentValue = self.Values[offset] if self.ChangeSubmits: element_callback_quit_mainloop(self) def Update(self, value=None, values=None, disabled=None, background_color=None, text_color=None, font=None, visible=None): if values != None: self.Values = values self.QT_Spinner.setStrings(values) # self.QT_Spinner.setRange(self.Values[0], self.Values[1]) if value is not None: # self.QT_Spinner.setValue(value) try: self.QT_Spinner.setValue(self.QT_Spinner.valueFromText(value)) self.DefaultValue = value except: pass if disabled == True: self.QT_Spinner.setDisabled(True) elif disabled == False: self.QT_Spinner.setDisabled(False) super().Update(self.QT_Spinner, background_color=background_color, text_color=text_color, font=font, visible=visible) def Get(self): return self.WxSpinCtrl.GetValue() def __del__(self): super().__del__() # ---------------------------------------------------------------------- # # Multiline # # ---------------------------------------------------------------------- # class Multiline(Element): def __init__(self, default_text='', enter_submits=False, disabled=False, autoscroll=False, size=(None, None), auto_size_text=None, background_color=None, text_color=None, change_submits=False, enable_events=False, do_not_clear=False, key=None, focus=False, font=None, pad=None, tooltip=None, visible=True, size_px=(None,None)): ''' Multiline Element :param default_text: :param enter_submits: :param disabled: :param autoscroll: :param size: :param auto_size_text: :param background_color: :param text_color: :param do_not_clear: :param key: :param focus: :param pad: :param tooltip: :param font: ''' self.DefaultText = default_text self.EnterSubmits = enter_submits bg = background_color if background_color else DEFAULT_INPUT_ELEMENTS_COLOR self.Focus = focus self.do_not_clear = do_not_clear fg = text_color if text_color is not None else DEFAULT_INPUT_TEXT_COLOR self.Autoscroll = autoscroll self.Disabled = disabled self.ChangeSubmits = change_submits or enable_events tsize = size # convert tkinter size to pixels if size[0] is not None and size[0] < 100: tsize = size[0]*DEFAULT_PIXELS_TO_CHARS_SCALING[0], size[1]*DEFAULT_PIXELS_TO_CHARS_SCALING[1] self.WxTextCtrl = None super().__init__(ELEM_TYPE_INPUT_MULTILINE, size=tsize, auto_size_text=auto_size_text, background_color=bg, text_color=fg, key=key, pad=pad, tooltip=tooltip, font=font or DEFAULT_FONT, visible=visible, size_px=size_px) return def Update(self, value=None, disabled=None, append=False, background_color=None, text_color=None, font=None, visible=None): if value is not None and not append: self.WxTextCtrl.SetLabel(value) elif value is not None and append: self.WxTextCtrl.AppendText(value) if background_color is not None: self.WxTextCtrl.SetBackgroundColour(background_color) if text_color is not None: self.WxTextCtrl.SetForegroundColour(text_color) if font is not None: self.WxTextCtrl.SetFont(font) if disabled: self.WxTextCtrl.Enable(True) elif disabled is False: self.WxTextCtrl.Enable(False) super().Update(self.WxTextCtrl, background_color=background_color, text_color=text_color, font=font, visible=visible) # # def Update(self, value=None, disabled=None, append=False, background_color=None, text_color=None, font=None, visible=None): # if value is not None and not append: # self.DefaultText = value # self.QT_TextEdit.setText(str(value)) # elif value is not None and append: # self.DefaultText = value # self.QT_TextEdit.setText(self.QT_TextEdit.toPlainText() + str(value)) # if disabled == True: # self.QT_TextEdit.setDisabled(True) # elif disabled == False: # self.QT_TextEdit.setDisabled(False) # super().Update(self.QT_TextEdit, background_color=background_color, text_color=text_color, font=font, visible=visible) def Get(self): self.WxTextCtrl.GetValue() def SetFocus(self): self.WxTextCtrl.SetFocus() def __del__(self): super().__del__() # ---------------------------------------------------------------------- # # Multiline Output # # ---------------------------------------------------------------------- # class MultilineOutput(Element): def __init__(self, default_text='', enter_submits=False, disabled=False, autoscroll=False, size=(None, None), auto_size_text=None, background_color=None, text_color=None, change_submits=False, enable_events=False, do_not_clear=False, key=None, focus=False, font=None, pad=None, tooltip=None, visible=True, size_px=(None,None)): ''' Multiline Element :param default_text: :param enter_submits: :param disabled: :param autoscroll: :param size: :param auto_size_text: :param background_color: :param text_color: :param do_not_clear: :param key: :param focus: :param pad: :param tooltip: :param font: ''' self.DefaultText = default_text self.EnterSubmits = enter_submits bg = background_color if background_color else DEFAULT_INPUT_ELEMENTS_COLOR self.Focus = focus self.do_not_clear = do_not_clear fg = text_color if text_color is not None else DEFAULT_INPUT_TEXT_COLOR self.Autoscroll = autoscroll self.Disabled = disabled self.ChangeSubmits = change_submits or enable_events tsize = size # convert tkinter size to pixels if size[0] is not None and size[0] < 100: tsize = size[0]*DEFAULT_PIXELS_TO_CHARS_SCALING[0], size[1]*DEFAULT_PIXELS_TO_CHARS_SCALING[1] self.WxTextCtrl = None super().__init__(ELEM_TYPE_MULTILINE_OUTPUT, size=tsize, auto_size_text=auto_size_text, background_color=bg, text_color=fg, key=key, pad=pad, tooltip=tooltip, font=font or DEFAULT_FONT, visible=visible, size_px=size_px) return def Update(self, value=None, disabled=None, append=False, background_color=None, text_color=None, font=None, visible=None): if value is not None and not append: self.WxTextCtrl.SetLabel(value) elif value is not None and append: self.WxTextCtrl.AppendText(value) if background_color is not None: self.WxTextCtrl.SetBackgroundColour(background_color) if text_color is not None: self.WxTextCtrl.SetForegroundColour(text_color) if font is not None: self.WxTextCtrl.SetFont(font) if disabled: self.WxTextCtrl.Enable(True) elif disabled is False: self.WxTextCtrl.Enable(False) super().Update(self.WxTextCtrl, background_color=background_color, text_color=text_color, font=font, visible=visible) def Get(self): self.WxTextCtrl.GetValue() def SetFocus(self): self.WxTextCtrl.SetFocus() def __del__(self): super().__del__() # ---------------------------------------------------------------------- # # Text # # ---------------------------------------------------------------------- # class Text(Element): def __init__(self, text, size=(None, None), auto_size_text=None, click_submits=None, enable_events=False, relief=None, border_width=None, font=None, text_color=None, background_color=None, justification=None, pad=None, margins=None, key=None, tooltip=None, visible=True, size_px=(None,None)): """ Text :param text: :param size: :param auto_size_text: :param click_submits: :param enable_events: :param relief: :param font: :param text_color: :param background_color: :param justification: :param pad: :param margins: :param key: :param tooltip: :param visible: :param size_px: """ self.DisplayText = text self.TextColor = text_color if text_color else DEFAULT_TEXT_COLOR self.Justification = justification self.Relief = relief self.ClickSubmits = click_submits or enable_events self.Margins = margins self.size_px = size_px if background_color is None: bg = DEFAULT_TEXT_ELEMENT_BACKGROUND_COLOR else: bg = background_color pixelsize = size if size[1] is not None and size[1] < 10: pixelsize = size[0]*10, size[1]*20 self.WxStaticText:wx.StaticText = None # wx.StaticText(form.MasterPanel, -1, element.DisplayText) self.BorderWidth = border_width if border_width is not None else DEFAULT_BORDER_WIDTH super().__init__(ELEM_TYPE_TEXT, pixelsize, auto_size_text, background_color=bg, font=font if font else DEFAULT_FONT, text_color=self.TextColor, pad=pad, key=key, tooltip=tooltip, size_px=size_px, visible=visible) return def Update(self, value=None, background_color=None, text_color=None, font=None, visible=None): if self.ParentForm.TKrootDestroyed: return if value is not None: self.WxStaticText.SetLabel(value) self.DisplayText = value if background_color is not None: self.WxStaticText.SetBackgroundColour(background_color) if text_color is not None: self.WxStaticText.SetForegroundColour(text_color) if font is not None: self.WxStaticText.SetFont(font) super().Update(self.WxStaticText, background_color=background_color, text_color=text_color, font=font, visible=visible) def __del__(self): super().__del__() # ------------------------- Text Element lazy functions ------------------------- # Txt = Text T = Text # ---------------------------------------------------------------------- # # TKProgressBar # # Emulate the TK ProgressBar using canvas and rectangles # ---------------------------------------------------------------------- # class TKProgressBar(): def __init__(self, root, max, length=400, width=DEFAULT_PROGRESS_BAR_SIZE[1], style=DEFAULT_PROGRESS_BAR_STYLE, relief=DEFAULT_PROGRESS_BAR_RELIEF, border_width=DEFAULT_PROGRESS_BAR_BORDER_WIDTH, orientation='horizontal', BarColor=(None, None), key=None): self.Length = length self.Width = width self.Max = max self.Orientation = orientation self.Count = None self.PriorCount = 0 if orientation[0].lower() == 'h': s = ttk.Style() s.theme_use(style) if BarColor != COLOR_SYSTEM_DEFAULT: s.configure(str(key) + "my.Horizontal.TProgressbar", background=BarColor[0], troughcolor=BarColor[1], troughrelief=relief, borderwidth=border_width, thickness=width) else: s.configure(str(key) + "my.Horizontal.TProgressbar", troughrelief=relief, borderwidth=border_width, thickness=width) self.TKProgressBarForReal = ttk.Progressbar(root, maximum=self.Max, style=str(key) + 'my.Horizontal.TProgressbar', length=length, orient=tk.HORIZONTAL, mode='determinate') else: s = ttk.Style() s.theme_use(style) if BarColor != COLOR_SYSTEM_DEFAULT: s.configure(str(length) + str(width) + "my.Vertical.TProgressbar", background=BarColor[0], troughcolor=BarColor[1], troughrelief=relief, borderwidth=border_width, thickness=width) else: s.configure(str(length) + str(width) + "my.Vertical.TProgressbar", troughrelief=relief, borderwidth=border_width, thickness=width) self.TKProgressBarForReal = ttk.Progressbar(root, maximum=self.Max, style=str(length) + str(width) + 'my.Vertical.TProgressbar', length=length, orient=tk.VERTICAL, mode='determinate') def Update(self, count=None, max=None): if max is not None: self.Max = max try: self.TKProgressBarForReal.config(maximum=max) except: return False if count is not None and count > self.Max: return False if count is not None: try: self.TKProgressBarForReal['value'] = count except: return False return True def __del__(self): try: self.TKProgressBarForReal.__del__() except: pass class RedirectText(object): def __init__(self, aWxTextCtrl): self.out = aWxTextCtrl def write(self, string): self.out.AppendText(string) def flush(self): return # ---------------------------------------------------------------------- # # Output # # Routes stdout, stderr to a scrolled window # # ---------------------------------------------------------------------- # class Output(Element): def __init__(self, size=(None, None), background_color=None, text_color=None, pad=None, font=None, tooltip=None, key=None, visible=True, size_px=(None,None), disabled=False): ''' Output Element :param size: :param background_color: :param text_color: :param pad: :param font: :param tooltip: :param key: ''' self._TKOut = None 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.WxTextCtrl = None # type: wx.TextCtrl self.redir = None self.output = None self.Disabled = disabled tsize = convert_tkinter_size_to_Wx(size) if size[0] is not None and size[0] < 100 else size super().__init__(ELEM_TYPE_OUTPUT, size=tsize, background_color=bg, text_color=fg, pad=pad, font=font, tooltip=tooltip, key=key, visible=visible, size_px=size_px) def reroute_stdout(self): self.my_stdout = sys.stdout self.my_stderr = sys.stderr self.redir = RedirectText(self.WxTextCtrl) sys.stdout = self.redir sys.stderr = self.redir Window.stdout_is_rerouted = True Window.stdout_location = self.redir def reroute_again(self): sys.stdout = self.redir def Update(self,value=None, background_color=None, text_color=None, font=None, visible=None): if value is not None: self.WxTextCtrl.AppendText(value) super().Update(self.WxTextCtrl, background_color=background_color, text_color=text_color, font=font, visible=visible) def __del__(self): try: sys.stdout = self.my_stdout sys.stderr = self.my_stderr except: pass super().__del__() # ---------------------------------------------------------------------- # # Button Class # # ---------------------------------------------------------------------- # class Button(Element): def __init__(self, button_text='', button_type=BUTTON_TYPE_READ_FORM, target=(None, None), tooltip=None, file_types=(("ALL Files", "*"),), initial_folder=None, disabled=False, change_submits=False, enable_events=False, image_filename=None, image_data=None, image_size=(None, None), image_subsample=None, border_width=None, size=(None, None), auto_size_button=None, button_color=None, font=None, bind_return_key=False, focus=False, pad=None, key=None, visible=True, size_px=(None,None)): ''' Button Element :param button_text: :param button_type: :param target: :param tooltip: :param file_types: :param initial_folder: :param disabled: :param image_filename: :param image_size: :param image_subsample: :param border_width: :param size: :param auto_size_button: :param button_color: :param default_value: :param font: :param bind_return_key: :param focus: :param pad: :param key: ''' self.AutoSizeButton = auto_size_button self.BType = button_type self.FileTypes = file_types self.TKButton = None self.Target = target self.ButtonText = button_text self.ButtonColor = button_color if button_color else DEFAULT_BUTTON_COLOR self.TextColor = self.ButtonColor[0] self.BackgroundColor = self.ButtonColor[1] self.ImageFilename = image_filename self.ImageData = image_data self.ImageSize = image_size self.ImageSubsample = image_subsample self.UserData = None self.BorderWidth = border_width if border_width is not None else DEFAULT_BORDER_WIDTH self.BindReturnKey = bind_return_key self.Focus = focus self.TKCal = None self.CalendarCloseWhenChosen = None self.DefaultDate_M_D_Y = (None, None, None) self.InitialFolder = initial_folder self.Disabled = disabled self.ChangeSubmits = change_submits or enable_events self.QT_QPushButton = None self.ColorChosen = None self.Relief = None # self.temp_size = size if size != (NONE, NONE) else super().__init__(ELEM_TYPE_BUTTON, size=size, font=font, pad=pad, key=key, tooltip=tooltip, text_color=self.TextColor, background_color=self.BackgroundColor, visible=visible, size_px=size_px) return # Realtime button release callback def ButtonReleaseCallBack(self, parm): self.LastButtonClickedWasRealtime = False self.ParentForm.LastButtonClicked = None # Realtime button callback def ButtonPressCallBack(self, parm): self.ParentForm.LastButtonClickedWasRealtime = True if self.Key is not None: self.ParentForm.LastButtonClicked = self.Key else: self.ParentForm.LastButtonClicked = self.ButtonText if self.ParentForm.CurrentlyRunningMainloop: pass # kick out of loop if read was called # ------- Button Callback ------- # def ButtonCallBack(self, event): # print('Button callback') # print(f'Parent = {self.ParentForm} Position = {self.Position}') # Buttons modify targets or return from the form # If modifying target, get the element object at the target and modify its StrVar target = self.Target target_element = None if target[0] == ThisRow: target = [self.Position[0], target[1]] if target[1] < 0: target[1] = self.Position[1] + target[1] strvar = None should_submit_window = False if target == (None, None): strvar = self.TKStringVar else: if not isinstance(target, str): if target[0] < 0: target = [self.Position[0] + target[0], target[1]] target_element = self.ParentContainer._GetElementAtLocation(target) else: target_element = self.ParentForm.FindElement(target) try: strvar = target_element.TKStringVar except: pass try: if target_element.ChangeSubmits: should_submit_window = True except: pass filetypes = (("ALL Files", "*"),) if self.FileTypes is None else self.FileTypes if self.BType == BUTTON_TYPE_BROWSE_FOLDER: # Browse Folder wx_types = convert_tkinter_filetypes_to_wx(self.FileTypes) if self.InitialFolder: dialog = wx.DirDialog(self.ParentForm.MasterFrame, style=wx.FD_OPEN) else: dialog = wx.DirDialog(self.ParentForm.MasterFrame) folder_name = '' if dialog.ShowModal() == wx.ID_OK: folder_name = dialog.GetPath() if folder_name != '': if target_element.Type == ELEM_TYPE_BUTTON: target_element.FileOrFolderName = folder_name else: target_element.Update(folder_name) elif self.BType == BUTTON_TYPE_BROWSE_FILE: # Browse File qt_types = convert_tkinter_filetypes_to_wx(self.FileTypes) if self.InitialFolder: dialog = wx.FileDialog(self.ParentForm.MasterFrame,defaultDir=self.InitialFolder, wildcard=qt_types, style=wx.FD_OPEN) else: dialog = wx.FileDialog(self.ParentForm.MasterFrame, wildcard=qt_types, style=wx.FD_OPEN) file_name = '' if dialog.ShowModal() == wx.ID_OK: file_name = dialog.GetPath() else: file_name = '' if file_name != '': if target_element.Type == ELEM_TYPE_BUTTON: target_element.FileOrFolderName = file_name else: target_element.Update(file_name) elif self.BType == BUTTON_TYPE_BROWSE_FILES: # Browse Files qt_types = convert_tkinter_filetypes_to_wx(self.FileTypes) if self.InitialFolder: dialog = wx.FileDialog(self.ParentForm.MasterFrame,defaultDir=self.InitialFolder, wildcard=qt_types, style=wx.FD_MULTIPLE) else: dialog = wx.FileDialog(self.ParentForm.MasterFrame, wildcard=qt_types, style=wx.FD_MULTIPLE) file_names = '' if dialog.ShowModal() == wx.ID_OK: file_names = dialog.GetPaths() else: file_names = '' if file_names != '': file_names = ';'.join(file_names) if target_element.Type == ELEM_TYPE_BUTTON: target_element.FileOrFolderName = file_names else: target_element.Update(file_names) elif self.BType == BUTTON_TYPE_SAVEAS_FILE: # Save As File qt_types = convert_tkinter_filetypes_to_wx(self.FileTypes) if self.InitialFolder: dialog = wx.FileDialog(self.ParentForm.MasterFrame,defaultDir=self.InitialFolder, wildcard=qt_types, style=wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT) else: dialog = wx.FileDialog(self.ParentForm.MasterFrame, wildcard=qt_types, style=wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT) file_name = '' if dialog.ShowModal() == wx.ID_OK: file_name = dialog.GetPath() else: file_name = '' if file_name != '': if target_element.Type == ELEM_TYPE_BUTTON: target_element.FileOrFolderName = file_name else: target_element.Update(file_name) elif self.BType == BUTTON_TYPE_COLOR_CHOOSER: # Color Chooser qcolor = QColorDialog.getColor() rgb_color = qcolor.getRgb() color= '#' + ''.join('%02x'% i for i in rgb_color[:3]) if self.Target == (None, None): self.FileOrFolderName = color else: target_element.Update(color) elif self.BType == BUTTON_TYPE_CLOSES_WIN: # Closes Window # first, get the results table built # modify the Results table in the parent FlexForm object if self.Key is not None: self.ParentForm.LastButtonClicked = self.Key else: self.ParentForm.LastButtonClicked = self.ButtonText self.ParentForm.FormRemainedOpen = False if self.ParentForm.CurrentlyRunningMainloop: self.ParentForm.App.ExitMainLoop() self.ParentForm.IgnoreClose = True self.ParentForm.MasterFrame.Close() if self.ParentForm.NonBlocking: Window.DecrementOpenCount() self.ParentForm._Close() elif self.BType == BUTTON_TYPE_READ_FORM: # Read Button # first, get the results table built # modify the Results table in the parent FlexForm object if self.Key is not None: self.ParentForm.LastButtonClicked = self.Key else: self.ParentForm.LastButtonClicked = self.ButtonText self.ParentForm.FormRemainedOpen = True if self.ParentForm.CurrentlyRunningMainloop: # if this window is running the mainloop, kick out self.ParentForm.App.ExitMainLoop() elif self.BType == BUTTON_TYPE_CLOSES_WIN_ONLY: # special kind of button that does not exit main loop if self.Key is not None: self.ParentForm.LastButtonClicked = self.Key else: self.ParentForm.LastButtonClicked = self.ButtonText if self.ParentForm.CurrentlyRunningMainloop: # if this window is running the mainloop, kick out self.ParentForm.App.ExitMainLoop() self.ParentForm.IgnoreClose = True self.ParentForm.MasterFrame.Close() self.ParentForm._Close() Window.DecrementOpenCount() elif self.BType == BUTTON_TYPE_CALENDAR_CHOOSER: # this is a return type button so GET RESULTS and destroy window should_submit_window = False if should_submit_window: self.ParentForm.LastButtonClicked = target_element.Key self.ParentForm.FormRemainedOpen = True if self.ParentForm.CurrentlyRunningMainloop: self.ParentForm.App.ExitMainLoop() return def Update(self, text=None, button_color=(None, None), disabled=None, image_data=None, image_filename=None, font=None, visible=None): if text is not None: self.QT_QPushButton.setText(str(text)) self.ButtonText = text if self.ParentForm.Font and (self.Font == DEFAULT_FONT or not self.Font): font = self.ParentForm.Font elif self.Font is not None: font = self.Font else: font = DEFAULT_FONT fg = bg = None if button_color != (None, None): self.ButtonColor = button_color fg, bg = button_color if self.Disabled != disabled and disabled is not None: if not disabled: # if enabling buttons, set the color fg, bg = self.ButtonColor self.Disabled = disabled if disabled: self.QT_QPushButton.setDisabled(True) else: self.QT_QPushButton.setDisabled(False) # fg, bg = self.ButtonColor # print(f'Button update fg, bg {fg}, {bg}') super().Update(self.WxButton, background_color=bg, text_color=fg, font=font, visible=visible) def GetText(self): return self.ButtonText def SetFocus(self): self.QT_QPushButton.setFocus() def __del__(self): super().__del__() def convert_tkinter_filetypes_to_wx(filetypes): wx_filetypes = '' for item in filetypes: filetype = item[0] + ' (' + item[1] + ')|'+ item[1] wx_filetypes += filetype return wx_filetypes # ---------------------------------------------------------------------- # # ProgreessBar # # ---------------------------------------------------------------------- # class ProgressBar(Element): def __init__(self, max_value, orientation=None, size=(None, None),start_value=0, auto_size_text=None, bar_color=(None, None), style=None, border_width=None, relief=None, key=None, pad=None, disabled=False, visible=True, size_px=(None,None)): ''' ProgressBar Element :param max_value: :param orientation: :param size: :param auto_size_text: :param bar_color: :param style: :param border_width: :param relief: :param key: :param pad: ''' self.MaxValue = max_value self.TKProgressBar = None self.Cancelled = False self.NotRunning = True self.Orientation = orientation if orientation else DEFAULT_METER_ORIENTATION self.BarColor = bar_color if bar_color != (None, None) else DEFAULT_PROGRESS_BAR_COLOR self.BarStyle = style if style else DEFAULT_PROGRESS_BAR_STYLE self.BorderWidth = border_width if border_width is not None else DEFAULT_PROGRESS_BAR_BORDER_WIDTH self.Relief = relief if relief else DEFAULT_PROGRESS_BAR_RELIEF self.BarExpired = False self.StartValue = start_value self.Disabled = disabled tsize = size if size[0] is not None and size[0] < 100: # tsize = size[0] * DEFAULT_PIXELS_TO_CHARS_SCALING[0], size[1] * DEFAULT_PIXELS_TO_CHARS_SCALING[1] tsize = size[0]*10, size[1] self.WxGauge = None # type: wx.Gauge super().__init__(ELEM_TYPE_PROGRESS_BAR, size=tsize, auto_size_text=auto_size_text, key=key, pad=pad, visible=visible, size_px=size_px) # returns False if update failed def UpdateBar(self, current_count, max=None): try: # Could havae been destroyed by user if max is not None: self.WxGauge.SetRange(max) self.WxGauge.SetValue(current_count) except: pass return True def Update(self, visible=None): super().Update(self.WxGauge, visible=visible) def __del__(self): super().__del__() # ---------------------------------------------------------------------- # # Image # # ---------------------------------------------------------------------- # class Image(Element): def __init__(self, filename=None, data=None, background_color=None, size=(None, None), pad=None, key=None, tooltip=None): ''' Image Element :param filename: :param data: :param background_color: :param size: :param pad: :param key: :param tooltip: ''' self.Filename = filename self.Data = data self.tktext_label = None self.BackgroundColor = background_color if data is None and filename is None: print('* Warning... no image specified in Image Element! *') super().__init__(ELEM_TYPE_IMAGE, size=size, background_color=background_color, pad=pad, key=key, tooltip=tooltip) return def Update(self, filename=None, data=None, size=(None, None)): if filename is not None: image = tk.PhotoImage(file=filename) elif data is not None: # if type(data) is bytes: try: image = tk.PhotoImage(data=data) except: return # an error likely means the window has closed so exit # else: # image = data else: return width, height = size[0] or image.width(), size[1] or image.height() self.tktext_label.configure(image=image, width=width, height=height) self.tktext_label.image = image def __del__(self): super().__del__() # ---------------------------------------------------------------------- # # Canvas # # ---------------------------------------------------------------------- # class Canvas(Element): def __init__(self, canvas=None, background_color=None, size=(None, None), pad=None, key=None, tooltip=None): ''' Canvas Element :param canvas: :param background_color: :param size: :param pad: :param key: :param tooltip: ''' self.BackgroundColor = background_color if background_color is not None else DEFAULT_BACKGROUND_COLOR self._TKCanvas = canvas super().__init__(ELEM_TYPE_CANVAS, background_color=background_color, size=size, pad=pad, key=key, tooltip=tooltip) return @property def TKCanvas(self): if self._TKCanvas is None: print('*** Did you forget to call Finalize()? Your code should look something like: ***') print('*** form = sg.Window("My Form").Layout(layout).Finalize() ***') return self._TKCanvas def __del__(self): super().__del__() # ---------------------------------------------------------------------- # # Graph # # ---------------------------------------------------------------------- # class Graph(Element): def __init__(self, canvas_size, graph_bottom_left, graph_top_right, background_color=None, pad=None, change_submits=False, drag_submits=False, key=None, tooltip=None): ''' Graph Element :param canvas_size: :param graph_bottom_left: :param graph_top_right: :param background_color: :param pad: :param key: :param tooltip: ''' self.CanvasSize = canvas_size self.BottomLeft = graph_bottom_left self.TopRight = graph_top_right self._TKCanvas = None self._TKCanvas2 = None self.ChangeSubmits = change_submits self.DragSubmits = drag_submits self.ClickPosition = (None, None) self.MouseButtonDown = False super().__init__(ELEM_TYPE_GRAPH, background_color=background_color, size=canvas_size, pad=pad, key=key, tooltip=tooltip) return def _convert_xy_to_canvas_xy(self, x_in, y_in): if None in (x_in, y_in): return None, None scale_x = (self.CanvasSize[0] - 0) / (self.TopRight[0] - self.BottomLeft[0]) scale_y = (0 - self.CanvasSize[1]) / (self.TopRight[1] - self.BottomLeft[1]) new_x = 0 + scale_x * (x_in - self.BottomLeft[0]) new_y = self.CanvasSize[1] + scale_y * (y_in - self.BottomLeft[1]) return new_x, new_y def _convert_canvas_xy_to_xy(self, x_in, y_in): if None in (x_in, y_in): return None, None scale_x = (self.CanvasSize[0] - 0) / (self.TopRight[0] - self.BottomLeft[0]) scale_y = (0 - self.CanvasSize[1]) / (self.TopRight[1] - self.BottomLeft[1]) new_x = x_in / scale_x + self.BottomLeft[0] new_y = (y_in - self.CanvasSize[1]) / scale_y + self.BottomLeft[1] return int(new_x), int(new_y) def DrawLine(self, point_from, point_to, color='black', width=1): if point_from == (None, None): return converted_point_from = self._convert_xy_to_canvas_xy(point_from[0], point_from[1]) converted_point_to = self._convert_xy_to_canvas_xy(point_to[0], point_to[1]) if self._TKCanvas2 is None: print('*** WARNING - The Graph element has not been finalized and cannot be drawn upon ***') print('Call Window.Finalize() prior to this operation') return None return self._TKCanvas2.create_line(converted_point_from, converted_point_to, width=width, fill=color) def DrawPoint(self, point, size=2, color='black'): if point == (None, None): return converted_point = self._convert_xy_to_canvas_xy(point[0], point[1]) if self._TKCanvas2 is None: print('*** WARNING - The Graph element has not been finalized and cannot be drawn upon ***') print('Call Window.Finalize() prior to this operation') return None return self._TKCanvas2.create_oval(converted_point[0] - size, converted_point[1] - size, converted_point[0] + size, converted_point[1] + size, fill=color, outline=color) def DrawCircle(self, center_location, radius, fill_color=None, line_color='black'): if center_location == (None, None): return converted_point = self._convert_xy_to_canvas_xy(center_location[0], center_location[1]) if self._TKCanvas2 is None: print('*** WARNING - The Graph element has not been finalized and cannot be drawn upon ***') print('Call Window.Finalize() prior to this operation') return None return self._TKCanvas2.create_oval(converted_point[0] - radius, converted_point[1] - radius, converted_point[0] + radius, converted_point[1] + radius, fill=fill_color, outline=line_color) def DrawOval(self, top_left, bottom_right, fill_color=None, line_color=None): converted_top_left = self._convert_xy_to_canvas_xy(top_left[0], top_left[1]) converted_bottom_right = self._convert_xy_to_canvas_xy(bottom_right[0], bottom_right[1]) if self._TKCanvas2 is None: print('*** WARNING - The Graph element has not been finalized and cannot be drawn upon ***') print('Call Window.Finalize() prior to this operation') return None return self._TKCanvas2.create_oval(converted_top_left[0], converted_top_left[1], converted_bottom_right[0], converted_bottom_right[1], fill=fill_color, outline=line_color) def DrawArc(self, top_left, bottom_right, extent, start_angle, style=None, arc_color='black'): converted_top_left = self._convert_xy_to_canvas_xy(top_left[0], top_left[1]) converted_bottom_right = self._convert_xy_to_canvas_xy(bottom_right[0], bottom_right[1]) tkstyle = tk.PIESLICE if style is None else style if self._TKCanvas2 is None: print('*** WARNING - The Graph element has not been finalized and cannot be drawn upon ***') print('Call Window.Finalize() prior to this operation') return None return self._TKCanvas2.create_arc(converted_top_left[0], converted_top_left[1], converted_bottom_right[0], converted_bottom_right[1], extent=extent, start=start_angle, style=tkstyle, outline=arc_color) def DrawRectangle(self, top_left, bottom_right, fill_color=None, line_color=None): converted_top_left = self._convert_xy_to_canvas_xy(top_left[0], top_left[1]) converted_bottom_right = self._convert_xy_to_canvas_xy(bottom_right[0], bottom_right[1]) if self._TKCanvas2 is None: print('*** WARNING - The Graph element has not been finalized and cannot be drawn upon ***') print('Call Window.Finalize() prior to this operation') return None return self._TKCanvas2.create_rectangle(converted_top_left[0], converted_top_left[1], converted_bottom_right[0], converted_bottom_right[1], fill=fill_color, outline=line_color) def DrawText(self, text, location, color='black', font=None, angle=0): if location == (None, None): return converted_point = self._convert_xy_to_canvas_xy(location[0], location[1]) if self._TKCanvas2 is None: print('*** WARNING - The Graph element has not been finalized and cannot be drawn upon ***') print('Call Window.Finalize() prior to this operation') return None text_id = self._TKCanvas2.create_text(converted_point[0], converted_point[1], text=text, font=font, fill=color, angle=angle) return text_id def Erase(self): if self._TKCanvas2 is None: print('*** WARNING - The Graph element has not been finalized and cannot be drawn upon ***') print('Call Window.Finalize() prior to this operation') return None self._TKCanvas2.delete('all') def Update(self, background_color): if self._TKCanvas2 is None: print('*** WARNING - The Graph element has not been finalized and cannot be drawn upon ***') print('Call Window.Finalize() prior to this operation') return None self._TKCanvas2.configure(background=background_color) def Move(self, x_direction, y_direction): zero_converted = self._convert_xy_to_canvas_xy(0, 0) shift_converted = self._convert_xy_to_canvas_xy(x_direction, y_direction) shift_amount = (shift_converted[0] - zero_converted[0], shift_converted[1] - zero_converted[1]) if self._TKCanvas2 is None: print('*** WARNING - The Graph element has not been finalized and cannot be drawn upon ***') print('Call Window.Finalize() prior to this operation') return None self._TKCanvas2.move('all', shift_amount[0], shift_amount[1]) def MoveFigure(self, figure, x_direction, y_direction): zero_converted = self._convert_xy_to_canvas_xy(0, 0) shift_converted = self._convert_xy_to_canvas_xy(x_direction, y_direction) shift_amount = (shift_converted[0] - zero_converted[0], shift_converted[1] - zero_converted[1]) if figure is None: print('*** WARNING - Your figure is None. It most likely means your did not Finalize your Window ***') print('Call Window.Finalize() prior to all graph operations') return None self._TKCanvas2.move(figure, shift_amount[0], shift_amount[1]) @property def TKCanvas(self): if self._TKCanvas2 is None: print('*** Did you forget to call Finalize()? Your code should look something like: ***') print('*** form = sg.Window("My Form").Layout(layout).Finalize() ***') return self._TKCanvas2 # Realtime button release callback def ButtonReleaseCallBack(self, event): self.ClickPosition = (None, None) self.LastButtonClickedWasRealtime = not self.DragSubmits if self.Key is not None: self.ParentForm.LastButtonClicked = self.Key else: self.ParentForm.LastButtonClicked = '__GRAPH__' # need to put something rather than None if self.ParentForm.CurrentlyRunningMainloop: self.ParentForm.TKroot.quit() if self.DragSubmits: self.ParentForm.LastButtonClicked = None self.MouseButtonDown = False # Realtime button callback def ButtonPressCallBack(self, event): self.ClickPosition = self._convert_canvas_xy_to_xy(event.x, event.y) self.ParentForm.LastButtonClickedWasRealtime = self.DragSubmits if self.Key is not None: self.ParentForm.LastButtonClicked = self.Key else: self.ParentForm.LastButtonClicked = '__GRAPH__' # need to put something rather than None if self.ParentForm.CurrentlyRunningMainloop: self.ParentForm.TKroot.quit() # kick out of loop if read was called self.MouseButtonDown = True # Realtime button callback def MotionCallBack(self, event): if not self.MouseButtonDown: return self.ClickPosition = self._convert_canvas_xy_to_xy(event.x, event.y) self.ParentForm.LastButtonClickedWasRealtime = self.DragSubmits if self.Key is not None: self.ParentForm.LastButtonClicked = self.Key else: self.ParentForm.LastButtonClicked = '__GRAPH__' # need to put something rather than None if self.ParentForm.CurrentlyRunningMainloop: self.ParentForm.TKroot.quit() # kick out of loop if read was called def __del__(self): super().__del__() # ---------------------------------------------------------------------- # # Frame # # ---------------------------------------------------------------------- # class Frame(Element): def __init__(self, title, layout, title_color=None, background_color=None, title_location=None, relief=DEFAULT_FRAME_RELIEF, size=(None, None), font=None, pad=None, border_width=None, key=None, tooltip=None): ''' Frame Element :param title: :param layout: :param title_color: :param background_color: :param title_location: :param relief: :param size: :param font: :param pad: :param border_width: :param key: :param tooltip: ''' self.UseDictionary = False self.ReturnValues = None self.ReturnValuesList = [] self.ReturnValuesDictionary = {} self.DictionaryKeyCounter = 0 self.ParentWindow = None self.Rows = [] # self.ParentForm = None self.TKFrame = None self.Title = title self.Relief = relief self.TitleLocation = title_location self.BorderWidth = border_width self.BackgroundColor = background_color if background_color is not None else DEFAULT_BACKGROUND_COLOR self.Layout(layout) super().__init__(ELEM_TYPE_FRAME, background_color=background_color, text_color=title_color, size=size, font=font, pad=pad, key=key, tooltip=tooltip) return def AddRow(self, *args): ''' Parms are a variable number of Elements ''' NumRows = len(self.Rows) # number of existing rows is our row number CurrentRowNumber = NumRows # this row's number CurrentRow = [] # start with a blank row and build up # ------------------------- Add the elements to a row ------------------------- # for i, element in enumerate(args): # Loop through list of elements and add them to the row element.Position = (CurrentRowNumber, i) element.ParentContainer = self CurrentRow.append(element) if element.Key is not None: self.UseDictionary = True # ------------------------- Append the row to list of Rows ------------------------- # self.Rows.append(CurrentRow) def Layout(self, rows): for row in rows: self.AddRow(*row) def _GetElementAtLocation(self, location): (row_num, col_num) = location row = self.Rows[row_num] element = row[col_num] return element def __del__(self): for row in self.Rows: for element in row: element.__del__() super().__del__() # ---------------------------------------------------------------------- # # Separator # # Routes stdout, stderr to a scrolled window # # ---------------------------------------------------------------------- # class VerticalSeparator(Element): def __init__(self, pad=None): ''' VerticalSeperator - A separator that spans only 1 row in a vertical fashion :param pad: ''' self.Orientation = 'vertical' # for now only vertical works super().__init__(ELEM_TYPE_SEPARATOR, pad=pad) def __del__(self): super().__del__() VSeperator = VerticalSeparator VSep = VerticalSeparator # ---------------------------------------------------------------------- # # Tab # # ---------------------------------------------------------------------- # class Tab(Element): def __init__(self, title, layout, title_color=None, background_color=None, font=None, pad=None, disabled=False, border_width=None, key=None, tooltip=None): ''' Tab Element :param title: :param layout: :param title_color: :param background_color: :param font: :param pad: :param disabled: :param border_width: :param key: :param tooltip: ''' self.UseDictionary = False self.ReturnValues = None self.ReturnValuesList = [] self.ReturnValuesDictionary = {} self.DictionaryKeyCounter = 0 self.ParentWindow = None self.Rows = [] self.TKFrame = None self.Title = title self.BorderWidth = border_width self.Disabled = disabled self.ParentNotebook = None self.TabID = None self.BackgroundColor = background_color if background_color is not None else DEFAULT_BACKGROUND_COLOR self.Layout(layout) super().__init__(ELEM_TYPE_TAB, background_color=background_color, text_color=title_color, font=font, pad=pad, key=key, tooltip=tooltip) return def AddRow(self, *args): ''' Parms are a variable number of Elements ''' NumRows = len(self.Rows) # number of existing rows is our row number CurrentRowNumber = NumRows # this row's number CurrentRow = [] # start with a blank row and build up # ------------------------- Add the elements to a row ------------------------- # for i, element in enumerate(args): # Loop through list of elements and add them to the row element.Position = (CurrentRowNumber, i) element.ParentContainer = self CurrentRow.append(element) if element.Key is not None: self.UseDictionary = True # ------------------------- Append the row to list of Rows ------------------------- # self.Rows.append(CurrentRow) def Layout(self, rows): for row in rows: self.AddRow(*row) return self def Update(self, disabled=None): # TODO Disable / enable of tabs is not complete if disabled is None: return self.Disabled = disabled state = 'disabled' if disabled is True else 'normal' self.ParentNotebook.tab(self.TabID, state=state) return self def _GetElementAtLocation(self, location): (row_num, col_num) = location row = self.Rows[row_num] element = row[col_num] return element def __del__(self): for row in self.Rows: for element in row: element.__del__() super().__del__() # ---------------------------------------------------------------------- # # TabGroup # # ---------------------------------------------------------------------- # class TabGroup(Element): def __init__(self, layout, tab_location=None, title_color=None, selected_title_color=None, background_color=None, font=None, change_submits=False, pad=None, border_width=None, theme=None, key=None, tooltip=None): ''' TabGroup Element :param layout: :param tab_location: :param title_color: :param selected_title_color: :param background_color: :param font: :param change_submits: :param pad: :param border_width: :param theme: :param key: :param tooltip: ''' self.UseDictionary = False self.ReturnValues = None self.ReturnValuesList = [] self.ReturnValuesDictionary = {} self.DictionaryKeyCounter = 0 self.ParentWindow = None self.SelectedTitleColor = selected_title_color self.Rows = [] self.TKNotebook = None self.TabCount = 0 self.BorderWidth = border_width self.Theme = theme self.BackgroundColor = background_color if background_color is not None else DEFAULT_BACKGROUND_COLOR self.ChangeSubmits = change_submits self.TabLocation = tab_location self.Layout(layout) super().__init__(ELEM_TYPE_TAB_GROUP, background_color=background_color, text_color=title_color, font=font, pad=pad, key=key, tooltip=tooltip) return def AddRow(self, *args): ''' Parms are a variable number of Elements ''' NumRows = len(self.Rows) # number of existing rows is our row number CurrentRowNumber = NumRows # this row's number CurrentRow = [] # start with a blank row and build up # ------------------------- Add the elements to a row ------------------------- # for i, element in enumerate(args): # Loop through list of elements and add them to the row element.Position = (CurrentRowNumber, i) element.ParentContainer = self CurrentRow.append(element) if element.Key is not None: self.UseDictionary = True # ------------------------- Append the row to list of Rows ------------------------- # self.Rows.append(CurrentRow) def Layout(self, rows): for row in rows: self.AddRow(*row) def _GetElementAtLocation(self, location): (row_num, col_num) = location row = self.Rows[row_num] element = row[col_num] return element def FindKeyFromTabName(self, tab_name): for row in self.Rows: for element in row: if element.Title == tab_name: return element.Key return None def __del__(self): for row in self.Rows: for element in row: element.__del__() super().__del__() # ---------------------------------------------------------------------- # # Slider # # ---------------------------------------------------------------------- # class Slider(Element): def __init__(self, range=(None, None), default_value=None, resolution=None, tick_interval=None, orientation=None, border_width=None, relief=None, change_submits=False, disabled=False, size=(None, None), font=None, background_color=None, text_color=None, key=None, pad=None, tooltip=None): ''' Slider Element :param range: :param default_value: :param resolution: :param orientation: :param border_width: :param relief: :param change_submits: :param disabled: :param size: :param font: :param background_color: :param text_color: :param key: :param pad: :param tooltip: ''' self.TKScale = None self.Range = (1, 10) if range == (None, None) else range self.DefaultValue = self.Range[0] if default_value is None else default_value self.Orientation = orientation if orientation else DEFAULT_SLIDER_ORIENTATION self.BorderWidth = border_width if border_width else DEFAULT_SLIDER_BORDER_WIDTH self.Relief = relief if relief else DEFAULT_SLIDER_RELIEF self.Resolution = 1 if resolution is None else resolution self.ChangeSubmits = change_submits self.Disabled = disabled self.TickInterval = tick_interval temp_size = size if temp_size == (None, None): temp_size = (20, 20) if orientation.startswith('h') else (8, 20) super().__init__(ELEM_TYPE_INPUT_SLIDER, size=temp_size, font=font, background_color=background_color, text_color=text_color, key=key, pad=pad, tooltip=tooltip) return def Update(self, value=None, range=(None, None), disabled=None): if value is not None: try: self.TKIntVar.set(value) if range != (None, None): self.TKScale.config(from_=range[0], to_=range[1]) except: pass self.DefaultValue = value if disabled == True: self.TKScale['state'] = 'disabled' elif disabled == False: self.TKScale['state'] = 'normal' def SliderChangedHandler(self, event): # first, get the results table built # modify the Results table in the parent FlexForm object if self.Key is not None: self.ParentForm.LastButtonClicked = self.Key else: self.ParentForm.LastButtonClicked = '' self.ParentForm.FormRemainedOpen = True if self.ParentForm.CurrentlyRunningMainloop: self.ParentForm.TKroot.quit() # kick the users out of the mainloop def __del__(self): super().__del__() # # ---------------------------------------------------------------------- # # Column # # ---------------------------------------------------------------------- # class Column(Element): def __init__(self, layout, background_color=None, size=(None, None), size_px=(None, None), pad=None, scrollable=False, vertical_scroll_only=False, right_click_menu=None, key=None, visible=True): ''' Column Element :param layout: :param background_color: :param size: :param pad: :param scrollable: :param key: ''' self.UseDictionary = False self.ReturnValues = None self.ReturnValuesList = [] self.ReturnValuesDictionary = {} self.DictionaryKeyCounter = 0 self.ParentWindow = None self.Rows = [] self.Scrollable = scrollable self.VerticalScrollOnly = vertical_scroll_only self.RightClickMenu = right_click_menu bg = background_color if background_color is not None else DEFAULT_BACKGROUND_COLOR self.WxBoxSizer = None # type: wx.BoxSizer self.WxHSizer = None # type: wx.BoxSizer self.Layout(layout) super().__init__(ELEM_TYPE_COLUMN, background_color=background_color, size=size, size_px=size_px, pad=pad, key=key, visible=visible) return def AddRow(self, *args): ''' Parms are a variable number of Elements ''' NumRows = len(self.Rows) # number of existing rows is our row number CurrentRowNumber = NumRows # this row's number CurrentRow = [] # start with a blank row and build up # ------------------------- Add the elements to a row ------------------------- # for i, element in enumerate(args): # Loop through list of elements and add them to the row element.Position = (CurrentRowNumber, i) element.ParentContainer = self CurrentRow.append(element) if element.Key is not None: self.UseDictionary = True # ------------------------- Append the row to list of Rows ------------------------- # self.Rows.append(CurrentRow) def Layout(self, rows): for row in rows: self.AddRow(*row) def _GetElementAtLocation(self, location): (row_num, col_num) = location row = self.Rows[row_num] element = row[col_num] return element def Update(self, visible=None): if visible: self.WxHSizer.Show(self.WxBoxSizer, recursive=True) self.ParentForm.VisibilityChanged() elif visible is False: self.WxHSizer.Hide(self.WxBoxSizer, recursive=True) self.ParentForm.VisibilityChanged() def __del__(self): for row in self.Rows: for element in row: element.__del__() try: del (self.TKFrame) except: pass super().__del__() # ---------------------------------------------------------------------- # # Menu # # ---------------------------------------------------------------------- # class Menu(Element): def __init__(self, menu_definition, background_color=None, size=(None, None), tearoff=False, pad=None, key=None): ''' Menu Element :param menu_definition: :param background_color: :param size: :param tearoff: :param pad: :param key: ''' self.BackgroundColor = background_color if background_color is not None else DEFAULT_BACKGROUND_COLOR self.MenuDefinition = menu_definition self.TKMenu = None self.Tearoff = tearoff super().__init__(ELEM_TYPE_MENUBAR, background_color=background_color, size=size, pad=pad, key=key) return def MenuItemChosenCallback(self, item_chosen): # print('IN MENU ITEM CALLBACK', item_chosen) self.ParentForm.LastButtonClicked = item_chosen self.ParentForm.FormRemainedOpen = True if self.ParentForm.CurrentlyRunningMainloop: self.ParentForm.TKroot.quit() # kick the users out of the mainloop def __del__(self): super().__del__() # ---------------------------------------------------------------------- # # Table # # ---------------------------------------------------------------------- # class Table(Element): def __init__(self, values, headings=None, visible_column_map=None, col_widths=None, def_col_width=10, auto_size_columns=True, max_col_width=20, select_mode=None, display_row_numbers=False, num_rows=None, font=None, justification='right', text_color=None, background_color=None, alternating_row_color=None, size=(None, None), change_submits=False, bind_return_key=False, pad=None, key=None, tooltip=None): ''' Table Element :param values: :param headings: :param visible_column_map: :param col_widths: :param def_col_width: :param auto_size_columns: :param max_col_width: :param select_mode: :param display_row_numbers: :param font: :param justification: :param text_color: :param background_color: :param size: :param pad: :param key: :param tooltip: ''' self.Values = values self.ColumnHeadings = headings self.ColumnsToDisplay = visible_column_map self.ColumnWidths = col_widths self.MaxColumnWidth = max_col_width self.DefaultColumnWidth = def_col_width self.AutoSizeColumns = auto_size_columns self.BackgroundColor = background_color if background_color is not None else DEFAULT_BACKGROUND_COLOR self.TextColor = text_color self.Justification = justification self.InitialState = None self.SelectMode = select_mode self.DisplayRowNumbers = display_row_numbers self.NumRows = num_rows if num_rows is not None else size[1] self.TKTreeview = None self.AlternatingRowColor = alternating_row_color self.SelectedRows = [] self.ChangeSubmits = change_submits self.BindReturnKey = bind_return_key self.StartingRowNumber = 0 # When displaying row numbers, where to start self.RowHeaderText = 'Row' super().__init__(ELEM_TYPE_TABLE, text_color=text_color, background_color=background_color, font=font, size=size, pad=pad, key=key, tooltip=tooltip) return def Update(self, values=None): if values is not None: children = self.TKTreeview.get_children() for i in children: self.TKTreeview.detach(i) self.TKTreeview.delete(i) children = self.TKTreeview.get_children() # self.TKTreeview.delete(*self.TKTreeview.get_children()) for i, value in enumerate(values): if self.DisplayRowNumbers: value = [i + self.StartingRowNumber] + value id = self.TKTreeview.insert('', 'end', text=i, iid=i + 1, values=value, tag=i % 2) if self.AlternatingRowColor is not None: self.TKTreeview.tag_configure(1, background=self.AlternatingRowColor) self.Values = values self.SelectedRows = [] def treeview_selected(self, event): selections = self.TKTreeview.selection() self.SelectedRows = [int(x) - 1 for x in selections] if self.ChangeSubmits: MyForm = self.ParentForm if self.Key is not None: self.ParentForm.LastButtonClicked = self.Key else: self.ParentForm.LastButtonClicked = '' self.ParentForm.FormRemainedOpen = True if self.ParentForm.CurrentlyRunningMainloop: self.ParentForm.TKroot.quit() def treeview_double_click(self, event): selections = self.TKTreeview.selection() self.SelectedRows = [int(x) - 1 for x in selections] if self.BindReturnKey: MyForm = self.ParentForm if self.Key is not None: self.ParentForm.LastButtonClicked = self.Key else: self.ParentForm.LastButtonClicked = '' self.ParentForm.FormRemainedOpen = True if self.ParentForm.CurrentlyRunningMainloop: self.ParentForm.TKroot.quit() def __del__(self): super().__del__() # ---------------------------------------------------------------------- # # Tree # # ---------------------------------------------------------------------- # class Tree(Element): def __init__(self, data=None, headings=None, visible_column_map=None, col_widths=None, col0_width=10, def_col_width=10, auto_size_columns=True, max_col_width=20, select_mode=None, show_expanded=False, change_submits=False, font=None, justification='right', text_color=None, background_color=None, num_rows=None, pad=None, key=None, tooltip=None): ''' Tree Element :param headings: :param visible_column_map: :param col_widths: :param def_col_width: :param auto_size_columns: :param max_col_width: :param select_mode: :param font: :param justification: :param text_color: :param background_color: :param num_rows: :param pad: :param key: :param tooltip: ''' self.TreeData = data self.ColumnHeadings = headings self.ColumnsToDisplay = visible_column_map self.ColumnWidths = col_widths self.MaxColumnWidth = max_col_width self.DefaultColumnWidth = def_col_width self.AutoSizeColumns = auto_size_columns self.BackgroundColor = background_color if background_color is not None else DEFAULT_BACKGROUND_COLOR self.TextColor = text_color self.Justification = justification self.InitialState = None self.SelectMode = select_mode self.ShowExpanded = show_expanded self.NumRows = num_rows self.Col0Width = col0_width self.TKTreeview = None self.SelectedRows = [] self.ChangeSubmits = change_submits super().__init__(ELEM_TYPE_TREE, text_color=text_color, background_color=background_color, font=font, pad=pad, key=key, tooltip=tooltip) return def treeview_selected(self, event): selections = self.TKTreeview.selection() self.SelectedRows = [x for x in selections] if self.ChangeSubmits: MyForm = self.ParentForm if self.Key is not None: self.ParentForm.LastButtonClicked = self.Key else: self.ParentForm.LastButtonClicked = '' self.ParentForm.FormRemainedOpen = True if self.ParentForm.CurrentlyRunningMainloop: self.ParentForm.TKroot.quit() def add_treeview_data(self, node): # print(f'Inserting {node.key} under parent {node.parent}') if node.key != '': self.TKTreeview.insert(node.parent, 'end', node.key, text=node.text, values=node.values, open=self.ShowExpanded) for node in node.children: self.add_treeview_data(node) def Update(self, values=None, key=None, value=None, text=None): if values is not None: children = self.TKTreeview.get_children() for i in children: self.TKTreeview.detach(i) self.TKTreeview.delete(i) children = self.TKTreeview.get_children() self.TreeData = values self.add_treeview_data(self.TreeData.root_node) self.SelectedRows = [] if key is not None: item = self.TKTreeview.item(key) if value is not None: self.TKTreeview.item(key, values=value) if text is not None: self.TKTreeview.item(key, text=text) item = self.TKTreeview.item(key) return self def __del__(self): super().__del__() class TreeData(object): class Node(object): def __init__(self, parent, key, text, values): self.parent = parent self.children = [] self.key = key self.text = text self.values = values def _Add(self, node): self.children.append(node) def __init__(self): self.tree_dict = {} self.root_node = self.Node("", "", 'root', []) self.tree_dict[""] = self.root_node def _AddNode(self, key, node): self.tree_dict[key] = node def Insert(self, parent, key, text, values): node = self.Node(parent, key, text, values) self.tree_dict[key] = node parent_node = self.tree_dict[parent] parent_node._Add(node) def __repr__(self): return self._NodeStr(self.root_node, 1) def _NodeStr(self, node, level): return '\n'.join( [str(node.key) + ' : ' + str(node.text)] + [' ' * 4 * level + self._NodeStr(child, level + 1) for child in node.children]) # ---------------------------------------------------------------------- # # Error Element # # ---------------------------------------------------------------------- # class ErrorElement(Element): def __init__(self, key=None): ''' Error Element :param key: ''' self.Key = key super().__init__(ELEM_TYPE_ERROR, key=key) return def Update(self, *args, **kwargs): PopupError('Keyword error in Update', 'You need to stop this madness and check your spelling', 'Bad key = {}'.format(self.Key), 'Your bad line of code may resemble this:', 'window.FindElement("{}")'.format(self.Key)) return self def Get(self): return 'This is NOT a valid Element!\nSTOP trying to do things with it or I will have to crash at some point!' def __del__(self): super().__del__() Stretch = ErrorElement # ------------------------------------------------------------------------- # # Tray CLASS # # ------------------------------------------------------------------------- # class SystemTray: def __init__(self, menu=None, filename=None, data=None, data_base64=None, tooltip=None): ''' SystemTray - create an icon in the system tray :param menu: Menu definition :param filename: filename for icon :param data: in-ram image for icon :param data_base64: basee-64 data for icon :param tooltip: tooltip string ''' self.Menu = menu self.TrayIcon = None self.Shown = False self.MenuItemChosen = TIMEOUT_KEY self.LastMessage = None self.LastTitle = None self.App = None self.Filename = filename self.timer = None self.DataBase64 = data_base64 if Window.highest_level_app is None: self.App = Window.highest_level_app = wx.App(False) else: self.App = Window.highest_level_app self.Tooltip = tooltip frame = wx.Frame(None, title='Tray icon frame') if filename: self.icon = wx.Icon(filename, wx.BITMAP_TYPE_ANY) elif data_base64: self.icon = PyEmbeddedImage(data_base64).GetIcon() else: self.icon = PyEmbeddedImage(DEFAULT_BASE64_ICON).GetIcon() self.TaskBarIcon = self.CustomTaskBarIcon(frame, self.App, self.Menu, self.icon, tooltip=tooltip) # self.App.MainLoop() class CustomTaskBarIcon(wx.adv.TaskBarIcon): def __init__(self, frame, app, menu, icon, tooltip=None): wx.adv.TaskBarIcon.__init__(self) self.frame = frame self.app = app self.menu_item_chosen = None self.menu = menu self.id_to_text = {} self.tooltip = tooltip or wx.EmptyString self.SetIcon(icon, tooltip=self.tooltip) self.Bind(wx.adv.EVT_TASKBAR_LEFT_DOWN, self.OnTaskBarLeftClick) self.Bind(wx.adv.EVT_TASKBAR_LEFT_DCLICK, self.OnTaskBarLeftDoubleClick) self.Bind(wx.adv.EVT_TASKBAR_RIGHT_DOWN, self.OnTaskBarRightClick) self.Bind(wx.adv.EVT_TASKBAR_BALLOON_CLICK, self.OnTaskBarMessageClick) self.Bind(wx.EVT_MENU, self.OnMenu) def OnTaskBarActivate(self, evt): pass def OnTaskBarClose(self, evt): self.frame.Close() def OnTaskBarLeftClick(self, evt): # print('Got a LEFT click!') self.menu_item_chosen = EVENT_SYSTEM_TRAY_ICON_ACTIVATED self.app.ExitMainLoop() def OnTaskBarMessageClick(self, evt): # print('Got a LEFT click!') self.menu_item_chosen = EVENT_SYSTEM_TRAY_MESSAGE_CLICKED self.app.ExitMainLoop() def OnTaskBarLeftDoubleClick(self, evt): # print('Got a double click!') self.menu_item_chosen = EVENT_SYSTEM_TRAY_ICON_DOUBLE_CLICKED self.app.ExitMainLoop() def CreatePopupMenu(self): # print(f'Popup menu = {self.menu}') menu = wx.Menu() AddMenuItem(menu, self.menu[1], self) return menu def OnTaskBarRightClick(self, evt): # print('Got a right click!') self.menu_item_chosen = EVENT_SYSTEM_TRAY_ICON_RIGHT_CLICK # self.app.ExitMainLoop() def OnMenu(self, event): # print(f'On Menu {event}') menu = event.EventObject text='' item = menu.FindItemById(event.Id) # for item in menu.MenuItems: # if item.Id == event.Id: # print('** FOUND MENU ENTRY! **') # print(f'item = {item}') text = self.id_to_text[item] # text = self.id_to_text[item.Id] self.menu_item_chosen = text self.app.ExitMainLoop() def Read(self, timeout=None): ''' Reads the context menu :param timeout: Optional. Any value other than None indicates a non-blocking read :return: ''' # if not self.Shown: # self.Shown = True # self.TrayIcon.show() timeout1 = timeout # if timeout1 == 0: # timeout1 = 1 # if wx.GetApp(): # wx.GetApp().ProcessPendingEvents() # self.App.ProcessPendingEvents() # self.App.ProcessIdle() # return self.MenuItemChosen if timeout1 is not None: try: self.timer = wx.Timer(self.TaskBarIcon) self.TaskBarIcon.Bind(wx.EVT_TIMER, self.timer_timeout) self.timer.Start(milliseconds=timeout1, oneShot=wx.TIMER_ONE_SHOT) except: print('*** Got error in Read ***') self.RunningMainLoop = True self.App.MainLoop() self.RunningMainLoop = False if self.timer: self.timer.Stop() self.MenuItemChosen = self.TaskBarIcon.menu_item_chosen return self.MenuItemChosen def timer_timeout(self, event): self.timer = None self.TaskBarIcon.menu_item_chosen = TIMEOUT_KEY self.App.ExitMainLoop() def Hide(self): self.TaskBarIcon.RemoveIcon() def UnHide(self): self.TaskBarIcon.SetIcon(icon=self.TaskBarIcon.icon, tooltip=self.TaskBarIcon.tooltip) def ShowMessage(self, title, message, filename=None, data=None, data_base64=None, messageicon=None, time=10000): ''' Shows a balloon above icon in system tray :param title: Title shown in balloon :param message: Message to be displayed :param filename: Optional icon filename :param data: Optional in-ram icon :param data_base64: Optional base64 icon :param time: How long to display message in milliseconds :return: ''' if messageicon is None: self.TaskBarIcon.ShowBalloon(title, message, msec=time) else: self.TaskBarIcon.ShowBalloon(title, message, msec=time, flags=messageicon) return self def Close(self): ''' :return: ''' self.TrayIcon.Hide() # Don't close app because windows could be depending on it # self.App.quit() def Update(self, menu=None, tooltip=None,filename=None, data=None, data_base64=None,): ''' Updates the menu, tooltip or icon :param menu: menu defintion :param tooltip: string representing tooltip :param filename: icon filename :param data: icon raw image :param data_base64: icon base 64 image :return: ''' # Menu if menu is not None: self.TaskBarIcon.menu = menu if filename: self.icon = wx.Icon(filename, wx.BITMAP_TYPE_ANY) elif data_base64: self.icon = PyEmbeddedImage(data_base64).GetIcon() elif not self.icon: self.icon = PyEmbeddedImage(DEFAULT_BASE64_ICON).GetIcon() if self.icon: self.Tooltip = tooltip or self.Tooltip self.TaskBarIcon.SetIcon(self.icon, tooltip=self.Tooltip) # Tooltip # if tooltip is not None: # self.TrayIcon.setToolTip(str(tooltip)) # Icon # qicon = None # if filename is not None: # icon = wx.Icon(filename, wx.BITMAP_TYPE_ICO) # self.TaskBarIcon.SetIcon(icon, tooltip=tooltip) # elif data is not None: # ba = QtCore.QByteArray.fromRawData(data) # pixmap = QtGui.QPixmap() # pixmap.loadFromData(ba) # qicon = QIcon(pixmap) # elif data_base64 is not None: # ico1 = base64.b64decode(data_base64) # fout = open("zzztemp_icon.ico", "wb") # fout.write(ico1) # fout.close() # icon = wx.Icon('zzztemp_icon.ico', wx.BITMAP_TYPE_ICO) # self.TrayIcon.SetIcon(icon, tooltip=tooltip) # os.remove("zzztemp_icon.ico") # if qicon is not None: # self.TrayIcon.setIcon(qicon) class DragFrame(wx.Frame): def __init__(self, title=''): wx.Frame.__init__(self, None, title=title) def on_mouse(self, event): ''' implement dragging ''' # print('on_mouse') if not event.Dragging(): self._dragPos = None return # self.CaptureMouse() if not self._dragPos: self._dragPos = event.GetPosition() else: pos = event.GetPosition() displacement = self._dragPos - pos self.SetPosition( self.GetPosition() - displacement ) # ------------------------------------------------------------------------- # # Window CLASS # # ------------------------------------------------------------------------- # class Window: NumOpenWindows = 0 user_defined_icon = None hidden_master_root = None QTApplication = None active_popups = {} highest_level_app = None stdout_is_rerouted = False stdout_location = None def __init__(self, title, default_element_size=DEFAULT_ELEMENT_SIZE, default_button_element_size=(None, None), auto_size_text=None, auto_size_buttons=None, location=(None, None), size=(None, None), element_padding=None, button_color=None, font=None, progress_bar_color=(None, None), background_color=None, border_depth=None, auto_close=False, auto_close_duration=None, icon=DEFAULT_BASE64_ICON, force_toplevel=False, alpha_channel=1, return_keyboard_events=False, use_default_focus=True, text_justification=None, no_titlebar=False, grab_anywhere=False, keep_on_top=False, resizable=True, disable_close=False, disable_minimize=False, background_image=None): ''' :param title: :param default_element_size: :param default_button_element_size: :param auto_size_text: :param auto_size_buttons: :param location: :param size: :param element_padding: :param button_color: :param font: :param progress_bar_color: :param background_color: :param border_depth: :param auto_close: :param auto_close_duration: :param icon: :param force_toplevel: :param alpha_channel: :param return_keyboard_events: :param use_default_focus: :param text_justification: :param no_titlebar: :param grab_anywhere: :param keep_on_top: :param resizable: :param disable_close: :param background_image: ''' self.AutoSizeText = auto_size_text if auto_size_text is not None else DEFAULT_AUTOSIZE_TEXT self.AutoSizeButtons = auto_size_buttons if auto_size_buttons is not None else DEFAULT_AUTOSIZE_BUTTONS self.Title = title self.Rows = [] # a list of ELEMENTS for this row self.DefaultElementSize = convert_tkinter_size_to_Wx(default_element_size) self.DefaultButtonElementSize = convert_tkinter_size_to_Wx(default_button_element_size) if default_button_element_size != ( None, None) else DEFAULT_BUTTON_ELEMENT_SIZE self.Location = location self.ButtonColor = button_color if button_color else DEFAULT_BUTTON_COLOR self.BackgroundColor = background_color if background_color else DEFAULT_BACKGROUND_COLOR self.ParentWindow = None self.Font = font if font else DEFAULT_FONT self.RadioDict = {} self.BorderDepth = border_depth self.WindowIcon = icon if icon is not None else Window.user_defined_icon self.AutoClose = auto_close self.NonBlocking = False self.TKroot = None self.TKrootDestroyed = False self.CurrentlyRunningMainloop = False self.FormRemainedOpen = False self.TKAfterID = None self.ProgressBarColor = progress_bar_color self.AutoCloseDuration = auto_close_duration self.RootNeedsDestroying = False self.Shown = False self.ReturnValues = None self.ReturnValuesList = [] self.ReturnValuesDictionary = {} self.DictionaryKeyCounter = 0 self.LastButtonClicked = None self.LastButtonClickedWasRealtime = False self.UseDictionary = False self.UseDefaultFocus = use_default_focus self.ReturnKeyboardEvents = return_keyboard_events self.LastKeyboardEvent = None self.TextJustification = text_justification self.NoTitleBar = no_titlebar self.GrabAnywhere = grab_anywhere self.KeepOnTop = keep_on_top self.ForcefTopLevel = force_toplevel self.Resizable = resizable self._AlphaChannel = alpha_channel self.Timeout = None self.TimeoutKey = TIMEOUT_KEY self.TimerCancelled = False self.DisableClose = disable_close self._Hidden = False # self.QTApplication = None # self.QT_QMainWindow = None self._Size=size self.ElementPadding = element_padding or DEFAULT_ELEMENT_PADDING self.FocusElement = None self.BackgroundImage = background_image self.XFound = False self.DisableMinimize = disable_minimize self.App = None # type: wx.App self.MasterFrame = None # type: wx.Frame self.MasterPanel = None # type wx.Panel self.IgnoreClose = False @classmethod def IncrementOpenCount(self): self.NumOpenWindows += 1 # print('+++++ INCREMENTING Num Open Windows = {} ---'.format(Window.NumOpenWindows)) @classmethod def DecrementOpenCount(self): self.NumOpenWindows -= 1 * (self.NumOpenWindows != 0) # decrement if not 0 # print('----- DECREMENTING Num Open Windows = {} ---'.format(Window.NumOpenWindows)) # ------------------------- Add ONE Row to Form ------------------------- # def AddRow(self, *args): ''' Parms are a variable number of Elements ''' NumRows = len(self.Rows) # number of existing rows is our row number CurrentRowNumber = NumRows # this row's number CurrentRow = [] # start with a blank row and build up # ------------------------- Add the elements to a row ------------------------- # for i, element in enumerate(args): # Loop through list of elements and add them to the row element.Position = (CurrentRowNumber, i) element.ParentContainer = self CurrentRow.append(element) # ------------------------- Append the row to list of Rows ------------------------- # self.Rows.append(CurrentRow) # ------------------------- Add Multiple Rows to Form ------------------------- # def AddRows(self, rows): for row in rows: self.AddRow(*row) def Layout(self, rows): self.AddRows(rows) return self def LayoutAndRead(self, rows, non_blocking=False): raise DeprecationWarning('LayoutAndRead is no longer supported... change your call to window.Layout(layout).Read()') # self.AddRows(rows) # self.Show(non_blocking=non_blocking) # return self.ReturnValues def LayoutAndShow(self, rows): raise DeprecationWarning('LayoutAndShow is no longer supported... change your call to LayoutAndRead') # ------------------------- ShowForm THIS IS IT! ------------------------- # def Show(self, non_blocking=False): self.Shown = True # Compute num rows & num cols (it'll come in handy debugging) self.NumRows = len(self.Rows) self.NumCols = max(len(row) for row in self.Rows) self.NonBlocking = non_blocking # Search through entire form to see if any elements set the focus # if not, then will set the focus to the first input element found_focus = False for row in self.Rows: for element in row: try: if element.Focus: found_focus = True except: pass try: if element.Key is not None: self.UseDictionary = True except: pass if not found_focus and self.UseDefaultFocus: self.UseDefaultFocus = True else: self.UseDefaultFocus = False # -=-=-=-=-=-=-=-=- RUN the GUI -=-=-=-=-=-=-=-=- ## 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 self.ReturnValues # ------------------------- SetIcon - set the window's fav icon ------------------------- # def SetIcon(self, icon=None, pngbase64=None): pass def _GetElementAtLocation(self, location): (row_num, col_num) = location row = self.Rows[row_num] element = row[col_num] return element def _GetDefaultElementSize(self): return self.DefaultElementSize def _AutoCloseAlarmCallback(self): try: window = self if window: if window.NonBlocking: self.CloseNonBlockingForm() else: window._Close() if self.CurrentlyRunningMainloop: self.QTApplication.exit() # kick the users out of the mainloop self.RootNeedsDestroying = True self.QT_QMainWindow.close() except: pass def timer_timeout(self, event): # first, get the results table built # modify the Results table in the parent FlexForm object # print('timer timeout') if self.TimerCancelled: return self.LastButtonClicked = self.TimeoutKey self.FormRemainedOpen = True if self.CurrentlyRunningMainloop: self.App.ExitMainLoop() def non_block_timer_timeout(self, event): # print('non-blocking timer timeout') self.App.ExitMainLoop() def autoclose_timer_callback(self, frame): # print('*** AUTOCLOSE TIMEOUT CALLBACK ***', frame) try: frame.Close() except: pass # if user has already closed the frame will get an error if self.CurrentlyRunningMainloop: self.App.ExitMainLoop() def callback_keyboard_char(self, event:wx.KeyEvent): self.LastButtonClicked = None self.FormRemainedOpen = True if event.ClassName == 'wxMouseEvent': if event.WheelRotation < 0: self.LastKeyboardEvent = 'MouseWheel:Down' else: self.LastKeyboardEvent = 'MouseWheel:Up' else: self.LastKeyboardEvent = event.GetKeyCode() if not self.NonBlocking: BuildResults(self, False, self) if self.CurrentlyRunningMainloop: # quit if this is the current mainloop, otherwise don't quit! self.App.ExitMainLoop() # kick the users out of the mainloop if event.ClassName != 'wxMouseEvent': event.DoAllowNextEvent() def Read(self, timeout=None, timeout_key=TIMEOUT_KEY): if timeout == 0: # timeout of zero runs the old readnonblocking event, values = self._ReadNonBlocking() if event is None: event = timeout_key if values is None: event = None return event, values # make event None if values was None and return # Read with a timeout self.Timeout = timeout self.TimeoutKey = timeout_key self.NonBlocking = False if not self.Shown: self.Show() else: # 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) self.LastButtonClicked = None return results InitializeResults(self) # if the last button clicked was realtime, emulate a read non-blocking # the idea is to quickly return realtime buttons without any blocks until released if self.LastButtonClickedWasRealtime: # print(f'RTime down {self.LastButtonClicked}' ) try: rc = self.TKroot.update() except: self.TKrootDestroyed = True Window.DecrementOpenCount() results = BuildResults(self, False, self) if results[0] != None and results[0] != timeout_key: return results else: pass # else: # print("** REALTIME PROBLEM FOUND **", results) # normal read blocking code.... if timeout != None: self.TimerCancelled = False timer = wx.Timer(self.App) self.App.Bind(wx.EVT_TIMER, self.timer_timeout) timer.Start(milliseconds=timeout, oneShot=wx.TIMER_ONE_SHOT) else: timer = None self.CurrentlyRunningMainloop = True # print(f'In main {self.Title}') ################################# CALL GUWxTextCtrlI MAINLOOP ############################ self.App.MainLoop() self.CurrentlyRunningMainloop = False self.TimerCancelled = True if timer: timer.Stop() if Window.stdout_is_rerouted: sys.stdout = Window.stdout_location if self.RootNeedsDestroying: # self.LastButtonClicked = None # self.App.Close() try: self.MasterFrame.Close() except: pass Window.DecrementOpenCount() # if form was closed with X if self.LastButtonClicked is None and self.LastKeyboardEvent is None and self.ReturnValues[0] is None: Window.DecrementOpenCount() # Determine return values if self.LastKeyboardEvent is not None or self.LastButtonClicked is not None: results = BuildResults(self, False, self) if not self.LastButtonClickedWasRealtime: self.LastButtonClicked = None return results else: if not self.XFound and self.Timeout != 0 and self.Timeout is not None and self.ReturnValues[0] is None: # Special Qt case because returning for no reason so fake timeout self.ReturnValues = self.TimeoutKey, self.ReturnValues[1] # fake a timeout elif not self.XFound and self.ReturnValues[0] is None: # TODO HIGHLY EXPERIMENTAL... added due to tray icon interaction # print("*** Faking timeout ***") self.ReturnValues = self.TimeoutKey, self.ReturnValues[1] # fake a timeout return self.ReturnValues def _ReadNonBlocking(self): if self.TKrootDestroyed: return None, None if not self.Shown: self.Show(non_blocking=True) else: # event = wx.Event() # self.App.QueueEvent(event) timer = wx.Timer(self.App) self.App.Bind(wx.EVT_TIMER, self.timer_timeout) timer.Start(milliseconds=0, oneShot=wx.TIMER_ONE_SHOT) self.CurrentlyRunningMainloop = True # print(f'In main {self.Title}') ################################# CALL GUWxTextCtrlI MAINLOOP ############################ self.App.MainLoop() if Window.stdout_is_rerouted: sys.stdout = Window.stdout_location # self.LastButtonClicked = 'TEST' self.CurrentlyRunningMainloop = False timer.Stop() # while self.App.HasPendingEvents(): # self.App.ProcessPendingEvents() return BuildResults(self, False, self) def Finalize(self): if self.TKrootDestroyed: return self if not self.Shown: self.Show(non_blocking=True) # else: # try: # self.QTApplication.processEvents() # refresh the window # except: # print('* ERROR FINALIZING *') # self.TKrootDestroyed = True # Window.DecrementOpenCount() return self def Refresh(self): # self.QTApplication.processEvents() # refresh the window return self def VisibilityChanged(self): self.SizeChanged() return self def Fill(self, values_dict): FillFormWithValues(self, values_dict) return self def FindElement(self, key): element = _FindElementFromKeyInSubForm(self, key) if element is None: print('*** WARNING = FindElement did not find the key. Please check your key\'s spelling ***') PopupError('Keyword error in FindElement Call', 'Bad key = {}'.format(key), 'Your bad line of code may resemble this:', 'window.FindElement("{}")'.format(key)) return ErrorElement(key=key) return element Element = FindElement # shortcut function definition def FindElementWithFocus(self): return self.FocusElement # element = _FindElementWithFocusInSubForm(self) # return element def SaveToDisk(self, filename): try: results = BuildResults(self, False, self) with open(filename, 'wb') as sf: pickle.dump(results[1], sf) except: print('*** Error saving form to disk ***') def LoadFromDisk(self, filename): try: with open(filename, 'rb') as df: self.Fill(pickle.load(df)) except: print('*** Error loading form to disk ***') def GetScreenDimensions(self): size = wx.GetDisplaySize() return size def Move(self, x, y): self.MasterFrame.SetPosition((x,y)) def Minimize(self): self.MasterFrame.Iconize() def Maximize(self): self.MasterFrame.Maximize() def _Close(self): try: self.TKroot.update() except: pass if not self.NonBlocking: BuildResults(self, False, self) if self.TKrootDestroyed: return None self.TKrootDestroyed = True self.RootNeedsDestroying = True self.__del__() return None def Close(self): if self.TKrootDestroyed: return try: self.MasterFrame.Close() except: print('error closing window') CloseNonBlockingForm = Close CloseNonBlocking = Close def Disable(self): self.MasterFrame.Enable(False) def Enable(self): self.MasterFrame.Enable(True) def Hide(self): self._Hidden = True self.MasterFrame.Hide() return def UnHide(self): if self._Hidden: self.MasterFrame.Show() self._Hidden = False def Disappear(self): self.MasterFrame.SetTransparent(0) def Reappear(self): self.MasterFrame.SetTransparent(255) def SetAlpha(self, alpha): ''' Change the window's transparency :param alpha: From 0 to 1 with 0 being completely transparent :return: ''' self._AlphaChannel = alpha * 255 if self._AlphaChannel is not None: self.MasterFrame.SetTransparent(self._AlphaChannel) @property def AlphaChannel(self): return self._AlphaChannel @AlphaChannel.setter def AlphaChannel(self, alpha): self.SetAlpha(alpha) def BringToFront(self): self.MasterFrame.ToggleWindowStyle(wx.STAY_ON_TOP) def CurrentLocation(self): location = self.MasterFrame.GetPosition() return location def OnClose(self, event): # print(f'CLOSE EVENT! event = {event}') if self.DisableClose: return # print('GOT A CLOSE EVENT!', event, self.Window.Title) if not self.IgnoreClose: self.LastButtonClicked = None self.XFound = True if not self.CurrentlyRunningMainloop: # quit if this is the current mainloop, otherwise don't quit! self.RootNeedsDestroying = True else: self.RootNeedsDestroying = True self.App.ExitMainLoop() # kick the users out of the mainloop self.MasterFrame.Destroy() self.TKrootDestroyed = True self.RootNeedsDestroying = True # if self.CurrentlyRunningMainloop: # print("quitting window") # self.QTApplication.exit() # kick the users out of the mainloop @property def Size(self): size = self.MasterFrame.GetSize() return size @Size.setter def Size(self, size): self.MasterFrame.SetSize(size[0], size[1]) def SizeChanged(self): size = self.Size self.Size = size[0] + 1, size[1] + 1 self.Size = size self.MasterFrame.SetSizer(self.OuterSizer) self.OuterSizer.Fit(self.MasterFrame) def __enter__(self): return self def __exit__(self, *a): self.__del__() return False def __del__(self): # print(f'+++++ Window {self.Title} being deleted +++++') for row in self.Rows: for element in row: element.__del__() FlexForm = Window # =========================================================================== # # Stops the mainloop and sets the event information # # =========================================================================== # def element_callback_quit_mainloop(element): if element.Key is not None: element.ParentForm.LastButtonClicked = element.Key else: element.ParentForm.LastButtonClicked = '' element.ParentForm.FormRemainedOpen = True if element.ParentForm.CurrentlyRunningMainloop: element.ParentForm.App.ExitMainLoop() # kick the users out of the mainloop def quit_mainloop(window): window.App.ExitMainLoop() # =========================================================================== # # Stops the mainloop and sets the event information # # =========================================================================== # def convert_tkinter_size_to_Wx(size): """ Converts size in characters to size in pixels :param size: size in characters, rows :return: size in pixels, pixels """ qtsize = size if size[1] is not None and size[1] < DEFAULT_PIXEL_TO_CHARS_CUTOFF: # change from character based size to pixels (roughly) qtsize = size[0]*DEFAULT_PIXELS_TO_CHARS_SCALING[0], size[1]*DEFAULT_PIXELS_TO_CHARS_SCALING[1] return qtsize def font_to_wx_font(font): """ Convert from font string/tyuple into a Qt style sheet string :param font: "Arial 10 Bold" or ('Arial', 10, 'Bold) :return: style string that can be combined with other style strings """ if font is None: return '' if type(font) is str: _font = font.split(' ') else: _font = font name = _font[0] family = _font[0] point_size = int(_font[1]) # style = _font[2] underline = 'underline' in _font[2:] bold = 'bold' in _font wxfont = wx.Font(point_size, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD if bold else wx.FONTWEIGHT_NORMAL, underline, faceName=family) return wxfont def preprocess_radio_elements(top_window, window): for row in window.Rows: for element in row: if element.Type == ELEM_TYPE_INPUT_RADIO: if element.WxRadioButton is None: element.WxRadioButton = wx.RadioButton(top_window.MasterPanel, id=wx.ID_ANY, label=element.Text, style=wx.RB_GROUP) create_wx_radio_buttons(top_window, top_window, element.GroupID) if element.Type in (ELEM_TYPE_COLUMN, ELEM_TYPE_FRAME,ELEM_TYPE_TAB_GROUP, ELEM_TYPE_TAB) : preprocess_radio_elements(top_window, element) def create_wx_radio_buttons(top_window, window, group_id): for row in window.Rows: for element in row: if element.Type == ELEM_TYPE_INPUT_RADIO: if element.GroupID == group_id and element.WxRadioButton is None: element.WxRadioButton = wx.RadioButton(top_window.MasterPanel, id=wx.ID_ANY, label=element.Text ) if element.Type in (ELEM_TYPE_COLUMN, ELEM_TYPE_FRAME,ELEM_TYPE_TAB_GROUP, ELEM_TYPE_TAB) : create_wx_radio_buttons(top_window, element, group_id) # ################################################################################ # ################################################################################ # END OF ELEMENT DEFINITIONS # ################################################################################ # ################################################################################ # =========================================================================== # # Button Lazy Functions so the caller doesn't have to define a bunch of stuff # # =========================================================================== # # ------------------------- FOLDER BROWSE Element lazy function ------------------------- # def FolderBrowse(button_text='Browse', target=(ThisRow, -1), initial_folder=None, tooltip=None, size=(None, None), auto_size_button=None, button_color=None, disabled=False, change_submits=False, font=None, pad=None, key=None): return Button(button_text=button_text, button_type=BUTTON_TYPE_BROWSE_FOLDER, target=target, initial_folder=initial_folder, tooltip=tooltip, size=size, auto_size_button=auto_size_button, disabled=disabled, button_color=button_color, change_submits=change_submits, font=font, pad=pad, key=key) # ------------------------- FILE BROWSE Element lazy function ------------------------- # def FileBrowse(button_text='Browse', target=(ThisRow, -1), file_types=(("ALL Files", "*.*"),), initial_folder=None, tooltip=None, size=(None, None), auto_size_button=None, button_color=None, change_submits=False, font=None, disabled=False, pad=None, key=None): return Button(button_text=button_text, button_type=BUTTON_TYPE_BROWSE_FILE, target=target, file_types=file_types, initial_folder=initial_folder, tooltip=tooltip, size=size, auto_size_button=auto_size_button, change_submits=change_submits, disabled=disabled, button_color=button_color, font=font, pad=pad, key=key) # ------------------------- FILES BROWSE Element (Multiple file selection) lazy function ------------------------- # def FilesBrowse(button_text='Browse', target=(ThisRow, -1), file_types=(("ALL Files", "*.*"),), disabled=False, initial_folder=None, tooltip=None, size=(None, None), auto_size_button=None, button_color=None, change_submits=False, font=None, pad=None, key=None): return Button(button_text=button_text, button_type=BUTTON_TYPE_BROWSE_FILES, target=target, file_types=file_types, initial_folder=initial_folder, change_submits=change_submits, tooltip=tooltip, size=size, auto_size_button=auto_size_button, disabled=disabled, button_color=button_color, font=font, pad=pad, key=key) # ------------------------- FILE BROWSE Element lazy function ------------------------- # def FileSaveAs(button_text='Save As...', target=(ThisRow, -1), file_types=(("ALL Files", "*.*"),), initial_folder=None, disabled=False, tooltip=None, size=(None, None), auto_size_button=None, button_color=None, change_submits=False, font=None, pad=None, key=None): return Button(button_text=button_text, button_type=BUTTON_TYPE_SAVEAS_FILE, target=target, file_types=file_types, initial_folder=initial_folder, tooltip=tooltip, size=size, disabled=disabled, auto_size_button=auto_size_button, button_color=button_color, change_submits=change_submits, font=font, pad=pad, key=key) # ------------------------- SAVE AS Element lazy function ------------------------- # def SaveAs(button_text='Save As...', target=(ThisRow, -1), file_types=(("ALL Files", "*.*"),), initial_folder=None, disabled=False, tooltip=None, size=(None, None), auto_size_button=None, button_color=None, change_submits=False, font=None, pad=None, key=None): return Button(button_text=button_text, button_type=BUTTON_TYPE_SAVEAS_FILE, target=target, file_types=file_types, initial_folder=initial_folder, tooltip=tooltip, size=size, disabled=disabled, auto_size_button=auto_size_button, button_color=button_color, change_submits=change_submits, font=font, pad=pad, key=key) # ------------------------- SAVE BUTTON lazy function ------------------------- # def Save(button_text='Save', size=(None, None), auto_size_button=None, button_color=None, bind_return_key=True, disabled=False, tooltip=None, font=None, focus=False, pad=None, key=None): return Button(button_text=button_text, button_type=BUTTON_TYPE_READ_FORM, tooltip=tooltip, size=size, auto_size_button=auto_size_button, button_color=button_color, font=font, disabled=disabled, bind_return_key=bind_return_key, focus=focus, pad=pad, key=key) # ------------------------- SUBMIT BUTTON lazy function ------------------------- # def Submit(button_text='Submit', size=(None, None), auto_size_button=None, button_color=None, disabled=False, bind_return_key=True, tooltip=None, font=None, focus=False, pad=None, key=None): return Button(button_text=button_text, button_type=BUTTON_TYPE_READ_FORM, tooltip=tooltip, size=size, auto_size_button=auto_size_button, button_color=button_color, font=font, disabled=disabled, bind_return_key=bind_return_key, focus=focus, pad=pad, key=key) # ------------------------- OPEN BUTTON lazy function ------------------------- # def Open(button_text='Open', size=(None, None), auto_size_button=None, button_color=None, disabled=False, bind_return_key=True, tooltip=None, font=None, focus=False, pad=None, key=None): return Button(button_text=button_text, button_type=BUTTON_TYPE_READ_FORM, tooltip=tooltip, size=size, auto_size_button=auto_size_button, button_color=button_color, font=font, disabled=disabled, bind_return_key=bind_return_key, focus=focus, pad=pad, key=key) # ------------------------- OK BUTTON lazy function ------------------------- # def OK(button_text='OK', size=(None, None), auto_size_button=None, button_color=None, disabled=False, bind_return_key=True, tooltip=None, font=None, focus=False, pad=None, key=None): return Button(button_text=button_text, button_type=BUTTON_TYPE_READ_FORM, tooltip=tooltip, size=size, auto_size_button=auto_size_button, button_color=button_color, font=font, disabled=disabled, bind_return_key=bind_return_key, focus=focus, pad=pad, key=key) # ------------------------- YES BUTTON lazy function ------------------------- # def Ok(button_text='Ok', size=(None, None), auto_size_button=None, button_color=None, disabled=False, bind_return_key=True, tooltip=None, font=None, focus=False, pad=None, key=None): return Button(button_text=button_text, button_type=BUTTON_TYPE_READ_FORM, tooltip=tooltip, size=size, auto_size_button=auto_size_button, button_color=button_color, font=font, disabled=disabled, bind_return_key=bind_return_key, focus=focus, pad=pad, key=key) # ------------------------- CANCEL BUTTON lazy function ------------------------- # def Cancel(button_text='Cancel', size=(None, None), auto_size_button=None, button_color=None, disabled=False, tooltip=None, font=None, bind_return_key=False, focus=False, pad=None, key=None): return Button(button_text=button_text, button_type=BUTTON_TYPE_READ_FORM, tooltip=tooltip, size=size, auto_size_button=auto_size_button, button_color=button_color, font=font, disabled=disabled, bind_return_key=bind_return_key, focus=focus, pad=pad, key=key) # ------------------------- QUIT BUTTON lazy function ------------------------- # def Quit(button_text='Quit', size=(None, None), auto_size_button=None, button_color=None, disabled=False, tooltip=None, font=None, bind_return_key=False, focus=False, pad=None, key=None): return Button(button_text=button_text, button_type=BUTTON_TYPE_READ_FORM, tooltip=tooltip, size=size, auto_size_button=auto_size_button, button_color=button_color, font=font, disabled=disabled, bind_return_key=bind_return_key, focus=focus, pad=pad, key=key) # ------------------------- Exit BUTTON lazy function ------------------------- # def Exit(button_text='Exit', size=(None, None), auto_size_button=None, button_color=None, disabled=False, tooltip=None, font=None, bind_return_key=False, focus=False, pad=None, key=None): return Button(button_text=button_text, button_type=BUTTON_TYPE_READ_FORM, tooltip=tooltip, size=size, auto_size_button=auto_size_button, button_color=button_color, font=font, disabled=disabled, bind_return_key=bind_return_key, focus=focus, pad=pad, key=key) # ------------------------- YES BUTTON lazy function ------------------------- # def Yes(button_text='Yes', size=(None, None), auto_size_button=None, button_color=None, disabled=False, tooltip=None, font=None, bind_return_key=True, focus=False, pad=None, key=None): return Button(button_text=button_text, button_type=BUTTON_TYPE_READ_FORM, tooltip=tooltip, size=size, auto_size_button=auto_size_button, button_color=button_color, font=font, disabled=disabled, bind_return_key=bind_return_key, focus=focus, pad=pad, key=key) # ------------------------- NO BUTTON lazy function ------------------------- # def No(button_text='No', size=(None, None), auto_size_button=None, button_color=None, disabled=False, tooltip=None, font=None, bind_return_key=False, focus=False, pad=None, key=None): return Button(button_text=button_text, button_type=BUTTON_TYPE_READ_FORM, tooltip=tooltip, size=size, auto_size_button=auto_size_button, button_color=button_color, font=font, disabled=disabled, bind_return_key=bind_return_key, focus=focus, pad=pad, key=key) # ------------------------- NO BUTTON lazy function ------------------------- # def Help(button_text='Help', size=(None, None), auto_size_button=None, button_color=None, disabled=False, font=None, tooltip=None, bind_return_key=False, focus=False, pad=None, key=None): return Button(button_text=button_text, button_type=BUTTON_TYPE_READ_FORM, tooltip=tooltip, size=size, auto_size_button=auto_size_button, button_color=button_color, font=font, disabled=disabled, bind_return_key=bind_return_key, focus=focus, pad=pad, key=key) # ------------------------- GENERIC BUTTON lazy function ------------------------- # def SimpleButton(button_text, image_filename=None, image_data=None, image_size=(None, None), image_subsample=None, border_width=None, tooltip=None, size=(None, None), auto_size_button=None, button_color=None, font=None, bind_return_key=False, disabled=False, focus=False, pad=None, key=None): return Button(button_text=button_text, button_type=BUTTON_TYPE_CLOSES_WIN, image_filename=image_filename, image_data=image_data, image_size=image_size, image_subsample=image_subsample, border_width=border_width, tooltip=tooltip, disabled=disabled, size=size, auto_size_button=auto_size_button, button_color=button_color, font=font, bind_return_key=bind_return_key, focus=focus, pad=pad, key=key) # ------------------------- CLOSE BUTTON lazy function ------------------------- # def CloseButton(button_text, image_filename=None, image_data=None, image_size=(None, None), image_subsample=None, border_width=None, tooltip=None, size=(None, None), auto_size_button=None, button_color=None, font=None, bind_return_key=False, disabled=False, focus=False, pad=None, key=None): return Button(button_text=button_text, button_type=BUTTON_TYPE_CLOSES_WIN, image_filename=image_filename, image_data=image_data, image_size=image_size, image_subsample=image_subsample, border_width=border_width, tooltip=tooltip, disabled=disabled, size=size, auto_size_button=auto_size_button, button_color=button_color, font=font, bind_return_key=bind_return_key, focus=focus, pad=pad, key=key) CButton = CloseButton # ------------------------- GENERIC BUTTON lazy function ------------------------- # def ReadButton(button_text, image_filename=None, image_data=None, image_size=(None, None), image_subsample=None, border_width=None, tooltip=None, size=(None, None), auto_size_button=None, button_color=None, font=None, bind_return_key=False, disabled=False, focus=False, pad=None, key=None): return Button(button_text=button_text, button_type=BUTTON_TYPE_READ_FORM, image_filename=image_filename, image_data=image_data, image_size=image_size, image_subsample=image_subsample, border_width=border_width, tooltip=tooltip, size=size, disabled=disabled, auto_size_button=auto_size_button, button_color=button_color, font=font, bind_return_key=bind_return_key, focus=focus, pad=pad, key=key) ReadFormButton = ReadButton RButton = ReadFormButton # ------------------------- Realtime BUTTON lazy function ------------------------- # def RealtimeButton(button_text, image_filename=None, image_data=None, image_size=(None, None), image_subsample=None, border_width=None, tooltip=None, size=(None, None), auto_size_button=None, button_color=None, font=None, disabled=False, bind_return_key=False, focus=False, pad=None, key=None): return Button(button_text=button_text, button_type=BUTTON_TYPE_REALTIME, image_filename=image_filename, image_data=image_data, image_size=image_size, image_subsample=image_subsample, border_width=border_width, tooltip=tooltip, disabled=disabled, size=size, auto_size_button=auto_size_button, button_color=button_color, font=font, bind_return_key=bind_return_key, focus=focus, pad=pad, key=key) # ------------------------- Dummy BUTTON lazy function ------------------------- # def DummyButton(button_text, image_filename=None, image_data=None, image_size=(None, None), image_subsample=None, border_width=None, tooltip=None, size=(None, None), auto_size_button=None, button_color=None, font=None, disabled=False, bind_return_key=False, focus=False, pad=None, key=None): return Button(button_text=button_text, button_type=BUTTON_TYPE_CLOSES_WIN_ONLY, image_filename=image_filename, image_data=image_data, image_size=image_size, image_subsample=image_subsample, border_width=border_width, tooltip=tooltip, size=size, auto_size_button=auto_size_button, button_color=button_color, font=font, disabled=disabled, bind_return_key=bind_return_key, focus=focus, pad=pad, key=key) # ------------------------- Calendar Chooser Button lazy function ------------------------- # def CalendarButton(button_text, target=(None, None), close_when_date_chosen=True, default_date_m_d_y=(None, None, None), image_filename=None, image_data=None, image_size=(None, None), image_subsample=None, tooltip=None, border_width=None, size=(None, None), auto_size_button=None, button_color=None, disabled=False, font=None, bind_return_key=False, focus=False, pad=None, key=None): button = Button(button_text=button_text, button_type=BUTTON_TYPE_CALENDAR_CHOOSER, target=target, image_filename=image_filename, image_data=image_data, image_size=image_size, image_subsample=image_subsample, border_width=border_width, tooltip=tooltip, size=size, auto_size_button=auto_size_button, button_color=button_color, font=font, disabled=disabled, bind_return_key=bind_return_key, focus=focus, pad=pad, key=key) button.CalendarCloseWhenChosen = close_when_date_chosen button.DefaultDate_M_D_Y = default_date_m_d_y return button # ------------------------- Calendar Chooser Button lazy function ------------------------- # def ColorChooserButton(button_text, target=(None, None), image_filename=None, image_data=None, image_size=(None, None), image_subsample=None, tooltip=None, border_width=None, size=(None, None), auto_size_button=None, button_color=None, disabled=False, font=None, bind_return_key=False, focus=False, pad=None, key=None): return Button(button_text=button_text, button_type=BUTTON_TYPE_COLOR_CHOOSER, target=target, image_filename=image_filename, image_data=image_data, image_size=image_size, image_subsample=image_subsample, border_width=border_width, tooltip=tooltip, size=size, auto_size_button=auto_size_button, button_color=button_color, font=font, disabled=disabled, bind_return_key=bind_return_key, focus=focus, pad=pad, key=key) ##################################### ----- RESULTS ------ ################################################## def AddToReturnDictionary(form, element, value): if element.Key is None: form.ReturnValuesDictionary[form.DictionaryKeyCounter] = value element.Key = form.DictionaryKeyCounter form.DictionaryKeyCounter += 1 else: form.ReturnValuesDictionary[element.Key] = value def AddToReturnList(form, value): form.ReturnValuesList.append(value) # ----------------------------------------------------------------------------# # ------- FUNCTION InitializeResults. Sets up form results matrix --------# def InitializeResults(form): BuildResults(form, True, form) return # ===== Radio Button RadVar encoding and decoding =====# # ===== The value is simply the row * 1000 + col =====# def DecodeRadioRowCol(RadValue): row = RadValue // 1000 col = RadValue % 1000 return row, col def EncodeRadioRowCol(row, col): RadValue = row * 1000 + col return RadValue # ------- 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): # Results for elements are: # TEXT - Nothing # INPUT - Read value from TK # Button - Button Text and position as a Tuple # Get the initialized results so we don't have to rebuild form.DictionaryKeyCounter = 0 form.ReturnValuesDictionary = {} form.ReturnValuesList = [] BuildResultsForSubform(form, initialize_only, top_level_form) # try: # BuildResultsForSubform(form, initialize_only, top_level_form) # except: # print('Error building return values') if not top_level_form.LastButtonClickedWasRealtime: top_level_form.LastButtonClicked = None return form.ReturnValues def BuildResultsForSubform(form, initialize_only, top_level_form): button_pressed_text = top_level_form.LastButtonClicked for row_num, row in enumerate(form.Rows): for col_num, element in enumerate(row): if element.Key is not None and WRITE_ONLY_KEY in str(element.Key): continue value = None if element.Type == ELEM_TYPE_COLUMN: element.DictionaryKeyCounter = top_level_form.DictionaryKeyCounter element.ReturnValuesList = [] element.ReturnValuesDictionary = {} BuildResultsForSubform(element, initialize_only, top_level_form) for item in element.ReturnValuesList: AddToReturnList(top_level_form, item) if element.UseDictionary: top_level_form.UseDictionary = True if element.ReturnValues[0] is not None: # if a button was clicked button_pressed_text = element.ReturnValues[0] if element.Type == ELEM_TYPE_FRAME: element.DictionaryKeyCounter = top_level_form.DictionaryKeyCounter element.ReturnValuesList = [] element.ReturnValuesDictionary = {} BuildResultsForSubform(element, initialize_only, top_level_form) for item in element.ReturnValuesList: AddToReturnList(top_level_form, item) if element.UseDictionary: top_level_form.UseDictionary = True if element.ReturnValues[0] is not None: # if a button was clicked button_pressed_text = element.ReturnValues[0] if element.Type == ELEM_TYPE_TAB_GROUP: element.DictionaryKeyCounter = top_level_form.DictionaryKeyCounter element.ReturnValuesList = [] element.ReturnValuesDictionary = {} BuildResultsForSubform(element, initialize_only, top_level_form) for item in element.ReturnValuesList: AddToReturnList(top_level_form, item) if element.UseDictionary: top_level_form.UseDictionary = True if element.ReturnValues[0] is not None: # if a button was clicked button_pressed_text = element.ReturnValues[0] if element.Type == ELEM_TYPE_TAB: element.DictionaryKeyCounter = top_level_form.DictionaryKeyCounter element.ReturnValuesList = [] element.ReturnValuesDictionary = {} BuildResultsForSubform(element, initialize_only, top_level_form) for item in element.ReturnValuesList: AddToReturnList(top_level_form, item) if element.UseDictionary: top_level_form.UseDictionary = True if element.ReturnValues[0] is not None: # if a button was clicked button_pressed_text = element.ReturnValues[0] if not initialize_only: if element.Type == ELEM_TYPE_INPUT_TEXT: value = element.WxTextCtrl.GetValue() if not top_level_form.NonBlocking and not element.do_not_clear and not top_level_form.ReturnKeyboardEvents: element.WxTextCtrl.SetValue('') elif element.Type == ELEM_TYPE_INPUT_CHECKBOX: value = element.WxCheckbox.GetValue() value = (value != 0) elif element.Type == ELEM_TYPE_INPUT_RADIO: value = element.WxRadioButton.GetValue() elif element.Type == ELEM_TYPE_BUTTON: if top_level_form.LastButtonClicked == element.ButtonText: button_pressed_text = top_level_form.LastButtonClicked if element.BType != BUTTON_TYPE_REALTIME: # Do not clear realtime buttons top_level_form.LastButtonClicked = None if element.BType == BUTTON_TYPE_CALENDAR_CHOOSER: try: value = element.TKCal.selection except: value = None else: try: value = element.TKStringVar.get() except: value = None elif element.Type == ELEM_TYPE_INPUT_COMBO: value = element.WxComboBox.GetValue() elif element.Type == ELEM_TYPE_INPUT_OPTION_MENU: value = element.TKStringVar.get() elif element.Type == ELEM_TYPE_INPUT_LISTBOX: try: items = element.TKListbox.curselection() value = [element.Values[int(item)] for item in items] except: value = '' elif element.Type == ELEM_TYPE_INPUT_SPIN: value = element.WxTextCtrl.GetValue() # value = element.CurrentValue elif element.Type == ELEM_TYPE_INPUT_SLIDER: try: value = element.TKIntVar.get() except: value = 0 elif element.Type == ELEM_TYPE_INPUT_MULTILINE: value = element.WxTextCtrl.GetValue() if not top_level_form.NonBlocking and not element.do_not_clear and not top_level_form.ReturnKeyboardEvents: element.WxTextCtrl.SetValue('') elif element.Type == ELEM_TYPE_TAB_GROUP: try: value = element.TKNotebook.tab(element.TKNotebook.index('current'))['text'] tab_key = element.FindKeyFromTabName(value) if tab_key is not None: value = tab_key except: value = None elif element.Type == ELEM_TYPE_TABLE: value = element.SelectedRows elif element.Type == ELEM_TYPE_TREE: value = element.SelectedRows elif element.Type == ELEM_TYPE_GRAPH: value = element.ClickPosition else: value = None # if an input type element, update the results if element.Type != ELEM_TYPE_BUTTON and \ element.Type != ELEM_TYPE_TEXT and \ element.Type != ELEM_TYPE_IMAGE and \ element.Type != ELEM_TYPE_OUTPUT and \ element.Type != ELEM_TYPE_PROGRESS_BAR and \ element.Type != ELEM_TYPE_COLUMN and \ element.Type != ELEM_TYPE_FRAME \ and element.Type != ELEM_TYPE_TAB: AddToReturnList(form, value) AddToReturnDictionary(top_level_form, element, value) elif (element.Type == ELEM_TYPE_BUTTON and element.BType == BUTTON_TYPE_CALENDAR_CHOOSER and element.Target == (None, None)) or \ (element.Type == ELEM_TYPE_BUTTON and element.BType == BUTTON_TYPE_COLOR_CHOOSER and element.Target == (None, None)) or \ (element.Type == ELEM_TYPE_BUTTON and element.Key is not None and (element.BType in (BUTTON_TYPE_SAVEAS_FILE, BUTTON_TYPE_BROWSE_FILE, BUTTON_TYPE_BROWSE_FILES, BUTTON_TYPE_BROWSE_FOLDER))): AddToReturnList(form, value) AddToReturnDictionary(top_level_form, element, value) # if this is a column, then will fail so need to wrap with tr try: if form.ReturnKeyboardEvents and form.LastKeyboardEvent is not None: button_pressed_text = form.LastKeyboardEvent form.LastKeyboardEvent = None except: pass try: form.ReturnValuesDictionary.pop(None, None) # clean up dictionary include None was included except: pass if not form.UseDictionary: form.ReturnValues = button_pressed_text, form.ReturnValuesList else: form.ReturnValues = button_pressed_text, form.ReturnValuesDictionary return form.ReturnValues def FillFormWithValues(form, values_dict): FillSubformWithValues(form, values_dict) def FillSubformWithValues(form, 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): 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_TAB: matching_elem = _FindElementFromKeyInSubForm(element, key) if matching_elem is not None: return matching_elem if element.Key == key: return element def _FindElementWithFocusInSubForm(form): for row_num, row in enumerate(form.Rows): for col_num, element in enumerate(row): if element.Type == ELEM_TYPE_COLUMN: matching_elem = _FindElementWithFocusInSubForm(element) if matching_elem is not None: return matching_elem if element.Type == ELEM_TYPE_FRAME: matching_elem = _FindElementWithFocusInSubForm(element) if matching_elem is not None: return matching_elem if element.Type == ELEM_TYPE_TAB_GROUP: matching_elem = _FindElementWithFocusInSubForm(element) if matching_elem is not None: return matching_elem if element.Type == ELEM_TYPE_TAB: matching_elem = _FindElementWithFocusInSubForm(element) if matching_elem is not None: return matching_elem if element.Type == ELEM_TYPE_INPUT_TEXT: if element.TKEntry is not None: if element.TKEntry is element.TKEntry.focus_get(): return element if element.Type == ELEM_TYPE_INPUT_MULTILINE: if element.TKText is not None: if element.TKText is element.TKText.focus_get(): return element if sys.version_info[0] >= 3: def AddMenuItem(top_menu, sub_menu_info, element, is_sub_menu=False, skip=False): return_val = None if type(sub_menu_info) is str: if not is_sub_menu and not skip: # print(f'Adding command {sub_menu_info}') pos = sub_menu_info.find('&') if pos != -1: if pos == 0 or sub_menu_info[pos - 1] != "\\": sub_menu_info = sub_menu_info[:pos] + sub_menu_info[pos + 1:] if sub_menu_info == '---': top_menu.Append(wx.ID_SEPARATOR) else: try: item_without_key = sub_menu_info[:sub_menu_info.index(MENU_KEY_SEPARATOR)] except: item_without_key = sub_menu_info if item_without_key[0] == MENU_DISABLED_CHARACTER: id = top_menu.Append(wx.ID_ANY, item_without_key[len(MENU_DISABLED_CHARACTER):]) element.id_to_text[id] = sub_menu_info[1:] top_menu.Enable(id.Id, False) else: id = top_menu.Append(wx.ID_ANY, item_without_key) element.id_to_text[id] = sub_menu_info else: i = 0 while i < (len(sub_menu_info)): item = sub_menu_info[i] if i != len(sub_menu_info) - 1: if type(sub_menu_info[i + 1]) == list: new_menu = wx.Menu() return_val = new_menu pos = sub_menu_info[i].find('&') if pos != -1: if pos == 0 or sub_menu_info[i][pos - 1] != "\\": sub_menu_info[i] = sub_menu_info[i][:pos] + sub_menu_info[i][pos + 1:] if sub_menu_info[i][0] == MENU_DISABLED_CHARACTER: id = top_menu.AppendSubMenu(new_menu, sub_menu_info[i][len(MENU_DISABLED_CHARACTER):]) top_menu.Enable(id.Id, False) else: top_menu.AppendSubMenu(new_menu, sub_menu_info[i]) AddMenuItem(new_menu, sub_menu_info[i + 1], element, is_sub_menu=True) i += 1 # skip the next one else: AddMenuItem(top_menu, item, element) else: AddMenuItem(top_menu, item, element) i += 1 return return_val if sys.version_info[0] >= 3: def AddMenuItem2(top_menu, sub_menu_info, element, is_sub_menu=False, skip=False): if type(sub_menu_info) is str: if not is_sub_menu and not skip: # print(f'Adding command {sub_menu_info}') pos = sub_menu_info.find('&') if pos != -1: if pos == 0 or sub_menu_info[pos - 1] != "\\": sub_menu_info = sub_menu_info[:pos] + sub_menu_info[pos + 1:] if sub_menu_info == '---': top_menu.Append(wx.ID_SEPARATOR) else: top_menu.Append(wx.ID_ANY, sub_menu_info) else: i = 0 while i < (len(sub_menu_info)): item = sub_menu_info[i] if i != len(sub_menu_info) - 1: if type(sub_menu_info[i + 1]) == list: new_menu = wx.Menu() pos = sub_menu_info[i].find('&') if pos != -1: if pos == 0 or sub_menu_info[i][pos - 1] != "\\": sub_menu_info[i] = sub_menu_info[i][:pos] + sub_menu_info[i][pos + 1:] top_menu.AppendSubMenu(new_menu, sub_menu_info[i]) AddMenuItem(new_menu, sub_menu_info[i + 1], element, is_sub_menu=True) i += 1 # skip the next one else: AddMenuItem(top_menu, item, element) else: AddMenuItem(top_menu, item, element) i += 1 else: def AddMenuItem(top_menu, sub_menu_info, element, is_sub_menu=False, skip=False): if isinstance(sub_menu_info, types.StringType): if not is_sub_menu and not skip: # print(f'Adding command {sub_menu_info}') pos = sub_menu_info.find('&') if pos != -1: if pos == 0 or sub_menu_info[pos - 1] != "\\": sub_menu_info = sub_menu_info[:pos] + sub_menu_info[pos + 1:] if sub_menu_info == '---': top_menu.add('separator') else: top_menu.add_command(label=sub_menu_info, underline=pos, command=lambda: Menu.MenuItemChosenCallback(element, sub_menu_info)) else: i = 0 while i < (len(sub_menu_info)): item = sub_menu_info[i] if i != len(sub_menu_info) - 1: if not isinstance(sub_menu_info[i + 1], types.StringType): new_menu = tk.Menu(top_menu, tearoff=element.Tearoff) pos = sub_menu_info[i].find('&') if pos != -1: if pos == 0 or sub_menu_info[i][pos - 1] != "\\": sub_menu_info[i] = sub_menu_info[i][:pos] + sub_menu_info[i][pos + 1:] top_menu.add_cascade(label=sub_menu_info[i], menu=new_menu, underline=pos) AddMenuItem(new_menu, sub_menu_info[i + 1], element, is_sub_menu=True) i += 1 # skip the next one else: AddMenuItem(top_menu, item, element) else: AddMenuItem(top_menu, item, element) i += 1 # ------------------------------------------------------------------------------------------------------------------ # # ------------------------------------------------------------------------------------------------------------------ # # ===================================== TK CODE STARTS HERE ====================================================== # # ------------------------------------------------------------------------------------------------------------------ # # ------------------------------------------------------------------------------------------------------------------ # def PackFormIntoFrame(form, containing_frame, toplevel_form): def pad_widget(widget): lrsizer = wx.BoxSizer(wx.HORIZONTAL) if full_element_pad[1] == full_element_pad[3]: # if right = left lrsizer.Add(widget, 0, wx.LEFT | wx.RIGHT, border=full_element_pad[1]) else: sizer = wx.BoxSizer(wx.HORIZONTAL) sizer.Add(widget, 0, wx.LEFT, border=full_element_pad[3]) lrsizer.Add(sizer, 0, wx.RIGHT, border=full_element_pad[1]) top_bottom_sizer = wx.BoxSizer(wx.HORIZONTAL) if full_element_pad[0] == full_element_pad[2]: # if top = bottom top_bottom_sizer.Add(lrsizer, 0, wx.TOP | wx.BOTTOM, border=full_element_pad[0]) else: sizer = wx.BoxSizer(wx.HORIZONTAL) sizer.Add(lrsizer, 0, wx.TOP, border=full_element_pad[0]) top_bottom_sizer.Add(sizer, 0, wx.BOTTOM, border=full_element_pad[2]) return top_bottom_sizer # # font, text color, background color, size, disabled, visible, tooltip # def do_font_and_color(widget): if font: widget.SetFont(font_to_wx_font(font)) if element.TextColor not in (None, COLOR_SYSTEM_DEFAULT): widget.SetForegroundColour(element.TextColor) if element.BackgroundColor not in (None, COLOR_SYSTEM_DEFAULT): widget.SetBackgroundColour(element.BackgroundColor) widget.SetMinSize(element_size) if element.Disabled: widget.Enable(False) if not element.Visible: widget.Hide() if element.Tooltip: widget.SetToolTip(element.Tooltip) def CharWidthInPixels(): return tkinter.font.Font().measure('A') # single character width border_depth = toplevel_form.BorderDepth if toplevel_form.BorderDepth is not None else DEFAULT_BORDER_WIDTH # --------------------------------------------------------------------------- # # **************** Use FlexForm to build the tkinter window ********** ----- # # Building is done row by row. # # --------------------------------------------------------------------------- # focus_set = False ######################### LOOP THROUGH ROWS ######################### # *********** ------- Loop through ROWS ------- ***********# for row_num, flex_row in enumerate(form.Rows): ######################### LOOP THROUGH ELEMENTS ON ROW ######################### # *********** ------- Loop through ELEMENTS ------- ***********# # *********** Make TK Row ***********# hsizer = wx.BoxSizer(wx.HORIZONTAL) for col_num, element in enumerate(flex_row): element.ParentForm = toplevel_form # save the button's parent form object if toplevel_form.Font and (element.Font == DEFAULT_FONT or not element.Font): font = toplevel_form.Font element.Font = font elif element.Font is not None: font = element.Font else: font = DEFAULT_FONT # ------- Determine Auto-Size setting on a cascading basis ------- # if element.AutoSizeText is not None: # if element overide auto_size_text = element.AutoSizeText elif toplevel_form.AutoSizeText is not None: # if form override auto_size_text = toplevel_form.AutoSizeText else: auto_size_text = DEFAULT_AUTOSIZE_TEXT element_type = element.Type # Set foreground color text_color = element.TextColor # Determine Element size element_size = element.Size if (element_size == (None, None) and element_type not in (ELEM_TYPE_BUTTON, ELEM_TYPE_BUTTONMENU)): # user did not specify a size element_size = toplevel_form.DefaultElementSize elif (element_size == (None, None) and element_type in (ELEM_TYPE_BUTTON, ELEM_TYPE_BUTTONMENU)): element_size = toplevel_form.DefaultButtonElementSize else: auto_size_text = False # if user has specified a size then it shouldn't autosize full_element_pad = [0, 0, 0, 0] # Top, Right, Bottom, Left elementpad = element.Pad if element.Pad is not None else toplevel_form.ElementPadding if type(elementpad[0]) != tuple: # left and right full_element_pad[1] = full_element_pad[3] = elementpad[0] else: full_element_pad[3], full_element_pad[1] = elementpad[0] if type(elementpad[1]) != tuple: # top and bottom full_element_pad[0] = full_element_pad[2] = elementpad[1] else: full_element_pad[0], full_element_pad[2] = elementpad[1] border_depth = toplevel_form.BorderDepth if toplevel_form.BorderDepth is not None else DEFAULT_BORDER_WIDTH try: if element.BorderWidth is not None: border_depth = element.BorderWidth except: pass # ------------------------- COLUMN element ------------------------- # if element_type == ELEM_TYPE_COLUMN: element = element # type: Column element.WxBoxSizer = vsizer = wx.BoxSizer(wx.VERTICAL) element.WxHSizer = hsizer # element.WxScrollBar = wx.ScrollBar(toplevel_form.MasterFrame, id=wx.ID_ANY, style=wx.SB_VERTICAL) # vsizer.Add(element.WxScrollBar) PackFormIntoFrame(element, vsizer, toplevel_form) hsizer.Add(pad_widget(vsizer), 0) if not element.Visible: hsizer.Hide(vsizer, recursive=True) # # column_widget = QWidget() # column_widget = QGroupBox() # element.QT_QGroupBox = column_widget # # column_widget.setFrameShape(QtWidgets.QFrame.NoFrame) # style = create_style_from_font(font) # if element.BackgroundColor is not None: # style = style_entry(background_color=element.BackgroundColor) # style += 'background-color: %s;' % element.BackgroundColor # style += style_entry(border='0px solid gray') # # style += 'border: 0px solid gray; ' # style = style_generate('QGroupBox', style) # column_widget.setStyleSheet(style) # # column_layout = QFormLayout() # column_vbox = QVBoxLayout() # # PackFormIntoFrame(element, column_layout, toplevel_win) # # column_vbox.addLayout(column_layout) # column_widget.setLayout(column_vbox) # # # column_widget.setStyleSheet(style) # if not element.Visible: # column_widget.setVisible(False) # # qt_row_layout.addWidget(column_widget) # if element.Scrollable: # col_frame = TkScrollableFrame(tk_row_frame, # element.VerticalScrollOnly) # do not use yet! not working # PackFormIntoFrame(element, col_frame.TKFrame, toplevel_form) # col_frame.TKFrame.update() # if element.Size == (None, None): # if no size specified, use column width x column height/2 # col_frame.canvas.config(width=col_frame.TKFrame.winfo_reqwidth(), # height=col_frame.TKFrame.winfo_reqheight() / 2) # else: # col_frame.canvas.config(width=element.Size[0], height=element.Size[1]) # # if not element.BackgroundColor in (None, COLOR_SYSTEM_DEFAULT): # col_frame.canvas.config(background=element.BackgroundColor) # col_frame.TKFrame.config(background=element.BackgroundColor, borderwidth=0, # highlightthickness=0) # col_frame.config(background=element.BackgroundColor, borderwidth=0, highlightthickness=0) # else: # col_frame = tk.Frame(tk_row_frame) # PackFormIntoFrame(element, col_frame, toplevel_form) # # col_frame.pack(side=tk.LEFT, padx=element.Pad[0], pady=element.Pad[1], expand=True, fill='both') # if element.BackgroundColor != COLOR_SYSTEM_DEFAULT and element.BackgroundColor is not None: # col_frame.configure(background=element.BackgroundColor, highlightbackground=element.BackgroundColor, # highlightcolor=element.BackgroundColor) # ------------------------- TEXT element ------------------------- # elif element_type == ELEM_TYPE_TEXT: element = element # type: Text if element.Justification is not None: justification = element.Justification elif toplevel_form.TextJustification is not None: justification = toplevel_form.TextJustification else: justification = DEFAULT_TEXT_JUSTIFICATION style = wx.ALIGN_LEFT if justification.startswith('l') else wx.ALIGN_CENTER if justification.startswith('c') else wx.ALIGN_RIGHT # print(border_depth, element.BorderWidth) if border_depth: if element.Relief: if element.Relief in (RELIEF_SOLID, RELIEF_FLAT): style |= wx.SIMPLE_BORDER elif element.Relief == RELIEF_SUNKEN: style |= wx.SUNKEN_BORDER elif element.Relief in(RELIEF_RAISED, RELIEF_RIDGE): style |= wx.RAISED_BORDER elif element.Relief in (RELIEF_SUNKEN, RELIEF_SUNKEN): style |= wx.SUNKEN_BORDER statictext = element.WxStaticText = wx.StaticText(toplevel_form.MasterPanel, -1, element.DisplayText, style=style) if font: statictext.SetFont(font_to_wx_font(font)) if element.TextColor not in (None, COLOR_SYSTEM_DEFAULT): statictext.SetForegroundColour(element.TextColor) if element.BackgroundColor not in (None, COLOR_SYSTEM_DEFAULT): statictext.SetBackgroundColour(element.BackgroundColor) display_text = element.DisplayText # text to display if auto_size_text is False: width, height = element_size else: lines = display_text.split('\n') max_line_len = max([len(l) for l in lines]) num_lines = len(lines) if max_line_len > element_size[0]: # if text exceeds element size, the will have to wrap width = element_size[0] else: width = max_line_len height = num_lines if element.ClickSubmits: # bind events statictext.Bind(wx.EVT_LEFT_UP, element.WxCallbackKeyboard) hsizer.Add(pad_widget(element.WxStaticText), 0) if not auto_size_text: statictext.SetMinSize((width,height)) if element.Tooltip: statictext.SetToolTip(element.Tooltip) if not element.Visible: statictext.Hide() # Set wrap-length for text (in PIXELS) == PAIN IN THE ASS # wraplen = tktext_label.winfo_reqwidth() + 40 # width of widget in Pixels # if not auto_size_text and height == 1: # wraplen = 0 # ------------------------- BUTTON element ------------------------- # elif element_type == ELEM_TYPE_BUTTON: element = element # type: Button element.WxButton = button = wx.Button(toplevel_form.MasterPanel, style=wx.NO_BORDER) button.SetLabelText(element.ButtonText) if font: button.SetFont(font_to_wx_font(font)) button.Bind(wx.EVT_BUTTON, element.ButtonCallBack) element.Location = (row_num, col_num) if element.AutoSizeButton is not None: auto_size = element.AutoSizeButton else: auto_size = toplevel_form.AutoSizeButtons if auto_size is False or element.Size[0] is not None: width, height = element_size else: width = 0 height = toplevel_form.DefaultButtonElementSize[1] if auto_size: element.WxButton.SetWindowStyleFlag(element.WxButton.GetWindowStyleFlag() | wx.BU_EXACTFIT) else: element.WxButton.SetMinSize(convert_tkinter_size_to_Wx((width,height))) if element.ButtonColor != (None, None) and element.ButtonColor != DEFAULT_BUTTON_COLOR: bc = element.ButtonColor elif toplevel_form.ButtonColor != (None, None) and toplevel_form.ButtonColor != DEFAULT_BUTTON_COLOR: bc = toplevel_form.ButtonColor else: bc = DEFAULT_BUTTON_COLOR button.SetBackgroundColour(bc[1]) button.SetForegroundColour(bc[0]) sizer = pad_widget(button) hsizer.Add(sizer, 0) if not element.Visible: button.Hide() if element.Tooltip: button.SetToolTip(element.Tooltip) # if btype != BUTTON_TYPE_REALTIME: # tkbutton = tk.Button(tk_row_frame, text=btext, width=width, height=height, # command=element.ButtonCallBack, justify=tk.LEFT, bd=border_depth, font=font) # else: # tkbutton = tk.Button(tk_row_frame, text=btext, width=width, height=height, justify=tk.LEFT, # bd=border_depth, font=font) # tkbutton.bind('', element.ButtonReleaseCallBack) # tkbutton.bind('', element.ButtonPressCallBack) # if element.ImageFilename: # if button has an image on it # tkbutton.config(highlightthickness=0) # photo = tk.PhotoImage(file=element.ImageFilename) # if element.ImageSize != (None, None): # width, height = element.ImageSize # if element.ImageSubsample: # photo = photo.subsample(element.ImageSubsample) # else: # width, height = photo.width(), photo.height() # tkbutton.config(image=photo, compound=tk.CENTER, width=width, height=height) # tkbutton.image = photo # if element.ImageData: # if button has an image on it # tkbutton.config(highlightthickness=0) # photo = tk.PhotoImage(data=element.ImageData) # if element.ImageSize != (None, None): # width, height = element.ImageSize # if element.ImageSubsample: # photo = photo.subsample(element.ImageSubsample) # else: # width, height = photo.width(), photo.height() # tkbutton.config(image=photo, compound=tk.CENTER, width=width, height=height) # tkbutton.image = photo # if width != 0: # tkbutton.configure(wraplength=wraplen + 10) # set wrap to width of widget # tkbutton.pack(side=tk.LEFT, padx=element.Pad[0], pady=element.Pad[1]) # if element.BindReturnKey: # element.TKButton.bind('', element.ReturnKeyHandler) # if element.Focus is True or (toplevel_form.UseDefaultFocus and not focus_set): # focus_set = True # element.TKButton.bind('', element.ReturnKeyHandler) # element.TKButton.focus_set() # toplevel_form.TKroot.focus_force() # if element.Disabled == True: # element.TKButton['state'] = 'disabled' # if element.Tooltip is not None: # element.TooltipObject = ToolTip(element.TKButton, text=element.Tooltip, # timeout=DEFAULT_TOOLTIP_TIME) # # ------------------------- INPUT element ------------------------- # elif element_type == ELEM_TYPE_INPUT_TEXT: element = element # type: InputText if element.Justification is not None: justification = element.Justification elif toplevel_form.TextJustification is not None: justification = toplevel_form.TextJustification else: justification = DEFAULT_TEXT_JUSTIFICATION justify = wx.ALIGN_LEFT if justification.startswith('l') else wx.ALIGN_CENTER_HORIZONTAL if justification.startswith('c') else wx.ALIGN_RIGHT if element.PasswordCharacter: justify |= wx.TE_PASSWORD element.WxTextCtrl = text_ctrl = wx.TextCtrl(toplevel_form.MasterPanel, style=justify) if element.DefaultText: text_ctrl.SetValue(element.DefaultText) if font: text_ctrl.SetFont(font_to_wx_font(font)) if element.TextColor not in (None, COLOR_SYSTEM_DEFAULT): text_ctrl.SetForegroundColour(element.TextColor) if element.BackgroundColor not in (None, COLOR_SYSTEM_DEFAULT): text_ctrl.SetBackgroundColour(element.BackgroundColor) text_ctrl.SetMinSize(element_size) if element.Disabled: text_ctrl.Enable(False) if element.ChangeSubmits: text_ctrl.Bind(wx.EVT_KEY_UP, element.WxCallbackKeyboard) text_ctrl.Bind(wx.EVT_TEXT_ENTER, element.ReturnKeyHandler) sizer = pad_widget(text_ctrl) hsizer.Add(sizer, 0) if not element.Visible: text_ctrl.Hide() if element.Tooltip: text_ctrl.SetToolTip(element.Tooltip) if element.Focus is True or (toplevel_form.UseDefaultFocus and not focus_set): focus_set = True element.SetFocus() # ------------------------- COMBO BOX (Drop Down) element ------------------------- # elif element_type == ELEM_TYPE_INPUT_COMBO: element = element # type: Combo if element.Readonly: element.WxComboBox = wx.Choice(toplevel_form.MasterPanel, id=wx.ID_ANY, choices=element.Values) else: element.WxComboBox = wx.ComboBox(toplevel_form.MasterPanel, id=wx.ID_ANY, choices=element.Values) if element.DefaultValue: element.WxComboBox.SetSelection(element.WxComboBox.FindString(element.DefaultValue)) if element.Readonly: element.WxComboBox.SetWindowStyle(wx.CB_READONLY) do_font_and_color(element.WxComboBox) sizer = pad_widget(element.WxComboBox) if element.ChangeSubmits: element.WxComboBox.Bind(wx.EVT_COMBOBOX, element.WxCallbackKeyboard) hsizer.Add(sizer, 0) # max_line_len = max([len(str(l)) for l in element.Values]) # if auto_size_text is False: # width = element_size[0] # else: # width = max_line_len # element.TKStringVar = tk.StringVar() # if element.BackgroundColor is not None and element.BackgroundColor != COLOR_SYSTEM_DEFAULT: # combostyle = ttk.Style() # try: # combostyle.theme_create('combostyle', # settings={'TCombobox': # {'configure': # {'selectbackground': element.BackgroundColor, # 'fieldbackground': element.BackgroundColor, # 'foreground': text_color, # 'background': element.BackgroundColor} # }}) # except: # try: # combostyle.theme_settings('combostyle', # settings={'TCombobox': # {'configure': # {'selectbackground': element.BackgroundColor, # 'fieldbackground': element.BackgroundColor, # 'foreground': text_color, # 'background': element.BackgroundColor} # }}) # except: # pass # # ATTENTION: this applies the new style 'combostyle' to all ttk.Combobox # combostyle.theme_use('combostyle') # element.TKCombo = ttk.Combobox(tk_row_frame, width=width, textvariable=element.TKStringVar, font=font) # if element.Size[1] != 1 and element.Size[1] is not None: # element.TKCombo.configure(height=element.Size[1]) # # element.TKCombo['state']='readonly' # element.TKCombo['values'] = element.Values # # # if element.InitializeAsDisabled: # # element.TKCombo['state'] = 'disabled' # # if element.BackgroundColor is not None: # # element.TKCombo.configure(background=element.BackgroundColor) # element.TKCombo.pack(side=tk.LEFT, padx=element.Pad[0], pady=element.Pad[1]) # if element.DefaultValue: # for i, v in enumerate(element.Values): # if v == element.DefaultValue: # element.TKCombo.current(i) # break # else: # element.TKCombo.current(0) # if element.ChangeSubmits: # element.TKCombo.bind('<>', element.ComboboxSelectHandler) # if element.Readonly: # element.TKCombo['state'] = 'readonly' # if element.Disabled is True: # note overrides readonly if disabled # element.TKCombo['state'] = 'disabled' # if element.Tooltip is not None: # element.TooltipObject = ToolTip(element.TKCombo, text=element.Tooltip, timeout=DEFAULT_TOOLTIP_TIME) # # ------------------------- LISTBOX element ------------------------- # elif element_type == ELEM_TYPE_INPUT_LISTBOX: pass # max_line_len = max([len(str(l)) for l in element.Values]) if len(element.Values) != 0 else 0 # if auto_size_text is False: # width = element_size[0] # else: # width = max_line_len # listbox_frame = tk.Frame(tk_row_frame) # element.TKStringVar = tk.StringVar() # element.TKListbox = tk.Listbox(listbox_frame, height=element_size[1], width=width, # selectmode=element.SelectMode, font=font) # for index, item in enumerate(element.Values): # element.TKListbox.insert(tk.END, item) # if element.DefaultValues is not None and item in element.DefaultValues: # element.TKListbox.selection_set(index) # if element.BackgroundColor is not None and element.BackgroundColor != COLOR_SYSTEM_DEFAULT: # element.TKListbox.configure(background=element.BackgroundColor) # if text_color is not None and text_color != COLOR_SYSTEM_DEFAULT: # element.TKListbox.configure(fg=text_color) # if element.ChangeSubmits: # element.TKListbox.bind('<>', element.ListboxSelectHandler) # vsb = tk.Scrollbar(listbox_frame, orient="vertical", command=element.TKListbox.yview) # element.TKListbox.configure(yscrollcommand=vsb.set) # element.TKListbox.pack(side=tk.LEFT) # vsb.pack(side=tk.LEFT, fill='y') # listbox_frame.pack(side=tk.LEFT, padx=element.Pad[0], pady=element.Pad[1]) # if element.BindReturnKey: # element.TKListbox.bind('', element.ListboxSelectHandler) # element.TKListbox.bind('', element.ListboxSelectHandler) # if element.Disabled == True: # element.TKListbox['state'] = 'disabled' # if element.Tooltip is not None: # element.TooltipObject = ToolTip(element.TKListbox, text=element.Tooltip, # timeout=DEFAULT_TOOLTIP_TIME) # ------------------------- INPUT MULTILINE element ------------------------- # elif element_type == ELEM_TYPE_INPUT_MULTILINE: element = element # type: Multiline justify = 0 if element.EnterSubmits: justify |= wx.TE_PROCESS_ENTER justify |= wx.TE_MULTILINE element.WxTextCtrl = text_ctrl = wx.TextCtrl(toplevel_form.MasterPanel, style=justify) if element.DefaultText: text_ctrl.SetValue(element.DefaultText) if font: text_ctrl.SetFont(font_to_wx_font(font)) if element.TextColor not in (None, COLOR_SYSTEM_DEFAULT): text_ctrl.SetForegroundColour(element.TextColor) if element.BackgroundColor not in (None, COLOR_SYSTEM_DEFAULT): text_ctrl.SetBackgroundColour(element.BackgroundColor) text_ctrl.SetMinSize(element_size) if element.Disabled: text_ctrl.Enable(False) if element.ChangeSubmits: text_ctrl.Bind(wx.EVT_KEY_UP, element.WxCallbackKeyboard) if element.EnterSubmits: text_ctrl.Bind(wx.EVT_TEXT_ENTER, element.ReturnKeyHandler) sizer = pad_widget(text_ctrl) hsizer.Add(sizer, 0) if not element.Visible: text_ctrl.Hide() if element.Tooltip: text_ctrl.SetToolTip(element.Tooltip) if element.Focus is True or (toplevel_form.UseDefaultFocus and not focus_set): focus_set = True element.SetFocus() # ------------------------- OUTPUT MULTILINE element ------------------------- # elif element_type == ELEM_TYPE_MULTILINE_OUTPUT: element = element # type: MultilineOutput style = 0 if element.EnterSubmits: style |= wx.TE_PROCESS_ENTER style |= wx.TE_MULTILINE | wx.TE_READONLY element.WxTextCtrl = text_ctrl = wx.TextCtrl(toplevel_form.MasterPanel, style=style) if element.DefaultText: text_ctrl.SetValue(element.DefaultText) do_font_and_color(element.WxTextCtrl) if element.ChangeSubmits: text_ctrl.Bind(wx.EVT_KEY_UP, element.WxCallbackKeyboard) if element.EnterSubmits: text_ctrl.Bind(wx.EVT_TEXT_ENTER, element.ReturnKeyHandler) sizer = pad_widget(text_ctrl) hsizer.Add(sizer, 0) if element.Focus is True or (toplevel_form.UseDefaultFocus and not focus_set): focus_set = True element.SetFocus() # ------------------------- OUTPUT element -----------------fd-------- # elif element_type == ELEM_TYPE_OUTPUT: element = element # type: Output style = 0 style |= wx.TE_MULTILINE | wx.TE_READONLY style = wx.TE_MULTILINE | wx.TE_READONLY | wx.HSCROLL element.WxTextCtrl = text_ctrl = wx.TextCtrl(toplevel_form.MasterPanel, style=style) do_font_and_color(element.WxTextCtrl) sizer = pad_widget(text_ctrl) hsizer.Add(sizer, 0) element.reroute_stdout() # ------------------------- INPUT CHECKBOX element ------------------------- # elif element_type == ELEM_TYPE_INPUT_CHECKBOX: element = element # type:Checkbox element.WxCheckbox = widget = wx.CheckBox(toplevel_form.MasterPanel) if element.Text: widget.SetLabel(element.Text) do_font_and_color(element.WxCheckbox) sizer = pad_widget(widget) if element.ChangeSubmits: widget.Bind(wx.EVT_CHECKBOX, element.WxCallbackKeyboard) hsizer.Add(sizer, 0) if element.InitialState: widget.SetValue(True) element.WxCheckbox = widget # # ------------------------- PROGRESS BAR element ------------------------- # elif element_type == ELEM_TYPE_PROGRESS_BAR: element = element # type: ProgressBar style = wx.GA_HORIZONTAL if element.Orientation.startswith('h') else wx.GA_VERTICAL element_size = element_size[::-1] if element.Orientation.startswith('v') else element_size element_size = wx.Size((element_size[0], element_size[1])) element.WxGauge = gauge = wx.Gauge(toplevel_form.MasterPanel, wx.ID_ANY, range=element.MaxValue, style=style, size=element_size) if element.StartValue is not None: gauge.SetValue(element.StartValue) do_font_and_color(element.WxGauge) sizer = pad_widget(gauge) hsizer.Add(sizer, 0) # ------------------------- INPUT RADIO BUTTON element ------------------------- # elif element_type == ELEM_TYPE_INPUT_RADIO: element = element # type: Radio widget = element.WxRadioButton # type: wx.RadioButton do_font_and_color(element.WxRadioButton) sizer = pad_widget(widget) if element.ChangeSubmits: widget.Bind(wx.EVT_RADIOBUTTON, element.WxCallbackKeyboard) hsizer.Add(sizer, 0) if element.InitialState: widget.SetValue(True) # ------------------------- INPUT SPINNER element ------------------------- # elif element_type == ELEM_TYPE_INPUT_SPIN: element = element # type:Spin ######## First make an Input widget that will be used to display the text ######## style = wx.ALIGN_RIGHT if element.ReadOnly: style |= wx.TE_READONLY element.WxTextCtrl = text_ctrl = wx.TextCtrl(toplevel_form.MasterPanel, style=style) do_font_and_color(element.WxTextCtrl) if element.ChangeSubmits: text_ctrl.Bind(wx.EVT_KEY_UP, element.WxCallbackKeyboard) text_ctrl.Bind(wx.EVT_TEXT_ENTER, element.ReturnKeyHandler) if element.DefaultValue: text_ctrl.SetValue(element.DefaultValue) element.CurrentValue = element.DefaultValue saved_pad = full_element_pad full_element_pad[3] = 0 # set right padding to 0 hsizer.Add(pad_widget(text_ctrl), 0) full_element_pad = saved_pad ######## Now make a "Spin Button" that has the arrows ######## # element.WxSpinCtrl = widget = wx.SpinCtrl(toplevel_form.MasterPanel, style=wx.SP_WRAP|wx.SP_ARROW_KEYS) element.WxSpinCtrl = widget = wx.SpinButton(toplevel_form.MasterPanel, style=wx.SP_WRAP|wx.SP_ARROW_KEYS) do_font_and_color(element.WxSpinCtrl) element.WxSpinCtrl.SetRange(0, len(element.Values)-1) if element.DefaultValue: element.WxSpinCtrl.SetValue(element.Values.index(element.DefaultValue)) widget.SetMinSize((25,25)) widget.Bind(wx.EVT_SPIN, element.WxSpinCallback) saved_pad = full_element_pad full_element_pad[1] = 0 # trying to set left pad to 0 but doesn't seem to work hsizer.Add(pad_widget(widget), 0) full_element_pad = saved_pad # ------------------------- IMAGE element ------------------------- # elif element_type == ELEM_TYPE_IMAGE: pass # if element.Filename is not None: # photo = tk.PhotoImage(file=element.Filename) # elif element.Data is not None: # photo = tk.PhotoImage(data=element.Data) # else: # photo = None # print('*ERROR laying out form.... Image Element has no image specified*') # # if photo is not None: # if element_size == ( # None, None) or element_size == None or element_size == toplevel_form.DefaultElementSize: # width, height = photo.width(), photo.height() # else: # width, height = element_size # if photo is not None: # element.tktext_label = tk.Label(tk_row_frame, image=photo, width=width, height=height, # bd=border_depth) # else: # element.tktext_label = tk.Label(tk_row_frame, width=width, height=height, bd=border_depth) # if element.BackgroundColor is not None: # element.tktext_label.config(background=element.BackgroundColor); # # element.tktext_label.image = photo # # tktext_label.configure(anchor=tk.NW, image=photo) # element.tktext_label.pack(side=tk.LEFT, padx=element.Pad[0], pady=element.Pad[1]) # if element.Tooltip is not None: # element.TooltipObject = ToolTip(element.tktext_label, text=element.Tooltip, # timeout=DEFAULT_TOOLTIP_TIME) # ------------------------- Canvas element ------------------------- # elif element_type == ELEM_TYPE_CANVAS: pass # width, height = element_size # if element._TKCanvas is None: # element._TKCanvas = tk.Canvas(tk_row_frame, width=width, height=height, bd=border_depth) # else: # element._TKCanvas.master = tk_row_frame # if element.BackgroundColor is not None and element.BackgroundColor != COLOR_SYSTEM_DEFAULT: # element._TKCanvas.configure(background=element.BackgroundColor, highlightthickness=0) # element._TKCanvas.pack(side=tk.LEFT, padx=element.Pad[0], pady=element.Pad[1]) # if element.Tooltip is not None: # element.TooltipObject = ToolTip(element._TKCanvas, text=element.Tooltip, # timeout=DEFAULT_TOOLTIP_TIME) # ------------------------- Graph element ------------------------- # elif element_type == ELEM_TYPE_GRAPH: pass # width, height = element_size # if element._TKCanvas is None: # element._TKCanvas = tk.Canvas(tk_row_frame, width=width, height=height, bd=border_depth) # else: # element._TKCanvas.master = tk_row_frame # element._TKCanvas2 = tk.Canvas(element._TKCanvas, width=width, height=height, bd=border_depth) # element._TKCanvas2.pack(side=tk.LEFT) # element._TKCanvas2.addtag_all('mytag') # if element.BackgroundColor is not None and element.BackgroundColor != COLOR_SYSTEM_DEFAULT: # element._TKCanvas2.configure(background=element.BackgroundColor, highlightthickness=0) # element._TKCanvas.configure(background=element.BackgroundColor, highlightthickness=0) # element._TKCanvas.pack(side=tk.LEFT, padx=element.Pad[0], pady=element.Pad[1]) # if element.Tooltip is not None: # element.TooltipObject = ToolTip(element._TKCanvas, text=element.Tooltip, # timeout=DEFAULT_TOOLTIP_TIME) # if element.ChangeSubmits: # element._TKCanvas2.bind('', element.ButtonReleaseCallBack) # element._TKCanvas2.bind('', element.ButtonPressCallBack) # if element.DragSubmits: # element._TKCanvas2.bind('', element.MotionCallBack) # ------------------------- MENUBAR element ------------------------- # elif element_type == ELEM_TYPE_MENUBAR: pass # menu_def = element.MenuDefinition # element.TKMenu = tk.Menu(toplevel_form.TKroot, tearoff=element.Tearoff) # create the menubar # menubar = element.TKMenu # for menu_entry in menu_def: # # print(f'Adding a Menubar ENTRY {menu_entry}') # baritem = tk.Menu(menubar, tearoff=element.Tearoff) # pos = menu_entry[0].find('&') # # print(pos) # if pos != -1: # if pos == 0 or menu_entry[0][pos - 1] != "\\": # menu_entry[0] = menu_entry[0][:pos] + menu_entry[0][pos + 1:] # menubar.add_cascade(label=menu_entry[0], menu=baritem, underline=pos) # if len(menu_entry) > 1: # AddMenuItem(baritem, menu_entry[1], element) # toplevel_form.TKroot.configure(menu=element.TKMenu) # ------------------------- Frame element ------------------------- # elif element_type == ELEM_TYPE_FRAME: pass # labeled_frame = tk.LabelFrame(tk_row_frame, text=element.Title, relief=element.Relief) # PackFormIntoFrame(element, labeled_frame, toplevel_form) # labeled_frame.pack(side=tk.LEFT, padx=element.Pad[0], pady=element.Pad[1]) # if element.BackgroundColor != COLOR_SYSTEM_DEFAULT and element.BackgroundColor is not None: # labeled_frame.configure(background=element.BackgroundColor, # highlightbackground=element.BackgroundColor, # highlightcolor=element.BackgroundColor) # if element.TextColor != COLOR_SYSTEM_DEFAULT and element.TextColor is not None: # labeled_frame.configure(foreground=element.TextColor) # if font is not None: # labeled_frame.configure(font=font) # if element.TitleLocation is not None: # labeled_frame.configure(labelanchor=element.TitleLocation) # if element.BorderWidth is not None: # labeled_frame.configure(borderwidth=element.BorderWidth) # if element.Tooltip is not None: # element.TooltipObject = ToolTip(labeled_frame, text=element.Tooltip, timeout=DEFAULT_TOOLTIP_TIME) # ------------------------- Tab element ------------------------- # elif element_type == ELEM_TYPE_TAB: pass # element.TKFrame = tk.Frame(form.TKNotebook) # PackFormIntoFrame(element, element.TKFrame, toplevel_form) # if element.Disabled: # form.TKNotebook.add(element.TKFrame, text=element.Title, state='disabled') # else: # form.TKNotebook.add(element.TKFrame, text=element.Title) # form.TKNotebook.pack(side=tk.LEFT, padx=element.Pad[0], pady=element.Pad[1]) # element.ParentNotebook = form.TKNotebook # element.TabID = form.TabCount # form.TabCount += 1 # if element.BackgroundColor != COLOR_SYSTEM_DEFAULT and element.BackgroundColor is not None: # element.TKFrame.configure(background=element.BackgroundColor, # highlightbackground=element.BackgroundColor, # highlightcolor=element.BackgroundColor) # # if element.TextColor != COLOR_SYSTEM_DEFAULT and element.TextColor is not None: # # element.TKFrame.configure(foreground=element.TextColor) # # # ttk.Style().configure("TNotebook", background='red') # # ttk.Style().map("TNotebook.Tab", background=[("selected", 'orange')], # # foreground=[("selected", 'green')]) # # ttk.Style().configure("TNotebook.Tab", background='blue', foreground='yellow') # # if element.BorderWidth is not None: # element.TKFrame.configure(borderwidth=element.BorderWidth) # if element.Tooltip is not None: # element.TooltipObject = ToolTip(element.TKFrame, text=element.Tooltip, # timeout=DEFAULT_TOOLTIP_TIME) # ------------------------- TabGroup element ------------------------- # elif element_type == ELEM_TYPE_TAB_GROUP: pass # custom_style = str(element.Key) + 'customtab.TNotebook' # style = ttk.Style(tk_row_frame) # if element.Theme is not None: # style.theme_use(element.Theme) # if element.TabLocation is not None: # position_dict = {'left': 'w', 'right': 'e', 'top': 'n', 'bottom': 's', 'lefttop': 'wn', # 'leftbottom': 'ws', 'righttop': 'en', 'rightbottom': 'es', 'bottomleft': 'sw', # 'bottomright': 'se', 'topleft': 'nw', 'topright': 'ne'} # try: # tab_position = position_dict[element.TabLocation] # except: # tab_position = position_dict['top'] # style.configure(custom_style, tabposition=tab_position) # # if element.BackgroundColor is not None and element.BackgroundColor != COLOR_SYSTEM_DEFAULT: # style.configure(custom_style, background=element.BackgroundColor, foreground='purple') # # # style.theme_create("yummy", parent="alt", settings={ # # "TNotebook": {"configure": {"tabmargins": [2, 5, 2, 0]}}, # # "TNotebook.Tab": { # # "configure": {"padding": [5, 1], "background": mygreen}, # # "map": {"background": [("selected", myred)], # # "expand": [("selected", [1, 1, 1, 0])]}}}) # # # style.configure(custom_style+'.Tab', background='red') # if element.SelectedTitleColor != None: # style.map(custom_style + '.Tab', foreground=[("selected", element.SelectedTitleColor)]) # if element.TextColor is not None and element.TextColor != COLOR_SYSTEM_DEFAULT: # style.configure(custom_style + '.Tab', foreground=element.TextColor) # # style.configure(custom_style, background='blue', foreground='yellow') # # element.TKNotebook = ttk.Notebook(tk_row_frame, style=custom_style) # # PackFormIntoFrame(element, toplevel_form.TKroot, toplevel_form) # # if element.ChangeSubmits: # element.TKNotebook.bind('<>', element.TabGroupSelectHandler) # if element.BorderWidth is not None: # element.TKNotebook.configure(borderwidth=element.BorderWidth) # if element.Tooltip is not None: # element.TooltipObject = ToolTip(element.TKNotebook, text=element.Tooltip, # timeout=DEFAULT_TOOLTIP_TIME) # ------------------------- SLIDER Box element ------------------------- # elif element_type == ELEM_TYPE_INPUT_SLIDER: pass # slider_length = element_size[0] * CharWidthInPixels() # slider_width = element_size[1] # element.TKIntVar = tk.IntVar() # element.TKIntVar.set(element.DefaultValue) # if element.Orientation[0] == 'v': # range_from = element.Range[1] # range_to = element.Range[0] # slider_length += DEFAULT_MARGINS[1] * (element_size[0] * 2) # add in the padding # else: # range_from = element.Range[0] # range_to = element.Range[1] # if element.ChangeSubmits: # tkscale = tk.Scale(tk_row_frame, orient=element.Orientation, variable=element.TKIntVar, # from_=range_from, to_=range_to, resolution=element.Resolution, # length=slider_length, width=slider_width, bd=element.BorderWidth, # relief=element.Relief, font=font, tickinterval=element.TickInterval, # command=element.SliderChangedHandler) # else: # tkscale = tk.Scale(tk_row_frame, orient=element.Orientation, variable=element.TKIntVar, # from_=range_from, to_=range_to, resolution=element.Resolution, # length=slider_length, width=slider_width, bd=element.BorderWidth, # relief=element.Relief, font=font, tickinterval=element.TickInterval) # tkscale.config(highlightthickness=0) # if element.BackgroundColor is not None and element.BackgroundColor != COLOR_SYSTEM_DEFAULT: # tkscale.configure(background=element.BackgroundColor) # if DEFAULT_SCROLLBAR_COLOR != COLOR_SYSTEM_DEFAULT: # tkscale.config(troughcolor=DEFAULT_SCROLLBAR_COLOR) # if text_color is not None and text_color != COLOR_SYSTEM_DEFAULT: # tkscale.configure(fg=text_color) # tkscale.pack(side=tk.LEFT, padx=element.Pad[0], pady=element.Pad[1]) # element.TKScale = tkscale # if element.Disabled == True: # element.TKScale['state'] = 'disabled' # if element.Tooltip is not None: # element.TooltipObject = ToolTip(element.TKScale, text=element.Tooltip, timeout=DEFAULT_TOOLTIP_TIME) # ------------------------- TABLE element ------------------------- # elif element_type == ELEM_TYPE_TABLE: pass # frame = tk.Frame(tk_row_frame) # # height = element.NumRows # if element.Justification == 'left': # anchor = tk.W # elif element.Justification == 'right': # anchor = tk.E # else: # anchor = tk.CENTER # column_widths = {} # for row in element.Values: # for i, col in enumerate(row): # col_width = min(len(str(col)), element.MaxColumnWidth) # try: # if col_width > column_widths[i]: # column_widths[i] = col_width # except: # column_widths[i] = col_width # if element.ColumnsToDisplay is None: # displaycolumns = element.ColumnHeadings # else: # displaycolumns = [] # for i, should_display in enumerate(element.ColumnsToDisplay): # if should_display: # displaycolumns.append(element.ColumnHeadings[i]) # column_headings = element.ColumnHeadings # if element.DisplayRowNumbers: # if display row number, tack on the numbers to front of columns # displaycolumns = [element.RowHeaderText, ] + displaycolumns # column_headings = [element.RowHeaderText, ] + element.ColumnHeadings # element.TKTreeview = ttk.Treeview(frame, columns=column_headings, # displaycolumns=displaycolumns, show='headings', height=height, # selectmode=element.SelectMode) # treeview = element.TKTreeview # if element.DisplayRowNumbers: # treeview.heading(element.RowHeaderText, text=element.RowHeaderText) # make a dummy heading # treeview.column(element.RowHeaderText, width=50, anchor=anchor) # for i, heading in enumerate(element.ColumnHeadings): # treeview.heading(heading, text=heading) # if element.AutoSizeColumns: # width = max(column_widths[i], len(heading)) # else: # try: # width = element.ColumnWidths[i] # except: # width = element.DefaultColumnWidth # # treeview.column(heading, width=width * CharWidthInPixels(), anchor=anchor) # # Insert values into the tree # for i, value in enumerate(element.Values): # if element.DisplayRowNumbers: # value = [i + element.StartingRowNumber] + value # id = treeview.insert('', 'end', text=value, iid=i + 1, values=value, tag=i % 2) # if element.AlternatingRowColor is not None: # treeview.tag_configure(1, background=element.AlternatingRowColor) # if element.BackgroundColor is not None and element.BackgroundColor != COLOR_SYSTEM_DEFAULT: # ttk.Style().configure("Treeview", background=element.BackgroundColor, # fieldbackground=element.BackgroundColor) # if element.TextColor is not None and element.TextColor != COLOR_SYSTEM_DEFAULT: # ttk.Style().configure("Treeview", foreground=element.TextColor) # # scrollable_frame.pack(side=tk.LEFT, padx=element.Pad[0], pady=element.Pad[1], expand=True, fill='both') # treeview.bind("<>", element.treeview_selected) # if element.BindReturnKey: # treeview.bind('', element.treeview_double_click) # treeview.bind('', element.treeview_double_click) # scrollbar = tk.Scrollbar(frame) # scrollbar.pack(side=tk.RIGHT, fill='y') # scrollbar.config(command=treeview.yview) # treeview.configure(yscrollcommand=scrollbar.set) # # element.TKTreeview.pack(side=tk.LEFT, expand=True, padx=0, pady=0, fill='both') # frame.pack(side=tk.LEFT, expand=True, padx=0, pady=0) # if element.Tooltip is not None: # element.TooltipObject = ToolTip(element.TKTreeview, text=element.Tooltip, # timeout=DEFAULT_TOOLTIP_TIME) # ------------------------- Tree element ------------------------- # elif element_type == ELEM_TYPE_TREE: pass # frame = tk.Frame(tk_row_frame) # # height = element.NumRows # if element.Justification == 'left': # justification # anchor = tk.W # elif element.Justification == 'right': # anchor = tk.E # else: # anchor = tk.CENTER # # if element.ColumnsToDisplay is None: # Which cols to display # displaycolumns = element.ColumnHeadings # else: # displaycolumns = [] # for i, should_display in enumerate(element.ColumnsToDisplay): # if should_display: # displaycolumns.append(element.ColumnHeadings[i]) # column_headings = element.ColumnHeadings # # ------------- GET THE TREEVIEW WIDGET ------------- # element.TKTreeview = ttk.Treeview(frame, columns=column_headings, # displaycolumns=displaycolumns, show='tree headings', height=height, # selectmode=element.SelectMode, ) # treeview = element.TKTreeview # for i, heading in enumerate(element.ColumnHeadings): # Configure cols + headings # treeview.heading(heading, text=heading) # if element.AutoSizeColumns: # width = min(element.MaxColumnWidth, len(heading) + 1) # else: # try: # width = element.ColumnWidths[i] # except: # width = element.DefaultColumnWidth # treeview.column(heading, width=width * CharWidthInPixels(), anchor=anchor) # # def add_treeview_data(node): # # print(f'Inserting {node.key} under parent {node.parent}') # if node.key != '': # treeview.insert(node.parent, 'end', node.key, text=node.text, values=node.values, # open=element.ShowExpanded) # for node in node.children: # add_treeview_data(node) # # add_treeview_data(element.TreeData.root_node) # treeview.column('#0', width=element.Col0Width * CharWidthInPixels(), anchor=anchor) # # ----- configure colors ----- # if element.BackgroundColor is not None and element.BackgroundColor != COLOR_SYSTEM_DEFAULT: # ttk.Style().configure("Treeview", background=element.BackgroundColor, # fieldbackground=element.BackgroundColor) # if element.TextColor is not None and element.TextColor != COLOR_SYSTEM_DEFAULT: # ttk.Style().configure("Treeview", foreground=element.TextColor) # # scrollbar = tk.Scrollbar(frame) # scrollbar.pack(side=tk.RIGHT, fill='y') # scrollbar.config(command=treeview.yview) # treeview.configure(yscrollcommand=scrollbar.set) # element.TKTreeview.pack(side=tk.LEFT, expand=True, padx=0, pady=0, fill='both') # frame.pack(side=tk.LEFT, expand=True, padx=0, pady=0) # treeview.bind("<>", element.treeview_selected) # if element.Tooltip is not None: # tooltip # element.TooltipObject = ToolTip(element.TKTreeview, text=element.Tooltip, # timeout=DEFAULT_TOOLTIP_TIME) # ------------------------- Separator element ------------------------- # elif element_type == ELEM_TYPE_SEPARATOR: pass # separator = ttk.Separator(tk_row_frame, orient=element.Orientation, ) # separator.pack(side=tk.LEFT, padx=element.Pad[0], pady=element.Pad[1], fill='both', expand=True) # # # ............................DONE WITH ROW pack the row of widgets ..........................# # done with row, pack the row of widgets containing_frame.Add(hsizer,0, wx.TOP|wx.BOTTOM, border=0) # tk_row_frame.grid(row=row_num+2, sticky=tk.NW, padx=DEFAULT_MARGINS[0]) # tk_row_frame.pack(side=tk.TOP, anchor='nw', padx=DEFAULT_MARGINS[0], expand=False) # if form.BackgroundColor is not None and form.BackgroundColor != COLOR_SYSTEM_DEFAULT: # tk_row_frame.configure(background=form.BackgroundColor) # toplevel_form.TKroot.configure(padx=DEFAULT_MARGINS[0], pady=DEFAULT_MARGINS[1]) return # ----====----====----====----====----==== STARTUP TK ====----====----====----====----====----# def StartupTK(window:Window): ow = Window.NumOpenWindows if Window.highest_level_app is None: app = Window.highest_level_app = wx.App(False) else: app = Window.highest_level_app Window.IncrementOpenCount() # -------- grab anywhere -------- if window.GrabAnywhere: frame = DragFrame(title=window.Title) else: frame = wx.Frame(None, title=window.Title) panel = wx.Panel(frame, -1, style=wx.TRANSPARENT_WINDOW) panel.SetTransparent(.5) if window.GrabAnywhere: panel.Bind(wx.EVT_MOTION, frame.on_mouse) window.App = app window.MasterFrame = frame window.MasterPanel = panel window.MasterFrame.panel = panel frame.Bind(wx.EVT_CLOSE, window.OnClose) # ----------------------------- Icon ----------------------------- if window.WindowIcon: if type(window.WindowIcon) is bytes: icon = PyEmbeddedImage(window.WindowIcon).GetIcon() else: if os.path.exists(window.WindowIcon): icon = wx.Icon(window.WindowIcon, wx.BITMAP_TYPE_ANY) else: icon = PyEmbeddedImage(DEFAULT_BASE64_ICON).GetIcon() if icon: frame.SetIcon(icon) # ----------------------------- Background ----------------------------- if window.BackgroundColor is not None and window.BackgroundColor != COLOR_SYSTEM_DEFAULT: panel.SetBackgroundColour(window.BackgroundColor) if window.BackgroundImage: if type(window.BackgroundImage) is bytes: pic = PyEmbeddedImage(window.BackgroundImage).GetBitmap() else: if os.path.exists(window.BackgroundImage): pic = wx.Image(window.BackgroundImage, wx.BITMAP_TYPE_ANY).ConvertToBitmap() else: pic = PyEmbeddedImage(DEFAULT_BASE64_ICON).GetBitmap() window.bitmap1 = wx.StaticBitmap(window.MasterPanel, -1, pic, (0, 0)) InitializeResults(window) # ----------------------------- ----------------------------- # ----------------------------- ----------------------------- # ----------------------------- handle settings using Style Flags ----------------------------- style = 0 if window.NoTitleBar: style |= wx.BORDER_NONE else: style |= wx.BORDER_DEFAULT if window.KeepOnTop: style |= wx.STAY_ON_TOP if style: window.MasterFrame.SetWindowStyleFlag(style) if window.ReturnKeyboardEvents: # style |= wx.WANTS_CHARS window.App.Bind(wx.EVT_CHAR_HOOK, window.callback_keyboard_char) window.App.Bind(wx.EVT_MOUSEWHEEL, window.callback_keyboard_char) # ----------------------------- Sizer creation and PACK FORM ----------------------------- vsizer = wx.BoxSizer(wx.VERTICAL) preprocess_radio_elements(window, window) # ----------------------------- Do the packing of the elements ----------------------------- PackFormIntoFrame(window, vsizer, window) # ----------------------------- Sizers to create margins ----------------------------- outersizer = wx.BoxSizer(wx.VERTICAL) outersizer.Fit(window.MasterFrame) outersizer.Add(vsizer, 1, wx.TOP|wx.BOTTOM|wx.EXPAND, border=DEFAULT_MARGINS[1]) window.OuterSizer = wx.BoxSizer(wx.VERTICAL) window.OuterSizer.Fit(window.MasterFrame) window.OuterSizer.Add(outersizer, 1, wx.LEFT|wx.RIGHT|wx.EXPAND, border=DEFAULT_MARGINS[0]) window.MasterPanel.SetSizer(window.OuterSizer) window.OuterSizer.Fit(window.MasterFrame) # ----------------------------- window location, size and alpha ----------------------------- if window.Location != (None, None): window.MasterFrame.Move(window.Location[0], window.Location[1]) else: window.MasterFrame.Center(wx.BOTH) if window._Size != (None, None): window.MasterFrame.SetSize(window._Size[0], window._Size[1]) if window._AlphaChannel is not None: window.SetAlpha(window._AlphaChannel) # ----------------------------- DISPLAY the window ----------------------------- window.MasterFrame.Show() # ....................................... DONE creating and laying out window ..........................# if RUN_INSPECTION_TOOL: wx.lib.inspection.InspectionTool().Show() window.CurrentlyRunningMainloop = True if window.Timeout: timer = wx.Timer(window.App) window.App.Bind(wx.EVT_TIMER, window.timer_timeout) timer.Start(milliseconds=window.Timeout, oneShot=wx.TIMER_ONE_SHOT) else: timer = None if window.AutoClose: window.timer = wx.Timer(window.App, id=Window.NumOpenWindows) window.App.Bind(wx.EVT_TIMER, lambda frame: window.autoclose_timer_callback(window.MasterFrame), id=Window.NumOpenWindows) window.timer.Start(milliseconds=window.AutoCloseDuration*1000, oneShot=wx.TIMER_ONE_SHOT) # ------------------------------------ MAINLOOP ------------------------------------ if not window.NonBlocking: window.App.MainLoop() else: window.non_block_timer = wx.Timer(window.App, id=5678) window.App.Bind(wx.EVT_TIMER, window.non_block_timer_timeout, id=5678) window.non_block_timer.Start(milliseconds=0, oneShot=wx.TIMER_ONE_SHOT) window.App.MainLoop() if Window.stdout_is_rerouted: sys.stdout = Window.stdout_location window.CurrentlyRunningMainloop = False if timer: timer.Stop() # if not window.FormRemainedOpen: # _my_windows.Decrement() # if window.RootNeedsDestroying: # window.TKroot.destroy() # window.RootNeedsDestroying = False return # ==============================_GetNumLinesNeeded ==# # Helper function for determining how to wrap text # # ===================================================# def _GetNumLinesNeeded(text, max_line_width): if max_line_width == 0: return 1 lines = text.split('\n') num_lines = len(lines) # number of original lines of text max_line_len = max([len(l) for l in lines]) # longest line lines_used = [] for L in lines: lines_used.append(len(L) // max_line_width + (len(L) % max_line_width > 0)) # fancy math to round up total_lines_needed = sum(lines_used) return total_lines_needed # ============================== PROGRESS METER ========================================== # def ConvertArgsToSingleString(*args): max_line_total, width_used, total_lines, = 0, 0, 0 single_line_message = '' # loop through args and built a SINGLE string from them for message in args: # fancy code to check if string and convert if not is not need. Just always convert to string :-) # if not isinstance(message, str): message = str(message) message = str(message) longest_line_len = max([len(l) for l in message.split('\n')]) width_used = max(longest_line_len, width_used) max_line_total = max(max_line_total, width_used) lines_needed = _GetNumLinesNeeded(message, width_used) total_lines += lines_needed single_line_message += message + '\n' return single_line_message, width_used, total_lines METER_REASON_CANCELLED = 'cancelled' METER_REASON_CLOSED = 'closed' METER_REASON_REACHED_MAX = 'finished' METER_OK = True METER_STOPPED = False class QuickMeter(object): active_meters = {} exit_reasons = {} def __init__(self, title, current_value, max_value, key, *args, orientation='v', bar_color=(None, None), button_color=(None, None), size=DEFAULT_PROGRESS_BAR_SIZE, border_width=None, grab_anywhere=False): self.start_time = datetime.datetime.utcnow() self.key = key self.orientation = orientation self.bar_color = bar_color self.size = size self.grab_anywhere = grab_anywhere self.button_color = button_color self.border_width = border_width self.title = title self.current_value = current_value self.max_value = max_value self.close_reason = None self.window = self.BuildWindow(*args) def BuildWindow(self, *args): layout = [] if self.orientation.lower().startswith('h'): col = [] col += [[T(arg)] for arg in args] col += [[T('', size=(25,8), key='_STATS_')], [ProgressBar(max_value=self.max_value, orientation='h', key='_PROG_', size=self.size)], [Cancel(button_color=self.button_color), Stretch()]] layout = [Column(col)] else: col = [[ProgressBar(max_value=self.max_value, orientation='v', key='_PROG_', size=self.size)]] col2 = [] col2 += [[T(arg)] for arg in args] col2 += [[T('', size=(25,8), key='_STATS_')], [Cancel(button_color=self.button_color), Stretch()]] layout = [Column(col), Column(col2)] self.window = Window(self.title, grab_anywhere=self.grab_anywhere, border_depth=self.border_width) self.window.Layout([layout]).Finalize() return self.window def UpdateMeter(self, current_value, max_value): self.current_value = current_value self.max_value = max_value self.window.Element('_PROG_').UpdateBar(self.current_value, self.max_value) self.window.Element('_STATS_').Update('\n'.join(self.ComputeProgressStats())) event, values = self.window.Read(timeout=0) if event in('Cancel', None) or current_value >= max_value: self.window.Close() del(QuickMeter.active_meters[self.key]) QuickMeter.exit_reasons[self.key] = METER_REASON_CANCELLED if event == 'Cancel' else METER_REASON_CLOSED if event is None else METER_REASON_REACHED_MAX return QuickMeter.exit_reasons[self.key] return METER_OK def ComputeProgressStats(self): utc = datetime.datetime.utcnow() time_delta = utc - self.start_time total_seconds = time_delta.total_seconds() if not total_seconds: total_seconds = 1 try: time_per_item = total_seconds / self.current_value except: time_per_item = 1 seconds_remaining = (self.max_value - self.current_value) * time_per_item time_remaining = str(datetime.timedelta(seconds=seconds_remaining)) time_remaining_short = (time_remaining).split(".")[0] time_delta_short = str(time_delta).split(".")[0] total_time = time_delta + datetime.timedelta(seconds=seconds_remaining) total_time_short = str(total_time).split(".")[0] self.stat_messages = [ '{} of {}'.format(self.current_value, self.max_value), '{} %'.format(100 * self.current_value // self.max_value), '', ' {:6.2f} Iterations per Second'.format(self.current_value / total_seconds), ' {:6.2f} Seconds per Iteration'.format(total_seconds / (self.current_value if self.current_value else 1)), '', '{} Elapsed Time'.format(time_delta_short), '{} Time Remaining'.format(time_remaining_short), '{} Estimated Total Time'.format(total_time_short)] return self.stat_messages def OneLineProgressMeter(title, current_value, max_value, key, *args, orientation='v', bar_color=(None, None), button_color=None, size=DEFAULT_PROGRESS_BAR_SIZE, border_width=None, grab_anywhere=False): if key not in QuickMeter.active_meters: meter = QuickMeter(title, current_value, max_value, key, *args, orientation=orientation, bar_color=bar_color, button_color=button_color, size=size, border_width=border_width, grab_anywhere=grab_anywhere) QuickMeter.active_meters[key] = meter else: meter = QuickMeter.active_meters[key] rc = meter.UpdateMeter(current_value, max_value) OneLineProgressMeter.exit_reasons = getattr(OneLineProgressMeter,'exit_reasons', QuickMeter.exit_reasons) return rc == METER_OK def OneLineProgressMeterCancel(key): try: meter = QuickMeter.active_meters[key] meter.window.Close() del(QuickMeter.active_meters[key]) QuickMeter.exit_reasons[key] = METER_REASON_CANCELLED except: # meter is already deleted return # input is #RRGGBB # output is #RRGGBB def GetComplimentaryHex(color): # strip the # from the beginning color = color[1:] # convert the string into hex color = int(color, 16) # invert the three bytes # as good as substracting each of RGB component by 255(FF) comp_color = 0xFFFFFF ^ color # convert the color back to hex by prefixing a # comp_color = "#%06X" % comp_color return comp_color # ======================== EasyPrint =====# # ===================================================# class DebugWin(): debug_window = None def __init__(self, size=(None, None), location=(None, None), font=None, no_titlebar=False, no_button=False, grab_anywhere=False, keep_on_top=False, title=None, do_not_reroute_stdout=False): # Show a form that's a running counter self.size = size self.location = location self.font = font self.no_titlebar = no_titlebar self.no_button = no_button self.grab_anywhere = grab_anywhere self.keep_on_top = keep_on_top self.do_not_reroute_stdout = do_not_reroute_stdout win_size = size if size != (None, None) else DEFAULT_DEBUG_WINDOW_SIZE self.window = Window(title=title or 'Debug Window', no_titlebar=no_titlebar, auto_size_text=True, location=location, font=font or ('Courier New', 10), grab_anywhere=grab_anywhere, keep_on_top=keep_on_top) self.output_element = MultilineOutput(size=win_size, key='_MULTILINE_') if do_not_reroute_stdout else Output(size=win_size) if no_button: self.layout = [[self.output_element]] else: self.layout = [ [self.output_element], [DummyButton('Quit'), Stretch()] ] self.window.AddRows(self.layout) self.window.Read(timeout=0) # Show a non-blocking form, returns immediately Window.active_popups[self.window] = 'debug window' return def Print(self, *args, end=None, sep=None): sepchar = sep if sep is not None else ' ' endchar = end if end is not None else '\n' if self.window is None: # if window was destroyed already, just print self.__init__(size=self.size, location=self.location, font=self.font, no_titlebar=self.no_titlebar, no_button=self.no_button, grab_anywhere=self.grab_anywhere, keep_on_top=self.keep_on_top, do_not_reroute_stdout=self.do_not_reroute_stdout) event, values = self.window.Read(timeout=0) if event == 'Quit' or event is None: self.Close() self.__init__(size=self.size, location=self.location, font=self.font, no_titlebar=self.no_titlebar, no_button=self.no_button, grab_anywhere=self.grab_anywhere, keep_on_top=self.keep_on_top, do_not_reroute_stdout=self.do_not_reroute_stdout) if self.do_not_reroute_stdout: outstring = '' for arg in args: outstring += str(arg) + sepchar outstring += endchar self.output_element.Update(outstring, append=True) else: print(*args, sep=sepchar, end=endchar) def Close(self): self.window.Close() self.window.__del__() self.window = None def PrintClose(): EasyPrintClose() def EasyPrint(*args, size=(None, None), end=None, sep=None, location=(None, None), font=None, no_titlebar=False, no_button=False, grab_anywhere=False, keep_on_top=False, do_not_reroute_stdout=True): if DebugWin.debug_window is None: DebugWin.debug_window = DebugWin(size=size, location=location, font=font, no_titlebar=no_titlebar, no_button=no_button, grab_anywhere=grab_anywhere, keep_on_top=keep_on_top, do_not_reroute_stdout=do_not_reroute_stdout) DebugWin.debug_window.Print(*args, end=end, sep=sep) Print = EasyPrint eprint = EasyPrint def EasyPrintClose(): if DebugWin.debug_window is not None: DebugWin.debug_window.Close() DebugWin.debug_window = None # ======================== Scrolled Text Box =====# # ===================================================# def PopupScrolled(*args, button_color=None, yes_no=False, auto_close=False, auto_close_duration=None, size=(None, None)): if not args: return width, height = size width = width if width else MESSAGE_BOX_LINE_WIDTH form = Window(args[0], auto_size_text=True, button_color=button_color, auto_close=auto_close, auto_close_duration=auto_close_duration) max_line_total, max_line_width, total_lines, height_computed = 0, 0, 0, 0 complete_output = '' for message in args: # fancy code to check if string and convert if not is not need. Just always convert to string :-) # if not isinstance(message, str): message = str(message) message = str(message) longest_line_len = max([len(l) for l in message.split('\n')]) width_used = min(longest_line_len, width) max_line_total = max(max_line_total, width_used) max_line_width = width lines_needed = _GetNumLinesNeeded(message, width_used) height_computed += lines_needed complete_output += message + '\n' total_lines += lines_needed height_computed = MAX_SCROLLED_TEXT_BOX_HEIGHT if height_computed > MAX_SCROLLED_TEXT_BOX_HEIGHT else height_computed if height: height_computed = height form.AddRow(Multiline(complete_output, size=(max_line_width, height_computed))) pad = max_line_total - 15 if max_line_total > 15 else 1 # show either an OK or Yes/No depending on paramater if yes_no: form.AddRow(Text('', size=(pad, 1), auto_size_text=False), Yes(), No()) button, values = form.Read() return button else: form.AddRow(Text('', size=(pad, 1), auto_size_text=False), Button('OK', size=(5, 1), button_color=button_color)) button, values = form.Read() return button ScrolledTextBox = PopupScrolled # ============================== SetGlobalIcon ======# # Sets the icon to be used by default # # ===================================================# def SetGlobalIcon(icon): global _my_windows try: with open(icon, 'r') as icon_file: pass except: raise FileNotFoundError _my_windows.user_defined_icon = icon return True # ============================== SetOptions =========# # Sets the icon to be used by default # # ===================================================# def SetOptions(icon=None, button_color=None, element_size=(None, None), button_element_size=(None, None), margins=(None, None), element_padding=(None, None), auto_size_text=None, auto_size_buttons=None, font=None, border_width=None, slider_border_width=None, slider_relief=None, slider_orientation=None, autoclose_time=None, message_box_line_width=None, progress_meter_border_depth=None, progress_meter_style=None, progress_meter_relief=None, progress_meter_color=None, progress_meter_size=None, text_justification=None, background_color=None, element_background_color=None, text_element_background_color=None, input_elements_background_color=None, input_text_color=None, scrollbar_color=None, text_color=None, element_text_color=None, debug_win_size=(None, None), window_location=(None, None), tooltip_time=None): global DEFAULT_ELEMENT_SIZE global DEFAULT_BUTTON_ELEMENT_SIZE global DEFAULT_MARGINS # Margins for each LEFT/RIGHT margin is first term global DEFAULT_ELEMENT_PADDING # Padding between elements (row, col) in pixels global DEFAULT_AUTOSIZE_TEXT global DEFAULT_AUTOSIZE_BUTTONS global DEFAULT_FONT global DEFAULT_BORDER_WIDTH global DEFAULT_AUTOCLOSE_TIME global DEFAULT_BUTTON_COLOR global MESSAGE_BOX_LINE_WIDTH global DEFAULT_PROGRESS_BAR_BORDER_WIDTH global DEFAULT_PROGRESS_BAR_STYLE global DEFAULT_PROGRESS_BAR_RELIEF global DEFAULT_PROGRESS_BAR_COLOR global DEFAULT_PROGRESS_BAR_SIZE global DEFAULT_TEXT_JUSTIFICATION global DEFAULT_DEBUG_WINDOW_SIZE global DEFAULT_SLIDER_BORDER_WIDTH global DEFAULT_SLIDER_RELIEF global DEFAULT_SLIDER_ORIENTATION global DEFAULT_BACKGROUND_COLOR global DEFAULT_INPUT_ELEMENTS_COLOR global DEFAULT_ELEMENT_BACKGROUND_COLOR global DEFAULT_TEXT_ELEMENT_BACKGROUND_COLOR global DEFAULT_SCROLLBAR_COLOR global DEFAULT_TEXT_COLOR global DEFAULT_WINDOW_LOCATION global DEFAULT_ELEMENT_TEXT_COLOR global DEFAULT_INPUT_TEXT_COLOR global DEFAULT_TOOLTIP_TIME global _my_windows if icon: try: with open(icon, 'r') as icon_file: pass except: raise FileNotFoundError _my_windows.user_defined_icon = icon if button_color != None: DEFAULT_BUTTON_COLOR = button_color if element_size != (None, None): DEFAULT_ELEMENT_SIZE = element_size if button_element_size != (None, None): DEFAULT_BUTTON_ELEMENT_SIZE = button_element_size if margins != (None, None): DEFAULT_MARGINS = margins if element_padding != (None, None): DEFAULT_ELEMENT_PADDING = element_padding if auto_size_text != None: DEFAULT_AUTOSIZE_TEXT = auto_size_text if auto_size_buttons != None: DEFAULT_AUTOSIZE_BUTTONS = auto_size_buttons if font != None: DEFAULT_FONT = font if border_width != None: DEFAULT_BORDER_WIDTH = border_width if autoclose_time != None: DEFAULT_AUTOCLOSE_TIME = autoclose_time if message_box_line_width != None: MESSAGE_BOX_LINE_WIDTH = message_box_line_width if progress_meter_border_depth != None: DEFAULT_PROGRESS_BAR_BORDER_WIDTH = progress_meter_border_depth if progress_meter_style != None: DEFAULT_PROGRESS_BAR_STYLE = progress_meter_style if progress_meter_relief != None: DEFAULT_PROGRESS_BAR_RELIEF = progress_meter_relief if progress_meter_color != None: DEFAULT_PROGRESS_BAR_COLOR = progress_meter_color if progress_meter_size != None: DEFAULT_PROGRESS_BAR_SIZE = progress_meter_size if slider_border_width != None: DEFAULT_SLIDER_BORDER_WIDTH = slider_border_width if slider_orientation != None: DEFAULT_SLIDER_ORIENTATION = slider_orientation if slider_relief != None: DEFAULT_SLIDER_RELIEF = slider_relief if text_justification != None: DEFAULT_TEXT_JUSTIFICATION = text_justification if background_color != None: DEFAULT_BACKGROUND_COLOR = background_color if text_element_background_color != None: DEFAULT_TEXT_ELEMENT_BACKGROUND_COLOR = text_element_background_color if input_elements_background_color != None: DEFAULT_INPUT_ELEMENTS_COLOR = input_elements_background_color if element_background_color != None: DEFAULT_ELEMENT_BACKGROUND_COLOR = element_background_color if window_location != (None, None): DEFAULT_WINDOW_LOCATION = window_location if debug_win_size != (None, None): DEFAULT_DEBUG_WINDOW_SIZE = debug_win_size if text_color != None: DEFAULT_TEXT_COLOR = text_color if scrollbar_color != None: DEFAULT_SCROLLBAR_COLOR = scrollbar_color if element_text_color != None: DEFAULT_ELEMENT_TEXT_COLOR = element_text_color if input_text_color is not None: DEFAULT_INPUT_TEXT_COLOR = input_text_color if tooltip_time is not None: DEFAULT_TOOLTIP_TIME = tooltip_time return True #################### ChangeLookAndFeel ####################### # Predefined settings that will change the colors and styles # # of the elements. # ############################################################## LOOK_AND_FEEL_TABLE = {'SystemDefault': {'BACKGROUND': COLOR_SYSTEM_DEFAULT, 'TEXT': COLOR_SYSTEM_DEFAULT, 'INPUT': COLOR_SYSTEM_DEFAULT, 'TEXT_INPUT': COLOR_SYSTEM_DEFAULT, 'SCROLL': COLOR_SYSTEM_DEFAULT, 'BUTTON': OFFICIAL_PYSIMPLEGUI_BUTTON_COLOR, 'PROGRESS': COLOR_SYSTEM_DEFAULT, 'BORDER': 1, 'SLIDER_DEPTH': 1, 'PROGRESS_DEPTH': 0}, 'Reddit': {'BACKGROUND': '#ffffff', 'TEXT': '#1a1a1b', 'INPUT': '#dae0e6', 'TEXT_INPUT': '#222222', 'SCROLL': '#a5a4a4', 'BUTTON': ('white', '#0079d3'), 'PROGRESS': DEFAULT_PROGRESS_BAR_COLOR, 'BORDER': 1, 'SLIDER_DEPTH': 0, 'PROGRESS_DEPTH': 0, 'ACCENT1': '#ff5414', 'ACCENT2': '#33a8ff', 'ACCENT3': '#dbf0ff'}, 'Topanga': {'BACKGROUND': '#282923', 'TEXT': '#E7DB74', 'INPUT': '#393a32', 'TEXT_INPUT': '#E7C855', 'SCROLL': '#E7C855', 'BUTTON': ('#E7C855', '#284B5A'), 'PROGRESS': DEFAULT_PROGRESS_BAR_COLOR, 'BORDER': 1, 'SLIDER_DEPTH': 0, 'PROGRESS_DEPTH': 0, 'ACCENT1': '#c15226', 'ACCENT2': '#7a4d5f', 'ACCENT3': '#889743'}, 'GreenTan': {'BACKGROUND': '#9FB8AD', 'TEXT': COLOR_SYSTEM_DEFAULT, 'INPUT': '#F7F3EC', 'TEXT_INPUT': 'black', 'SCROLL': '#F7F3EC', 'BUTTON': ('white', '#475841'), 'PROGRESS': DEFAULT_PROGRESS_BAR_COLOR, 'BORDER': 1, 'SLIDER_DEPTH': 0, 'PROGRESS_DEPTH': 0}, 'Dark': {'BACKGROUND': 'gray25', 'TEXT': 'white', 'INPUT': 'gray30', 'TEXT_INPUT': 'black', 'SCROLL': 'gray44', 'BUTTON': ('white', '#004F00'), 'PROGRESS': DEFAULT_PROGRESS_BAR_COLOR, 'BORDER': 1, 'SLIDER_DEPTH': 0, 'PROGRESS_DEPTH': 0}, 'LightGreen': {'BACKGROUND': '#B7CECE', 'TEXT': 'black', 'INPUT': '#FDFFF7', 'TEXT_INPUT': 'black', 'SCROLL': '#FDFFF7', 'BUTTON': ('white', '#658268'), 'PROGRESS': DEFAULT_PROGRESS_BAR_COLOR, 'BORDER': 1, 'SLIDER_DEPTH': 0, 'ACCENT1': '#76506d', 'ACCENT2': '#5148f1', 'ACCENT3': '#0a1c84', 'PROGRESS_DEPTH': 0}, 'Dark2': {'BACKGROUND': 'gray25', 'TEXT': 'white', 'INPUT': 'white', 'TEXT_INPUT': 'black', 'SCROLL': 'gray44', 'BUTTON': ('white', '#004F00'), 'PROGRESS': DEFAULT_PROGRESS_BAR_COLOR, 'BORDER': 1, 'SLIDER_DEPTH': 0, 'PROGRESS_DEPTH': 0}, 'Black': {'BACKGROUND': 'black', 'TEXT': 'white', 'INPUT': 'gray30', 'TEXT_INPUT': 'black', 'SCROLL': 'gray44', 'BUTTON': ('black', 'white'), 'PROGRESS': DEFAULT_PROGRESS_BAR_COLOR, 'BORDER': 1, 'SLIDER_DEPTH': 0, 'PROGRESS_DEPTH': 0}, 'Tan': {'BACKGROUND': '#fdf6e3', 'TEXT': '#268bd1', 'INPUT': '#eee8d5', 'TEXT_INPUT': '#6c71c3', 'SCROLL': '#eee8d5', 'BUTTON': ('white', '#063542'), 'PROGRESS': DEFAULT_PROGRESS_BAR_COLOR, 'BORDER': 1, 'SLIDER_DEPTH': 0, 'PROGRESS_DEPTH': 0}, 'TanBlue': {'BACKGROUND': '#e5dece', 'TEXT': '#063289', 'INPUT': '#f9f8f4', 'TEXT_INPUT': '#242834', 'SCROLL': '#eee8d5', 'BUTTON': ('white', '#063289'), 'PROGRESS': DEFAULT_PROGRESS_BAR_COLOR, 'BORDER': 1, 'SLIDER_DEPTH': 0, 'PROGRESS_DEPTH': 0}, 'DarkTanBlue': {'BACKGROUND': '#242834', 'TEXT': '#dfe6f8', 'INPUT': '#97755c', 'TEXT_INPUT': 'white', 'SCROLL': '#a9afbb', 'BUTTON': ('white', '#063289'), 'PROGRESS': DEFAULT_PROGRESS_BAR_COLOR, 'BORDER': 1, 'SLIDER_DEPTH': 0, 'PROGRESS_DEPTH': 0}, 'DarkAmber': {'BACKGROUND': '#2c2825', 'TEXT': '#fdcb52', 'INPUT': '#705e52', 'TEXT_INPUT': '#fdcb52', 'SCROLL': '#705e52', 'BUTTON': ('black', '#fdcb52'), 'PROGRESS': DEFAULT_PROGRESS_BAR_COLOR, 'BORDER': 1, 'SLIDER_DEPTH': 0, 'PROGRESS_DEPTH': 0}, 'DarkBlue': {'BACKGROUND': '#1a2835', 'TEXT': '#d1ecff', 'INPUT': '#335267', 'TEXT_INPUT': '#acc2d0', 'SCROLL': '#1b6497', 'BUTTON': ('black', '#fafaf8'), 'PROGRESS': DEFAULT_PROGRESS_BAR_COLOR, 'BORDER': 1, 'SLIDER_DEPTH': 0, 'PROGRESS_DEPTH': 0}, 'Reds': {'BACKGROUND': '#280001', 'TEXT': 'white', 'INPUT': '#d8d584', 'TEXT_INPUT': 'black', 'SCROLL': '#763e00', 'BUTTON': ('black', '#daad28'), 'PROGRESS': DEFAULT_PROGRESS_BAR_COLOR, 'BORDER': 1, 'SLIDER_DEPTH': 0, 'PROGRESS_DEPTH': 0}, 'Green': {'BACKGROUND': '#82a459', 'TEXT': 'black', 'INPUT': '#d8d584', 'TEXT_INPUT': 'black', 'SCROLL': '#e3ecf3', 'BUTTON': ('white', '#517239'), 'PROGRESS': DEFAULT_PROGRESS_BAR_COLOR, 'BORDER': 1, 'SLIDER_DEPTH': 0, 'PROGRESS_DEPTH': 0}, 'BluePurple': {'BACKGROUND': '#A5CADD', 'TEXT': '#6E266E', 'INPUT': '#E0F5FF', 'TEXT_INPUT': 'black', 'SCROLL': '#E0F5FF', 'BUTTON': ('white', '#303952'), 'PROGRESS': DEFAULT_PROGRESS_BAR_COLOR, 'BORDER': 1, 'SLIDER_DEPTH': 0, 'PROGRESS_DEPTH': 0}, 'Purple': {'BACKGROUND': '#B0AAC2', 'TEXT': 'black', 'INPUT': '#F2EFE8', 'SCROLL': '#F2EFE8', 'TEXT_INPUT': 'black', 'BUTTON': ('black', '#C2D4D8'), 'PROGRESS': DEFAULT_PROGRESS_BAR_COLOR, 'BORDER': 1, 'SLIDER_DEPTH': 0, 'PROGRESS_DEPTH': 0}, 'BlueMono': {'BACKGROUND': '#AAB6D3', 'TEXT': 'black', 'INPUT': '#F1F4FC', 'SCROLL': '#F1F4FC', 'TEXT_INPUT': 'black', 'BUTTON': ('white', '#7186C7'), 'PROGRESS': DEFAULT_PROGRESS_BAR_COLOR, 'BORDER': 1, 'SLIDER_DEPTH': 0, 'PROGRESS_DEPTH': 0}, 'GreenMono': {'BACKGROUND': '#A8C1B4', 'TEXT': 'black', 'INPUT': '#DDE0DE', 'SCROLL': '#E3E3E3', 'TEXT_INPUT': 'black', 'BUTTON': ('white', '#6D9F85'), 'PROGRESS': DEFAULT_PROGRESS_BAR_COLOR, 'BORDER': 1, 'SLIDER_DEPTH': 0, 'PROGRESS_DEPTH': 0}, 'BrownBlue': {'BACKGROUND': '#64778d', 'TEXT': 'white', 'INPUT': '#f0f3f7', 'SCROLL': '#A6B2BE', 'TEXT_INPUT': 'black', 'BUTTON': ('white', '#283b5b'), 'PROGRESS': DEFAULT_PROGRESS_BAR_COLOR, 'BORDER': 1, 'SLIDER_DEPTH': 0, 'PROGRESS_DEPTH': 0}, 'BrightColors': {'BACKGROUND': '#b4ffb4', 'TEXT': 'black', 'INPUT': '#ffff64', 'SCROLL': '#ffb482', 'TEXT_INPUT': 'black', 'BUTTON': ('black', '#ffa0dc'), 'PROGRESS': DEFAULT_PROGRESS_BAR_COLOR, 'BORDER': 1, 'SLIDER_DEPTH': 0, 'PROGRESS_DEPTH': 0}, 'NeutralBlue': {'BACKGROUND': '#92aa9d', 'TEXT': 'black', 'INPUT': '#fcfff6', 'SCROLL': '#fcfff6', 'TEXT_INPUT': 'black', 'BUTTON': ('black', '#d0dbbd'), 'PROGRESS': DEFAULT_PROGRESS_BAR_COLOR, 'BORDER': 1, 'SLIDER_DEPTH': 0, 'PROGRESS_DEPTH': 0}, 'Kayak': {'BACKGROUND': '#a7ad7f', 'TEXT': 'black', 'INPUT': '#e6d3a8', 'SCROLL': '#e6d3a8', 'TEXT_INPUT': 'black', 'BUTTON': ('white', '#5d907d'), 'PROGRESS': DEFAULT_PROGRESS_BAR_COLOR, 'BORDER': 1, 'SLIDER_DEPTH': 0, 'PROGRESS_DEPTH': 0}, 'SandyBeach': {'BACKGROUND': '#efeccb', 'TEXT': '#012f2f', 'INPUT': '#e6d3a8', 'SCROLL': '#e6d3a8', 'TEXT_INPUT': '#012f2f', 'BUTTON': ('white', '#046380'), 'PROGRESS': DEFAULT_PROGRESS_BAR_COLOR, 'BORDER': 1, 'SLIDER_DEPTH': 0, 'PROGRESS_DEPTH': 0}, 'TealMono': {'BACKGROUND': '#a8cfdd', 'TEXT': 'black', 'INPUT': '#dfedf2', 'SCROLL': '#dfedf2', 'TEXT_INPUT': 'black', 'BUTTON': ('white', '#183440'), 'PROGRESS': DEFAULT_PROGRESS_BAR_COLOR, 'BORDER': 1, 'SLIDER_DEPTH': 0, 'PROGRESS_DEPTH': 0} } def ListOfLookAndFeelValues(): return list(LOOK_AND_FEEL_TABLE.keys()) def ChangeLookAndFeel(index): # global LOOK_AND_FEEL_TABLE if sys.platform == 'darwin': print('*** Changing look and feel is not supported on Mac platform ***') return # look and feel table try: colors = LOOK_AND_FEEL_TABLE[index] SetOptions(background_color=colors['BACKGROUND'], text_element_background_color=colors['BACKGROUND'], element_background_color=colors['BACKGROUND'], text_color=colors['TEXT'], input_elements_background_color=colors['INPUT'], button_color=colors['BUTTON'], progress_meter_color=colors['PROGRESS'], border_width=colors['BORDER'], slider_border_width=colors['SLIDER_DEPTH'], progress_meter_border_depth=colors['PROGRESS_DEPTH'], scrollbar_color=(colors['SCROLL']), element_text_color=colors['TEXT'], input_text_color=colors['TEXT_INPUT']) except: # most likely an index out of range print('** Warning - Look and Feel value not valid. Change your ChangeLookAndFeel call. **') # ============================== sprint ======# # Is identical to the Scrolled Text Box # # Provides a crude 'print' mechanism but in a # # GUI environment # # ============================================# sprint = ScrolledTextBox # Converts an object's contents into a nice printable string. Great for dumping debug data def ObjToStringSingleObj(obj): if obj is None: return 'None' return str(obj.__class__) + '\n' + '\n'.join( (repr(item) + ' = ' + repr(obj.__dict__[item]) for item in sorted(obj.__dict__))) def ObjToString(obj, extra=' '): if obj is None: return 'None' return str(obj.__class__) + '\n' + '\n'.join( (extra + (str(item) + ' = ' + (ObjToString(obj.__dict__[item], extra + ' ') if hasattr(obj.__dict__[item], '__dict__') else str( obj.__dict__[item]))) for item in sorted(obj.__dict__))) # ------------------------------------------------------------------------------------------------------------------ # # ===================================== Upper PySimpleGUI ======================================================== # # Pre-built dialog boxes for all your needs These are the "high level API calls # # ------------------------------------------------------------------------------------------------------------------ # # ----------------------------------- The mighty Popup! ------------------------------------------------------------ # def Popup(*args, title=None, button_color=None, background_color=None, text_color=None, button_type=POPUP_BUTTONS_OK, auto_close=False, auto_close_duration=None, custom_text=(None, None), non_blocking=False, icon=DEFAULT_WINDOW_ICON, line_width=None, font=None, no_titlebar=False, grab_anywhere=False, keep_on_top=False, location=(None, None)): """ Popup - Display a popup box with as many parms as you wish to include :param args: :param button_color: :param background_color: :param text_color: :param button_type: :param auto_close: :param auto_close_duration: :param non_blocking: :param icon: :param line_width: :param font: :param no_titlebar: :param grab_anywhere: :param keep_on_top: :param location: :return: """ if not args: args_to_print = [''] else: args_to_print = args if line_width != None: local_line_width = line_width else: local_line_width = MESSAGE_BOX_LINE_WIDTH _title = title if title is not None else args_to_print[0] window = Window(_title, auto_size_text=True, background_color=background_color, button_color=button_color, auto_close=auto_close, auto_close_duration=auto_close_duration, icon=icon, font=font, no_titlebar=no_titlebar, grab_anywhere=grab_anywhere, keep_on_top=keep_on_top, location=location) max_line_total, total_lines = 0, 0 for message in args_to_print: # fancy code to check if string and convert if not is not need. Just always convert to string :-) # if not isinstance(message, str): message = str(message) message = str(message) if message.count('\n'): message_wrapped = message else: message_wrapped = textwrap.fill(message, local_line_width) message_wrapped_lines = message_wrapped.count('\n') + 1 longest_line_len = max([len(l) for l in message.split('\n')]) width_used = min(longest_line_len, local_line_width) max_line_total = max(max_line_total, width_used) # height = _GetNumLinesNeeded(message, width_used) height = message_wrapped_lines window.AddRow( Text(message_wrapped, auto_size_text=True, text_color=text_color, background_color=background_color)) total_lines += height if non_blocking: PopupButton = DummyButton # important to use or else button will close other windows too! else: PopupButton = CloseButton # show either an OK or Yes/No depending on paramater if custom_text != (None, None): if type(custom_text) is not tuple: window.AddRow(PopupButton(custom_text,size=(len(custom_text),1), button_color=button_color, focus=True, bind_return_key=True)) elif custom_text[1] is None: window.AddRow(PopupButton(custom_text[0],size=(len(custom_text[0]),1), button_color=button_color, focus=True, bind_return_key=True)) else: window.AddRow(PopupButton(custom_text[0], button_color=button_color, focus=True, bind_return_key=True, size=(len(custom_text[0]), 1)), PopupButton(custom_text[1], button_color=button_color, size=(len(custom_text[0]), 1))) elif button_type is POPUP_BUTTONS_YES_NO: window.AddRow(PopupButton('Yes', button_color=button_color, focus=True, bind_return_key=True, pad=((20, 5), 3), size=(5, 1)), PopupButton('No', button_color=button_color, size=(5, 1))) elif button_type is POPUP_BUTTONS_CANCELLED: window.AddRow( PopupButton('Cancelled', button_color=button_color, focus=True, bind_return_key=True, pad=((20, 0), 3))) elif button_type is POPUP_BUTTONS_ERROR: window.AddRow(PopupButton('Error', size=(6, 1), button_color=button_color, focus=True, bind_return_key=True, pad=((20, 0), 3))) elif button_type is POPUP_BUTTONS_OK_CANCEL: window.AddRow(PopupButton('OK', size=(6, 1), button_color=button_color, focus=True, bind_return_key=True), PopupButton('Cancel', size=(6, 1), button_color=button_color)) elif button_type is POPUP_BUTTONS_NO_BUTTONS: pass else: window.AddRow(PopupButton('OK', size=(5, 1), button_color=button_color, focus=True, bind_return_key=True, pad=((20, 0), 3))) if non_blocking: button, values = window.Read(timeout=0) return button, window else: button, values = window.Read() return button # ============================== MsgBox============# # Lazy function. Same as calling Popup with parms # # This function WILL Disappear perhaps today # # ==================================================# # MsgBox is the legacy call and should not be used any longer def MsgBox(*args): raise DeprecationWarning('MsgBox is no longer supported... change your call to Popup') # --------------------------- PopupNoButtons --------------------------- def PopupNoButtons(*args, button_color=None, background_color=None, text_color=None, auto_close=False, auto_close_duration=None, non_blocking=False, icon=DEFAULT_WINDOW_ICON, line_width=None, font=None, no_titlebar=False, grab_anywhere=False, keep_on_top=False, location=(None, None)): """ Show a Popup but without any buttons :param args: :param button_color: :param background_color: :param text_color: :param auto_close: :param auto_close_duration: :param non_blocking: :param icon: :param line_width: :param font: :param no_titlebar: :param grab_anywhere: :param keep_on_top: :param location: :return: """ Popup(*args, button_color=button_color, background_color=background_color, text_color=text_color, button_type=POPUP_BUTTONS_NO_BUTTONS, auto_close=auto_close, auto_close_duration=auto_close_duration, non_blocking=non_blocking, icon=icon, line_width=line_width, font=font, no_titlebar=no_titlebar, grab_anywhere=grab_anywhere, keep_on_top=keep_on_top, location=location) # --------------------------- PopupNonBlocking --------------------------- def PopupNonBlocking(*args, button_type=POPUP_BUTTONS_OK, button_color=None, background_color=None, text_color=None, auto_close=False, auto_close_duration=None, non_blocking=True, icon=DEFAULT_WINDOW_ICON, line_width=None, font=None, no_titlebar=False, grab_anywhere=False, keep_on_top=False, location=(None, None)): """ Show Popup box and immediately return (does not block) :param args: :param button_type: :param button_color: :param background_color: :param text_color: :param auto_close: :param auto_close_duration: :param non_blocking: :param icon: :param line_width: :param font: :param no_titlebar: :param grab_anywhere: :param keep_on_top: :param location: :return: """ return Popup(*args, button_color=button_color, background_color=background_color, text_color=text_color, button_type=button_type, auto_close=auto_close, auto_close_duration=auto_close_duration, non_blocking=non_blocking, icon=icon, line_width=line_width, font=font, no_titlebar=no_titlebar, grab_anywhere=grab_anywhere, keep_on_top=keep_on_top, location=location) PopupNoWait = PopupNonBlocking # --------------------------- PopupQuick - a NonBlocking, Self-closing Popup --------------------------- def PopupQuick(*args, button_type=POPUP_BUTTONS_OK, button_color=None, background_color=None, text_color=None, auto_close=True, auto_close_duration=2, non_blocking=True, icon=DEFAULT_WINDOW_ICON, line_width=None, font=None, no_titlebar=False, grab_anywhere=False, keep_on_top=False, location=(None, None)): """ Show Popup box that doesn't block and closes itself :param args: :param button_type: :param button_color: :param background_color: :param text_color: :param auto_close: :param auto_close_duration: :param non_blocking: :param icon: :param line_width: :param font: :param no_titlebar: :param grab_anywhere: :param keep_on_top: :param location: :return: """ Popup(*args, button_color=button_color, background_color=background_color, text_color=text_color, button_type=button_type, auto_close=auto_close, auto_close_duration=auto_close_duration, non_blocking=non_blocking, icon=icon, line_width=line_width, font=font, no_titlebar=no_titlebar, grab_anywhere=grab_anywhere, keep_on_top=keep_on_top, location=location) # --------------------------- PopupQuick - a NonBlocking, Self-closing Popup with no titlebar and no buttons --------------------------- def PopupQuickMessage(*args, button_type=POPUP_BUTTONS_NO_BUTTONS, button_color=None, background_color=None, text_color=None, auto_close=True, auto_close_duration=2, non_blocking=True, icon=DEFAULT_WINDOW_ICON, line_width=None, font=None, no_titlebar=True, grab_anywhere=False, keep_on_top=False, location=(None, None)): """ Show Popup box that doesn't block and closes itself :param args: :param button_type: :param button_color: :param background_color: :param text_color: :param auto_close: :param auto_close_duration: :param non_blocking: :param icon: :param line_width: :param font: :param no_titlebar: :param grab_anywhere: :param keep_on_top: :param location: :return: """ Popup(*args, button_color=button_color, background_color=background_color, text_color=text_color, button_type=button_type, auto_close=auto_close, auto_close_duration=auto_close_duration, non_blocking=non_blocking, icon=icon, line_width=line_width, font=font, no_titlebar=no_titlebar, grab_anywhere=grab_anywhere, keep_on_top=keep_on_top, location=location) # --------------------------- PopupNoTitlebar --------------------------- def PopupNoTitlebar(*args, button_type=POPUP_BUTTONS_OK, button_color=None, background_color=None, text_color=None, auto_close=False, auto_close_duration=None, non_blocking=False, icon=DEFAULT_WINDOW_ICON, line_width=None, font=None, grab_anywhere=True, keep_on_top=False, location=(None, None)): """ Display a Popup without a titlebar. Enables grab anywhere so you can move it :param args: :param button_type: :param button_color: :param background_color: :param text_color: :param auto_close: :param auto_close_duration: :param non_blocking: :param icon: :param line_width: :param font: :param grab_anywhere: :param keep_on_top: :param location: :return: """ Popup(*args, button_color=button_color, background_color=background_color, text_color=text_color, button_type=button_type, auto_close=auto_close, auto_close_duration=auto_close_duration, non_blocking=non_blocking, icon=icon, line_width=line_width, font=font, no_titlebar=True, grab_anywhere=grab_anywhere, keep_on_top=keep_on_top, location=location) PopupNoFrame = PopupNoTitlebar PopupNoBorder = PopupNoTitlebar PopupAnnoying = PopupNoTitlebar # --------------------------- PopupAutoClose --------------------------- def PopupAutoClose(*args, button_type=POPUP_BUTTONS_OK, button_color=None, background_color=None, text_color=None, auto_close=True, auto_close_duration=DEFAULT_AUTOCLOSE_TIME, non_blocking=False, icon=DEFAULT_WINDOW_ICON, line_width=None, font=None, no_titlebar=False, grab_anywhere=False, keep_on_top=False, location=(None, None)): """ Popup that closes itself after some time period :param args: :param button_type: :param button_color: :param background_color: :param text_color: :param auto_close: :param auto_close_duration: :param non_blocking: :param icon: :param line_width: :param font: :param no_titlebar: :param grab_anywhere: :param keep_on_top: :param location: :return: """ Popup(*args, button_color=button_color, background_color=background_color, text_color=text_color, button_type=button_type, auto_close=auto_close, auto_close_duration=auto_close_duration, non_blocking=non_blocking, icon=icon, line_width=line_width, font=font, no_titlebar=no_titlebar, grab_anywhere=grab_anywhere, keep_on_top=keep_on_top, location=location) PopupTimed = PopupAutoClose # --------------------------- PopupError --------------------------- def PopupError(*args, button_color=DEFAULT_ERROR_BUTTON_COLOR, background_color=None, text_color=None, auto_close=False, auto_close_duration=None, non_blocking=False, icon=DEFAULT_WINDOW_ICON, line_width=None, font=None, no_titlebar=False, grab_anywhere=False, keep_on_top=False, location=(None, None)): """ Popup with colored button and 'Error' as button text :param args: :param button_color: :param background_color: :param text_color: :param auto_close: :param auto_close_duration: :param non_blocking: :param icon: :param line_width: :param font: :param no_titlebar: :param grab_anywhere: :param keep_on_top: :param location: :return: """ Popup(*args, button_type=POPUP_BUTTONS_ERROR, background_color=background_color, text_color=text_color, non_blocking=non_blocking, icon=icon, line_width=line_width, button_color=button_color, auto_close=auto_close, auto_close_duration=auto_close_duration, font=font, no_titlebar=no_titlebar, grab_anywhere=grab_anywhere, keep_on_top=keep_on_top, location=location) # --------------------------- PopupCancel --------------------------- def PopupCancel(*args, button_color=None, background_color=None, text_color=None, auto_close=False, auto_close_duration=None, non_blocking=False, icon=DEFAULT_WINDOW_ICON, line_width=None, font=None, no_titlebar=False, grab_anywhere=False, keep_on_top=False, location=(None, None)): """ Display Popup with "cancelled" button text :param args: :param button_color: :param background_color: :param text_color: :param auto_close: :param auto_close_duration: :param non_blocking: :param icon: :param line_width: :param font: :param no_titlebar: :param grab_anywhere: :param keep_on_top: :param location: :return: """ Popup(*args, button_type=POPUP_BUTTONS_CANCELLED, background_color=background_color, text_color=text_color, non_blocking=non_blocking, icon=icon, line_width=line_width, button_color=button_color, auto_close=auto_close, auto_close_duration=auto_close_duration, font=font, no_titlebar=no_titlebar, grab_anywhere=grab_anywhere, keep_on_top=keep_on_top, location=location) # --------------------------- PopupOK --------------------------- def PopupOK(*args, button_color=None, background_color=None, text_color=None, auto_close=False, auto_close_duration=None, non_blocking=False, icon=DEFAULT_WINDOW_ICON, line_width=None, font=None, no_titlebar=False, grab_anywhere=False, keep_on_top=False, location=(None, None)): """ Display Popup with OK button only :param args: :param button_color: :param background_color: :param text_color: :param auto_close: :param auto_close_duration: :param non_blocking: :param icon: :param line_width: :param font: :param no_titlebar: :param grab_anywhere: :param keep_on_top: :param location: :return: """ Popup(*args, button_type=POPUP_BUTTONS_OK, background_color=background_color, text_color=text_color, non_blocking=non_blocking, icon=icon, line_width=line_width, button_color=button_color, auto_close=auto_close, auto_close_duration=auto_close_duration, font=font, no_titlebar=no_titlebar, grab_anywhere=grab_anywhere, keep_on_top=keep_on_top, location=location) # --------------------------- PopupOKCancel --------------------------- def PopupOKCancel(*args, button_color=None, background_color=None, text_color=None, auto_close=False, auto_close_duration=None, non_blocking=False, icon=DEFAULT_WINDOW_ICON, line_width=None, font=None, no_titlebar=False, grab_anywhere=False, keep_on_top=False, location=(None, None)): """ Display popup with OK and Cancel buttons :param args: :param button_color: :param background_color: :param text_color: :param auto_close: :param auto_close_duration: :param non_blocking: :param icon: :param line_width: :param font: :param no_titlebar: :param grab_anywhere: :param keep_on_top: :param location: :return: OK, Cancel or None """ return Popup(*args, button_type=POPUP_BUTTONS_OK_CANCEL, background_color=background_color, text_color=text_color, non_blocking=non_blocking, icon=icon, line_width=line_width, button_color=button_color, auto_close=auto_close, auto_close_duration=auto_close_duration, font=font, no_titlebar=no_titlebar, grab_anywhere=grab_anywhere, keep_on_top=keep_on_top, location=location) # --------------------------- PopupYesNo --------------------------- def PopupYesNo(*args, button_color=None, background_color=None, text_color=None, auto_close=False, auto_close_duration=None, non_blocking=False, icon=DEFAULT_WINDOW_ICON, line_width=None, font=None, no_titlebar=False, grab_anywhere=False, keep_on_top=False, location=(None, None)): """ Display Popup with Yes and No buttons :param args: :param button_color: :param background_color: :param text_color: :param auto_close: :param auto_close_duration: :param non_blocking: :param icon: :param line_width: :param font: :param no_titlebar: :param grab_anywhere: :param keep_on_top: :param location: :return: Yes, No or None """ return Popup(*args, button_type=POPUP_BUTTONS_YES_NO, background_color=background_color, text_color=text_color, non_blocking=non_blocking, icon=icon, line_width=line_width, button_color=button_color, auto_close=auto_close, auto_close_duration=auto_close_duration, font=font, no_titlebar=no_titlebar, grab_anywhere=grab_anywhere, keep_on_top=keep_on_top, location=location) ############################################################################## # The PopupGet_____ functions - Will return user input # ############################################################################## # --------------------------- PopupGetFolder --------------------------- def PopupGetFolder(message, title=None, default_path='', no_window=False, size=(None, None), button_color=None, background_color=None, text_color=None, icon=DEFAULT_WINDOW_ICON, font=None, no_titlebar=False, grab_anywhere=False, keep_on_top=False, location=(None, None), initial_folder=None): """ Display popup with text entry field and browse button. Browse for folder :param message: :param default_path: :param no_window: :param size: :param button_color: :param background_color: :param text_color: :param icon: :param font: :param no_titlebar: :param grab_anywhere: :param keep_on_top: :param location: :return: Contents of text field. None if closed using X or cancelled """ if no_window: app = wx.App(False) frame = wx.Frame() if initial_folder: dialog = wx.DirDialog(frame, style=wx.FD_OPEN) else: dialog = wx.DirDialog(frame) folder_name = '' if dialog.ShowModal() == wx.ID_OK: folder_name = dialog.GetPath() return folder_name layout = [[Text(message, auto_size_text=True, text_color=text_color, background_color=background_color)], [InputText(default_text=default_path, size=size), FolderBrowse(initial_folder=initial_folder)], [CloseButton('Ok', size=(60, 20), bind_return_key=True), CloseButton('Cancel', size=(60, 20))]] _title = title if title is not None else message window = Window(title=_title, icon=icon, auto_size_text=True, button_color=button_color, background_color=background_color, font=font, no_titlebar=no_titlebar, grab_anywhere=grab_anywhere, keep_on_top=keep_on_top, location=location) (button, input_values) = window.Layout(layout).Read() if button != 'Ok': return None else: path = input_values[0] return path # --------------------------- PopupGetFile --------------------------- def PopupGetFile(message, title=None, default_path='', default_extension='', save_as=False, file_types=(("ALL Files", "*"),), no_window=False, size=(None, None), button_color=None, background_color=None, text_color=None, icon=DEFAULT_WINDOW_ICON, font=None, no_titlebar=False, grab_anywhere=False, keep_on_top=False, location=(None, None), initial_folder=None): """ Display popup with text entry field and browse button. Browse for file :param message: :param default_path: :param default_extension: :param save_as: :param file_types: :param no_window: :param size: :param button_color: :param background_color: :param text_color: :param icon: :param font: :param no_titlebar: :param grab_anywhere: :param keep_on_top: :param location: :return: string representing the path chosen, None if cancelled or window closed with X """ if no_window: app = wx.App(False) frame = wx.Frame() qt_types = convert_tkinter_filetypes_to_wx(file_types) style = wx.FD_SAVE if save_as else wx.FD_OPEN if initial_folder: dialog = wx.FileDialog(frame, defaultDir=initial_folder, wildcard=qt_types, style=style) else: dialog = wx.FileDialog(frame, wildcard=qt_types, style=style) if dialog.ShowModal() == wx.ID_OK: file_name = dialog.GetPath() else: file_name = '' return file_name browse_button = SaveAs(file_types=file_types, initial_folder=initial_folder) if save_as else FileBrowse( file_types=file_types, initial_folder=initial_folder) layout = [[Text(message, auto_size_text=True, text_color=text_color, background_color=background_color)], [InputText(default_text=default_path, size=(30,1)), browse_button], [CButton('Ok', size=(60, 20), bind_return_key=True), CButton('Cancel', size=(60, 20))]] _title = title if title is not None else message window = Window(title=_title, icon=icon, auto_size_text=True, button_color=button_color, font=font, background_color=background_color, no_titlebar=no_titlebar, grab_anywhere=grab_anywhere, keep_on_top=keep_on_top, location=location) (button, input_values) = window.Layout(layout).Read() # window.Close() if button != 'Ok': return None else: path = input_values[0] return path # --------------------------- PopupGetText --------------------------- def PopupGetText(message, title=None, default_text='', password_char='', size=(None, None), button_color=None, background_color=None, text_color=None, icon=DEFAULT_WINDOW_ICON, font=None, no_titlebar=False, grab_anywhere=False, keep_on_top=False, location=(None, None)): """ Display Popup with text entry field :param message: :param default_text: :param password_char: :param size: :param button_color: :param background_color: :param text_color: :param icon: :param font: :param no_titlebar: :param grab_anywhere: :param keep_on_top: :param location: :return: Text entered or None if window was closed """ layout = [[Text(message, auto_size_text=True, text_color=text_color, background_color=background_color, font=font)], [InputText(default_text=default_text, size=size, password_char=password_char)], [CloseButton('Ok', size=(60, 20), bind_return_key=True), CloseButton('Cancel', size=(60, 20))]] _title = title if title is not None else message window = Window(title=_title, icon=icon, auto_size_text=True, button_color=button_color, no_titlebar=no_titlebar, background_color=background_color, grab_anywhere=grab_anywhere, keep_on_top=keep_on_top, location=location) (button, input_values) = window.Layout(layout).Read() if button != 'Ok': return None else: return input_values[0] def main(): ChangeLookAndFeel('GreenTan') layout = [ [Text('Welcome to PySimpleGUI!', font='Arial 15', text_color='red')], [Text('You should be importing this module rather than running it', justification='l', size=(50, 1))], [Text('Here is your sample input window....')], [InputText('Source', focus=True), FileBrowse()], [InputText('Dest'), FolderBrowse()], [Checkbox('Checkbox 1', size=(15,1)), Checkbox('Checkbox 2')], [Radio('Radio 1', 'group', size=(15,1)), Radio('Radio 2', 'group')], [Multiline('Multiline Input', do_not_clear=True, size=(40,4), enable_events=True)], [MultilineOutput('Multiline Output', size=(40,5), text_color='blue')], [Combo(values=['Combo 1', 'Combo 2', 'Combo 3'], default_value='Combo 2', key='_COMBO_', enable_events=True, readonly=False, tooltip='Combo box', disabled=False, font='Courier 18', size=(12, 1))], [Spin(values=['Spin a', 'Spin b', 'Spin c'], font='ANY 15', key='_SPIN_', size=(10, 1), enable_events=True)], [Button('Ok'), Button('Exit')]] window = Window('Demo window..', default_element_size=(35,1), auto_size_text=True, auto_size_buttons=True, no_titlebar=False, disable_close=False, disable_minimize=True, grab_anywhere=True, ).Layout(layout) while True: event, values = window.Read() print(event, values) if event in (None, 'Exit'): break window.Close() if __name__ == '__main__': main() sys.exit(69)