QMainWindow and ownership takeover policy - qt

I stumbled upon this in the documentation for QMainWindow::setMenuBar(QMenuBar * menuBar):
Note: QMainWindow takes ownership of the menuBar pointer and deletes it at the appropriate time.
Example code (in a method of a class deriving from QMainWindow):
QMenuBar * menuBar = new QMenuBar(this);
setMenuBar(menuBar) // <-- immediately transfer ownership
// use menuBar pointer to add actions, menus, and what not
Can I still rely on my local pointer to my QMenuBar after a call to setMenuBar? I mean, is it completely guaranteed?
When I delete my QMainWindow derived class, the QMenuBar object is also deleted because the QMainWindow is set as its parent when constructing it - but what policy lies in the later "ownership takeover" through setMenuBar other than a copy of reference/pointer?

Yes, it's safe to use that pointer as long as the object that took ownership is alive.
The fact that QMainWindow "takes ownership" of the menu means that it will take care of deleting it when it is not needed anymore. This is very common for Qt, see the Object Trees & Ownership documentation.
That being said, your sample code could be rewritten like this:
QMenuBar *menu = menuBar();
This will create an empty menu if necessary, so you don't have to worry about any transfer of ownership. Just call that member function whenever you need to act on the windows's menu bar.

Related

destroy non-Qwidget member variable in custom QWidget

For a custom QWidget class that contains both QWidget member variable and non-widget member variable, what is the proper way to write the destructor of the class? For example, I have
class CustomWidget: public QWidget {
Q_OBJECT
public:
QWidget* x_widget;
SomeOtherClass* x_non_widget;
}
and set the parent of x_widget to this when creating it, how should I write the destructor? Should I just put delete x_non_widget in the destructor?
QWidget inherits from QObject, so if its parent is set, then the object gets deleted automatically when the parent is being destroyed. Since you set this as parent, then the child x_widget gets automatically deleted when the parent CustomWidget instance is deleted. So no destructor is needed in this case.
Note however that if you put a widget into a layout, then it is re-parented (if it already had a parent) to the widget which holds the layout. But I guess this is not your case.
If your non-widget object is derived from QObject then you can set its parent too. And then you do not need to delete it in destructor because it will be deleted automatically the same way as widgets.
If your non-widget is not derived from QObject or you do not want to set a parent for it (for any reason, e.g. you move it to a thread), then you can wrap it in some owning/strong smart pointer such as std::unique_ptr, std::shared_ptr or QScopedPointer. Then it will be deleted automatically via the smart pointer. You do not need to delete it in the destructor either.
And only if you do not want to wrap it in any such an owning/strong smartpointer, you need to delete it in the destructor manually.
PS: Aside from the question you have, for non-owned members kept by pointer inherited from QObject you can also benefit from using QPointer, which is an extremely handy class which ensures automatic nullification of the pointer when the object gets deleted anywhere in the code. So no more invalid pointers to deleted QObjects... But unlike owning/strong smart pointers, QPointer does not ensure automatic object deletion.

Display QQmlComponent in QQuickWidget

According to QQuickWidget's documentation:
you can instantiate your own objects using QQmlComponent and place
them in a manually set up QQuickWidget.
But I can't find any example of that. I would like to have multiple QQmlComponents loaded into RAM and display them in QQuickWidget depending on which one is active. Any idea on how to display any content in QQuickWidget except for setSource()?
I've end up with following solution: create new QQuickWidget widget and use its QQuickWidget::setContent() to display already created QML content in it. It works in my Qt 5.9.
Note: setContent() is marked as internal and have some drawbacks although this API is public and available in public header.
First of all, QQuickWidget doesn't clear its content when QQuickWidget::setContent() is consequently called for different data. So old and new content overlaps. That's why I have to create a new QQuickWidget on every content change and replace old QQuickWidget with new fresh one.
Secondly, QQuickWidget thinks it owns pointers passed via QQuickWidget::setContent() and tries to delete content at destruction. To bypass this you may execute QQuickWidget::setContent(QUrl(), nullptr, nullptr) before QQuickWidget instance is destroyed. But this triggers a warning message from QML engine in stdout about incorrect qml content. So better approach is to set dummy data:
QQmlComponent* dummy = new QQmlComponent(engine);
dummy->setData(QByteArray("import QtQuick 2.0; Item { }"), QUrl());
wgt->setContent(dummy->url(), dummy, dummy->create());
wgt->deleteLater();
With these hacks I was able to load multiple QML objects (plugins with own UI) with QQmlComponent at runtime. Instantiate them and display one of them in QWidgets-based application depending on plugin selected.

Docking with QWinWidget: Adding DockWidgetAreas to QWidgets

I have an application utilizing QWinWidget in a Win32 window. I'd like to add DockWidgets and the associated behaviour to it. There don't seem to be any exposed APIs for adding custom DockAreas, and the latest docs are sparse beyond adding DockWidgets to a QMainWindow. Older docs imply there once was a public QDockArea class.
So far, my best option appears to be adding a neutered QMainWindow (no top-level status, no frame, etc.) to the QWinWidget and going from there (second source).
I was hoping there was a way to add DockAreas to any container, but it doesn't appear that way. As a side note, QWinWidget is used to have window manager control with our custom frame requirement, but if there's a pure QMainWindow/QWidget way to have the same result (with Qt::FramelessWindowHint), I'd be happy to switch over.
As I said in the comments, I've added within my QWinWidget in my Win32 window a QMainWindow field. That is:
class QWinWidget : public QWidget
{
...
QMainWidget* mainWidget;
}
QWinWidget::QWinWidget()
{
mainWidget = new QMainWindow(this);
mainWidget->setWindowFlags(Qt::Widget); //1
}
Note that while the docs and some forum posts (from this post) indicate you need to set window flags explicitly due to the QMainWindow constructor setting Qt::Window, I tested it without the setWindowFlags() line (marked with //1 above) without noticing anything wrong.
So, this gives me the nice QWinWidget window I spent so much time making, inside a frameless Win32 window, with a QMainWindow child and all the features that brings along with it. Docking, menu bar, status bar, etc.

Add a delete Button to each Item in QListView

Is it somehow possible to add to each Item in a QListview a Button which is deleting the Object onClick? As shown in the following Picture:
EDIT: As I'm new in QT it would be nice to have some example, to understand it better. And as it seems there are three different Ways? What will be the best? Do use a QAbstractItemView?
Yes. You'll need to use:
QAbstractItemView::setIndexWidget ( const QModelIndex & index, QWidget * widget )
QListView inherits QAbstractItemView and when you're trying to customize list/tree views that's usually the place to look. Be careful though, without a delegate this doesn't scale very well. Check out this thread: http://www.qtcentre.org/threads/26916-inserting-custom-Widget-to-listview
You can also go for a generic approach that can work on variety of containers, including the underlying model of your list view.
Each item in the list has a requestRemoval(Item*) signal and a removeMe() slot, connect the X button to the removeMe() slot in each item constructor, in removeMe() you emit the requestRemoval(this) signal, which is connected to a removeHandler(Item*) slot in your "parent" object upon creation of that item, which receives the pointer of the item which has requests deletion, and removes it from the underlying container being used.
Basically, pressing the remove button causes that particular item to send a pointer of itself to the parent's remove handler which removes that entry.
EDIT: Note that this is a generic approach, as noted in the comments below it can be applied without signals and slots as well, and even though it will work it is not the most efficient solution in your particular case.

Best practice to handle multiple documents in QMdiArea?

I need to design and develop a kind of graphics piece of software, which can edit customized files containing graphical elements, etc.
I expect the piece of software to contain many documents thanks to the QMdiArea which is actually my central widget inside of my QMainWindow.
For each document, I will need both a QGraphicsView and a QGraphicsScene as well, since they work together.
Now, my question is, should I inherit QGraphicsView with a protected/private member to its own QGraphicsScene, or should I create a class which inherits QWidget and handles instances of QGraphicsView / QGraphicsScene ?
Or is there any solution left that I didn't think about?
First off, I don't think you need a QWidget to manage the QGraphicsScene and QGraphicsView. With that in mind, the "best practice" is typically to avoid subclassing if possible. Eventually you might have to subclass QGraphicsView (if you want to change its default functionality), but nothing in your question implies that you need to right now. Also note that there is a function QGraphicsView::scene() that returns the view's current scene, so there is no need to make the scene a member (it already is).
If you ever need to access a particular view or scene, you can do something like this:
MainWindow::onActionClearActiveWindow() // just an example
{
QMdiArea *myMdiArea = static_cast<QMdiArea*>(centralWidget());
QGraphicsView *activeView = static_cast<QGraphicsView*>(myMdiArea->widget());
QGraphicsScene *activeScene = activeView->scene();
activeScene->clear();
}
See also QMdiArea::subWindowList() which returns a list of all the sub windows.

Resources