PyQt 5: findChild returns None
-
Hi all,
I have created a tabbed window where the labels and qlineedits are created using a for loop, distinguishing between the objects by having different objectName.
class TabWidget(QWidget): def __init__(self, parent): super(QWidget, self).__init__(parent) item_names = [ "so", "dc", "cn", "co", "ea", "tn", "sz", "m1", "m2", "ad", "de", "dl", "sd", "cp", "sh", ] for itemnum in range(0, len(item_names) - 2): self.label = QLabel(form_labels[itemnum]) self.qledit = QLineEdit() if item_names[itemnum] == "so" or item_names[itemnum] == "dc": self.qledit.setEnabled(False) self.label.setObjectName(f"{item_names[itemnum]}_l") self.qledit.setObjectName(f"{item_names[itemnum]}_qle") self.qledit.setFixedWidth(500) form_layout.addRow(self.label, self.qledit)
This TabWidget class is then called in the setupUI function of the QMainWindow:
class MainWindow(QMainWindow): def __init__(self): super().__init__() self.initUI() def initUI(self): print("Initialising UI...") self.tab_widget = TabWidget(self) print("UI initialised.") self.setCentralWidget(self.tab_widget) self.move(300, 150) self.setWindowTitle("TopperWorks DE Utility") self.show()
I have omitted the layout formatting of the TabWidget as I believe that to be irrelevant to the question.
I want to change the value of one of the qlineedits that I have created from the for loop with findChild:qle_by_name = self.findChild(QLineEdit, "dc_qle") qle_by_name.setText("Test")
However, findChild returns None. The findChild usage is within the TabWidget class.
Thanks.
-
@JonB Once again thank you for the reply.
I have done your suggestion and that indeed did suffice.
I have considered @jsulm's reply. I used the following functions:
... print(self.findChildren(QWidget)) print(self.findChildren(QLabel)) print(self.findChildren(QLineEdit)) print(self.findChildren(QPushButton)) print(self.findChild(QLineEdit)) ...
which returned:
[] [] [] [] None
@Hubris
OK, let's go back to basics :)You add your widgets via
form_layout.addRow(self.label, self.qledit)
. Can you please- Show what
form_layout
is - Show how it is connected to your widget hierarchy, what its parent is
We should like to try
print(form_layout.findChildren())
to verify that can find the widgets you added. Ifform_layout
is a layout (e.g.QFormLayout
) then this needs to be called on its parent widget, e.g.form_layout.parentWidget().findChildren()
.Furthermore it is not clear when you are trying these
findChild
/findChildren()
calls. They will only work when the layout/sub-widgets you have added have actually been added onto their parent to find from. For example, if you have added them toform_layout
but that has not yet been set as the layout on a widget you won't find them. - Show what
-
Hi all,
I have created a tabbed window where the labels and qlineedits are created using a for loop, distinguishing between the objects by having different objectName.
class TabWidget(QWidget): def __init__(self, parent): super(QWidget, self).__init__(parent) item_names = [ "so", "dc", "cn", "co", "ea", "tn", "sz", "m1", "m2", "ad", "de", "dl", "sd", "cp", "sh", ] for itemnum in range(0, len(item_names) - 2): self.label = QLabel(form_labels[itemnum]) self.qledit = QLineEdit() if item_names[itemnum] == "so" or item_names[itemnum] == "dc": self.qledit.setEnabled(False) self.label.setObjectName(f"{item_names[itemnum]}_l") self.qledit.setObjectName(f"{item_names[itemnum]}_qle") self.qledit.setFixedWidth(500) form_layout.addRow(self.label, self.qledit)
This TabWidget class is then called in the setupUI function of the QMainWindow:
class MainWindow(QMainWindow): def __init__(self): super().__init__() self.initUI() def initUI(self): print("Initialising UI...") self.tab_widget = TabWidget(self) print("UI initialised.") self.setCentralWidget(self.tab_widget) self.move(300, 150) self.setWindowTitle("TopperWorks DE Utility") self.show()
I have omitted the layout formatting of the TabWidget as I believe that to be irrelevant to the question.
I want to change the value of one of the qlineedits that I have created from the for loop with findChild:qle_by_name = self.findChild(QLineEdit, "dc_qle") qle_by_name.setText("Test")
However, findChild returns None. The findChild usage is within the TabWidget class.
Thanks.
@Hubris You could iterate over all children (https://doc.qt.io/qt-6/qobject.html#children) and print out their names to see whether you really have such an object.
As far as I can see you also never set the parent on the labels and line edits. -
Hi all,
I have created a tabbed window where the labels and qlineedits are created using a for loop, distinguishing between the objects by having different objectName.
class TabWidget(QWidget): def __init__(self, parent): super(QWidget, self).__init__(parent) item_names = [ "so", "dc", "cn", "co", "ea", "tn", "sz", "m1", "m2", "ad", "de", "dl", "sd", "cp", "sh", ] for itemnum in range(0, len(item_names) - 2): self.label = QLabel(form_labels[itemnum]) self.qledit = QLineEdit() if item_names[itemnum] == "so" or item_names[itemnum] == "dc": self.qledit.setEnabled(False) self.label.setObjectName(f"{item_names[itemnum]}_l") self.qledit.setObjectName(f"{item_names[itemnum]}_qle") self.qledit.setFixedWidth(500) form_layout.addRow(self.label, self.qledit)
This TabWidget class is then called in the setupUI function of the QMainWindow:
class MainWindow(QMainWindow): def __init__(self): super().__init__() self.initUI() def initUI(self): print("Initialising UI...") self.tab_widget = TabWidget(self) print("UI initialised.") self.setCentralWidget(self.tab_widget) self.move(300, 150) self.setWindowTitle("TopperWorks DE Utility") self.show()
I have omitted the layout formatting of the TabWidget as I believe that to be irrelevant to the question.
I want to change the value of one of the qlineedits that I have created from the for loop with findChild:qle_by_name = self.findChild(QLineEdit, "dc_qle") qle_by_name.setText("Test")
However, findChild returns None. The findChild usage is within the TabWidget class.
Thanks.
@Hubris
In addition/follow up to @jsulmform_layout.addRow(self.label, self.qledit)
As code stands
form_layout
is a non-existent local variable.Separate issue:
self.label = QLabel(form_labels[itemnum]) self.qledit = QLineEdit()
You are executing these statements multiple times inside a loop. These should not be assigned to (the same) class member variables.
-
@Hubris You could iterate over all children (https://doc.qt.io/qt-6/qobject.html#children) and print out their names to see whether you really have such an object.
As far as I can see you also never set the parent on the labels and line edits.@jsulm Thanks for the reply. I used self.findChildren to return the QLineEdit, QPushbutton, and QLabel children but it just returns an empty array.
I also tried to set the parent for the objects by using self.qledit.setParent(TabWidget), however I encounter the following error:
setParent(self, QWidget): argument 1 has unexpected type 'sip.wrappertype'
-
@Hubris
In addition/follow up to @jsulmform_layout.addRow(self.label, self.qledit)
As code stands
form_layout
is a non-existent local variable.Separate issue:
self.label = QLabel(form_labels[itemnum]) self.qledit = QLineEdit()
You are executing these statements multiple times inside a loop. These should not be assigned to (the same) class member variables.
@JonB Thanks for the reply.
form_layout is declared as a QFormLayout object earlier in the code. I just omitted that section. If you'd need that information I am happy to provide the whole code.
As for assigning to the same class member variables inside the for loop,
I am making a form which has a lot of multiple repeating QLabels, and QLineEdits. If I do not instantiate a new label for every loop, I would just be modifying the same QLabel/QLineEdit every iteration, and the result of that is undesirable.
Is this idea not the right approach?
Here is the output of my code:
Each QLabel and QLineEdit has a distinct objectName.
-
@JonB Thanks for the reply.
form_layout is declared as a QFormLayout object earlier in the code. I just omitted that section. If you'd need that information I am happy to provide the whole code.
As for assigning to the same class member variables inside the for loop,
I am making a form which has a lot of multiple repeating QLabels, and QLineEdits. If I do not instantiate a new label for every loop, I would just be modifying the same QLabel/QLineEdit every iteration, and the result of that is undesirable.
Is this idea not the right approach?
Here is the output of my code:
Each QLabel and QLineEdit has a distinct objectName.
@Hubris
That's fine.The observation about your class variables is probably not relevant. They end up referencing just the final label/edit you happen to create from the loop. I doubt that is useful to you as a member variable reference.
label = QLabel(form_labels[itemnum]) qledit = QLineEdit() ...
Wouldn't this suffice?
If I wanted to debug your situation I'd start with @jsulm's
@Hubris You could iterate over all children (https://doc.qt.io/qt-6/qobject.html#children) and print out their names to see whether you really have such an object.
You could also do a quick
self.findChild(QLineEdit)
to see whether it finds any line edits. -
@Hubris
That's fine.The observation about your class variables is probably not relevant. They end up referencing just the final label/edit you happen to create from the loop. I doubt that is useful to you as a member variable reference.
label = QLabel(form_labels[itemnum]) qledit = QLineEdit() ...
Wouldn't this suffice?
If I wanted to debug your situation I'd start with @jsulm's
@Hubris You could iterate over all children (https://doc.qt.io/qt-6/qobject.html#children) and print out their names to see whether you really have such an object.
You could also do a quick
self.findChild(QLineEdit)
to see whether it finds any line edits.@JonB Once again thank you for the reply.
I have done your suggestion and that indeed did suffice.
I have considered @jsulm's reply. I used the following functions:
... print(self.findChildren(QWidget)) print(self.findChildren(QLabel)) print(self.findChildren(QLineEdit)) print(self.findChildren(QPushButton)) print(self.findChild(QLineEdit)) ...
which returned:
[] [] [] [] None
-
@JonB Once again thank you for the reply.
I have done your suggestion and that indeed did suffice.
I have considered @jsulm's reply. I used the following functions:
... print(self.findChildren(QWidget)) print(self.findChildren(QLabel)) print(self.findChildren(QLineEdit)) print(self.findChildren(QPushButton)) print(self.findChild(QLineEdit)) ...
which returned:
[] [] [] [] None
@Hubris
OK, let's go back to basics :)You add your widgets via
form_layout.addRow(self.label, self.qledit)
. Can you please- Show what
form_layout
is - Show how it is connected to your widget hierarchy, what its parent is
We should like to try
print(form_layout.findChildren())
to verify that can find the widgets you added. Ifform_layout
is a layout (e.g.QFormLayout
) then this needs to be called on its parent widget, e.g.form_layout.parentWidget().findChildren()
.Furthermore it is not clear when you are trying these
findChild
/findChildren()
calls. They will only work when the layout/sub-widgets you have added have actually been added onto their parent to find from. For example, if you have added them toform_layout
but that has not yet been set as the layout on a widget you won't find them. - Show what
-
@Hubris
OK, let's go back to basics :)You add your widgets via
form_layout.addRow(self.label, self.qledit)
. Can you please- Show what
form_layout
is - Show how it is connected to your widget hierarchy, what its parent is
We should like to try
print(form_layout.findChildren())
to verify that can find the widgets you added. Ifform_layout
is a layout (e.g.QFormLayout
) then this needs to be called on its parent widget, e.g.form_layout.parentWidget().findChildren()
.Furthermore it is not clear when you are trying these
findChild
/findChildren()
calls. They will only work when the layout/sub-widgets you have added have actually been added onto their parent to find from. For example, if you have added them toform_layout
but that has not yet been set as the layout on a widget you won't find them.@JonB Wow. You hit the nail on the head.
As it turned out I was using tabs in my GUI, where each tab was its own QWidget. The parent for the objects was that QWidget.
Many thanks. I have learned something new today. I still need to read up a bit more on Children and Parents to fully understand it.
- Show what
-
Here is the code snippet that best explains that:
form_layout = QFormLayout() # Array of form_labels = [ "Sales Order #", "Date Created", "Customer Name", "Contact #", "Email Address", "Template Name", "Size", "Material 1", "Material 2", "Additional", "Delivery", "Delivery Location", "Ship by Date", "Completed", "Shipped", ] item_names = [ "so", "dc", "cn", "co", "ea", "tn", "sz", "m1", "m2", "ad", "de", "dl", "sd", "cp", "sh", ] # ---------- Create new tab ----------# tabs = QTabWidget() new_tab = QWidget() for itemnum in range(0, len(item_names) - 2): label = QLabel(form_labels[itemnum]) qledit = QLineEdit() if item_names[itemnum] == "so" or item_names[itemnum] == "dc": qledit.setEnabled(False) label.setText(form_labels[itemnum]) label.setObjectName(f"{item_names[itemnum]}_l") qledit.setObjectName(f"{item_names[itemnum]}_qle") # self.qledit.setParent(TabWidget) qledit.setFixedWidth(500) form_layout.addRow(label, qledit) cl_btn = QPushButton("Clear Fields") ce_btn = QPushButton("Create Entry") em_l = QLabel() btn_box = QHBoxLayout() btn_box.addWidget(em_l) btn_box.addWidget(ce_btn) btn_box.addWidget(cl_btn) form_layout.addRow(btn_box) new_tab.setLayout(form_layout) qle_by_name = new_tab.findChild(QLineEdit, "dc_qle") qle_by_name.setText("Test")
-
Here is the code snippet that best explains that:
form_layout = QFormLayout() # Array of form_labels = [ "Sales Order #", "Date Created", "Customer Name", "Contact #", "Email Address", "Template Name", "Size", "Material 1", "Material 2", "Additional", "Delivery", "Delivery Location", "Ship by Date", "Completed", "Shipped", ] item_names = [ "so", "dc", "cn", "co", "ea", "tn", "sz", "m1", "m2", "ad", "de", "dl", "sd", "cp", "sh", ] # ---------- Create new tab ----------# tabs = QTabWidget() new_tab = QWidget() for itemnum in range(0, len(item_names) - 2): label = QLabel(form_labels[itemnum]) qledit = QLineEdit() if item_names[itemnum] == "so" or item_names[itemnum] == "dc": qledit.setEnabled(False) label.setText(form_labels[itemnum]) label.setObjectName(f"{item_names[itemnum]}_l") qledit.setObjectName(f"{item_names[itemnum]}_qle") # self.qledit.setParent(TabWidget) qledit.setFixedWidth(500) form_layout.addRow(label, qledit) cl_btn = QPushButton("Clear Fields") ce_btn = QPushButton("Create Entry") em_l = QLabel() btn_box = QHBoxLayout() btn_box.addWidget(em_l) btn_box.addWidget(ce_btn) btn_box.addWidget(cl_btn) form_layout.addRow(btn_box) new_tab.setLayout(form_layout) qle_by_name = new_tab.findChild(QLineEdit, "dc_qle") qle_by_name.setText("Test")