PyQt: Parenting a Widget

Veek M vek.m1234 at gmail.com
Tue Sep 26 02:16:12 EDT 2017


On Tuesday, September 26, 2017 at 11:18:54 AM UTC+5:30, Veek M wrote:
> Summary: Could someone explain widget and dialog parenting - the text book is not making sense.
> ######################
> I'm trying to understand widget parenting, from the book: Rapid GUI Programming, pg 118, and thereabouts - he says:
> 
> A. All PyQt classes that derive from QObjectand this includes all the widgets,
> since QWidget is a QObject subclasscan have a “parent”.
> 
> B. PyQt automatically repar-
> ents the widgets that are laid out. So although we did not give our widgets a
> parent of self (the Form instance),when we call setLayout() the layout manager
> gives ownership of the widgets and of itself to the form,and takes ownership of
> any nested layouts itself. This means that none of the widgets that are laid out
> is a top-level window, and all of them have parents, which is what we want. So
> when the form is deleted, all its child widgets and layouts will be deleted with
> -----------------------------
> 1. In A, does he mean, you are ALLOWED to set a parent on a widget ONLY because its Base Class is QObject? 
> 
> With DockWidgets, you have to explicitly parent them - why?
> 
> 2. If I create two widgets and wdget.show() them, and app.exec_() - which one becomes the main-window and which one is the memory leak? I have not used a layout manager so, one widget with no parent auto-becomes the main-window (as per B), which would result in a leak with the other?
> 
> #!/usr/bin/python
> 
> import sys, os, re
> 
> 
> from PyQt4.QtCore import *
> from PyQt4.QtGui import *
> 
> app = QApplication(sys.argv)
> 
> lbl = QLabel('<font size=11 color=red><b>Hello World</b></font>')
> lbl.setWindowFlags(Qt.SplashScreen)
> lbl.show()
> txtBrw = QTextBrowser()
> txtBrw.show()
> 
> QTimer.singleShot(3000, app.quit)
> app.exec_()
> 
> 3. QObject --> QWidget --> QDialog --> Form --> Form_Layout_Manager --> Nested_Layout_Manager
> 
> B, says that the layout manager parents the widgets under it and makes 'Form' the parent. If the Form Layout Manager is taking charge of the Nested Layout Manager, who is the parent of the widgets under the Nested Layout Mangaer? 
> 
> 4. In the Chapter on 'Dialogs', I am trying to create a QMainWindow Style application with one label as the central widget and one button to invoke a dialog. It doesn't work and I get:
> 
> QWidget::setLayout: Attempting to set QLayout "" on Parent "", which already has a layout
> 
> I tried this link and it made no sense:
> https://stackoverflow.com/questions/25450598/qlayout-attempting-to-add-qlayout-to-qwidget-which-already-has-a-layout
> 
> How does parenting work in PyQt? What is autoparented, what needs to be explicitly parented and who is scrwing whom? Additionally, why is my button, hiding?
> 
> 
> #!/usr/bin/python
> 
> import sys, os, re
> 
> 
> from PyQt4.QtCore import *
> from PyQt4.QtGui import *
> 
> app = QApplication(sys.argv)
> 
> class Dialog(QDialog):
>     def __init__(self, parent = None):
>         super(Dialog, self).__init__(parent)
>         
>         self.lbl = QLabel('Width: ')
>         self.spn = QSpinBox()
>         self.spn.setRange(0, 100)
>         self.lbl.setBuddy(self.spn)
>         
>         self.chk = QCheckBox('&Beveled Edges')
> 
>         self.lbl_styl = QLabel('Style')
>         self.lst = QComboBox()
>         self.lst.addItems(['dashed', 'dotted', 'star'])
>         self.lbl_styl.setBuddy(self.lst)
>         
>         self.ok_btn = QPushButton('&Ok')
>         self.cncl_btn = QPushButton('&Cancel')
> 
>         self.layout([(self.lbl, 0, 0), (self.spn, 0, 1), (self.chk, 0, 2), 
>                      (self.lbl_styl, 1, 0), (self.lst, 1, 1), 
>                      (self.ok_btn, 2, 0), (self.cncl_btn, 2, 1)])
> 
>     def layout(self, wgts = []):
>         self.lyt = QGridLayout()
>         for wgt, row, col in wgts:
>             self.lyt.addWidget(wgt, row, col)
>             
>         self.setLayout(self.lyt)
>         
> 
> class Parent(QMainWindow):
>     def __init__(self, parent = None):
>         super(Parent, self).__init__(parent)
>         
>         lbl = QLabel('HELLO WORLD')
>         btn = QPushButton('&Start Dialog')
>         lbl.setBuddy(btn)
>         
>         lyt = QHBoxLayout()
>         lyt.addWidget(lbl)
>         lyt.addWidget(btn)
>         
>         self.setLayout(lyt)
>         self.connect(btn, SIGNAL('clicked()'), self.popup_dialog)
> 
>     def popup_dialog(self):
>         x = Dialog(self)
>         if x.exec_():
>             print(x.spn.value())
> 
> p = Parent()    
> p.show()
> 
> app.exec_()

I fixed some of it by deleting the:
Parent
 self.setLayout(lyt) 

I don't understand why that works - aren't we supposed to attach a layout to the Parent/MainWindow object? Why not?

Also, I made the: 
Parent
 self.setCentralWidget(btn)

so the button is the central widget. To use the Label, I think I would have to create a composite widget which is too complicated for me, currently.

Now. it works so I tested some more and added:
    def popup_dialog(self):
        x = Dialog(self)
        y = Dialog(self)
        y.show()
        if x.exec_():
            print(x.spn.value())
AND

class Dialog(QDialog):
    self.connect(self.cncl_btn, SIGNAL('clicked()'), self.close)

So my dialog pops up and because exec_ is being called on 'x', I have to first close that widget before I can interact with my button and 'y'. However, let's say I close the 'x' dialog - then I can click on 'Button' and I get two more dialogs which don't lock anything - why??



More information about the Python-list mailing list