Facing issues while creating multiple instances of Dependent QComboBox
Tags: python, pyqt, pyqt5, help
Published: 2023-07-18 16:07:09

I'm working on the GUI part of the input dock on the [truss_connection_bolted](https://github.com/iamwatchdogs/Osdag/blob/truss-connection-gui/design_type/connection/truss_connection_bolted.py) module on a project called [Osdag](https://github.com/osdag-admin/Osdag) and the whole GUI part is written using the **PyQt5** module. My task is to finish the connecting members attribute on the Input dock which happens to be a set of `QComboBox` widgets on a single `QTableWidget`. I have successfully written most of the part by there is one section of `QComboBox` in the Table widget that depends on another `QComboBox`.

After long research, I was able to create a stud that shows the required functionality. Here is the following code snippet for the stub.

```py
# ---------------
# More Code above
# ---------------

# Table Widget Creation
table_widget = QtWidgets.QTableWidget(self.dockWidgetContents)
table_widget.setObjectName(option[0])
table_widget.setRowCount(8)
table_widget.setColumnCount(6)

# Attributes dictionary 
selectable_options = {
  'Section profile': ['Angle', 'Star Angles', 'Back to Back Angles', 'Channel','Back to Back Channels'],
  'Connection Location': {
    'Angle': ['Long leg connected', 'Short leg connected'],
    'Channel': ['Web-connected']
  },
  'Section Size': ['20 x 20 x 3', '20 x 20 x 4', '25 x 25 x 3', '25 x 25 x 4', ...],
  'Material': [ 'E165', 'E250 (Fe 410W) A', 'E250 (Fe 410W) B', 'E250 (Fe 410W) C', ....]
}

# Setting Head Labels to the table widget
table_widget.setHorizontalHeaderLabels(
  list(selectable_options.keys()) + ["Angle with x-axis (Degrees)", "Factored Load (KN)"]
)

# Creating two indivdual QComboBox for testing out the dependency functionality
combo_box_secpro = QtWidgets.QComboBox()
combo_box_connloc = QtWidgets.QComboBox()

# Adding values to the "Section Profile" QComboBox
for item in selectable_options['Section profile']:
  value = None
  if item in ['Angle', 'Star Angles', 'Back to Back Angles']:
    value = selectable_options['Connection Location']['Angle']
  elif item in ['Channel', 'Back to Back Channels']:
    value = selectable_options['Connection Location']['Channel']
combo_box_secpro.addItem(item, value)

# Connecting "Section Profile" QComboBox to "Connection Location" QComboBox
combo_box_secpro.activated.connect(
  lambda: combo_box_connloc.clear() or combo_box_connloc.addItems(
            selectable_options['Connection Location'][ 'Angle' if combo_box_secpro.currentText() in ['Angle', 'Star Angles', 'Back to Back Angles'] else 'Channel']
            )
  )

# Placing both of those the QComboBoxes into table Widget
table_widget.setCellWidget(0,0,combo_box_secpro)
table_widget.setCellWidget(0,1,combo_box_connloc)

# ---------------
# More code below
# ---------------
```

![Output of stub code snippet](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/att1qka44t5jn21bqsvo.gif)

The above code snippet worked fine but, when I tried to loop the same logic... It's not working as Intended... The code snippet for the looping logic:

```py
# ---------------------
# More other code above
# ---------------------

# Note that this is just a looped version of the above logic,
# so all the other declarations of the dictionary mentioned above are present here..

combo_box_dictionary = dict()  # Just in case, if we need the combo_box object for each option

for col, (key, value) in enumerate(selectable_options.items()):

  # Skipping 'Connection location' as I have handled it in 'Section profile'
  if key == 'Connection Location':
    continue

  # Creating 'Connection location' QComboBox that depend on 'Section profile' QComboBox
  elif key == 'Section profile':

    combo_box_section_profile_list = []
    combo_box_connection_location_list = []

    # Looping for 8 times for each row in table widget
    for row in range(8):

      # Creating QComboBox Object for both 'Section profile' & 'Connection location'
      combo_box_section_profile = QtWidgets.QComboBox()
      combo_box_connection_location = QtWidgets.QComboBox()

      # Adding items into 'Section profile' QComboBox
      for item in selectable_options['Section profile']:
        value = None
        if item in ['Angle', 'Star Angles', 'Back to Back Angles']:
          value = selectable_options['Connection Location']['Angle']
        elif item in ['Channel', 'Back to Back Channels']:
          value = selectable_options['Connection Location']['Channel']
        combo_box_section_profile.addItem(item, value)

      # Connecting 'Section profile' dependent functionality to 'Connection Location'
      combo_box_section_profile.activated.connect(
        lambda: combo_box_connection_location.clear() or combo_box_connection_location.addItems(
          selectable_options['Connection Location']['Angle' if combo_box_section_profile.currentText() in ['Angle', 'Star Angles', 'Back to Back Angles'] else 'Channel']
                 )
         )

      # Added Default Items into 'Connection Location'
      combo_box_connection_location.addItems(selectable_options['Connection Location']['Angle'])

      # Setting the QComboBoxes into their respective places
      table_widget.setCellWidget(row, col, combo_box_section_profile)
      table_widget.setCellWidget(row, col+1, combo_box_connection_location)

      # Storing their Object References per each row
      combo_box_section_profile_list.append(combo_box_section_profile)
      combo_box_connection_location_list.append(combo_box_connection_location)

    # Collectively storing Object References for both of them for all the rows
    combo_box_dictionary['Section profile'] = combo_box_section_profile_list
    combo_box_dictionary['Connection Location'] = combo_box_connection_location_list

  else:
    # Logic for adding simple QComboBoxes to the table widget
    combo_box_list = []
    for row in range(8):
      combo_box = QtWidgets.QComboBox()
      combo_box.addItems(value)
      table_widget.setCellWidget(row, col, combo_box)
      combo_box_list.append(combo_box)
      combo_box_dictionary[key] = combo_box_list

# ---------------------
# More other code below
# ---------------------
```

Output:
![The main problem](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bsbys6m95yicvymr5n8z.gif)

> **Note**:
>
> - If you want to see the whole code you can find it within my GitHub in [truss-connection-bolted-gui](https://github.com/iamwatchdogs/Osdag/blob/698771e2dca630883af684dd899db403585ca248/gui/ui_template.py#L631).
> - If you wish to setup the project within you system, make sure the following things;
>   - Use **Ubuntu** 20.04 LTS version through your VM.
>   - Follow the [README.md](https://github.com/osdag-admin/Osdag#2-ubuntu-installation) instrustion to install the project environment.
>   - And It's recommended to use Pycharm IDE.

I have spent a lot of time search for some answers but, could find one. Is there way to fix this problem ?

Other than my original implementation, I have tried searching for an alternative to the connecting method but couldn't find one...

Then I tried different approaches like storing the object references and then assigning the connecting method to link up the required functionality to the respective QComboBoxes. But, That didn't work out either...

```py
for col, (key, value) in enumerate(selectable_options.items()):
  combo_box_list = []
  for row in range(8):
    combo_box = QtWidgets.QComboBox()
    if key == 'Connection Location':
      value = selectable_options['Connection Location']['Angle']
    combo_box.addItems(value)
    table_widget.setCellWidget(row, col, combo_box)
    combo_box_list.append(combo_box)
  combo_box_dictionary[key] = combo_box_list

for index, secpro_QComboBox in enumerate(combo_box_dictionary['Section profile']):
  connloc_QComboBox = combo_box_dictionary['Connection Location'][index]
  secpro_QComboBox.activated.connect(lambda:
    connloc_QComboBox.clear() or
    connloc_QComboBox.addItems(
      selectable_options['Connection Location']['Angle' if secpro_QComboBox.currentText() in ['Angle', 'Star Angles', 'Back to Back Angles'] else 'Channel']
     )
  )
```

Output:
![The main problem](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bsbys6m95yicvymr5n8z.gif)

I don't know what to do, it's giving me the same error. Can anyone figure out what's going on ?