Can I subclass QEvent? - qt

I tried to make a class which is a subclass of QEvent, but I got error after building.
My steps,
1. Create a project using Qt console template
2. create the following code
#ifndef MYEVENT_H
#define MYEVENT_H
#include <QEvent>
#include <QObject>
class MyEvent : public QEvent
{
Q_OBJECT
public:
explicit MyEvent();
signals:
public slots:
};
#endif
//CPP File
MyEvent::MyEvent() :
QEvent(QEvent::User)
{
}
moc_MyEvent.cpp:70:21: error: invalid use of non-static data member 'd_ptr'
return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject;
~~~~~~~~~^~~~~
moc_MyEvent.cpp:70:21: error: 'd_ptr' is a protected member of 'QObject'
../../../../../../Qt5.1.0/5.1.0/clang_64/include/QtCore/qobject.h:411:33: note: declared protected here
QScopedPointer<QObjectData> d_ptr;
^
Qt5
Mac OSX 10.8.4
How do I solve it and why? Thanks.

Dcow gives corrent answer.
Your mistake is that QEvent does not inherit from QObject, and you try to do it. You should not use Q_OBJECT macros or you should interhit your class from QObject too. But it's dark side.

First of all WHY? You should write why you need this, I'm sure that your problem solution which you are trying to fix is just wrong!
Secondly problem is Q_OBJECT macro. QEvent is not a QObject so this macro is not applicable and this is why you have this error.

As already pointed out: No Q_OBJECT. But let me add something and point your attention to a rarely used and widely unknown macro: Q_GADGET
Almost a Q_OBJECT for non-QObjects.
From the Qt Docs:
Use Q_GADGET instead of Q_OBJECT to enable the meta object system's
support for enums in a class that is not a QObject subclass. Q_GADGET
makes a class member, staticMetaObject, available. staticMetaObject is
of type QMetaObject and provides access to the enums declared with
Q_ENUMS. Q_GADGET is provided only for C++.
Comes handy from time to time.

Related

Q_ENUMS with enum in header file

I want to use the elements of an enum as items in a QComboBox. I can do so if the enum is defined in the same class but I would like to use an enum defined in a header file. My goal is to use the enum directly from the header file, without altering the header file. Moreover, I would like my code to adapt to a changing enum, both in the name of the elements and in the number of them.
I have found this answer and this link that have helped me understand how to populate a QComboBox with an enum. The solution in the answer works for me but only if the enum is defined in the class.
The basic code I would like to implement looks like:
definitions.h
#ifndef _DEFINITIONS_H_
#define _DEFINITIONS_H_
typedef enum
{
FIRST = 0,
SECOND,
THIRD
} elements;
#endif
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "definitions.h"
class MainWindow : public QMainWindow
{
Q_OBJECT
Q_ENUMS(elements);
public:
explicit MainWindow(QWidget *parent = 0);
QComboBox *comboBox;
};
#endif
mainwindow.cc
#include "mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
{
int index = metaObject()->indexOfEnumerator("elements");
QMetaEnum metaEnum = metaObject()->enumerator(index);
for (int i = 0; i < metaEnum.keyCount(); i++)
comboBox->addItem(metaEnum.valueToKey(i));
}
This code does not encounter any issue at compilation on runtime but has no effect at all. Defining the enum in MainWindow class works like a charm.
It does not look like a visibility issue because I can use the elements of the enum in my code and I have not encountered any compilation problem.
I have tried redefining my enum in mainwindow.h with typedef without success:
typedef elements new_elements
I have also tried replacing Q_ENUMS with Q_ENUM as suggested by the answer below but the result is the same.
Is it possible to use Q_ENUMS/Q_ENUM with an enum defined in a header file?
What should I do different?
You can't do that. Q_ENUMS need a meta object provided either by the QObject class or the Q_GADGET macro, that's why it works when the enum is declared in a class derived from a QObject.
Since Qt 5.8, a new macro was introduced Q_ENUM_NS that makes this possible:
This macro registers an enum type with the meta-object system. It must be placed after the enum declaration in a namespace that has the Q_NAMESPACE macro. It is the same as Q_ENUM but in a namespace.
You can do something like that:
namespace MyNamespace {
Q_NAMESPACE
enum elements {
FIRST = 0,
SECOND,
THIRD
};
Q_ENUM_NS(elements)
}
See this post for more information.
Updates
Regarding the last comment, you can create a new enumeration and associate each element with the value of the new one.
class MainWindow : public QMainWindow {
Q_OBJECT
public:
enum elements {
FIRST = ::elements::FIRST,
SECOND = ::elements::SECOND,
THIRD = ::elements::THIRD,
};
Q_ENUM(elements);
}
Then, for a function like:
void use_enum(elements e);
// Call it with the original one
use_enum(elements::FIRST);
// Call it with the new one, you just created
use_enum(MainWindow::elements::FIRST);
Check the Q_ENUM that registers automatically as metatype as it is said in the documentation What's New in Qt 5.5:
Added Q_ENUM to replace Q_ENUMS, which allows to get a QMetaEnum at compile time using QMetaEnum::fromType. Such enums are now automatically registered as metatypes, and can be converted to strings within QVariant, or printed as string by qDebug().

Q_ENUM external header

I will have a rather large amounts of enums to be used in Qt c++ frontend, QML and also in c++ backend with no Qt libraries.
I am presenting two ways to do this, both works runtime. The funny thing is moc file generated for both solutions are identical. What is the QML engine use to lookup its QT_ENUMs if the MOC files alone aren't sufficient?
Therefore i make a header file with those enums defined and include the file "inline" to make sure it is part of the class. This works, but autocomplete in QML is missing (need to alt-tab back and forward and loose efficiency)
#include <QObject>
class ButtonEnums : public QObject
{
Q_OBJECT
public:
ButtonEnums(QObject* parent = nullptr);
#include "backend/app/messages_frontend.h"
Q_ENUM(EnTaskSelection)
};
Now i have to remember copy paste and get a larger header file then desired if i do this, but autocomplete in QML works:
#include <QObject>
class ButtonEnums : public QObject
{
Q_OBJECT
public:
ButtonEnums(QObject* parent = nullptr);
enum EnTaskSelection {
TASK_ONE = 0, //Strict indexes defined by main menu
TASK_TWO,
TASK_THREE,
TASK_FOUR
};
Q_ENUM(EnTaskSelection)
};

No such slot when connecting widget signal with parent widget slot

I have the following classes:
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QStringList pluginsToStart, QWidget *parent = 0);
~MainWindow();
// some other stuff
public slots:
void on_timeDataChanged(logging::TimeValueVector<bool>& aData);
void on_importStarted();
}
and
class DataImporterWidget : public PluginWidget
{
Q_OBJECT
public:
explicit DataImporterWidget(QWidget *parent = 0);
~DataImporterWidget();
void initConnections(QMap<QString, PluginWidget*> pluginWidgetMap);
in the method initConnections, I want the widget to init the signal-slot connections like so:
void DataImporterWidget::initConnections(QMap<QString, PluginWidget*> pluginWidgetMap)
{
for(Importer* importer : this->getImporterMap().values())
{
connect(importer, SIGNAL(signal_timeDataChanged(logging::TimeValueVector<bool>&)),
parentWidget(), SLOT(on_timeDataChanged(logging::TimeValueVector<bool>&)));
}
connect(this, SIGNAL(signal_importStarted()), parentWidget(), SLOT(on_importStarted()));
}
Importer is a QGroupBox and a base class for derived sub classes specifying concrete data importer types.
It works like so: If I press a button, an DataImporterWidget is created and added to a QMdiArea as a QMdiSubWindow. When creating the DataImporterWidget I call the initConnections() method which sets up the signal-slot connections.
Now, when I run the program, I get the following message:
QObject::connect: No such slot
QMdiSubWindow::on_timeDataChanged(logging::TimeValueVector<bool>&) in src/dataimporter/DataImporterWidget.cpp:81
QObject::connect: No such slot QMdiSubWindow::on_importStarted() in src/dataimporter/DataImporterWidget.cpp:85
QObject::connect: (sender name: 'DataImporterWidget')
I do not understand why I get it because the slot is there. Even if I cast the parentWidget to the MainWindow, I get the same error.
PluginWidget is just a base class deriving from QWidget that holds some common functionality for my used plugins.
I put Q_OBJECT on each base and derived class but still get this error. However, if I set up the connections in the MainWindow, it works just fine, but I wonder why the above solution won't work.
Don't create the connection from child object, instead create it from parent object code after creating the child object.
This way you won't need to cast any type.
You did not shown a huge chunk of important code (like creating DataImporterWidget, setting MainWindow as its parent, the place where you call initConnections...). However, you said
If I use the new signal slot syntax, my program crashes with a
segmentation fault...
If it crashes, than you have to find a reason why. Using old signal-slot connect syntax does not cure the disease, it just delay its manifestation. According to this, the reason why you get a segfault can be parentWidget() == nullptr or parent is not initialized yet.
My advice, check your code, and make user the parent of DataImporterWidget is created and specified before your call initConnections().
I've found the problem. The reason is, that the MainWidget class holds a QMdiArea where I add my PluginWidgets. So, when I create the PluginWidget, I set the MainWidget as its parent, but as soon as I add it to the QMdiArea, it also becomes a child of QMdiSubWindow. The parentWidget was never null but it was the wrong one ...

compiler error C2248:'QObject::Qobject':cannot access private member declared in class 'QObject'

Hi Everyone i have a foo class
Code in foo.h
namespace GUI
{
class Foo : public QObject
{
Q_OBJECT
public:
explicit Foo(QObject *parent = 0);
virtual ~Foo();
....
};
}
Now this is working and compiling fine but i want to save this custom c++ class using QSettings and one of the step is registering your class with Q_DECLARE_METATYPE
and therefore as soon as i put this line
Q_DECLARE_METATYPE(Foo)
at the end of my foo.h file i get these compiler error C2248:'QObject::Qobject':cannot access private member declared in class 'QObject' and which when clicked only takes me to last line of my connection.h header file and gives no other information as to what might be wrong i,e the error point me to
Class Foo
{
};<---- point me here
Q_DECLARE_METATYPE(Foo)
I know that QObject cannot be copied and this is related to it but i have no idea what maybe wrong here and how can i rectify it.
Thanks in advance
I know that QObject cannot be copied and this is related to it but i have no idea what maybe wrong here and how can i rectify it.
It is related. Q_DECLARE_METATYPE requires your type to be copiable, but your type inherits from QObject, so you can't do that. Sure, you could instead Q_DECLARE_METATYPE(Foo*), but I think you should instead move the settings into a separate value class, which then you can save using QSettings.
Make sure your Q_DECLARE_METATYPE statement is outside of your namespace and that you fully qualify your class name. See the Q_DECLARE_METATYPE doc for more detail.
namespace GUI
{
class Connection : public QObject
{
...
};
}
Q_DECLARE_METATYPE(GUI::Connection)
I know that QObject cannot be copied and this is related to it but i
have no idea what maybe wrong here and how can i rectify it.
So declare a copy constructor, then it will be ok.
...
Foo(const Foo &_other);
...

Qt Signals and slots - No matching function for call

I am learning QT and am trying to get my signals and slots working. I am having no luck.
Here is my Main
int main(int argc, char** argv) {
QApplication app(argc, argv);
FilmInput fi;
FilmWriter fw;
QObject::connect (&fi->okButton, SIGNAL( clicked() ), &fi, SLOT( okButtonClicked() )
); //Error received Base operand of '->' has non-pointer type 'FilmInput'
QObject::connect(&fi,SIGNAL(obtainFilmData(QVariant*)),&fw,SLOT(saveFilmData(QVariant*)));
//Error received No matching function for call to 'QObject::connect(Filminput*, const char*, FilmWriter*, const char*)
fi.show();
return app.exec();
}
and here is my sad attempt at signals and slots:
FilmInput.h
public:
FilmInput();
void okButtonClicked();
QPushButton* okButton;
signals:
void obtainFilmData(Film *film);
Here is FilmWriter.h
public slots:
int saveFilm(Film &f);
Here is Film Input.cpp
void FilmInput::okButtonClicked(){
Film *aFilm=new Film();
aFilm->setDirector(this->edtDirector->text());
emit obtainFilmData(aFilm);
}
Here is FilmWriter.cpp
void FilmInput::okButtonClicked(){
Film *aFilm=new Film();
aFilm->setDirector(this->edtDirector->text());
emit obtainFilmData(aFilm);
}
Please assist me in getting the signals and slots to work, I have spent hours but am no closer to getting it working. I have added the errors received in my comments above.
Regards
okButton is already a pointer, then you should remove the ampersand:
QObject::connect(fi.okButton, SIGNAL(clicked()), &fi, SLOT(okButtonClicked()));
(actually, be sure you create the button in FilmInput' constructor...)
Next, your methods signature doesn't match what you say in connect: given your functions, should be
Object::connect(&fi, SIGNAL(obtainFilmData(Film*)), &fw, SLOT(saveFilmData(Film*)));
this will work, because you are exchanging a pointer, and then Qt can make a copy of it. Otherwise, your type should be registered.
The first error is caused by &fi->okButton because -> has a higher precedence than &. See Operator Precedence. Easily fixed with (&fi)->okButton.
The second error is likely caused by one or both objects not inheriting from QObject. Signals and slots can only work between QObjects. Just a quick checklist:
Both sender and receiver must inherit from the QObject class
The Q_OBJECT macro must be used in the definition of each class
You must generate the appropriate meta-object code and compile it into your project. See Meta-Object Compiler
Also, if you're using Qt version 5.0 or higher, you should start passing function pointers to the connect methods instead of using the SIGNAL and SLOT macros. It'll provide compile-time checking of the connections.

Resources