Reputation: 53
I wrote a script that automatically creates a QT "object" made up of a category label, a combobox_1 with possible attributes, a push button and a combobox_2 to list all values available for the attribute selected. the script creates as many of these "objects" as necessary.
For each "object" the push button created is meant to grab the selected attribute in combobox_1 and use this information to retrieve relevant values from the database and populate combobx_2
Now the problem I have is that I can't figure out how to reference the comboboxes once they have been created. For the buttons, I use the serve function which listen to any button for a click so that's fine, but how can I reference combobox that have been created with a function. Although they all have different setObjectName, there doesn't seem to be a way of referencing that attribute so when I click on any button they all return the value of the last object's combobox instead of the value of its related comboxbox to which they are attached.
here is the Frontend script:
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(709, 357)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.gridLayout_2 = QtWidgets.QGridLayout(self.centralwidget)
self.gridLayout_2.setObjectName("gridLayout_2")
self.gridLayout = QtWidgets.QGridLayout()
self.gridLayout.setObjectName("gridLayout")
self.gridLayout_4 = QtWidgets.QGridLayout()
self.gridLayout_4.setObjectName("gridLayout_4")
spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.gridLayout_4.addItem(spacerItem, 1, 1, 1, 1)
self.VLayout_0 = QtWidgets.QVBoxLayout()
self.VLayout_0.setObjectName("VLayout_0")
self.HLayout_0 = QtWidgets.QHBoxLayout()
self.HLayout_0.setObjectName("HLayout_0")
spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Minimum)
self.HLayout_0.addItem(spacerItem1)
self.CB_L0 = QtWidgets.QComboBox(self.centralwidget)
self.CB_L0.setObjectName("CB_L0")
self.HLayout_0.addWidget(self.CB_L0)
self.pushButton = QtWidgets.QPushButton(self.centralwidget)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.pushButton.sizePolicy().hasHeightForWidth())
self.pushButton.setSizePolicy(sizePolicy)
self.pushButton.setMaximumSize(QtCore.QSize(40, 16777215))
self.pushButton.setObjectName("pushButton")
self.HLayout_0.addWidget(self.pushButton)
spacerItem2 = QtWidgets.QSpacerItem(50, 20, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Minimum)
self.HLayout_0.addItem(spacerItem2)
self.VLayout_0.addLayout(self.HLayout_0)
spacerItem3 = QtWidgets.QSpacerItem(20, 10, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed)
self.VLayout_0.addItem(spacerItem3)
self.gridLayout_4.addLayout(self.VLayout_0, 1, 0, 1, 1)
self.PB_create_cb = QtWidgets.QPushButton(self.centralwidget)
self.PB_create_cb.setObjectName("PB_create_cb")
self.gridLayout_4.addWidget(self.PB_create_cb, 0, 1, 1, 1)
self.gridLayout.addLayout(self.gridLayout_4, 0, 0, 1, 1)
self.gridLayout_2.addLayout(self.gridLayout, 0, 0, 1, 1)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 709, 22))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.pushButton.setText(_translate("MainWindow", "search"))
self.PB_create_cb.setText(_translate("MainWindow", "Create dropdown"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
and here is the backend example (which creates two "objects"):
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import QCoreApplication
from PyQt5.QtGui import QColor
from PyQt5.QtWidgets import QMainWindow, QApplication, QWidget, QAction, QTableWidget, QTableWidgetItem, QVBoxLayout, QMessageBox, QDialog, QLineEdit, QPushButton, QMenu, QSizePolicy, QLabel,QTreeWidget,QTreeWidgetItem
from PyQt5.QtWidgets import (QApplication, QWidget, QToolTip, QPushButton, QMessageBox)
import sys
from test3 import *
class Run_script(QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super(Run_script, self).__init__(parent)
self.setupUi(self)
print("Run script initizalised")
self.PB_create_cb.clicked.connect(self.click_select)
def create_V_0_object(self,List_attributes):
V_list = []
for i,x in enumerate(List_attributes):
for k,v in x.items():
if type(v) == dict:
for k1,v1 in v.items():
if type(v) == dict:
self.HLayout_1 = QtWidgets.QHBoxLayout()
self.HLayout_1.setObjectName("H_layout_1")
self.VLayout_0 = QtWidgets.QVBoxLayout()
self.VLayout_0.setObjectName("V_L2"+k+str(i))
self.Attr_label = QtWidgets.QLabel(self.centralwidget)
self.Attr_label.setObjectName(k)
self.Attr_label.setText(k)
self.VLayout_0.addWidget(self.Attr_label)
self.attr_list = []
for k1,v1 in v.items():
self.attr_list.append(k1)
print("K1 is "+str(k1))
self.comboBox = QtWidgets.QComboBox(self.centralwidget)
self.comboBox.setObjectName("CB_"+k)
self.comboBox.addItems(self.attr_list)
self.comboBox.setToolTip("CB_"+k)
self.VLayout_0.addWidget(self.comboBox)
self.comboBox1 = QtWidgets.QComboBox(self.centralwidget)
self.comboBox1.setObjectName("CB_l2_"+k)
self.comboBox1.setToolTip("CB_l2_"+k)
self.VLayout_0.addWidget(self.comboBox1)
self.pushButton = QtWidgets.QPushButton(self.centralwidget)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.pushButton.sizePolicy().hasHeightForWidth())
self.pushButton.setSizePolicy(sizePolicy)
self.pushButton.setMaximumSize(QtCore.QSize(40, 16777215))
PB_name = "PB_"+str(k)
self.pushButton.setObjectName(PB_name)
self.pushButton.setToolTip("Search " + str(PB_name))
self.pushButton.setText(PB_name)
self.pushButton.clicked.connect(self.buttonClicked)
self.HLayout_1.addLayout(self.VLayout_0)
self.HLayout_1.addWidget(self.pushButton)
else:
pass
V_list.append(self.HLayout_1)
return V_list
def buttonClicked(self):
sender = self.sender()
cat_l_0 = sender.text()
for i in range(self.VLayout_0.count()):
name = self.VLayout_0.itemAt(i).widget().objectName()
print("this is:",name)
def click_select(self):
self.selection = [{"Category1":{"Attr1": "test1","Attr2":"test2"}},{"Category2":{"Attr1":"test3","Attr2":"test4"}}]
self.v = self.create_V_0_object(self.selection)
self.create_horizontal_display(self.v)
def deleteItemsOfLayout(self,layout):
if layout is not None:
while layout.count():
item = layout.takeAt(0)
widget = item.widget()
if widget is not None:
widget.setParent(None)
else:
self.deleteItemsOfLayout(item.layout())
def create_horizontal_display(self,vertical_layout_list):
self.deleteItemsOfLayout(self.HLayout_0)
for i,x in enumerate(vertical_layout_list):
self.HLayout_0.addLayout(x)
if __name__ == '__main__':
app = QApplication(sys.argv)
prog = Run_script()
prog.show()
sys.exit(app.exec_())
to create the objects just press the "create dropdown" button
Upvotes: 0
Views: 711
Reputation: 244301
You have many bad practices:
The variables that are created in a loop are generally not going to be a member of the class because they are temporary variables, so do not use them as they will be overwritten, therefore when accessing self.VLayout_0
you will always get the last element.
Another bad habit is that everything you want to do in one place, as you say the "object" s are similar except for the data so you should create a class that builds it, as they say: divide and conquer.
You have other errors but they are minor, correcting the above you have the following:
from PyQt5 import QtCore, QtGui, QtWidgets
from test3 import Ui_MainWindow
class Widget(QtWidgets.QWidget):
clicked = QtCore.pyqtSignal()
def __init__(self, text, values, parent=None):
super(Widget, self).__init__(parent)
hlay = QtWidgets.QHBoxLayout(self)
vlay = QtWidgets.QVBoxLayout()
self.label = QtWidgets.QLabel(text)
self.combobox_1 = QtWidgets.QComboBox()
self.combobox_1.addItems(values.keys())
self.combobox_2 = QtWidgets.QComboBox()
vlay.addWidget(self.label)
vlay.addWidget(self.combobox_1)
vlay.addWidget(self.combobox_2)
hlay.addLayout(vlay)
self.button = QtWidgets.QPushButton(text)
self.button.clicked.connect(self.clicked)
hlay.addWidget(self.button)
self.setFixedSize(self.sizeHint())
class Run_script(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super(Run_script, self).__init__(parent)
self.setupUi(self)
print("Run script initizalised")
self.PB_create_cb.clicked.connect(self.click_select)
def create_V_0_object(self, attributes):
v_list = []
for x in attributes:
for key, value in x.items():
w = Widget(key, value)
w.clicked.connect(self.buttonClicked)
v_list.append(w)
return v_list
def buttonClicked(self):
w = self.sender()
print(w.combobox_1.currentText())
print(w.combobox_2.currentText())
print(w.label.text())
print(w.button.text())
def click_select(self):
selection = [{"Category1":{"Attr1": "test1","Attr2":"test2"}},{"Category2":{"Attr1": "test3", "Attr2": "test4"}}]
v = self.create_V_0_object(selection)
self.create_horizontal_display(v)
def deleteItemsOfLayout(self,layout):
if layout is not None:
while layout.count():
item = layout.takeAt(0)
widget = item.widget()
if widget is not None:
widget.setParent(None)
else:
self.deleteItemsOfLayout(item.layout())
def create_horizontal_display(self, vertical_layout_list):
self.deleteItemsOfLayout(self.HLayout_0)
for i, x in enumerate(vertical_layout_list):
self.HLayout_0.addWidget(x)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
prog = Run_script()
prog.show()
sys.exit(app.exec_())
Upvotes: 1