From 882002a0a615460e31267219c88b666ac7702823 Mon Sep 17 00:00:00 2001 From: MikeTheWatchGuy Date: Fri, 21 Jun 2019 14:37:11 -0400 Subject: [PATCH] Added Versio #, Added self.Widget to all Elements, Pixel to Chars cutoff changed from 12 to 15, new Button.Click() method cross ported, New Graph Methods RelocateFigure, DrawRectangle, use Find Element dictionary use, FindElementWithFocus added, Style Changes to Graph Element, newer test harness --- PySimpleGUIQt/PySimpleGUIQt.py | 323 +++++++++++++++++++++------------ 1 file changed, 208 insertions(+), 115 deletions(-) diff --git a/PySimpleGUIQt/PySimpleGUIQt.py b/PySimpleGUIQt/PySimpleGUIQt.py index 696cbda7..f63b0c0c 100644 --- a/PySimpleGUIQt/PySimpleGUIQt.py +++ b/PySimpleGUIQt/PySimpleGUIQt.py @@ -1,4 +1,6 @@ #!/usr/bin/python3 +version = __version__ = "0.27.0 Unreleased" + import sys import types import datetime @@ -114,7 +116,7 @@ DEFAULT_MARGINS = (10, 5) # Margins for each LEFT/RIGHT margin is first term DEFAULT_ELEMENT_PADDING = (4, 2) # Padding between elements (row, col) in pixels # DEFAULT_ELEMENT_PADDING = (0, 0) # Padding between elements (row, col) in pixels DEFAULT_PIXELS_TO_CHARS_SCALING = (10,35) # 1 character represents x by y pixels -DEFAULT_PIXEL_TO_CHARS_CUTOFF = 12 # number of chars that triggers using pixels instead of chars +DEFAULT_PIXEL_TO_CHARS_CUTOFF = 15 # number of chars that triggers using pixels instead of chars DEFAULT_AUTOSIZE_TEXT = True DEFAULT_AUTOSIZE_BUTTONS = True DEFAULT_FONT = ("Helvetica", 10) @@ -526,7 +528,7 @@ class InputText(Element): self.Justification = justification or 'left' self.Disabled = disabled self.ChangeSubmits = change_submits or enable_events - self.QT_QLineEdit = None + self.Widget = self.QT_QLineEdit = None # type: QLineEdit self.ValueWasChanged = False 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) @@ -634,7 +636,7 @@ class Combo(Element): fg = text_color if text_color is not None else DEFAULT_INPUT_TEXT_COLOR self.VisibleItems = visible_items self.AutoComplete = auto_complete - self.QT_ComboBox = None + self.Widget = self.QT_ComboBox = None # type: QComboBox 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) @@ -694,7 +696,7 @@ 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, visible=True, size_px=(None,None)): ''' - InputOptionMenu + InputOptionMenu - NOT USED IN QT :param values: :param default_value: :param size: @@ -717,21 +719,7 @@ class OptionMenu(Element): text_color=fg, key=key, pad=pad, tooltip=tooltip, visible=visible, size_px=size_px) 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' + return def __del__(self): try: @@ -788,7 +776,7 @@ class Listbox(Element): 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 - self.QT_ListWidget = None + self.Widget = self.QT_ListWidget = None # type: QListWidget 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] @@ -865,7 +853,7 @@ class Radio(Element): self.Disabled = disabled self.TextColor = text_color or DEFAULT_TEXT_COLOR self.ChangeSubmits = change_submits or enable_events - self.QT_Radio_Button = None + self.Widget = self.QT_Radio_Button = None # type: QRadioButton 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, @@ -916,7 +904,7 @@ class Checkbox(Element): self.Disabled = disabled self.TextColor = text_color if text_color else DEFAULT_TEXT_COLOR self.ChangeSubmits = change_submits or enable_events - self.QT_Checkbox = None + self.Widget = self.QT_Checkbox = None # type: QCheckBox 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, @@ -979,7 +967,7 @@ class Spin(Element): 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.QT_Spinner = None + self.Widget = self.QT_Spinner = None # type: StringBox 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) @@ -1071,7 +1059,7 @@ class Multiline(Element, QWidget): 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.QT_TextEdit = None + self.Widget = self.QT_TextEdit = None # type: QTextEdit 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) @@ -1088,7 +1076,7 @@ class Multiline(Element, QWidget): if self.Element.EnterSubmits and event.type() == QEvent.KeyPress and widget is self.QT_TextEdit: key = event.key() if key in (Qt.Key_Return, Qt.Key_Enter): - self.Element.ReturnKeyHandler(0) + self.Element._ReturnKeyHandler(0) if event.type() == QEvent.FocusIn and widget is self.QT_TextEdit: self.Element.ParentForm.FocusElement = self.Element return QWidget.eventFilter(self, widget, event) @@ -1156,7 +1144,7 @@ class MultilineOutput(Element): self.Autoscroll = autoscroll self.Disabled = disabled self.ChangeSubmits = change_submits or enable_events - self.QT_TextBrowser = None + self.Widget = self.QT_TextBrowser = None # type: QTextBrowser super().__init__(ELEM_TYPE_MULTILINE_OUTPUT, 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) @@ -1216,7 +1204,7 @@ class Text(Element): bg = DEFAULT_TEXT_ELEMENT_BACKGROUND_COLOR else: bg = background_color - self.QT_Label = None + self.Widget = self.QT_Label = None # type: QLabel self.Visible = visible super().__init__(ELEM_TYPE_TEXT, size, auto_size_text, background_color=bg, font=font if font else DEFAULT_FONT, @@ -1229,6 +1217,15 @@ class Text(Element): element_callback_quit_mainloop(self) def Update(self, value=None, background_color=None, text_color=None, font=None, visible=None): + ''' + + :param value: + :param background_color: + :param text_color: + :param font: + :param visible: + :return: + ''' if value is not None: self.DisplayText = str(value) self.QT_Label.setText(str(value)) @@ -1264,7 +1261,7 @@ class Output(Element): 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.QT_TextBrowser = None + self.Widget = self.QT_TextBrowser = None # type: QTextBrowser tsize = convert_tkinter_size_to_Qt(size) if size[0] is not None and size[0] < 100 else size @@ -1353,7 +1350,7 @@ class Button(Element): self.InitialFolder = initial_folder self.Disabled = disabled self.ChangeSubmits = change_submits or enable_events - self.QT_QPushButton = None + self.Widget = self.QT_QPushButton = None # type: QPushButton self.ColorChosen = None # self.temp_size = size if size != (NONE, NONE) else @@ -1526,6 +1523,14 @@ class Button(Element): def SetFocus(self): self.QT_QPushButton.setFocus() + def Click(self): + if self.Widget is None: + return + try: + self.Widget.click() + except Exception as e: + print('Exception {} \nclicking button {}'.format(e, self.ButtonText)) + def __del__(self): super().__del__() @@ -1580,7 +1585,7 @@ class ButtonMenu(Element): self.ImageSize = image_size self.ImageSubsample = image_subsample self.Disabled = disabled - self.QT_QPushButton = None + self.Widget = self.QT_QPushButton = None # type: QPushButton self.IsButtonMenu = True self.MenuItemChosen = None @@ -1606,6 +1611,12 @@ class ButtonMenu(Element): super().Update(self.QT_QPushButton, background_color=button_color[1], text_color=button_color[0], font=font, visible=visible) + def Click(self): + """ """ + try: + self.QT_QPushButton.click() + except Exception as e: + print('Exception {} clicking button. Has your Window been Finalized() or Read()?'.format(e)) def __del__(self): super().__del__() @@ -1646,7 +1657,7 @@ class ProgressBar(Element): 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.QT_QProgressBar = None + self.Widget = self.QT_QProgressBar = None # type: QProgressBar super().__init__(ELEM_TYPE_PROGRESS_BAR, size=tsize, auto_size_text=auto_size_text, key=key, pad=pad, visible=visible, size_px=size_px) @@ -1689,7 +1700,7 @@ class Image(Element): self.ClickSubmits = click_submits or enable_events if data is None and filename is None and data_base64 is None: print('* Warning... no image specified in Image Element! *') - self.QT_QLabel = None + self.Widget = self.QT_QLabel = None # type: QLabel super().__init__(ELEM_TYPE_IMAGE, size=size, background_color=background_color, pad=pad, key=key, tooltip=tooltip, visible=visible, size_px=size_px) @@ -1736,7 +1747,7 @@ class Image(Element): class Canvas(Element): def __init__(self, canvas=None, background_color=None, size=(None, None), pad=None, key=None, tooltip=None): ''' - Canvas Element + Canvas Element - NOT USED IN QT PORT :param canvas: :param background_color: :param size: @@ -1767,7 +1778,7 @@ class Canvas(Element): # ---------------------------------------------------------------------- # class Graph(Element): def __init__(self, canvas_size, graph_bottom_left, graph_top_right, background_color=None, pad=None, key=None, - tooltip=None, visible=True, size_px=(None,None)): + tooltip=None, visible=True, size_px=(None,None), change_submits=False, enable_events=False, drag_submits=False): ''' Graph Element :param canvas_size: @@ -1782,7 +1793,7 @@ class Graph(Element): self.BottomLeft = graph_bottom_left self.TopRight = graph_top_right self.x = self.y = 0 - self.QT_QGraphicsScene = None # type: QGraphicsScene + self.Widget = self.QT_QGraphicsScene = None # type: QGraphicsScene super().__init__(ELEM_TYPE_GRAPH, background_color=background_color, size=canvas_size, pad=pad, key=key, tooltip=tooltip, visible=visible, size_px=size_px) @@ -1807,6 +1818,19 @@ class Graph(Element): line = self.QT_QGraphicsScene.addLine(self.x+converted_point_from[0],self.y+ converted_point_from[1], self.x+converted_point_to[0],self.y+ converted_point_to[1], pen=pen) # self.QT_QGraphicsItemGroup.addToGroup(line) + def DrawRectangle(self, top_left, bottom_right, fill_color=None, line_color=None): + converted_point_top_left = self._convert_xy_to_canvas_xy(top_left[0], top_left[1]) + converted_point_bottom_right = self._convert_xy_to_canvas_xy(bottom_right[0], bottom_right[1]) + + qcolor = QColor(line_color) + pen = QPen(qcolor, 1) + qcolor = QColor(fill_color) + brush = QBrush(qcolor) + line = self.QT_QGraphicsScene.addRect(converted_point_top_left[0],converted_point_top_left[1], + converted_point_bottom_right[0]-converted_point_top_left[0], + converted_point_bottom_right[1]-converted_point_top_left[1], + pen, brush) + # self.QT_QGraphicsItemGroup.addToGroup(line) def DrawCircle(self, center_location, radius, fill_color=None, line_color='black'): @@ -1815,8 +1839,16 @@ class Graph(Element): pen = QPen(qcolor) qcolor = QColor(fill_color) brush = QBrush(qcolor) - line = self.QT_QGraphicsScene.addEllipse(self.x+converted_point[0], self.y+converted_point[1], + circle_id = self.QT_QGraphicsScene.addEllipse(self.x+converted_point[0], self.y+converted_point[1], radius, radius, pen=pen, brush=brush) + return circle_id # type: QGraphicsEllipseItem + + def RelocateFigure(self, id, x, y): + id=id # type: QtWidgets.QGraphicsEllipseItem + converted_point = self._convert_xy_to_canvas_xy(x, y) + id.setX(converted_point[0]) + id.setY(converted_point[1]) + def DrawText(self, text, location, color='black', font=None, angle=0): @@ -1828,9 +1860,9 @@ class Graph(Element): qfont = QFont(_font[0], _font[1]) # qfont.setWeight(.5) - qpath.addText(self.x+converted_point[0], self.y+converted_point[1], qfont, str(text)) + text_id = qpath.addText(self.x+converted_point[0], self.y+converted_point[1], qfont, str(text)) self.QT_QGraphicsScene.addPath(qpath, qcolor) - + return text_id def Move(self, x_direction, y_direction): x_direction = -x_direction @@ -1886,7 +1918,7 @@ class Graph(Element): 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): + def DrawRectangleOld(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: @@ -1970,7 +2002,7 @@ class Frame(Element): self.TitleLocation = title_location self.BorderWidth = border_width self.BackgroundColor = background_color if background_color is not None else DEFAULT_BACKGROUND_COLOR - self.QT_QGroupBox = None + self.Widget = self.QT_QGroupBox = None # type: QGroupBox self.Layout(layout) super().__init__(ELEM_TYPE_FRAME, background_color=background_color, text_color=title_color, size=size, @@ -2089,7 +2121,7 @@ class Tab(Element): self.ParentNotebook = None self.TabID = None self.BackgroundColor = background_color if background_color is not None else DEFAULT_BACKGROUND_COLOR - self.QT_QWidget = None + self.Widget = self.QT_QWidget = None # type: QWidget self.Layout(layout) @@ -2176,7 +2208,7 @@ class TabGroup(Element): self.BackgroundColor = background_color if background_color is not None else COLOR_SYSTEM_DEFAULT self.ChangeSubmits = change_submits or enable_events self.TabLocation = tab_location - self.QT_QTabWidget = None + self.Widget = self.QT_QTabWidget = None # type: QTabWidget self.Layout(layout) super().__init__(ELEM_TYPE_TAB_GROUP, background_color=self.BackgroundColor, text_color=title_color, font=font, @@ -2272,7 +2304,7 @@ class Slider(Element): temp_size = (150, 30) if self.Orientation.startswith('h') else (30, 150) elif size[0] is not None and size[0] < 100: temp_size = size[0]*10, size[1]*3 - self.QT_Slider = None + self.Widget = self.QT_Slider = None # type:QSlider 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, visible=visible, size_px=size_px) @@ -2347,7 +2379,7 @@ class Dial(Element): temp_size = size if temp_size == (None, None): temp_size = (20, 20) if self.Orientation.startswith('h') else (8, 20) - self.QT_Dial = None + self.Widget = self.QT_Dial = None # type: QDial super().__init__(ELEM_TYPE_INPUT_DIAL, size=temp_size, font=font, background_color=background_color, text_color=text_color, key=key, pad=pad, tooltip=tooltip, visible=visible, size_px=size_px) @@ -2390,7 +2422,7 @@ class Stretch(Element): :param pad: :param tooltip: ''' - + self.Widget = None # type: Stretch super().__init__(ELEM_TYPE_STRETCH, size=size, font=font, background_color=background_color, text_color=text_color, key=key, pad=pad, tooltip=tooltip) return @@ -2428,7 +2460,7 @@ class Column(Element): # self.ImageSize = image_size # self.ImageSubsample = image_subsample bg = background_color if background_color is not None else DEFAULT_BACKGROUND_COLOR - self.QT_QGroupBox = None + self.Widget = self.QT_QGroupBox = None # type: QGroupBox self.Layout(layout) super().__init__(ELEM_TYPE_COLUMN, background_color=bg, size=size, pad=pad, key=key, visible=visible) @@ -2493,7 +2525,8 @@ class Menu(Element): self.Tearoff = tearoff self.IsButtonMenu = False self.MenuItemChosen = None - self.QT_QMenuBar = None + self.Widget = self.QT_QMenuBar = None # type: QMenuBar + super().__init__(ELEM_TYPE_MENUBAR, background_color=background_color, size=size, pad=pad, key=key, visible=visible) @@ -2578,7 +2611,7 @@ class Table(Element): self.SelectedRows = [] self.ChangeSubmits = change_submits or enable_events self.BindReturnKey = bind_return_key - self.QT_TableWidget = None + self.Widget = self.QT_TableWidget = None # type: QTabWidget super().__init__(ELEM_TYPE_TABLE, text_color=text_color, background_color=background_color, font=font, size=size, pad=pad, key=key, tooltip=tooltip, visible=visible, size_px=size_px) @@ -2722,7 +2755,7 @@ class Tree(Element): self.SelectedRows = [] self.ChangeSubmits = change_submits or enable_events self.Size = size - self.QT_QTreeWidget = None # type: QTreeWidget + self.Widget = self.QT_QTreeWidget = None # type: QTreeWidget super().__init__(ELEM_TYPE_TREE, text_color=text_color, background_color=background_color, font=font, pad=pad, key=key, tooltip=tooltip, size=size, visible=visible, size_px=size_px) return @@ -2845,6 +2878,7 @@ class ErrorElement(Element): :param key: ''' self.Key = key + self.Widget = None super().__init__(ELEM_TYPE_ERROR, key=key) return @@ -2896,7 +2930,7 @@ class SystemTray: if Window.QTApplication is None: Window.QTApplication = QApplication(sys.argv) self.App = Window.QTApplication - self.QWidget = QWidget() + self.Widget = self.QWidget = QWidget() # type: QWidget qicon = None if filename is not None: @@ -3209,6 +3243,7 @@ class Window: def Layout(self, rows): self.AddRows(rows) + self.BuildKeyDict() return self def LayoutAndRead(self, rows, non_blocking=False): @@ -3425,23 +3460,63 @@ class Window: FillFormWithValues(self, values_dict) return self - def FindElement(self, key): - element = _FindElementFromKeyInSubForm(self, key) + def FindElement(self, key, silent_on_error=False): + try: + element = self.AllKeysDict[key] + except KeyError: + element = None + # 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) + if not silent_on_error: + 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) + else: + return False return element - Element = FindElement # shortcut function definition + Element = FindElement # Shortcut function + + def BuildKeyDict(self): + dict = {} + self.AllKeysDict = self._BuildKeyDictForWindow(self,self, dict) + + def _BuildKeyDictForWindow(self, top_window, window, key_dict): + for row_num, row in enumerate(window.Rows): + for col_num, element in enumerate(row): + if element.Type == ELEM_TYPE_COLUMN: + key_dict = self._BuildKeyDictForWindow(top_window, element, key_dict) + if element.Type == ELEM_TYPE_FRAME: + key_dict = self._BuildKeyDictForWindow(top_window, element, key_dict) + if element.Type == ELEM_TYPE_TAB_GROUP: + key_dict = self._BuildKeyDictForWindow(top_window, element, key_dict) + if element.Type == ELEM_TYPE_TAB: + key_dict = self._BuildKeyDictForWindow(top_window, element, key_dict) + if element.Key is None: # if no key has been assigned.... create one for input elements + if element.Type == ELEM_TYPE_BUTTON: + element.Key = element.ButtonText + if element.Type in (ELEM_TYPE_MENUBAR, ELEM_TYPE_BUTTONMENU, ELEM_TYPE_CANVAS, + ELEM_TYPE_INPUT_SLIDER, ELEM_TYPE_GRAPH, ELEM_TYPE_IMAGE, + ELEM_TYPE_INPUT_CHECKBOX, ELEM_TYPE_INPUT_LISTBOX, ELEM_TYPE_INPUT_COMBO, + ELEM_TYPE_INPUT_MULTILINE, ELEM_TYPE_INPUT_OPTION_MENU, ELEM_TYPE_INPUT_SPIN, + ELEM_TYPE_INPUT_TEXT): + element.Key = top_window.DictionaryKeyCounter + top_window.DictionaryKeyCounter += 1 + if element.Key is not None: + if element.Key in key_dict.keys(): + print('*** Duplicate key found in your layout {} ***'.format(element.Key)) if element.Type != ELEM_TYPE_BUTTON else None + element.Key = element.Key + str(self.UniqueKeyCounter) + self.UniqueKeyCounter += 1 + print('*** Replaced new key with {} ***'.format(element.Key)) if element.Type != ELEM_TYPE_BUTTON else None + key_dict[element.Key] = element + return key_dict def FindElementWithFocus(self): - return self.FocusElement - element = _FindElementWithFocusInSubForm(self) - return element + return _FindElementWithFocusInSubForm(self) + # return self.FocusElement def SaveToDisk(self, filename): try: @@ -3692,6 +3767,7 @@ class Window: + def __enter__(self): return self @@ -4036,6 +4112,8 @@ def ColorChooserButton(button_text, target=(None, None), image_filename=None, im ##################################### ----- RESULTS ------ ################################################## def AddToReturnDictionary(form, element, value): + form.ReturnValuesDictionary[element.Key] = value + return if element.Key is None: form.ReturnValuesDictionary[form.DictionaryKeyCounter] = value element.Key = form.DictionaryKeyCounter @@ -4345,10 +4423,15 @@ def _FindElementWithFocusInSubForm(form): matching_elem = _FindElementWithFocusInSubForm(element) if matching_elem is not None: return matching_elem - if element.Type == ELEM_TYPE_INPUT_TEXT: - if element.QT_QLineEdit is not None: - if element.QT_QLineEdit is element.TKEntry.focus_get(): - return element + try: + if element.Widget.hasFocus(): + return element + except: + continue + # if element.Type == ELEM_TYPE_INPUT_TEXT: + # if element.QT_QLineEdit is not None: + # if element.QT_QLineEdit is element.TKEntry.focus_get(): + # return element def AddTrayMenuItem(top_menu, sub_menu_info, element, is_sub_menu=False, skip=False): @@ -4594,7 +4677,7 @@ def PackFormIntoFrame(window, containing_frame, toplevel_win): if element_type == ELEM_TYPE_COLUMN: # column_widget = QWidget() column_widget = QGroupBox() - element.QT_QGroupBox = column_widget + element.Widget = element.QT_QGroupBox = column_widget # column_widget.setFrameShape(QtWidgets.QFrame.NoFrame) style = create_style_from_font(font) if element.BackgroundColor is not None: @@ -4620,7 +4703,7 @@ def PackFormIntoFrame(window, containing_frame, toplevel_win): qt_row_layout.addWidget(column_widget) # ------------------------- TEXT element ------------------------- # elif element_type == ELEM_TYPE_TEXT: - element.QT_Label = qlabel = QLabel(element.DisplayText, toplevel_win.QTWindow) + element.Widget = element.QT_Label = qlabel = QLabel(element.DisplayText, toplevel_win.QTWindow) if element.Justification is not None: justification = element.Justification elif toplevel_win.TextJustification is not None: @@ -4666,7 +4749,7 @@ def PackFormIntoFrame(window, containing_frame, toplevel_win): elif element_type == ELEM_TYPE_BUTTON: btext = element.ButtonText btype = element.BType - element.QT_QPushButton = QPushButton(btext) + element.Widget = element.QT_QPushButton = QPushButton(btext) style = Style('QPushButton') style.append(create_style_from_font(font)) style.add(color=(element.TextColor, COLOR_SYSTEM_DEFAULT)) @@ -4719,7 +4802,7 @@ def PackFormIntoFrame(window, containing_frame, toplevel_win): # ------------------------- INPUT element ------------------------- # elif element_type == ELEM_TYPE_INPUT_TEXT: default_text = element.DefaultText - element.QT_QLineEdit = qlineedit = QLineEdit() + element.Widget = element.QT_QLineEdit = qlineedit = QLineEdit() qlineedit.setAcceptDrops(True) qlineedit.dragEnterEvent = element.dragEnterEvent @@ -4769,7 +4852,7 @@ def PackFormIntoFrame(window, containing_frame, toplevel_win): qt_row_layout.addWidget(element.QT_QLineEdit) # ------------------------- COMBO BOX (Drop Down) element ------------------------- # elif element_type == ELEM_TYPE_INPUT_COMBO: - element.QT_ComboBox = QComboBox() + element.Widget = element.QT_ComboBox = QComboBox() max_line_len = max([len(str(l)) for l in element.Values]) if auto_size_text is False: width = element_size[0] @@ -4822,7 +4905,7 @@ def PackFormIntoFrame(window, containing_frame, toplevel_win): # ------------------------- LISTBOX element ------------------------- # elif element_type == ELEM_TYPE_INPUT_LISTBOX: max_line_len = max([len(str(l)) for l in element.Values]) if len(element.Values) != 0 else 0 - element.QT_ListWidget = QListWidget() + element.Widget = element.QT_ListWidget = QListWidget() style = element.QT_ListWidget.styleSheet() # style += """QScrollBar:vertical { # border: none; @@ -4872,7 +4955,7 @@ def PackFormIntoFrame(window, containing_frame, toplevel_win): elif element_type == ELEM_TYPE_INPUT_MULTILINE: default_text = element.DefaultText width, height = element_size - element.QT_TextEdit = QTextEdit() + element.Widget = element.QT_TextEdit = QTextEdit() style = 'QTextEdit {' style += create_style_from_font(font) @@ -4885,7 +4968,7 @@ def PackFormIntoFrame(window, containing_frame, toplevel_win): style += '}' element.QT_TextEdit.setStyleSheet(style) - if element.AutoSizeText is False or toplevel_win.AutoSizeButtons is False or element.Size[0] is not None: + if element.AutoSizeText is False or element.Size[0] is not None: if element_size[0] is not None: element.QT_TextEdit.setFixedWidth(element_size[0]) if element_size[1] is not None: @@ -4915,7 +4998,7 @@ def PackFormIntoFrame(window, containing_frame, toplevel_win): elif element_type == ELEM_TYPE_MULTILINE_OUTPUT: default_text = element.DefaultText width, height = element_size - element.QT_TextBrowser = QTextBrowser() + element.Widget = element.QT_TextBrowser = QTextBrowser() element.QT_TextBrowser.setDisabled(False) style = 'QTextBrowser {' style += create_style_from_font(font) @@ -4928,7 +5011,7 @@ def PackFormIntoFrame(window, containing_frame, toplevel_win): style += '}' element.QT_TextBrowser.setStyleSheet(style) - if element.AutoSizeText is False or toplevel_win.AutoSizeButtons is False or element.Size[0] is not None: + if element.AutoSizeText is False or element.Size[0] is not None: if element_size[0] is not None: element.QT_TextBrowser.setFixedWidth(element_size[0]) if element_size[1] is not None: @@ -4957,7 +5040,7 @@ def PackFormIntoFrame(window, containing_frame, toplevel_win): style += 'margin: {}px {}px {}px {}px;'.format(*full_element_pad) element.QT_Checkbox.setStyleSheet(style) - if element.AutoSizeText is False or toplevel_win.AutoSizeButtons is False or element.Size[0] is not None: + if element.AutoSizeText is False or element.Size[0] is not None: if element_size[0] is not None: element.QT_Checkbox.setFixedWidth(element_size[0]) if element_size[1] is not None: @@ -4972,7 +5055,7 @@ def PackFormIntoFrame(window, containing_frame, toplevel_win): qt_row_layout.addWidget(element.QT_Checkbox) # ------------------------- PROGRESS BAR element ------------------------- # elif element_type == ELEM_TYPE_PROGRESS_BAR: - element.QT_QProgressBar = QProgressBar() + element.Widget = element.QT_QProgressBar = QProgressBar() orientation = element.Orientation.lower()[0] if element.Size[0] is not None: if element_size[0] is not None: @@ -5007,8 +5090,7 @@ def PackFormIntoFrame(window, containing_frame, toplevel_win): # ------------------------- INPUT RADIO BUTTON element ------------------------- # elif element_type == ELEM_TYPE_INPUT_RADIO: default_value = element.InitialState - ID = element.GroupID - qradio = QRadioButton(element.Text) + element.Widget = qradio = QRadioButton(element.Text) element.QT_Radio_Button = qradio if element.Disabled: element.QT_Radio_Button.setDisabled(True) @@ -5022,7 +5104,7 @@ def PackFormIntoFrame(window, containing_frame, toplevel_win): style += 'margin: {}px {}px {}px {}px;'.format(*full_element_pad) element.QT_Radio_Button.setStyleSheet(style) - if element.AutoSizeText is False or toplevel_win.AutoSizeButtons is False or element.Size[0] is not None: + if element.AutoSizeText is False or element.Size[0] is not None: if element_size[0] is not None: element.QT_Radio_Button.setFixedWidth(element_size[0]) if element_size[1] is not None: @@ -5045,7 +5127,8 @@ def PackFormIntoFrame(window, containing_frame, toplevel_win): # ------------------------- INPUT SPIN Box element ------------------------- # elif element_type == ELEM_TYPE_INPUT_SPIN: # element.QT_Spinner = QSpinBox() - element.QT_Spinner = Spin.StringBox(element.Values) + element = element # type: Spin + element.Widget = element.QT_Spinner = Spin.StringBox(element.Values) if element.DefaultValue is not None: # try to set the default value without crashing on error try: element.QT_Spinner.setValue(element.QT_Spinner.valueFromText(element.DefaultValue)) @@ -5079,7 +5162,7 @@ def PackFormIntoFrame(window, containing_frame, toplevel_win): qt_row_layout.addWidget(element.QT_Spinner) # ------------------------- OUTPUT element ------------------------- # elif element_type == ELEM_TYPE_OUTPUT: - element.QT_TextBrowser = QTextBrowser() + element.Widget = element.QT_TextBrowser = QTextBrowser() element.QT_TextBrowser.setDisabled(False) style = 'QTextBrowser {' style += create_style_from_font(font) @@ -5098,7 +5181,7 @@ def PackFormIntoFrame(window, containing_frame, toplevel_win): style += '}' element.QT_TextBrowser.setStyleSheet(style) - if element.AutoSizeText is False or toplevel_win.AutoSizeButtons is False or element.Size[0] is not None: + if element.AutoSizeText is False or element.Size[0] is not None: if element_size[0] is not None: element.QT_TextBrowser.setFixedWidth(element_size[0]) if element_size[1] is not None: @@ -5150,18 +5233,23 @@ def PackFormIntoFrame(window, containing_frame, toplevel_win): width, height = element_size # ------------------------- Graph element ------------------------- # elif element_type == ELEM_TYPE_GRAPH: + element = element # type: Graph width, height = element_size - element.QT_QGraphicsView = qgraphicsview = QGraphicsView() + print(f'Graph element size = {element_size}') + element.Widget = element.QT_QGraphicsView = qgraphicsview = QGraphicsView() # element.QT_QGraphicsView.setGeometry(0,0,element.CanvasSize[0],element.CanvasSize[1]) + print(f'Graph Canvas size = {element.CanvasSize}') + element.QT_QGraphicsScene = QGraphicsScene() element.QT_QGraphicsScene.setSceneRect(0,0,element.CanvasSize[0],element.CanvasSize[1]) element.QT_QGraphicsView.setScene(element.QT_QGraphicsScene) - style = '' - style += 'border: 0px solid gray; ' - style += 'margin: {}px {}px {}px {}px;'.format(*full_element_pad) - # print(style) - element.QT_QGraphicsView.setStyleSheet(style) + style = Style('QGraphicsView') + style.add(background_color=(element.BackgroundColor, COLOR_SYSTEM_DEFAULT)) + style.add(margin='{}px {}px {}px {}px'.format(*full_element_pad)) + style.add(border='{}px solid gray '.format(border_depth)) + print(f'style content = {style.content}') + element.QT_QGraphicsView.setStyleSheet(style.content) qgraphicsview.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) qgraphicsview.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) @@ -5174,7 +5262,7 @@ def PackFormIntoFrame(window, containing_frame, toplevel_win): # ------------------------- MENUBAR element ------------------------- # elif element_type == ELEM_TYPE_MENUBAR: menu_def = element.MenuDefinition - element.QT_QMenuBar = QMenuBar(toplevel_win.QT_QMainWindow) + element.Widget = element.QT_QMenuBar = QMenuBar(toplevel_win.QT_QMainWindow) for menu_entry in menu_def: # print(f'Adding a Menubar ENTRY {menu_entry}') @@ -5192,7 +5280,7 @@ def PackFormIntoFrame(window, containing_frame, toplevel_win): # ------------------------- BUTTONMENU element ------------------------- # elif element_type == ELEM_TYPE_BUTTONMENU: btext = element.ButtonText - element.QT_QPushButton = QPushButton(btext) + element.Widget = element.QT_QPushButton = QPushButton(btext) style = create_style_from_font(font) if element.TextColor is not None and element.TextColor != COLOR_SYSTEM_DEFAULT: style += 'color: %s;' % element.TextColor @@ -5237,7 +5325,7 @@ def PackFormIntoFrame(window, containing_frame, toplevel_win): qt_row_layout.addWidget(element.QT_QPushButton) # ------------------------- Frame element ------------------------- # elif element_type == ELEM_TYPE_FRAME: - column_widget = QGroupBox() + element.Widget = column_widget = QGroupBox() element.QT_QGroupBox = column_widget style = create_style_from_font(font) if element.TextColor is not None: @@ -5262,7 +5350,7 @@ def PackFormIntoFrame(window, containing_frame, toplevel_win): qt_row_layout.addWidget(column_widget) # ------------------------- Tab element ------------------------- # elif element_type == ELEM_TYPE_TAB: - tab_widget = QWidget() + element.Widget = tab_widget = QWidget() element.QT_QWidget = tab_widget # tab_widget.setFrameShape(QtWidgets.QFrame.NoFrame) style = create_style_from_font(font) @@ -5296,7 +5384,7 @@ def PackFormIntoFrame(window, containing_frame, toplevel_win): # ------------------------- TabGroup element ------------------------- # elif element_type == ELEM_TYPE_TAB_GROUP: - element.QT_QTabWidget = qtab =QTabWidget() + element.Widget = element.QT_QTabWidget = qtab =QTabWidget() style = qtab.styleSheet() if element.SelectedTitleColor not in (None, COLOR_SYSTEM_DEFAULT): @@ -5317,7 +5405,7 @@ def PackFormIntoFrame(window, containing_frame, toplevel_win): element.QT_QTabWidget.currentChanged.connect(element.QtCallbackStateChanged) # ------------------------- SLIDER element ------------------------- # elif element_type == ELEM_TYPE_INPUT_SLIDER: - element.QT_Slider = QSlider() + element.Widget = element.QT_Slider = QSlider() if element.Orientation.startswith('h'): element.QT_Slider.setOrientation(Qt.Horizontal) else: @@ -5369,7 +5457,7 @@ def PackFormIntoFrame(window, containing_frame, toplevel_win): qt_row_layout.addWidget(element.QT_Slider) # ------------------------- DIAL element ------------------------- # elif element_type == ELEM_TYPE_INPUT_DIAL: - element.QT_Dial = qdial = QDial() + element.Widget = element.QT_Dial = qdial = QDial() style = create_style_from_font(font) if element.BackgroundColor is not None: @@ -5405,10 +5493,11 @@ def PackFormIntoFrame(window, containing_frame, toplevel_win): qt_row_layout.addWidget(element.QT_Dial) # ------------------------- Stretch element ------------------------- # elif element_type == ELEM_TYPE_STRETCH: - qt_row_layout.addStretch(1) + element.Widget = qt_row_layout.addStretch(1) # ------------------------- TABLE element ------------------------- # elif element_type == ELEM_TYPE_TABLE: - element.QT_TableWidget = Table.QTTableWidget(toplevel_win.ReturnKeyboardEvents, toplevel_win) + element = element # type: Table + element.Widget = element.QT_TableWidget = Table.QTTableWidget(toplevel_win.ReturnKeyboardEvents, toplevel_win) if element.NumRows is not None: element.QT_TableWidget.setFixedHeight(element.NumRows*35+25) # element.QT_TableWidget = QTableWidget() @@ -5438,17 +5527,20 @@ def PackFormIntoFrame(window, containing_frame, toplevel_win): for colnum, columns in enumerate(rows): element.QT_TableWidget.setItem(rownum, colnum, QTableWidgetItem(element.Values[rownum][colnum])) - element.QT_TableWidget.installEventFilter(element.QT_TableWidget) + if element.ColumnHeadings is not None: + element.QT_TableWidget.setHorizontalHeaderLabels(element.ColumnHeadings) + element.QT_TableWidget.installEventFilter(element.QT_TableWidget) element.QT_TableWidget.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustToContents) if element.Tooltip: element.QT_TableWidget.setToolTip(element.Tooltip) if not element.Visible: element.QT_TableWidget.setVisible(False) + qt_row_layout.addWidget(element.QT_TableWidget) # ------------------------- Tree element ------------------------- # elif element_type == ELEM_TYPE_TREE: - element.QT_QTreeWidget = QTreeWidget() + element.Widget = element.QT_QTreeWidget = QTreeWidget() if element_size != (None, None): element.QT_QTreeWidget.setFixedWidth(element_size[0]) element.QT_QTreeWidget.setFixedHeight(element_size[1]) @@ -5523,7 +5615,8 @@ def PackFormIntoFrame(window, containing_frame, toplevel_win): qt_row_layout.addWidget(element.QT_QTreeWidget) # ------------------------- Separator element ------------------------- # elif element_type == ELEM_TYPE_SEPARATOR: - element.QT_Label = qlabel = QLabel('', toplevel_win.QTWindow) + element = element # type: HorizontalSeparator + element.Widget = element.QT_Label = qlabel = QLabel('', toplevel_win.QTWindow) if not auto_size_text: if element_size[0] is not None: element.QT_Label.setFixedWidth(element_size[0]) @@ -7052,21 +7145,21 @@ def PopupGetFolder(message, title=None, default_path='', no_window=False, size=( 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)], + [InputText(default_text=default_path, size=size, key='_INPUT_'), 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, + window = Window(title=_title, layout=layout, 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() + button, values = window.Read() if button != 'Ok': return None else: - path = input_values[0] + path = values['_INPUT_'] return path @@ -7114,21 +7207,21 @@ def PopupGetFile(message, title=None, default_path='', default_extension='', sav 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], + [InputText(default_text=default_path, size=(30,1), key='_INPUT_'), 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, + window = Window(title=_title, layout=layout, 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() + button, values = window.Read() # window.Close() if button != 'Ok': return None else: - path = input_values[0] + path = values['_INPUT_'] return path @@ -7161,16 +7254,16 @@ def PopupGetText(message, title=None, default_text='', password_char='', size=(N _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, + window = Window(title=_title, layout=layout, 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() + button, values = window.Read() if button != 'Ok': return None else: - return input_values[0] + return values['_INPUT_'] def main(): @@ -7198,7 +7291,7 @@ def main(): treedata.Insert('_C_', i, i, []) frame1 = [ - [Input('Input Text', do_not_clear=True, size=(250, 35), tooltip='Input'), Stretch()], + [Input('Input Text', do_not_clear=True, size=(250, 35), tooltip='Input'), FileBrowse(), Stretch()], [Multiline(size=(250, 75), do_not_clear=True, default_text='Multiline Input', tooltip='Multiline input'), MultilineOutput(size=(250, 75), default_text='Multiline Output', tooltip='Multiline output')], ] @@ -7223,7 +7316,7 @@ def main(): matrix = [[str(x * y) for x in range(4)] for y in range(8)] frame5 = [ - [Table(values=matrix, max_col_width=25, + [Table(values=matrix, max_col_width=25, headings=('aaa', 'bbb', 'ccc', 'ddd'), auto_size_columns=True, display_row_numbers=True, change_submits=False, bind_return_key=True, justification='right', num_rows=6, alternating_row_color='lightblue', key='_table_', text_color='black', tooltip='Table'),