diff --git a/src/view/frm_asbuilt.py b/src/view/frm_asbuilt.py index 977589d3..4912e894 100644 --- a/src/view/frm_asbuilt.py +++ b/src/view/frm_asbuilt.py @@ -23,7 +23,6 @@ def __init__(self, parent, qris_project: Project, event_type_id: int, event: Eve self.lblPhase.setVisible(True) self.txtPhase.setVisible(True) - self.txtPhase.setPlaceholderText('Phase 1, Phase 2, Pilot, Demo, Maintenance of Phase 1 etc.') self.lblAssociatedDesign = QtWidgets.QLabel('Design this As-Built is based on', self) self.tabGrid.addWidget(self.lblAssociatedDesign, 1, 0) @@ -42,10 +41,10 @@ def __init__(self, parent, qris_project: Project, event_type_id: int, event: Eve self.lblStartDate.setText('Date of As-Built Survey') self.lblConstructionDate = QtWidgets.QLabel('Date of Construction', self) - self.tabGrid.addWidget(self.lblConstructionDate, 5, 0) + self.tabGrid.addWidget(self.lblConstructionDate, 6, 0) self.uc_construction = FrmDatePicker(self) - self.tabGrid.addWidget(self.uc_construction, 5, 1) + self.tabGrid.addWidget(self.uc_construction, 6, 1) self.lblPlatform.setVisible(False) self.cboPlatform.setVisible(False) @@ -54,11 +53,11 @@ def __init__(self, parent, qris_project: Project, event_type_id: int, event: Eve self.cboRepresentation.setVisible(False) self.lblDesigners = QtWidgets.QLabel('Observer(s)', self) - self.tabGrid.addWidget(self.lblDesigners, 7, 0, 1, 1) + self.tabGrid.addWidget(self.lblDesigners, 8, 0, 1, 1) self.tabGrid.setAlignment(self.lblDesigners, QtCore.Qt.AlignTop) self.txtDesigners = QtWidgets.QPlainTextEdit(self) - self.tabGrid.addWidget(self.txtDesigners, 7, 1, 1, 1) + self.tabGrid.addWidget(self.txtDesigners, 8, 1, 1, 1) # Create a checkbox widget for each design source self.design_source_widgets, self.design_sources = add_checkbox_widgets( @@ -67,13 +66,13 @@ def __init__(self, parent, qris_project: Project, event_type_id: int, event: Eve # Add the checkboxes to the form self.lblDesignSources = QtWidgets.QLabel('As-Built Observations', self) self.lblDesignSources.setAlignment(QtCore.Qt.AlignTop) - self.tabGrid.addWidget(self.lblDesignSources, 8, 0, 1, 1) + self.tabGrid.addWidget(self.lblDesignSources, 9, 0, 1, 1) self.groupBoxDesignSources = QtWidgets.QGroupBox(self) self.groupBoxDesignSources.setLayout(QtWidgets.QVBoxLayout()) [self.groupBoxDesignSources.layout().addWidget(widget) for widget in self.design_source_widgets] # add vertical spacer to group box layout - self.tabGrid.addWidget(self.groupBoxDesignSources, 8, 1) + self.tabGrid.addWidget(self.groupBoxDesignSources, 9, 1) self.tabGrid.setAlignment(self.groupBoxDesignSources, QtCore.Qt.AlignTop) surface_tab_index = self.tab.indexOf(self.surfaces_widget) @@ -115,9 +114,6 @@ def __init__(self, parent, qris_project: Project, event_type_id: int, event: Eve widget_id = widget.property('id') if widget_id == source_id: widget.setChecked(True) - - if 'phase' in self.metadata_widget.metadata['system']: - self.txtPhase.setText(self.metadata_widget.metadata['system']['phase']) if 'associatedDesignId' in self.metadata_widget.metadata['system']: associated_design_id = self.metadata_widget.metadata['system']['associatedDesignId'] @@ -202,11 +198,6 @@ def accept(self): self.metadata_widget.add_system_metadata('observers', self.txtDesigners.toPlainText()) - if self.txtPhase.text() != '': - self.metadata_widget.add_system_metadata('phase', self.txtPhase.text()) - else: - self.metadata_widget.delete_item('system', 'phase') - if self.cboAssociatedDesign.currentData(QtCore.Qt.UserRole).id != 0: self.metadata_widget.add_system_metadata('associatedDesignId', self.cboAssociatedDesign.currentData(QtCore.Qt.UserRole).id) else: diff --git a/src/view/frm_design2.py b/src/view/frm_design2.py index e479b102..9400c1ac 100644 --- a/src/view/frm_design2.py +++ b/src/view/frm_design2.py @@ -4,7 +4,7 @@ from ..model.db_item import DBItem, DBItemModel, dict_factory from ..model.project import Project -from ..model.event import Event, DESIGN_EVENT_TYPE_ID, AS_BUILT_EVENT_TYPE_ID +from ..model.event import Event, DESIGN_EVENT_TYPE_ID, AS_BUILT_EVENT_TYPE_ID, DCE_EVENT_TYPE_ID, PLANNING_EVENT_TYPE_ID from .frm_event import FrmEvent @@ -16,25 +16,56 @@ def __init__(self, parent, qris_project: Project, event_type_id: int, event: Eve event_type = 'Design' if event_type_id == DESIGN_EVENT_TYPE_ID else 'As-Built Survey' self.setWindowTitle(f'Create New {event_type}' if event is None else f'Edit {event_type}') - self.lblPlatform.setText('Design completed at') + self.mandatory_layers = ['complexes'] - self.lblStatus = QtWidgets.QLabel('Design Status', self) - self.tabGrid.addWidget(self.lblStatus, 6, 0) + self.lblPhase.setVisible(True) + self.txtPhase.setVisible(True) - statuses = qris_project.lookup_tables['lkp_design_status'] + self.lblPlatform.setVisible(False) + self.cboPlatform.setVisible(False) + + self.lblRepresentation.setVisible(False) + self.cboRepresentation.setVisible(False) + + self.lblPercentComplete = QtWidgets.QLabel('Percent Complete', self) + self.tabGrid.addWidget(self.lblPercentComplete, 7, 0) + + self.horiz_slider = QtWidgets.QHBoxLayout() + self.tabGrid.addLayout(self.horiz_slider, 7, 1, 1, 1) + self.sliderPercentComplete = QtWidgets.QSlider(QtCore.Qt.Horizontal, self) + self.sliderPercentComplete.setMinimum(0) + self.sliderPercentComplete.setMaximum(100) + self.sliderPercentComplete.setTickPosition(QtWidgets.QSlider.TicksBelow) + self.sliderPercentComplete.setTickInterval(5) + self.sliderPercentComplete.setSingleStep(5) + self.sliderPercentComplete.update() + self.sliderPercentComplete.valueChanged.connect(self.adjustSliderValue) + self.horiz_slider.addWidget(self.sliderPercentComplete) + + init_value = self.sliderPercentComplete.value() + self.lblPercentCompleteValue = QtWidgets.QLabel(f'{init_value}%', self) + font_metrics = QtGui.QFontMetrics(self.lblPercentCompleteValue.font()) + text_width = font_metrics.width("100% ") + text_height = font_metrics.height() + self.lblPercentCompleteValue.setMinimumSize(text_width, text_height) + self.lblPercentCompleteValue.setMaximumSize(text_width, text_height) + self.horiz_slider.addWidget(self.lblPercentCompleteValue) + + self.lblStatus = QtWidgets.QLabel('Design Status Label', self) + self.tabGrid.addWidget(self.lblStatus, 8, 0) + + statuses = {key: DBItem('', key, value) for key, value in enumerate(['In Progress', 'Provisional (awaiting review)', 'Final'])} self.cboStatus = QtWidgets.QComboBox(self) self.status_model = DBItemModel(statuses) self.cboStatus.setModel(self.status_model) - self.tabGrid.addWidget(self.cboStatus, 6, 1, 1, 1) - - self.tab.setTabEnabled(0, False) + self.tabGrid.addWidget(self.cboStatus, 8, 1, 1, 1) self.lblDesigners = QtWidgets.QLabel(self) self.lblDesigners.setText('Designers') - self.tabGrid.addWidget(self.lblDesigners, 7, 0, 1, 1) + self.tabGrid.addWidget(self.lblDesigners, 9, 0, 1, 1) self.txtDesigners = QtWidgets.QPlainTextEdit(self) - self.tabGrid.addWidget(self.txtDesigners, 7, 1, 1, 1) + self.tabGrid.addWidget(self.txtDesigners, 9, 1, 1, 1) # Create a checkbox widget for each design source self.design_source_widgets, self.design_sources = add_checkbox_widgets( @@ -43,38 +74,120 @@ def __init__(self, parent, qris_project: Project, event_type_id: int, event: Eve # Add the checkboxes to the form self.lblDesignSources = QtWidgets.QLabel('Design Sources', self) self.lblDesignSources.setAlignment(QtCore.Qt.AlignTop) - self.tabGrid.addWidget(self.lblDesignSources, 8, 0, 1, 1) + self.tabGrid.addWidget(self.lblDesignSources, 10, 0, 1, 1) self.groupBoxDesignSources = QtWidgets.QGroupBox(self) self.groupBoxDesignSources.setLayout(QtWidgets.QVBoxLayout()) [self.groupBoxDesignSources.layout().addWidget(widget) for widget in self.design_source_widgets] - self.tabGrid.addWidget(self.groupBoxDesignSources, 8, 1, 1, 1) + self.tabGrid.addWidget(self.groupBoxDesignSources, 10, 1, 1, 1) - if event is not None: - self.chkAddToMap.setVisible(False) + surface_tab_index = self.tab.indexOf(self.surfaces_widget) + self.tab.setTabText(surface_tab_index, 'Bases for Design') + + self.lblBasedOn = QtWidgets.QLabel('Data Capture Events', self) + self.vert_surfaces.addWidget(self.lblBasedOn) + + self.grid_based_on_dces = QtWidgets.QGridLayout() + self.vert_surfaces.addLayout(self.grid_based_on_dces) + + self.lblExistingDCEs = QtWidgets.QLabel('Existing', self) + self.grid_based_on_dces.addWidget(self.lblExistingDCEs, 0, 0) + + dce_events = {key: value for key, value in self.qris_project.events.items() if value.event_type.id in [DCE_EVENT_TYPE_ID]} + dce_events[0] = DBItem('', 0, 'None') + planning_events = {key: value for key, value in self.qris_project.events.items() if value.event_type.id in [PLANNING_EVENT_TYPE_ID]} + planning_events[0] = DBItem('', 0, 'None') + + self.cboExistingDCEs = QtWidgets.QComboBox(self) + self.existing_dce_model = DBItemModel(dce_events) + self.existing_dce_model.sort_data_by_key() + self.cboExistingDCEs.setModel(self.existing_dce_model) + self.grid_based_on_dces.addWidget(self.cboExistingDCEs, 0, 1) + + self.lblHistoricalDCEs = QtWidgets.QLabel('Historic', self) + self.grid_based_on_dces.addWidget(self.lblHistoricalDCEs, 1, 0) - status_id = event.metadata['statusId'] - status_index = self.status_model.getItemIndexById(status_id) - self.cboStatus.setCurrentIndex(status_index) + self.cboHistoricalDCEs = QtWidgets.QComboBox(self) + self.historical_dce_model = DBItemModel(dce_events) + self.historical_dce_model.sort_data_by_key() + self.cboHistoricalDCEs.setModel(self.historical_dce_model) + self.grid_based_on_dces.addWidget(self.cboHistoricalDCEs, 1, 1) - if 'designers' in event.metadata: - self.txtDesigners.setPlainText(event.metadata['designers']) + self.lblFutureRecoveryDCEs = QtWidgets.QLabel('Future (Recovery Potential)', self) + self.grid_based_on_dces.addWidget(self.lblFutureRecoveryDCEs, 2, 0) - if 'designSourceIds' in event.metadata: - design_source_ids = event.metadata['designSourceIds'] - if design_source_ids is not None: - for source_id in design_source_ids: - for widget in self.design_source_widgets: - widget_id = widget.property('id') - if widget_id == source_id: - widget.setChecked(True) + self.cboFutureRecoveryDCEs = QtWidgets.QComboBox(self) + self.future_recovery_dce_model = DBItemModel(planning_events) + self.future_recovery_dce_model.sort_data_by_key() + self.cboFutureRecoveryDCEs.setModel(self.future_recovery_dce_model) + self.grid_based_on_dces.addWidget(self.cboFutureRecoveryDCEs, 2, 1) + + if event is not None: + self.chkAddToMap.setVisible(False) + + if 'system' in self.metadata_widget.metadata: + # if 'statusId' in self.metadata_widget.metadata['system']: + # status_id = self.metadata_widget.metadata['system']['statusId'] + # status_index = self.status_model.getItemIndexById(status_id) + # self.cboStatus.setCurrentIndex(status_index) + + if 'status' in self.metadata_widget.metadata['system']: + status = self.metadata_widget.metadata['system']['status'] + status_index = self.status_model.getItemIndexByName(status) + self.cboStatus.setCurrentIndex(status_index) + + if 'designers' in self.metadata_widget.metadata['system']: + self.txtDesigners.setPlainText(self.metadata_widget.metadata['system']['designers']) + + if 'designSourceIds' in self.metadata_widget.metadata['system']: + design_source_ids = self.metadata_widget.metadata['system']['designSourceIds'] + if design_source_ids is not None: + for source_id in design_source_ids: + for widget in self.design_source_widgets: + widget_id = widget.property('id') + if widget_id == source_id: + widget.setChecked(True) + if 'percentComplete' in self.metadata_widget.metadata['system']: + self.sliderPercentComplete.setValue(int(self.metadata_widget.metadata['system']['percentComplete'])) + + if 'based_on_exising_dce_id' in self.metadata_widget.metadata['system']: + existing_dce_id = self.metadata_widget.metadata['system']['based_on_exising_dce_id'] + existing_dce_index = self.existing_dce_model.getItemIndexById(existing_dce_id) + self.cboExistingDCEs.setCurrentIndex(existing_dce_index) + + if 'based_on_historical_dce_id' in self.metadata_widget.metadata['system']: + historical_dce_id = self.metadata_widget.metadata['system']['based_on_historical_dce_id'] + historical_dce_index = self.historical_dce_model.getItemIndexById(historical_dce_id) + self.cboHistoricalDCEs.setCurrentIndex(historical_dce_index) + + if 'based_on_planning_dce_id' in self.metadata_widget.metadata['system']: + planning_dce_id = self.metadata_widget.metadata['system']['based_on_planning_dce_id'] + planning_dce_index = self.future_recovery_dce_model.getItemIndexById(planning_dce_id) + self.cboFutureRecoveryDCEs.setCurrentIndex(planning_dce_index) + + else: + # iterate through the tree model and children to find the first 'structure_points' layer + for index in range(self.tree_model.rowCount()): + protocol_item = self.tree_model.item(index) + for layer_index in range(protocol_item.rowCount()): + layer_item = protocol_item.child(layer_index) + if 'complexes' in layer_item.data(QtCore.Qt.UserRole).fc_name: + self.add_selected_layers(layer_item) + + def adjustSliderValue(self, value): + # Calculate the nearest multiple of 5 + adjusted_value = round(value / 5) * 5 + # Set the slider's value to this adjusted value + # Block signals to prevent infinite loop + self.sliderPercentComplete.blockSignals(True) + self.sliderPercentComplete.setValue(adjusted_value) + self.sliderPercentComplete.blockSignals(False) + # Update the label + self.lblPercentCompleteValue.setText(f'{adjusted_value}%') def accept(self): - if self.metadata is None: - self.metadata = {} - - self.metadata['statusId'] = self.cboStatus.currentData(QtCore.Qt.UserRole).id - self.metadata['designers'] = self.txtDesigners.toPlainText() + self.metadata_widget.add_system_metadata('statusId', self.cboStatus.currentData(QtCore.Qt.UserRole).id) + self.metadata_widget.add_system_metadata('designers', self.txtDesigners.toPlainText()) design_source_ids = [] for widget in self.design_source_widgets: @@ -82,16 +195,22 @@ def accept(self): design_source_ids.append(widget.property('id')) if len(design_source_ids) > 0: - self.metadata['designSourceIds'] = design_source_ids - - self.protocols = [self.qris_project.protocols[4]] - for protocol in self.protocols: - for method in protocol.methods: - for layer in method.layers: - layer_si = QtGui.QStandardItem(layer.name) - layer_si.setEditable(False) - layer_si.setData(layer, QtCore.Qt.UserRole) - self.layers_model.appendRow(layer_si) + self.metadata_widget.add_system_metadata('designSourceIds', design_source_ids) + else: + if 'designSourceIds' in self.metadata_widget.metadata['system']: + self.metadata_widget.delete_item('system', 'designSourceIds') + + self.metadata_widget.add_system_metadata('status', self.cboStatus.currentData(QtCore.Qt.UserRole).name) + self.metadata_widget.add_system_metadata('percentComplete', self.sliderPercentComplete.value()) + + existing_dce_id = self.cboExistingDCEs.currentData(QtCore.Qt.UserRole).id + self.metadata_widget.add_system_metadata('based_on_exising_dce_id', existing_dce_id) + + historical_dce_id = self.cboHistoricalDCEs.currentData(QtCore.Qt.UserRole).id + self.metadata_widget.add_system_metadata('based_on_historical_dce_id', historical_dce_id) + + future_recovery_dce_id = self.cboFutureRecoveryDCEs.currentData(QtCore.Qt.UserRole).id + self.metadata_widget.add_system_metadata('based_on_planning_dce_id', future_recovery_dce_id) super().accept() diff --git a/src/view/frm_event.py b/src/view/frm_event.py index 221c9be7..d49365ba 100644 --- a/src/view/frm_event.py +++ b/src/view/frm_event.py @@ -3,7 +3,7 @@ from PyQt5 import QtCore, QtGui, QtWidgets -from ..model.event import Event, PLANNING_EVENT_TYPE_ID, PLANNING_MACHINE_CODE, AS_BUILT_EVENT_TYPE_ID, AS_BUILT_MACHINE_CODE, insert as insert_event +from ..model.event import Event, PLANNING_EVENT_TYPE_ID, PLANNING_MACHINE_CODE, AS_BUILT_EVENT_TYPE_ID, AS_BUILT_MACHINE_CODE, DESIGN_EVENT_TYPE_ID, DESIGN_MACHINE_CODE, insert as insert_event from ..model.db_item import DBItem, DBItemModel from ..model.datespec import DateSpec from ..model.project import Project @@ -31,6 +31,7 @@ def __init__(self, parent, qris_project: Project, event_type_id: int = DATA_CAPT self.event_type_id = event_type_id # Note that "event" is already a method from QDialog(), hence the weird name self.the_event = event + self.mandatory_layers = None init_metadata = None if event is not None and event.metadata is not None: @@ -46,7 +47,8 @@ def __init__(self, parent, qris_project: Project, event_type_id: int = DATA_CAPT self.surface_library = SurfaceLibraryWidget(self, qris_project) self.setupUi() - self.setWindowTitle('Create New Data Capture Event' if event is None else 'Edit Data Capture Event') + dce_type = 'Data Capture' if event_type_id == DATA_CAPTURE_EVENT_TYPE_ID else 'Planning' + self.setWindowTitle(f'Create New {dce_type} Event' if event is None else f'Edit {dce_type} Event') self.tree_model = None self.load_layer_tree() @@ -98,6 +100,8 @@ def __init__(self, parent, qris_project: Project, event_type_id: int = DATA_CAPT if self.metadata_widget.metadata is not None and 'system' in self.metadata_widget.metadata: if 'valley_bottom_id' in self.metadata_widget.metadata['system']: self.cboValleyBottom.setCurrentIndex(self.valley_bottom_model.getItemIndexById(self.metadata_widget.metadata['system']['valley_bottom_id'])) + if 'phase' in self.metadata_widget.metadata['system']: + self.txtPhase.setText(self.metadata_widget.metadata['system']['phase']) for event_layer in event.event_layers: item = QtGui.QStandardItem(event_layer.layer.name) @@ -135,6 +139,9 @@ def load_hierarchical_tree(self): if self.event_type_id == AS_BUILT_EVENT_TYPE_ID: if protocol.machine_code.lower() != AS_BUILT_MACHINE_CODE.lower(): continue + if self.event_type_id == DESIGN_EVENT_TYPE_ID: + if protocol.machine_code.lower() != DESIGN_MACHINE_CODE.lower(): + continue protocol_si.setData(protocol, QtCore.Qt.UserRole) protocol_si.setEditable(False) @@ -326,6 +333,10 @@ def add_selected_layers(self, item: QtGui.QStandardItem) -> None: def on_remove_layer(self): for index in self.layer_list.selectedIndexes(): + if self.mandatory_layers is not None: + layer = self.layers_model.itemFromIndex(index).data(QtCore.Qt.UserRole) + if layer.fc_name in self.mandatory_layers: + continue self.layers_model.removeRow(index.row()) def on_opt_date_change(self): @@ -353,6 +364,16 @@ def check_surface_types(self): def accept(self): + selected_layers = [] + for index in range(self.layers_model.rowCount()): + item = self.layers_model.item(index) + selected_layers.append(item.data(QtCore.Qt.UserRole).fc_name) + # make sure all mandatory layers are present + if self.mandatory_layers is not None: + if any(layer not in selected_layers for layer in self.mandatory_layers): + QtWidgets.QMessageBox.warning(self, 'Error', f'All mandatory layers ({",".join(self.mandatory_layers)}) must be selected.') + return + if not self.check_surface_types(): QtWidgets.QMessageBox.warning(self, 'Invalid Surface Types', 'Only one DEM can be selected') return @@ -400,8 +421,12 @@ def accept(self): if self.cboValleyBottom.currentText() != 'None': self.metadata_widget.add_system_metadata('valley_bottom_id', self.cboValleyBottom.currentData(QtCore.Qt.UserRole).id) else: - if 'system' in self.metadata_widget.metadata and 'valley_bottom_id' in self.metadata_widget.metadata['system']: - del self.metadata_widget.metadata['system']['valley_bottom_id'] + self.metadata_widget.delete_item('system', 'valley_bottom_id') + + if self.txtPhase.text() != '': + self.metadata_widget.add_system_metadata('phase', self.txtPhase.text()) + else: + self.metadata_widget.delete_item('system', 'phase') if not self.metadata_widget.validate(): return @@ -550,44 +575,45 @@ def setupUi(self): self.lblPhase.setVisible(False) self.txtPhase = QtWidgets.QLineEdit(self) + self.txtPhase.setPlaceholderText('Phase 1, Phase 2, Pilot, Demo, Maintenance of Phase 1 etc.') self.tabGrid.addWidget(self.txtPhase, 2, 1, 1, 1) self.txtPhase.setVisible(False) self.optSingleDate = QtWidgets.QRadioButton('Single Point in Time') self.optSingleDate.setChecked(True) - self.tabGrid.addWidget(self.optSingleDate, 2, 0, 1, 1) + self.tabGrid.addWidget(self.optSingleDate, 3, 0, 1, 1) self.optDateRange = QtWidgets.QRadioButton('Date Range') - self.tabGrid.addWidget(self.optDateRange, 3, 0, 1, 1) + self.tabGrid.addWidget(self.optDateRange, 4, 0, 1, 1) self.lblStartDate = QtWidgets.QLabel() self.lblStartDate.setText('Date') - self.tabGrid.addWidget(self.lblStartDate, 4, 0, 1, 1) + self.tabGrid.addWidget(self.lblStartDate, 5, 0, 1, 1) self.uc_start = FrmDatePicker(self) - self.tabGrid.addWidget(self.uc_start, 4, 1, 1, 1) + self.tabGrid.addWidget(self.uc_start, 5, 1, 1, 1) self.lblEndDate = QtWidgets.QLabel() self.lblEndDate.setText('End Date') self.lblEndDate.setVisible(False) - self.tabGrid.addWidget(self.lblEndDate, 5, 0, 1, 1) + self.tabGrid.addWidget(self.lblEndDate, 6, 0, 1, 1) self.uc_end = FrmDatePicker(self) self.uc_end.setVisible(False) - self.tabGrid.addWidget(self.uc_end, 5, 1, 1, 1) + self.tabGrid.addWidget(self.uc_end, 6, 1, 1, 1) self.lblPlatform = QtWidgets.QLabel() self.lblPlatform.setText('Event completed at') - self.tabGrid.addWidget(self.lblPlatform, 6, 0, 1, 1) + self.tabGrid.addWidget(self.lblPlatform, 7, 0, 1, 1) self.cboPlatform = QtWidgets.QComboBox() - self.tabGrid.addWidget(self.cboPlatform, 6, 1, 1, 1) + self.tabGrid.addWidget(self.cboPlatform, 7, 1, 1, 1) self.lblRepresentation = QtWidgets.QLabel("Representation") - self.tabGrid.addWidget(self.lblRepresentation, 7, 0, 1, 1) + self.tabGrid.addWidget(self.lblRepresentation, 8, 0, 1, 1) self.cboRepresentation = QtWidgets.QComboBox() - self.tabGrid.addWidget(self.cboRepresentation, 7, 1, 1, 1) + self.tabGrid.addWidget(self.cboRepresentation, 8, 1, 1, 1) verticalSpacer = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) self.tabGrid.addItem(verticalSpacer)