Qt metaObject->indexOfMethod always return -1 - c++

I have one function declared in Foo class:
Q_INVOKABLE void setImageUrl(const QString &imageUrl);
However I cannot get the function index of that method:
Foo* foo = new Foo();
const QMetaObject* metaObject = foo->metaObject();
QString functionNameWithparameter("setImageUrl(QString)");
int functionIndex = metaObject->indexOfMethod(functionNameWithParameter.toStdString().c_str());
if (functionIndex >= 0) {
// never the case
}
What am I missing?

Apart from the two compiler errors, your approach seems to be correct. I assume that you had some changes that required to rerun moc, but you have not actually done so. This is the working code for me.
main.cpp
#include <QMetaObject>
#include <QDebug>
#include <QString>
class Foo : public QObject
{
Q_OBJECT
public:
explicit Foo(QObject *parent = Q_NULLPTR) : QObject(parent) {}
Q_INVOKABLE void setImageUrl(const QString &) {}
};
#include "main.moc"
int main()
{
Foo* foo = new Foo();
const QMetaObject* metaObject = foo->metaObject();
QString functionNameWithParameter("setImageUrl(QString)");
qDebug() << metaObject->indexOfMethod(functionNameWithParameter.toStdString().c_str());
return 0;
}
main.pro
TEMPLATE = app
TARGET = main
QT = core
CONFIG += c++11
SOURCES += main.cpp
Build and Run
qmake && make && ./main
Output
5

Related

Register custom type in Qt with QJsEngine

I have a custom class named LObject, with a method "test" i want to call.I have a method registered in a QJSEngine that returns an instance of LObject.
I get the error message when executing the method :
"Error: Unknown method return type: LObject"
I tried to register my type with Q_DECLARE_METATYPE, but then i can't call the method of my LObject.
What's the way to do it ?
Edit : A Minimal example with 3 files
server.h :
#ifndef SERVER_H
#define SERVER_H
#include <QObject>
#include <QString>
#include <QQmlEngine>
#include <QQuickView>
#include <QQmlContext>
#include <qqml.h>
class TObject : public QObject
{
Q_OBJECT
QML_ELEMENT
public :
TObject(QObject * parent = nullptr, const QString & data = "") : QObject(parent) ,m_data(data){}
TObject(const TObject & other) : QObject() ,m_data(other.m_data) {}
~TObject(){};
TObject& operator=(const TObject & other) { m_data = other.m_data;return *this;}
Q_INVOKABLE QString getData() { return m_data;}
Q_INVOKABLE void setData(const QString & data) {m_data = data;}
private :
QString m_data;
};
class Server : public QObject
{
Q_OBJECT
public :
QQmlEngine * newEngine()
{
QQmlEngine * ret = new QQmlEngine(this);
ret->rootContext()->setContextProperty("Server",this);
return ret;
}
Q_INVOKABLE TObject newTObject() { return TObject();}
};
Q_DECLARE_METATYPE(TObject)
#endif // SERVER_H
main.cpp :
#include "server.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Server s;
QQmlEngine * e = s.newEngine();
QQuickView view(e,nullptr);
view.setSource(QUrl("test.qml"));
view.show();
return a.exec();
}
test.qml
import QtQuick 2.9
import QtQuick.Window 2.9
Text
{
function test()
{
let t = Server.newTObject() //test.qml:8: Error: Unknown method return type: TObject
t.setData("TEST")
return t.getData()
}
text : test();
}
Solved !
qmlRegisterInterface<TObject>("TObject",1);
and then the methods have to return a TObject*.
Registering QMetaType::qRegisterMetaType should fix your issue. In short, QT meta-object needs this to match the return type's name to your class' name:
qRegisterMetaType<TObject>();

Qt: Cannot queue arguments of type MyClass

I'm trying to pass my Class trough a signal with this:
connect(this, SIGNAL(SIG_connectSerial(SerialSetting::Settings)), serial, SLOT(openConnection(SerialSetting::Settings)),Qt::QueuedConnection);
The class I want to pass is that class:
#ifndef SERIALSETTING_H
#define SERIALSETTING_H
#include <QWidget>
#include <QtSerialPort/QSerialPort>
namespace Ui {
class SerialSetting;
}
class QIntValidator;
class SerialSetting : public QWidget
{
Q_OBJECT
public:
struct Settings {
QString portName;
qint32 baudRate;
};
Settings settings();
public:
explicit SerialSetting(QWidget *parent = 0);
~SerialSetting();
private slots:
void apply();
void on_btnApply_clicked();
private:
void fillPortsParameters();
void fillPortsInfo();
void updateSettings();
private:
Ui::SerialSetting *ui;
Settings currentSettings;
QIntValidator *intValidator;
};
#endif // SERIALSETTING_H
#include "serialsetting.h"
#include "ui_serialsetting.h"
#include <QtSerialPort/QSerialPortInfo>
#include <QIntValidator>
#include <QLineEdit>
QT_USE_NAMESPACE
static const char blankString[] = QT_TRANSLATE_NOOP("SettingsDialog", "N/A");
SerialSetting::SerialSetting(QWidget *parent) :
QWidget(parent),
ui(new Ui::SerialSetting)
{
ui->setupUi(this);
intValidator = new QIntValidator(0, 4000000, this);
//ui->cboBaudRate->setInsertPolicy(QComboBox::NoInsert);
fillPortsParameters(); //call function to fill comboboxes
connect(ui->btnApply, SIGNAL(clicked()),this, SLOT(apply()));
}
SerialSetting::~SerialSetting()
{
delete ui;
}
void SerialSetting::fillPortsParameters()
{
//fill cboComport with all available comports
foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts())
{
ui->cboComport->addItem(info.portName());
}
}
void SerialSetting::apply()
{
SerialSetting::currentSettings.portName = ui->cboComport->currentText();
hide();
}
SerialSetting::Settings SerialSetting::settings()
{
return SerialSetting::currentSettings;
}
void SerialSetting::on_btnApply_clicked()
{
}
The compiler throws this exception:
QObject::connect: Cannot queue arguments of type 'SerialSetting::Settings'
(Make sure 'SerialSetting::Settings' is registered using qRegisterMetaType().)
I tried qRegisterMetaType<SerialSetting>(); but this ended in the following error:
static assertion failed: Type is not registered, please use the Q_DECLARE_METATYPE macro to make it known to Qt's meta-object system
#define Q_STATIC_ASSERT_X(Condition, Message) static_assert(bool(Condition), Message)
Adding the Makro Q_DECLARE_METATYPE(Ui::SerialSetting) at the end of the class-header throws another error:
invalid application of 'sizeof' to incomplete type 'Ui::SerialSetting'
isLarge = (sizeof(T)>sizeof(void*)),
You can't call Q_DECLARE_METATYPE on a forward-declared class (Ui::SerialSetting). Also, you need to declare the type that the signal uses as a parameter, in this case, SerialSetting::Settings.
Replace
Q_DECLARE_METATYPE(Ui::SerialSetting)
with
Q_DECLARE_METATYPE(SerialSetting::Settings)
and you should be fine.

Why does my attempt at connecting a pushbutton to a lambda fail?

I have some issues while trying to use lambda expression to make connections between a pushbutton and a function I want to call when I click the button.
I am using Qt 5.6, with the compiler MinGW 4.9.2 (the default one). My code is the following :
In mainwindow.cpp :
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
initBuildings();
initPage();
for (int i(0); i<buildings.size(); ++i) {
connect(static_cast<QAbstractButton*>(widgetlist.at(i).at(2)), &QAbstractButton::clicked, [this, i]() {
buildings.at(i).buy(amountMultiplier);});
}
}
void MainWindow::initBuildings()
{
Building b1 = Building("Building 1",100,1,200);
Building b2 = Building("Building 2",1000,10,2000);
buildings.append(b1);
buildings.append(b2);
}
void MainWindow::initPage()
{
for (int i(0); i<buildings.size(); i++) {
QList<QWidget *> buttons;
QLabel *namelabel = new QLabel(buildings.at(i).getName());
QLabel *amountlabel = new QLabel;
QPushButton *buybutton = new QPushButton(this);
QPushButton *upgradebutton = new QPushButton(this);
amountlabel->setFixedSize(50,40);
buybutton->setFixedSize(100,40);
upgradebutton->setFixedSize(100,40);
buttons.append(namelabel);
buttons.append(amountlabel);
buttons.append(buybutton);
buttons.append(upgradebutton);
widgetlist.append(buttons);
}
}
In mainwindow.h :
#include <QMainWindow>
#include <QScrollArea>
#include <QList>
#include <building.h>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
void initBuildings();
void initPage();
Ui::MainWindow *ui;
int amountMultiplier;
QList<Building> buildings;
QList<QList<QWidget*>> widgetlist;
};
And "Building" is a class I have created which does not inherit from another class. The function I want to use is a public funtion of this class:
void buy(int amount) const;
It doesn't compile and I get several errors :
no matching function for call to 'MainWindow::connect(QAbstractButton*, void (QAbstractButton::*)(bool), MainWindow::MainWindow(QWidget*)::<lambda()>)
invalid use of incomplete type 'struct QtPrivate::QEnableIf< false, QMetaObject::Connection>
cannot convert '<lambda closure object>MainWindow::MainWindow(QWidget*)::< lambda()>{((MainWindow*)this), i}' (type 'MainWindow::MainWindow(QWidget*)::< lambda()>') to type 'const QObject*
I tried to change the lambda capture list, or to change the way I get the value in the lists but it doesn't change anything and I don't figure what is the problem. Maybe I am wrong in the use of the lambda ?
Two problems:
buildings.at() returns a const Building &, and the buy method is not const. You must index the buildings using [] instead.
The type returned from widgetlist.at(i).at(2) is definitely not QPushButton* - if it was, the code would compile. Even the error message indicates what the issue is:
no matching function for call to 'MainWindow::connect(QWidget* const&, void (QAbstractButton::*)(bool), [...])
This compiles:
// https://github.com/KubaO/stackoverflown/tree/master/questions/lambda-list-37615204
#include <QtWidgets>
struct Building {
void buy() {}
};
class Class : public QObject {
QList<Building> m_buildings;
QList<QList<QWidget*>> m_widgets;
public:
Class() {
for (int i = 0; i<m_buildings.size(); ++i)
connect(static_cast<QAbstractButton*>(m_widgets.at(i).at(2)), &QAbstractButton::clicked, [=] {
m_buildings[i].buy();
});
}
};
int main() {}
If you wish an extra measure of safety in face of programming errors on your part, replace the static_cast with a qobject_cast, it'll then abort if you cast a non-button instead of doing something possibly misleading.
According to the documentation, your lambda should accept a bool argument.

Templates class connect

mainwindow.cpp
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
Form* form = new Form;
Form1* form1 = new Form1;
obj = new MyObj<Form>(form);
emit mySig(form1);
emit mySig(form);
}
myobject.h
#include <QObject>
#include "form.h"
#include "form1.h"
class MyObjBase : public QObject
{
Q_OBJECT
public:
MyObjBase() {}
private slots:
virtual void mySlot(Form* f) = 0;
virtual void mySlot(Form1* f) = 0;
signals:
void mySig(Form* f);
void mySig(Form1* f);
};
template <typename T>
class MyObj : public MyObjBase
{
public:
MyObj(T* obj) : MyObjBase()
{
this->obj = obj;
connect(this,SIGNAL(mySig(T*)),this,SLOT(mySlot(Form*)));
}
T* obj = NULL;
void mySlot(Form* f) {
qDebug() << Q_FUNC_INFO;
}
void mySlot(Form1* f) {
qDebug() << Q_FUNC_INFO;
}
void emitSig() {
emit mySig(obj);
}
};
Why is the connect not working? I thought when i specialize my template class via <> when i initialize it, that the compiler creates new code for that class where T = Form. Then the connect should work in my opinion :D
Get a generic connect like that working would make my code shorter.
It compiles fine but the output is:
QObject::connect: No such signal MyObjBase::mySig(T*) in
..\overload_signals\myobj.h:30
thank you for helping me

QObject factory in Qt Plugin(non-creator)

I am starting to be very nervous with my problem, I will try to desribe my need, hope that somebody understands.
Imagine that I have project which generates one executable and some plugins( runtime loaded library ). That executable is some kind of daemon/service which looks for ist suitable plugins at the start. So these plugins should provide some abstract communication layer.
I have looked at the Qt Doc and found QPluginLoader class which should provide interface loading from .so, but the interface cannot have signal/slot, must be pure virtual. So I was thinking about somethink which will return QObject based objects...
!!! Please dont get scared, its just 2 interfaces and 2 implementations :)
My Project layout and contents:
./Daemon/Interfaces/PluginInterface.h
#include <QObject>
#include "PluginInterface.h"
class PluginInterface {
public:
virtual ~PluginInterface() = 0;
virtual ProtocolInterface* getInterface() = 0;
virtual int getPluginId() const = 0;
};
Q_DECLARE_INTERFACE( PluginInterface, "com.porta.protocol.PluginInterface/1.0")
./Daemon/Interfaces/ProtocolInterface.h
#include <QObject>
#include "turnstile.h"
class ProtocolInterface : public QObject {
Q_OBJECT
public:
ProtocolInterface( QObject *parent = 0 ) : QObject( parent ) {}
virtual QWidget* getConfigureGUI() = 0;
virtual void init() = 0;
virtual void start() = 0;
signals:
void someSignal();
};
./Daemon/ProtocolHander.cpp(&h) <- just plugin loading and some logic
./Daemon.pro
QT += core gui
TARGET = porta_daemon
CONFIG += console
CONFIG -= app_bundle
TEMPLATE = app
SOURCES += main.cpp \
protocolhandler.cpp
HEADERS += protocolhandler.h \
Interfaces/protocolinterface.h \
Interfaces/protocolloader.h \
Interfaces/turnstile.h
./Plugins/Dummy/DummyPluginInterface.h
#include "protocolloader.h"
#include <QObject>
class DummyPluginInterface : public QObject, PluginInterface {
Q_OBJECT
Q_INTERFACES(PluginInterface)
public:
ProtocolInterface* getInterface();
int getPluginId() const;
};
./Plugins/Dummy/DummyPluginInterface.cpp
#include "DummyPluginInterface.h"
#include "DummyProtocolInterface.h"
ProtocolInterface *DummyPluginInterface::getInterface() {
return new DummyProtocolInterface();
}
int DummyPluginInterface::getPluginId() const {
return 1;
}
Q_EXPORT_PLUGIN2(dummyplugin, DummyPluginInterface)
./Plugins/Dummy/DummyProtocolInterface.h
#include "protocolinterface.h"
#include <QObject>
class DummyProtocolInterface : public ProtocolInterface {
public:
void init();
QWidget* getConfigureGUI();
void start();
int getPluginId() { return 1; }
};
./Plugins/Dummy/DummyProtocolInterface.cpp
#include "DummyProtocolInterface.h"
QWidget* DummyProtocolInterface::getConfigureGUI() {
return 0;
}
void DummyProtocolInterface::start() {
}
void DummyProtocolInterface::init() {
emit someSignal(); /// !!! this is important for me
}
./Plugins/Dummy/Dummy.pro
TEMPLATE = lib
CONFIG += plugin
QT += network
INCLUDEPATH += ../../Daemon/Interfaces/
HEADERS += ****
SOURCES += ****
TARGET = *****
DESTDIR = *****
My promblem is that I am getting linking errors or runtime unresolved symbols( mostly somethink from QObject ) or my signals cannot by connected... ProtocolHandler should be the one, who connects signals/slots..
Can anybody tell me how to make this approach right? Qt examples are not covering such think..
THANK YOU!
Adam
So adding ProtocolInterface.h into HEADERS += section of Plugin.pro file SOLVED THE PROBLEM :)