What is the parent argument for? - pyqt

I read in the pyqt docs that if parent is None, the QWidget will become a window. But in my main widget I create several QWidget subclasses without passing the parent argument, and it works fine:
widget = MyWidget()
layout = QVBoxLayout()
layout.addWidget(widget)
self.setLayout(layout)
How does this work, and what is the parent argument really for?

When you use setLayout, the layout is automatically made a child of the widget to which it is assigned:
http://pyqt.sourceforge.net/Docs/PyQt4/qwidget.html#setLayout
Hence, what you have discovered doesn't seem to be an issue with parent in general, but a feature of setLayout. Note that QLayout is not a QWidget, so will never be made an independent window -- it is forced to sit there in memory waiting to be glued to a widget.

Related

Is there a way to resize a QAction

The QAction inside a QToolBar is away bigger than the icon I am using (16x16 or 32x32). How to resize a QAction to fit an icon without extra space. I tried to subclass, but I could find a method for the QAction to resize.
class MyAction(QAction):
def __init__(self)
super().__init__()
I tried to use setIconSize(QSize(32,32)), but it is not affecting the QAction it self. I believe this is related to the app stylesheet I am using, but I don't want to change that.
My current solution is to use a QToolButton, and addWidget inside the QToolBar(), is there better way ?
I am simply using a QMainWindow:
class Window(QMainWindow):
def__init__(self)
super().__init__()
self._Bar_1 = self.addToolBar('bar_1')
self._Bar_1.setIconSize(QSize(41, 41))
act1 = QAction(QIcon(r'icons\exit.png'), 'Exit', self)
self._Bar_1.addAction(act1)
I can't take a snapshot cause I need to hover or click the action to show its size, but it looks like this. I believe it is related to the stylesheet I am using:
This is ascrren shot I could get. notice, when hovering or press on the QAction in the first ToolBar, the action is seems too big for the icon inside ! Hope it helps
I am using the qt_material , find the link https://github.com/UN-GCPDS/qt-material

How to add logic to QListWidget drag/drop

I'm a Python/PyQt (v4) newbie who is subclassing the QListWidget and making use of its internal drag and drop mechanism:
from PyQt4.QtCore import *
from PyQt4.QtGui import *
class AlgorithmListControl(QListWidget):
def __init__(self, parent = None):
super(AlgorithmListControl, self).__init__(parent)
self.setAcceptDrops(True)
self.setDragEnabled(True)
self.setDragDropMode(QAbstractItemView.InternalMove)
I'm happy with the default behavior and appearance and I'm able to drag/drop items internally in the widget. Now, I'd like to add some custom logic that occurs when the drag operation begins and after the drop operation ends. The trouble I'm having is if I handle the events, for example the dragEnterEvent as follows:
def dragEnterEvent(self, event):
...
then I no longer get the nice default drag/drop behavior (I'm unable to drag an item to a new location, I don't get the horizontal insertion indicator, etc). How do I retain the standard drag-drop behavior but add my custom logic at these two event points? Thank you in advance.
Since you override the method when you use the same name, you need to implement all the actions that happen in the standard way, or call the parent (standard) method inside.
You can call the method from the parent class with inheritance, thanks to the function super()and then implement your own logic :
def dragEnterEvent(self, event):
super().dragEnterEvent(event)
print('enter')

PyQt: how to create a dialog as a child of another dialog

In PyQt, I have a dialog that spawns another dialog (when you click a button to do so in the first dialog). I want to maintain a strong parent-child relationship, for garbage collection purposes, and to make the .findChild and .findChildren functions usable.
The root of the question may be: how do you use .setParent() but still have the object in question be shown as a separate window, rather than shown within the parent widget?
The 'parent' dialog (actually a container widget within a tab within a dialog) is 'newEntryWidget'. It spawns 'clueDialog' when a signal (not shown here) calls newEntryWidget.quickTextClueAction as a slot. Visually, clueDialog should be a "top level window" with its own banner, its own window attributes (I want to keep it on top of everything else), etc.
class newEntryWidget(QWidget,Ui_newEntryWidget):
def __init__(self,parent,sec=0,formattedLocString='',fleet='',dev='',origLocString='',amendFlag=False,amendRow=None):
QDialog.__init__(self)
self.parent=parent # just an attribute; not the same as setParent
...
...
def quickTextClueAction(self):
self.newClueDialog=clueDialog(self,self.ui.timeField.text(),self.ui.teamField.text(),self.ui.radioLocField.text(),lastClueNumber+1)
self.newClueDialog.show()
class clueDialog(QDialog,Ui_clueDialog):
def __init__(self,parent,t,callsign,radioLoc,newClueNumber):
QDialog.__init__(self)
self.parent=parent # just an attribute; not the same as setParent
...
...
Right now, since I am using self.parent=parent, which is just an attribute and not true "parent/child relationship" in Qt terms, clueDialog does display as a top level window, which is what I want:
But, if I add 'self.setParent(parent)' in the clueDialog init function, I get this:
How can I preserve the top-level-window behavior, and have the real-honest-parent-child-relationship so that .findChild(clueDialog) will work from within the newEntryWidget object?
Ultimately, I want to enforce that the newEntryWidget object should not be closed if it still has and 'child' clueDialogs open.
Instead of calling .setParent, call QDialog.__init__(self, parent) which constructs the clue dialog with a parent from the beginning. Setting it this way allows Qt establishes the parent-child relationship at the beginning of clueDialog's lifetime.
I believe this will fix both your issues: 1) the clue window frame, caption, etc. will be painted, 2) you will be able to iterate for proper children of newEntry.

QT5: What is the Significance of a Layout's Parent?

I am attempting to write my first program using Qt5. I found a tutorial (zetcode.com/gui/qt5) with a number of examples, which all used dynamic layout creation. I'm trying to create a nested layout configuration, but I'm having a problem with specifying the parent parameter of the layout constructor. When I use the main window as the parent for the main layout and its sub-layouts, I get an error message, apparently telling me that QWidget can have only one QLayout. The window looks OK, but I haven't implemented all my functionality yet (slots and other code), so I don't know what, if anything, is broken. If I omit the parent parameter from the sub-layouts, I get no error messages and the window looks OK as well, but again I'm wondering whether this would affect my subsequent code additions.
Can anyone explain to me the significance of a layout's parent? I've noted that specification of the parent window in the layout's constructor is apparently not sufficient, because all of the examples I've seen call setLayout() at the end of the window's constructor. In particular, will my omission of a parent ever cause problems?
The "rules" are that there can be at most one top level layout on a given widget, and that widgets can be only children of other widgets, not of layouts. So what happens is that:
when you set a layout on a widget, the widget will take ownership of that layout;
when you add widgets on a layout, these widgets will be reparented to the widget the layout is/gets installed upon;
when you add a layout inside another layout, the inner layout becomes a child of the outer layout.
What you're probably seeing is a side-effect of creating a layout with a widget as parent, as in
QLayout *layout = new SomeLayout(widget);
This will try to install the layout on widget, and fail in case there's already one. The good news is, you can pretty much ignore passing parents around and rely on the system to do "the right thing". For instance:
MyWidget::MyWidget(QWidget *parent)
: QWidget(parent)
{
QHBoxLayout *mainLayout = new QHBoxLayout; // top level layout
QVBoxLayout *subLayout1 = new QVBoxLayout; // sub layout 1 stuff
QPushButton *button = new QPushButton("button");
subLayout1->addWidget(button);
// create more widgets...
mainLayout->addLayout(subLayout1);
QVBoxLayout *subLayout2 = new QVBoxLayout; // sub layout 2 stuff
QLineEdit *edit = new QLineEdit;
subLayout2->addWidget(edit);
mainLayout->addLayout(subLayout2);
setLayout(mainLayout);
}
This will correctly create a layout hierarchy and a parent/child relation so that nothing will get leaked.

PyQt4: disable deleting widget after setCentralWidget

I have two custom widgets (two classes based on QtGui.QWidget). In __init__ of QtGui.QMainWindow I create their instances:
self.MyWidget1 = MyWidget1()
self.MyWidget2 = MyWidget2()
There are also two buttons (QtGui.QPushButton) in __init__ part, and there are two slots when user clicks each of them:
def clickButton1(self):
self.setCentralWidget(self.MyWidget1)
def clickButton2(self):
self.setCentralWidget(self.MyWidget2)
But it works only on first click and then PyQt says that underlying widget (MyWidget1 or MyWidget2) was deleted. I think it was done by sip module. Is there a way to prevent deleting widgets after reseting of central widget? Thanks!
I think it's almost impossible.
From setCentralWidget docs:
Note: QMainWindow takes ownership of the widget pointer and deletes it at the appropriate time.
So, you should create new MyWidget instance.
def clickButton2(self):
self.setCentralWidget(MyWidget2())
But the right way of doing such things is to use QStackedWidget

Resources