I'm working on the GUI part of the input dock on the truss_connection_bolted module on a project called 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
.
Note: Before proceeding to the remaining code: This is not a typical code snippet for a small program. This is used in a huge application containing multiple modules. So, you just can't you can use it within a class and create a method to handle the connect()
and access a QComboBox
using self.secpro_QComboBox
. You can't just do that, please take a look at the project files mainly ui_template.py#L631.
After long research, I created a stub that shows the required functionality. Here is the following code snippet for the stub.
# ---------------
# More Code above
# ---------------
class Window(QMainWindow):
# other code
def setupUi(self, MainWindow, main, folder):
# other code
# 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 QComboBoxes into the table Widget
table_widget.setCellWidget(0,0,combo_box_secpro)
table_widget.setCellWidget(0,1,combo_box_connloc)
# ---------------
# More code below
# ---------------
Output: Output of stub code snippet
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:
# ---------------------
# More other code above
# ---------------------
# Note that this is just a looped version of the above logic within same class & method,
# 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 codes below
# ---------------------
Output: The main problem
Note:
- If you want to see the whole code you can find it within my GitHub in truss-connection-bolted-gui.
- If you wish to set up the project within you system, make sure the following things;
- Use Ubuntu 20.04 LTS version through your VM.
- Follow the README.md instruction to install the project environment.
- And it's recommended to use Pycharm IDE.
I have spent a lot of time searching for some answers but, could find one. Is there a 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 assigning the connecting method to link the required functionality to the respective QComboBoxes. But, that didn't work out either.
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(
connloc_QComboBox.clear() or
connloc_QComboBox.addItems(lambda:
selectable_options['Connection Location']['Angle' if secpro_QComboBox.currentText() in ['Angle', 'Star Angles', 'Back to Back Angles'] else 'Channel']
)
)
Output: Output Remains same...
I don't know what to do, it's giving me the same error. Can anyone figure out what's going on and help me fix it?