PDA

View Full Version : Q_DECLARE_METATYPE problem



gib
19th August 2019, 04:17
I'm now building with Qt5 code that compiled with no problems with Qt4, and getting an error message that is a bit obscure to me.

F:\Qt\5.13.0\msvc2017\include\QtCore\qmetatype.h:1 798: error: C2338: Type is not registered, please use the Q_DECLARE_METATYPE macro to make it known to Qt's meta-object system
F:\Qt\5.13.0\msvc2017\include\QtCore\qmetatype.h:1 805: see reference to function template instantiation 'int qMetaTypeId<T>(void)' being compiled
with
[
T=QMouseEvent *
]
D:\testing\build-vspheroid-Qt3d\release\moc_myqgraphicsview.cpp:98: see reference to function template instantiation 'int qRegisterMetaType<QMouseEvent*>(void)' being compiled
F:\Qt\5.13.0\msvc2017\include\QtCore\qatomic.h:56: see reference to class template instantiation 'QBasicAtomicInteger<int>' being compiled
F:\Qt\5.13.0\msvc2017\include\QtCore\qatomic.h:154 : see reference to class template instantiation 'QAtomicInteger<int>' being compiled

I have extended QGraphicsView to allow image save on a mouse click like this:

myqgraphicsview.h:



#ifndef MYQGRAPHICSVIEW_H
#define MYQGRAPHICSVIEW_H

#include <QWidget>
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QMouseEvent>
#include <QFileDialog>

#include "log.h"
LOG_USE();

class MyQGraphicsView : public QGraphicsView
{
Q_OBJECT
public:
explicit MyQGraphicsView(QWidget *parent = nullptr);

signals:
void viewClicked();
public slots:
void mouseReleaseEvent(QMouseEvent * e);
void saveImage();
private:
// member variable to store click position
QPoint m_lastPoint;
// member variable - flag of click beginning
bool m_mouseClick;
};

#endif // MYQGRAPHICSVIEW_H


myqgraphicsview.cpp:



#include "myqgraphicsview.h"

MyQGraphicsView::MyQGraphicsView(QWidget *parent) :
QGraphicsView(parent)
{
}

void MyQGraphicsView::mouseReleaseEvent(QMouseEvent * e)
{
if (e->button() == Qt::RightButton) {
saveImage();
}
}

void MyQGraphicsView::saveImage()
{
QGraphicsScene *ascene = this->scene();
ascene->clearSelection(); // Selections would also render to the file
ascene->setSceneRect(ascene->itemsBoundingRect()); // Re-shrink the scene to it's bounding contents
QImage image(ascene->sceneRect().size().toSize(), QImage::Format_ARGB32); // Create the image with the exact size of the shrunk scene
image.fill(Qt::transparent); // Start all pixels transparent
QPainter painter(&image);
ascene->render(&painter);
QString fileName = QFileDialog::getSaveFileName(this, tr("Image File Name"), ".", tr("Image Files (*.png)"));
if (fileName.compare("") != 0) {
image.save(fileName);
}
}

I don't know where and how I should insert the Q_DECLARE_METATYPE line. I don't know what metatype it is referring to (or even what a metatype is).

Fareanor
19th August 2019, 10:04
I tried the code you posted and it compiles fine without any error (as expected). So to be honest I don't understand why you have this error message.

In fact you don't have to declare Qt's types as metatypes as Qt already knows them.
Normally you should not have to declare any metatype for overriding the mouseReleaseEvent().

Perhaps you can try to rebuild everything from scratch, from a clean base (remove every build-generated files, check your .pro file, run qmake and then run the compilation).

To answer your questioning about the metatypes, you need to use Q_DECLARE_METATYPE for user custom classes/structures if you want to use them in QVariant or in signals/slots connections. The related type must provide a public default constructor, a public copy constructor and a public destructor to be eligible to be declared as a metatype. Usually, we call the macro right below the class/struct declaration in the header file. If you use queued connections, you'll need to call qRegisterMetaType() too.
For more accurate information, look at the documentation (https://doc.qt.io/qt-5/qmetatype.html#Q_DECLARE_METATYPE) about it.

gib
19th August 2019, 13:33
Thanks for looking at this. The situation now is even more confusing. I have removed MyQGraphicsView from the program, which eliminated that error. But after adding back most of the rest of the code (I started with a very stripped-down version of the program I am converting over from Qt4 to Qt5) I am getting the same Q_DECLARE_METATYPE error, but now I can't see where it is coming from. These are the 5 lines of error messages:

F:\Qt\5.13.0\msvc2017\include\QtCore\qmetatype.h:1 798: error: C2338: Type is not registered, please use the Q_DECLARE_METATYPE macro to make it known to Qt's meta-object system
F:\Qt\5.13.0\msvc2017\include\QtCore\qmetatype.h:1 805: see reference to function template instantiation 'int qMetaTypeId<T>(void)' being compiled
with
[
T=QMouseEvent *
]
D:\testing\build-vspheroid-Qt3d\release\moc_mainwindow.cpp:686: see reference to function template instantiation 'int qRegisterMetaType<QMouseEvent*>(void)' being compiled
F:\Qt\5.13.0\msvc2017\include\QtCore\qatomic.h:56: see reference to class template instantiation 'QBasicAtomicInteger<int>' being compiled
F:\Qt\5.13.0\msvc2017\include\QtCore\qatomic.h:154 : see reference to class template instantiation 'QAtomicInteger<int>' being compiled

The relevant code in moc_mainwindow.cpp is:


case 73:
switch (*reinterpret_cast<int*>(_a[1])) {
default: *reinterpret_cast<int*>(_a[0]) = -1; break;
case 0:
*reinterpret_cast<int*>(_a[0]) = qRegisterMetaType< QMouseEvent* >(); break;
}
break;


i.e. again reference to QMouseEvent. The file mainwindow.cpp is quite long, a couple of thousand lines, and I have no idea what part of the code is generating this error. There is no indication of what is causing the error. I have cleaned everything, run qmake and rebuilt (many times).

Edit: I have discovered that the error is triggered by this function:



void MainWindow::clickedGraph(QMouseEvent *event)
{
if (event->button() == Qt::RightButton) {
LOG_QMSG("Right button click");
QString fileName = QFileDialog::getSaveFileName(this, tr("Select image file"), ".",
tr("Image files (*.png)"));
if (fileName.compare("") == 0) {
return;
}
colony_plot->savePng(fileName);
}
}


specifically, it appears, by the function argument. There doesn't seem to be anything unusual about this.

Fareanor
19th August 2019, 14:05
It seems strange indeed.

When you "cleaned everything", did you also remove the moc files ? (in order to let qmake regenerate them properly).

If this problem still appears, I think it comes either from the way you do the porting from Qt4 to Qt5 or from some code that becomes wrong from a version to another by generating side effects (which makes it harder to track).
I do not pretend it is the case but if we could have a complete, minimal, reproducible (compilable and runnable) example that illustrates your problem, it would be much better to find the problem (and this way, we will avoid uncertain conjectures).

d_stranz
19th August 2019, 18:32
Any errors from Qt's metatype systems are usually due to MOC (the "meta-object compiler"), which reads your header files and generates a "moc" file with metatype information for every class where the Q_OBJECT macro is declared.

If, in doing your porting, you are simply copying over moc_*.cpp and ui_*.h files, then this is incorrect. These files are generated during the build process from the corresponding *.h and *.ui files by the MOC and UIC programs. You should remove them then rebuild the whole thing so they can be regenerated against the proper set of Qt 5 headers and libraries.

gib
19th August 2019, 23:17
No, I started with just the source files, certainly no moc_ files and no ui_*.h files. I'm on the trail of the bug again this morning.

Edit: If I comment out clickedGraph I can build a working version of the program (not yet complete, but displaying the UI). If I comment out just the contents of the function, so I have just:

void MainWindow::clickedGraph(QMouseEvent *event)
{
}

I get the metatype error.

There is something very odd about this line:

void MainWindow::clickedGraph(QMouseEvent *event)

In Qt Creator 'MainWindow' normally shows as pink, the rest of the line a dark blue. On this line 'inWindow::cl' was pink, the rest dark blue. I made a copy of the line (commenting out the original line), and this showed all as dark blue. After a couple of cycles of commenting and uncommenting, the anomalous pink disappeared, now what I see is either:



//void MainWindow::clickedGraph(QMouseEvent *event)
void MainWindow::clickedGraph(QMouseEvent *event)


or


void MainWindow::clickedGraph(QMouseEvent *event)
//void MainWindow::clickedGraph(QMouseEvent *event)


In the first case, the uncommented line is all black, while in the second case it is all dark blue (I don't know if these colours show up here.)

Oh, now after some commenting and uncommenting, the uncommented line is all black in both cases. So I have a moving target, and I don't even know what it is. :(
It is looking increasingly like bad behaviour on the part of Qt Creator.

d_stranz
19th August 2019, 23:38
Then are you running qmake after adding new files to the project? Qmake is necessary in order to ensure that the moc_*.cpp and ui*.h files are added to the project when you add new source files.

gib
20th August 2019, 01:22
Yes, I always run qmake after a clean I also manually deleted the contents of the build directory.

Added after 12 minutes:

The part of the error message that refers to moc_mainwindow.cpp:

D:\testing\build-vspheroid-Qt3d\release\moc_mainwindow.cpp:677: see reference to function template instantiation 'int qRegisterMetaType<QMouseEvent*>(void)' being compiled

gives the line number that corresponds to the third-to-last line in this chunk of code:



case 71: _t->clickedGraph((*reinterpret_cast< QMouseEvent*(*)>(_a[1]))); break;
case 72: _t->on_cbox_SAVE_PROFILE_DATA_toggled((*reinterpret_ca st< bool(*)>(_a[1]))); break;
case 73: _t->on_cbox_SAVE_SLICE_DATA_toggled((*reinterpret_cast< bool(*)>(_a[1]))); break;
case 74: _t->on_cbox_SAVE_FACS_DATA_toggled((*reinterpret_cast< bool(*)>(_a[1]))); break;
case 75: _t->buttonClick_cell_constituent((*reinterpret_cast< QAbstractButton*(*)>(_a[1]))); break;
case 76: _t->buttonClick_field_constituent((*reinterpret_cast< QAbstractButton*(*)>(_a[1]))); break;
case 77: _t->buttonClick_plane((*reinterpret_cast< QAbstractButton*(*)>(_a[1]))); break;
case 78: _t->buttonClick_canvas((*reinterpret_cast< QAbstractButton*(*)>(_a[1]))); break;
case 79: _t->textChanged_fraction((*reinterpret_cast< QString(*)>(_a[1]))); break;
case 80: _t->textEdited_fraction((*reinterpret_cast< QString(*)>(_a[1]))); break;
case 81: _t->sc_textEdited((*reinterpret_cast< QString(*)>(_a[1]))); break;
case 82: _t->onSelectCellConstituent(); break;
case 83: _t->onSelectFieldConstituent(); break;
case 84: _t->setColourScheme((*reinterpret_cast< int(*)>(_a[1]))); break;
case 85: _t->showColours((*reinterpret_cast< int(*)>(_a[1]))); break;
case 86: _t->on_pushButton_update_FACS_Histo_clicked(); break;
case 87: _t->on_pushButton_saveHisto_clicked(); break;
case 88: _t->on_pushButton_saveFACS_clicked(); break;
case 89: _t->showSummary((*reinterpret_cast< int(*)>(_a[1]))); break;
case 90: _t->updateProfilePlots(); break;
case 91: _t->showFACS(); break;
case 92: _t->showHisto(); break;
case 93: _t->saveFACSImage(); break;
case 94: _t->saveHistoImage((*reinterpret_cast< bool(*)>(_a[1]))); break;
case 95: _t->saveHistoData((*reinterpret_cast< QString(*)>(_a[1]))); break;
case 96: _t->processGroupBoxClick((*reinterpret_cast< QString(*)>(_a[1]))); break;
case 97: _t->createFACSPage(); break;
case 98: _t->test_histo(); break;
case 99: _t->makeHistoPlot((*reinterpret_cast< int(*)>(_a[1])),(*reinterpret_cast< double(*)>(_a[2])),(*reinterpret_cast< double(*)>(_a[3])),(*reinterpret_cast< QVector<double>(*)>(_a[4])),(*reinterpret_cast< QString(*)>(_a[5]))); break;
case 100: _t->pauseServer(); break;
case 101: _t->stopServer(); break;
case 102: { int _r = _t->main3d((*reinterpret_cast< QWidget*(*)>(_a[1])));
if (_a[0]) *reinterpret_cast< int*>(_a[0]) = std::move(_r); } break;
case 103: _t->mover((*reinterpret_cast< QVector3D(*)>(_a[1]))); break;
case 104: _t->runMover(); break;
case 105: _t->start_runMover(); break;
case 106: _t->initialiseSteps(); break;
default: ;
}
} else if (_c == QMetaObject::RegisterMethodArgumentMetaType) {
switch (_id) {
default: *reinterpret_cast<int*>(_a[0]) = -1; break;
case 11:
switch (*reinterpret_cast<int*>(_a[1])) {
default: *reinterpret_cast<int*>(_a[0]) = -1; break;
case 0:
*reinterpret_cast<int*>(_a[0]) = qRegisterMetaType< QTableWidget* >(); break;
}
break;
case 12:
switch (*reinterpret_cast<int*>(_a[1])) {
default: *reinterpret_cast<int*>(_a[0]) = -1; break;
case 0:
*reinterpret_cast<int*>(_a[0]) = qRegisterMetaType< QTableWidget* >(); break;
}
break;
case 31:
switch (*reinterpret_cast<int*>(_a[1])) {
default: *reinterpret_cast<int*>(_a[0]) = -1; break;
case 0:
*reinterpret_cast<int*>(_a[0]) = qRegisterMetaType< QAbstractButton* >(); break;
}
break;
case 39:
switch (*reinterpret_cast<int*>(_a[1])) {
default: *reinterpret_cast<int*>(_a[0]) = -1; break;
case 0:
*reinterpret_cast<int*>(_a[0]) = qRegisterMetaType< QRadioButton* >(); break;
}
break;
case 63:
switch (*reinterpret_cast<int*>(_a[1])) {
default: *reinterpret_cast<int*>(_a[0]) = -1; break;
case 0:
*reinterpret_cast<int*>(_a[0]) = qRegisterMetaType< QAbstractButton* >(); break;
}
break;
case 64:
switch (*reinterpret_cast<int*>(_a[1])) {
default: *reinterpret_cast<int*>(_a[0]) = -1; break;
case 0:
*reinterpret_cast<int*>(_a[0]) = qRegisterMetaType< QAbstractButton* >(); break;
}
break;
case 65:
switch (*reinterpret_cast<int*>(_a[1])) {
default: *reinterpret_cast<int*>(_a[0]) = -1; break;
case 0:
*reinterpret_cast<int*>(_a[0]) = qRegisterMetaType< QAbstractButton* >(); break;
}
break;
case 71:
switch (*reinterpret_cast<int*>(_a[1])) {
default: *reinterpret_cast<int*>(_a[0]) = -1; break;
case 0:
*reinterpret_cast<int*>(_a[0]) = qRegisterMetaType< QMouseEvent* >(); break;
}
break;


Note that case 71 at the start of this extract refers to clickedGraph.
It seems crazy that this could be related to the odd colouring of that line in Qt Creator, but surely it's not just a coincidence. (BTW I tried using highlighting on the relevant parts of the above, but it didn't display, so I removed it.)

Added after 13 minutes:

I closed Qt Creator and restarted it, and now the line colouring is OK. The compile error persists.

d_stranz
20th August 2019, 18:51
What does your MainWindow.h file look like? That's the source of the error.

gib
21st August 2019, 01:08
What does your MainWindow.h file look like? That's the source of the error.

I want to either insert the code here or attach the file, but I don't see how to do either. At the moment the last icon in the row is "Add link to QtCentre Wiki article", and if I click "Go Advanced" it takes me to a page where I'm told to push the back button and reload, which just cancels my reply. I don't understand why I sometimes but not always see the "#" icon.

Now when I try to post this I get an error "Your submission could not be processed because the token has expired. Please reload the window."

Edit: After logging out and in again, I now see the "#" and the "Attachments: icon.

mainwindow.h attached.

Thanks
Gib

gib
21st August 2019, 07:01
In answer to an old question on QtForum, raven-worx said "don't declare your mouse-handlers as slots". I had "void clickedGraph(MouseEvent *)" declared under "private slots:". I shifted it to "private:", and now the build completes without error.
I have no idea why, but it seems that my problem is solved.

d_stranz
22nd August 2019, 17:36
I have no idea why, but it seems that my problem is solved.

In a header file, "slots" is a magic keyword that the C++ compiler ignores, but which triggers the MOC compiler to create boilerplate code in the moc_*.cpp file to support the slots you have declared. Qt events are not declared as slots in their base classes (QObject or QWidget), but as ordinary C++ protected virtual methods. The Qt "Q*Event" classes are not registered with the Qt metatype system (ie., there's no Q_DECLARE_METATYPE for them) so trying to compile the MOC-generated code produces the error.