class CustomScrollableList(QWidget): def __init__(self, parent, item_type, floating_widget=None): super(CustomScrollableList, self).__init__() self.parent = parent self.item_type = item_type self.floating_widget = floating_widget self.layout = QVBoxLayout(self) self.layout.setContentsMargins(0, 0, 0, 0) self.list_widget = QWidget() self.list_layout = QVBoxLayout(self.list_widget) self.list_layout.setContentsMargins(0, 0, 0, 0) self.list_layout.setSpacing(10) self.list_layout.setAlignment(Qt.AlignmentFlag.AlignTop) self.scroll_area = QScrollArea() self.scroll_area.setWidgetResizable(True) self.scroll_area.setFrameStyle(0) self.scroll_area.setWidget(self.list_widget) self.layout.addWidget(self.scroll_area) if self.floating_widget is not None: self.list_layout.addWidget(self.floating_widget) self.item_widgets = [] self.num_visible_item_widgets = 0 def last_item_widget(self): return self.item_widgets[self.num_visible_item_widgets - 1] def update_item_list(self, item_list, params=None): if self.floating_widget is not None: self.list_layout.removeWidget(self.floating_widget) # make sure that there are enough item widgets while len(item_list) > len(self.item_widgets): self.item_widgets.append(self.item_type(self.parent)) # make sure that the correct number of item widgets is shown while len(item_list) > self.num_visible_item_widgets: widget = self.item_widgets[self.num_visible_item_widgets] self.list_layout.addWidget(widget) widget.show() self.num_visible_item_widgets += 1 while len(item_list) < self.num_visible_item_widgets: widget = self.item_widgets[self.num_visible_item_widgets - 1] widget.hide() self.list_layout.removeWidget(widget) self.num_visible_item_widgets -= 1 if self.floating_widget is not None: self.list_layout.addWidget(self.floating_widget) # update item widgets for item, item_widget in zip(item_list, self.item_widgets[:len(item_list)]): item_widget.update_item(item, params) def enable_input(self): for item_widget in self.item_widgets: item_widget.enable_input() def disable_input(self): for item_widget in self.item_widgets: item_widget.disable_input()
class AgentVariablesGroupView(QWidget): onVariablesChange = pyqtSignal(dict) def __init__( self, variables: dict[str, tuple[type, Any]], parent: Optional[QWidget] = None, *args: Tuple[Any, Any], **kwargs: Tuple[Any, Any], ) -> None: """ The two vertical box layouts of the variable names and their respective values. """ super(AgentVariablesGroupView, self).__init__(parent=parent, *args, **kwargs) self.__variables = variables self.setContentsMargins(0, 0, 0, 0) # keep our name and value labels here so we can destroy them when we need to redraw with updated variables namesLabels = list[QLabel]() valuesLabels = list[QLabel]() self.__horizontalGroupBoxLayout = QHBoxLayout() self.__variableNamesBox = QVBoxLayout() self.__variableValuesBox = QVBoxLayout() # submethod to update the 'names' and 'values' vertical views properly def updateVariableViews(vars: dict[str, tuple[type, Any]]) -> None: # for each name label in the list of namelabel widgets, for nameLabel in namesLabels: # then clear the label so it doesn't redraw later… nameLabel.clear() # and remove it from the vertical box layout. self.__variableNamesBox.removeWidget(nameLabel) # for each value label in the list of valuelabel widgets, for valueLabel in valuesLabels: # then clear the label so it doesn't redraw later… valueLabel.clear() # and remove it from the vertical box layout. self.__variableValuesBox.removeWidget(valueLabel) self.__variables = vars # for each variable name, then… # make a copy of the KeysView (keys) so it won't unexpectedly change size during iteration currentKeys = list(self.__variables.keys()) for variableName in currentKeys: # add it to the list of label widgets as a QLabel namesLabels.append(QLabel(variableName)) # …also add it to the vertical labelNames labels box self.__variableNamesBox.addWidget(namesLabels[-1]) # for each variable value, then… for variableValue in self.__variables.values(): # add it to the list of label widgets as a QLabel valuesLabels.append(QLabel(str(variableValue))) # …also add it to the vertical labelValues labels box self.__variableValuesBox.addWidget(valuesLabels[-1]) # add the layouts to our main window layout self.__horizontalGroupBoxLayout.addLayout(self.__variableNamesBox) self.__horizontalGroupBoxLayout.addLayout(self.__variableValuesBox) # aaand finally update the window to reflect our changes. self.update() self.onVariablesChange.connect(updateVariableViews) updateVariableViews(self.__variables) self.setLayout(self.__horizontalGroupBoxLayout)