Qt object management with Qt Plugins - c++

My question is how to do proper object/resource management when working with Qt plugins. Default RAII does not seem to work well with Qt.
In our application we work with modules (Qt plugins) that are dynamically loaded at runtime. When loaded plugins can initialize themselves and as part of this initialization phase they can add their own widgets to the application.
- to the toolbar
- to a side panel
- etc.
Widgets that are added to the main windows have their ownership also transferred.
This all works fine, but now that our application grows more complicated we also need to pay attention to the shutdown phase. Simply unloading the modules will get us into all kinds of trouble. Objects that aren't there or types that are unloaded while their objects are still alive.
To have a reliable shutdown it seems that the only proper way to go is to do reverse initialization. This also means that every module that adds widgets to the mainwindow must remove them as well. Already trying to do this with the first widgets got me into trouble.
Module A registers widget W with the MainWindow. Preferably I would want to return a scoped object removing and deleting the widget when going out of scope. However already it seems that given widget W you cannot remove it simply from the toolbar as it works with actions (and removing the action does not delete the widget! See example below).
Concluding, it seems to me Qt is made in such a way that it gets ownership of everything and you have to rely on Qt to delete it. This does not work well with modules. I'm looking for a solution/best practice here.
Edit:
I added an example where a module adds a custom widget to the toolbar of the MainWindow. My goal is that the module is in charge of when the widget is deleted, for the reasons stated before. The example is to make the question more concrete. It represents the generic problem - ownership of qt objects - that use this pattern in combination with plugins.
example:
executable.cpp
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0) {
ui->setupUi(this);
LoadPlugin();
}
void LoadPlugin() {
m_plugin = new QPluginLoader("module.dll");
m_plugin->load();
IModule* moduleInstance = qobject_cast<IModule*>(m_plugin->instance());
moduleInstance->Initialize(this);
}
void AddToolbarSection(QWidget* widget) {
/** ownership is transferred here to Qt */
mainToolBar->insertWidget(pWidget);
}
void RemoveToolbarSection(){
/** How to get the widget deleted? */
}
/** this is called before the destructor */
void UnloadPlugin() {
moduleInstance->Shutdown();
m_plugin->unload();
}
~MainWindow() {
/** deletion of toolbar sections must already been done here
as the modules are already unloaded. Otherwise access violations occur
because specific type information is not accessible anymore.
*/
}
private:
Ui::MainWindow *ui;
QPluginLoader* m_plugin;
IModule* m_moduleInstance;
};
module.cpp
class EXPORT_MODULE IModule : public QObject
{
Q_OBJECT
Q_PLUGIN_METADATA(IID IModuleIID)
Q_INTERFACES(IModule)
public:
IModule() {
}
void Initialize(QMainWindow* window) {
/** QMyToolbarSectionWidget is a custom widget defined in this module (module.dll)
it has a specific destructor and triggers all kinds application
specific cleanup */
m_toolbarSection = new QMyToolbarSectionWidget();
window->AddToolbarSection(m_toolbarSection);
}
void Shutdown() {
window->RemoveToolbarSection(m_toolbarSection);
}
private:
QWidget* m_toolbarSection;
};

That's a bit difficult to answer since it depends on your architecture.
In general Qt's idea of cleanup is tied to the parent pointer. i.e
QObject *root;
QObject *leaf = new QObject();
leaf->setParent(root);
root->deleteLater();
QPluginLoader will even cleanup your root component on unload, so in theory, any tree below your plugin is cleared. Simply make sure that everything you return from your root is a QObject parented to your root. If it's not a QObject, wrap it in QObject.
class MyExtension : public QWidget {
QAction *myAction;
MyExtension() : QWidget() {
myAction = new QAction(this);
}
QAction *getAction() {
return myAction
}
}
from your question i understand you might also be working like this:
class MyExtension : public QObject {
MyWindow * myWindow;
QAction * myAction;
MyExtension() : QObject() {
myWindow = new MyWindow(this);
myAction = new QAction(this);
}
void addToMainThing(TheMainThing *tmt) {
tmt->addWidget(myAction);
}
}
same thing. simply always make sure your QObject is parented to something that is parented to your plugin root.

Cross posting this question on the Qt forum got me the following answer.
Even though Qt takes ownership of QWidgets/QObjects that are added to the Ui, it is still possible to delete them from the client side. Qts resource management system is built in such a way that it will know when a QObject gets deleted and it will handle this deletion by updating the UI as well as removing internal references to it. See the link for more details.

Related

Qt slot and signal: no matching function in MainWindow

I have looked at a variety of the Qt discussions for this error "no matching function for call to" and I still cannot see what is different in this case. I have successfully set up slot/signal pairs between GUI elements, but for some reason the latest set of slot/signal pairs is creating an error.
In order to allow all GUI elements to update the status bar on the main window I have created a signal in each panel as shown here
class PanelA : public QWidget
{
...
public signals:
void UpdateStatusBar(std::string);
...
}
Then in MainWindow there is a slot
//from MainWindow.h
class MainWindow : public QMainWindow
{
private slots:
void ReceiveStatus(std::string);
}
//from MainWindow.cpp
void MainWindow::ReceiveStatus(std::string s)
{
//I can provide other controls, filters, etc.
//but currently there are none
ui->statusBar->showMessage(tr("System status: "+s));
}
And finally, in the MainWindow constructor I have several signals already and I have added one new connect line for each GUI element.
connect(ui->panelA, &PanelA::SelectionChanged, ui->panelB, &PanelB::UpdateSelection);
//this one works
connect(ui->panelA, &PanelA::UpdateStatusBar, ui, &MainWindow::ReceiveStatus);
//this one generates an error there is one status bar connection for each
So, as far as I can tell the syntax is right. both ui->panelA and ui are pointers. I don't know why one is correct and the other is wrong. I'd appreciate any suggestions.
Probably should be:
connect(ui->panelA, &PanelA::UpdateStatusBar, this, &MainWindow::ReceiveStatus);
The ui object isn't a MainWindow, but this will be.

Qt Architecture Advice Needed

iI have a Qt application using QGLWidget for drawing (simply a Viewport for 3D drawing etc...)
There is two main classes in the application.
MainWindow
Inherits from QWidget which holds many GUI widgets (menubar, toolbars, viewport, treeview...etc)
System
Does every other operation from GUI (math, geometry, IO, data processing, etc and holds "Scene" object which has drawable components.) Also it has Singleton pattern to create one global Instance for itself.
I am using Qt signal-slot mechanism to communucate between MainWindow and System, actually MainWindow has the signals and System has the slots. My problem starts here, how can I signal from System to MainWindow slots? When I define MainWindow in System object it gives me lots of error. Normaly System references in MainWindow don't give error. But when I include MainWindow's header file in System.h, System references give error in MainWindow side "'System': the symbol to the left of a '::' must be a type".
Basically my structure is look like this.
// MainWindow.h
#include "System.h"
class MainWindow : public QWidget
{
Q_OBJECT
public:
QToolBar* MyToolBar; // etc...
MainWindow()
{
ConnectSignals();
}
void ConnectSignals() { connect(my_action, SIGNAL(triggered()), System::GetInstance()->Actions, SLOT(action())); }
}
// System.h
#include "MainWindow.h" // if I wrote this, it gives me error in compile time.
class System
{
static bool m_instance;
static System* m_system;
// private constructor
System()
{
Actions = new MyActionList();
}
public:
MyActionList* Actions;
System* GetInstance()
{
if (!m_instance)
{
m_system = new System();
m_instance = true;
return m_system;
}
else { return m_system; }
}
}
// System.cpp
bool System::m_instance = false;
System* System::m_system = NULL;
Of course Actions has slot action()
So how can I access MainWindow from System?
The problem in your approach is the cyclic dependency between MainWindow and System - MainWindow includes System, System includes MainWindow.
In order to pass signals from System to MainWindow you need to make MyActionList of Sytem to emit signals that any receiver (MainWindow in your case) can handle. You absolutely do not need to include MainWindow stuff into the System - keep your backend (System) independent of any GUI component. Just incapsulate System into your MainWindow class and connect MyActionList signals to MainWindow slots. You need to have something like this in your MainWindow:
connect(my_action, SIGNAL(triggered()), System::GetInstance()->Actions, SLOT(action()));
connect(System::GetInstance()->Actions, SIGNAL(systemSignal()), this, SLOT(handleSystemSignal()));
where systemSignal() is a signal emitted from System or its MyActionList component.
As #vahancho states, you should keep a separation between the GUI and other systems. Another method to do this would be to introduce a delegate object to handle the communication between the two.
In addition, if you're inlining code as you've shown in your question, then that will increase the possibility of cyclic dependencies. Move the implementation into the .cpp file and use forward declarations instead of including headers in other header files where possible. This also has the benefit of speeding up compilation, which you'll notice with large projects.

Why do we pass "this" pointer to setupUi function?

I'm fairly new in QT. Taking below fairly simply explain from qt docs :
class CalculatorForm : public QWidget
{
Q_OBJECT
public:
CalculatorForm(QWidget *parent = 0);
private slots:
void on_inputSpinBox1_valueChanged(int value); //why is that slots are private?
private:
Ui::CalculatorForm ui;
};
and implementation of constructor
CalculatorForm::CalculatorForm(QWidget *parent)
: QWidget(parent) {
ui.setupUi(this); // <-- Question below
}
Q: I was wondering why do we pass this pointer to setupUi function?, what does it do ?
So that the dialog will have the caller as parent, so that eg when the parent is closed the dialog can be closed automatically. Generally all gui elements have a pointer to their parent.
private slots:
void on_inputSpinBox1_valueChanged(int value); //why is that slots are private?
These are auto generated slots which exactly match the naming of the gui elments in QtDesigner. They are only meant to do the direct hookup to those gui elements and so should be dealt with in this class. If these signals were extended to other classes then any change in the gui would require changing a lot of other code which doesn't need to know details of the gui.
In the handler slot for the specific gui element you can then emit another more general signal to the rest of the app.
The only widget that setupUi doesn't create is the widget at the top of the hierarchy in the ui file, and as the Ui::CalculatorForm class instance doesn't know the widget it has to fill, it (this) has to be passed explicitly to the class at some point.
this or any other widget you would pass to it, is used as the parent to all other subwidgets. For example, you could fill a widget without inheritance like this:
QWidget *widget = new QWidget;
Ui::CalculatorForm *ui = new Ui::CalculatorForm;
ui->setupUi(widget);
widget->show();
But really, it would be easier to understand if you read the content of the uic generated file (probably named ui_calculatorform.h).
setupUi creates the instances of widgets (QLabel, QTextEdit and so on). The [user interface compiler] (http://qt-project.org/doc/qt-4.8/uic.html) gets information for you from the .UI form and generates widget-creation code in the generated moc source files.
The manual way of creating widgets without using the Qt Designer or a UI file would be like so:
QWidget* pWidget = new QWidget(this);
I think it is to add the caller widget to the layout of this UI.
This widget will be the toplevel widget.
Martin Beckett answer might be correct as well, as what he described is a common behavior in Qt (cf the 'parent' argument in most of widget's derived class constructor)
Note that you have alternative ways how designer can auto-generate code.
In this case you have a separate 'UI' class for this code which is not QObject so it also is not a QWidget.
Auto generated code needs information about parent widget and to make auto-conections of slots and signals so this is why you have to pass this.
This pater is less intrusive then other pasterns (that is why it is default). You can also try alternative patters (check Qt Creator Designer options), but I recommend you to see what is generated by designer tools in default settings.

Qt4: The best way to access parent class (1 level up, 2 levels up .... )

I'm wondering how to access parent class in my Qt application.
Lets say my project has following structure:
mainWindow: MainWindow
tabWidget: QTabWidget
tab1: MySubClass1
tab2: MySubClass2
tabWidget: QTabWidget
xtab1: MySubSubClass1
xtab2: MySubSubClass2
It is a little simplified.
What I want to do is to access mainWindows object from one of xtab2 slot functions.
(1) What would be the best method ?
I tried to pass the pointer to mainWindow along the tree but I get runtime errors.
(2) Should I include mainwindow.h in xtab.h file or should I do it in xtab.cpp file ?
Thanks for help :)
If you really need the mainwindow, passing the MainWindow pointer is the best way to do it. A static method has the drawback that it will stop working with more than one mainwindow.
I would suggest to avoid accessing the mainwindow from the contained widgets though and use signals instead. E.g.:
class MainWindow {
public:
explicit MainWindow( QWidget* parent=0 ) {
tab = new TabWidget;
...
MySubSubClass1* ssw1 = new MySubSubClass;
connect( ssw1, SIGNAL(textChanged(QString)), this, SLOT(page1TextChanged(QString));
tab->addWidget( ssw1 );
}
private Q_SLOTS:
void page1TextChanged( const QString& ) {
//do something...
}
};
MySubSubClass1 then emits textChanged(), addresseeChanged() (e.g. in Addressbook), or whatever level of abstraction or detail makes sense on the higher level. That way MySubSubClass is generic and doesn't have to know about MainWindow at all. It can be reused in any other context. If MySubSubClass itself contains other widgets, it can again connect to their signals.
You could create a static method and object inside MainWindow that would return mainwindow object.
Something like this:
private:
static MainWindow* _windowInstance
public:
static MainWindow* windowInstance()
{
return _windowInstance;
}
This seems to be the simples solution in most cases. Now you just have to include mainwindow.h whenever you need to access this object.
And don't forget to initialize _windowInstance in the contructor, like this;
_windowInstance = this;
By parent class, I assume you mean parent widget?
If you want to find the top level widget, QWidget::window() will point you to it. Use dynamic_cast or qobject_cast to turn it into your MainWindow object.
If you want to go up some arbitrary level, use paerntWidget().
There are a variety of different solutions to this problem, the one you chose as the answer is in terms of object orientation and encapsulation one of the worse ones. Some thoughts
Encapsulation: if you find yourself having to provide access accross a large distance in relation (down a long chain of containers or subclasses) you might want to look at the functionality that you are trying to distribute. I might be that it should be encapsulated in a class by itself that can passed around easier than where it is currently located (the main window in your case).
Abstraction: Unless it is actually functionality of QMainWindow that you need to access don't pass a pointer to your MainWindow class, create an interface for the functionality that you need, have your MainWindow implement that interface and pass around and object of the interface type instead of your MainWindow type.
Signals and Slots: As Frank noted, implement the appropriate functionality using Qt's signalling mechanism, this makes the connection between the caller and callee into a dynamic one, again separating it from the actual MainWindow class
QApplication: If you absolutely have to have global information restrict the entry point, you already have one singleton the QApplication object, make it the maintainer of all the other objects that need to be globally accessible, derive your own QApplication class and maintain global references in there. Your QApplication class can then create or destroy the needed global objects.
With more information about what you need to do with the MainWindow instance or what needs to be communicated you will also get better answers
QWidget* parent = this ;
while (parent -> parentWidget()) parent = parent -> parentWidget() ;

qt GUI connecting

I am just starting out with QT. I have read through some tutorials, and I think I have an understanding of signals and slots. I am writing a GUI that has various buttons that change the state of my main program. So for example in a drawing app, you would pick different drawing tools (using various buttons).
What is the best way to go about this? My first thought was to try to connect the clicked signal of the PushButton to some function that sets a current_tool variable. I did some searching and couldn't find a way to connect a QObject signal to a regular function.
This leads me to believe that there is probably a different approach. One where I create a new QObject (my own extension that is) that has various GUI properties. I would then define my slots here for the various buttons.
What is the best way to do this in QT. I am new and do not know of the preferred practice.
Any info would be useful,
thanks
You can define these "normal functions" as slots. Slots are just normal functions that can also be called by signals:
class ToolSelector : public QObject {
Q_OBJECT
public:
Tool *selected;
public slots:
void selectBrush();
void selectPen();
void selectFill();
};
ToolSelector::selectBrush() {
delete selected;
selected = new Brush();
}
ToolSelector::selectPen() {
// ...
}
// ...
toolsel = new ToolSelector();
brushButton = new QPushButton();
connect(brushButton, SIGNAL(clicked()), toolsel, SLOT(selectBrush()));
Inherit from the class that uic generates, creating, say, a MyAppWindow class. Provide extra METHODs in that class, as well as a Document or Drawing object. Connect these methods to the signals you're interested in, and them alter a member variable that contains the drawing state.