Module [] is not installed - registration of user C ++ shell for QML

I need to access the C ++ API to work with the CAN bus. It seems like the best solution is to write a QML wrapper to provide all the functionality I need.

Here is my canservice.cpp :

 #include "canservice.h" #include <QCanBus> #include <QDebug> #include <QCanBusFrame> #include <QTimer> #include <QtCore/qbytearray.h> #include <QtCore/qvariant.h> #include <QtCore/qdebug.h> CANService::CANService(QObject *parent) : QObject(parent), m_canDevice(nullptr) { QString status = ""; initializeSettings(); // TODO" disable sending messages until connection is stablished } CANService::~CANService() { delete m_canDevice; } void CANService::receiveError(QCanBusDevice::CanBusError error) const { switch (error) { case QCanBusDevice::ReadError: case QCanBusDevice::WriteError: case QCanBusDevice::ConnectionError: case QCanBusDevice::ConfigurationError: case QCanBusDevice::UnknownError: qWarning() << m_canDevice->errorString(); default: break; } } void CANService::initializeSettings() { foreach (const QByteArray &backend, QCanBus::instance()->plugins()) { qInfo() << "found: " + backend; if (backend == "socketcan") { // found socketcan m_currentSettings.backendName = "socketcan"; break; } } if(m_currentSettings.backendName.length() < 1) { qWarning() << "did not find a backend"; } m_currentSettings.backendName = "socketcan"; m_currentSettings.deviceInterfaceName = QStringLiteral("vcan0"); } void CANService::connectDevice() { m_canDevice = QCanBus::instance()->createDevice(m_currentSettings.backendName.toLocal8Bit(), m_currentSettings.deviceInterfaceName); if (!m_canDevice) { showStatusMessage(tr("Connection error")); return; } connect(m_canDevice, &QCanBusDevice::errorOccurred, this, &MainWindow::receiveError); connect(m_canDevice, &QCanBusDevice::framesReceived, this, &MainWindow::checkMessages); connect(m_canDevice, &QCanBusDevice::framesWritten, this, &MainWindow::framesWritten); if (p.useConfigurationEnabled) { foreach (const ConnectDialog::ConfigurationItem &item, p.configurations) m_canDevice->setConfigurationParameter(item.first, item.second); } if (!m_canDevice->connectDevice()) { delete m_canDevice; m_canDevice = nullptr; qInfo() << "Connection error"; } else { qInfo() << m_currentSettings.backendName << "is connected"; } } void CANService::sendMessage() const { if (!m_canDevice) return; // TODO: replace test message with input QByteArray writings = dataFromHex("1122334455667788"); QCanBusFrame frame; const int maxPayload = 8; // 64 : 8; int size = writings.size(); if (size > maxPayload) size = maxPayload; writings = writings.left(size); frame.setPayload(writings); //TODO: get from UI qint32 id = 100; if (id > 2047) { //11 bits id = 2047; } frame.setFrameId(id); frame.setExtendedFrameFormat(true); // frame.setFrameType(QCanBusFrame::RemoteRequestFrame); // frame.setFrameType(QCanBusFrame::ErrorFrame); frame.setFrameType(QCanBusFrame::DataFrame); m_canDevice->writeFrame(frame); } void CANService::checkMessages() { if (!m_canDevice) return; const QCanBusFrame frame = m_canDevice->readFrame(); const qint8 dataLength = frame.payload().size(); const qint32 id = frame.frameId(); QString view; if (frame.frameType() == QCanBusFrame::ErrorFrame) { interpretError(view, frame); } else { view += QLatin1String("Id: "); view += QString::number(id, 16).toUpper(); view += QLatin1String(" bytes: "); view += QString::number(dataLength, 10); view += QLatin1String(" data: "); view += dataToHex(frame.payload()); } if (frame.frameType() == QCanBusFrame::RemoteRequestFrame) { qInfo() << "got remote request message" << view; } else if (frame.frameType() == QCanBusFrame::ErrorFrame) { qWarning() << "got can error frame: " << view; } else { qInfo() << "got can frame: " << view; } } void CANService::interpretError(QString &view, const QCanBusFrame &frame) { if (!m_canDevice) return; view = m_canDevice->interpretErrorFrame(frame); } static QByteArray dataToHex(const QByteArray &data) { QByteArray result = data.toHex().toUpper(); for (int i = 0; i < result.size(); i += 3) result.insert(i, ' '); return result; } static QByteArray dataFromHex(const QString &hex) { QByteArray line = hex.toLatin1(); line.replace(' ', QByteArray()); return QByteArray::fromHex(line); } 

In canservice.h I have:

 #ifndef CANSERVICE_H #define CANSERVICE_H #include <QObject> #include <QQuickItem> #include <QCanBusDevice> class CANService : public QObject { Q_OBJECT public: explicit CANService(QObject *parent = 0); typedef QPair<QCanBusDevice::ConfigurationKey, QVariant> ConfigurationItem; struct Settings { QString backendName; QString deviceInterfaceName; QList<ConfigurationItem> configurations; bool useConfigurationEnabled; }; void connectDevice(); Q_INVOKABLE void connect(const QString &query) { qDebug() << "invoking connect with " << query; } explicit ConnectDialog(QWidget *parent = nullptr); ~ConnectDialog(); Settings settings() const; private: Settings m_currentSettings; void initializeSettings(); signals: public slots: }; qmlRegisterType<MyObject>("can.myapp", 1, 0, "CANService"); #endif // CANSERVICE_H 

In my QML file, I first try to import the newly defined service: import can.myapp 1.0 , and then declare an instance of it:

 CANService { id: "myCanService" } 

When I try to run this application and load the QML file that makes the CANService call, it does not load, and I get the following error in the application console:

  component not ready: "file:///home/aras/Projects/myapp/apps/com.myapp.diagnostics/Diagnostics.qml:5 module \"can.myapp\" is not installed\n" 

EDIT : The problem is most likely where I call qmlRegisterType . I use appman , so my application does not have a main function. Where is the right place to run qmlRegisterType ?

0
c ++ qt qt-creator qml
source share
1 answer

I answer because you marked the older post as similar.

Here are a couple of questions: 1) Where do you call qmlRegisterType<MyObject>("can.myapp", 1, 0, "CANService"); My understanding is that this needs to be called in the main method before creating an instance of QtQuickApplicationViewer (if you load it this way.)

2) Does this work with a simple example (passing a simple QString value for a function)?

I'm not actively coding in Qt right now, but hopefully this might point you in the right direction:

Here is the main method from one of my applications that uses custom components (for simple Java command line communications).

 #include <QtGui/QGuiApplication> #include <QtCore> #include <QtQml> #include "qtquick2applicationviewer.h" #include "globals.h" #include "lightassistant.h" #include "reporting.h" int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); //C++ Types qmlRegisterType<LightAssistant>("com.lightassistant", 1, 0, "LightAssistant"); qmlRegisterType<Reporting>("com.lightassistant", 1, 0, "Reporting"); //Singletons //qmlRegisterSingletonType(QUrl("file:///qml/LightAssistant/Styles.qml"), "com.lightassistant", 1, 0, "Styles"); QtQuick2ApplicationViewer viewer; viewer.setMainQmlFile(QStringLiteral("qml/LightAssistant/main.qml")); viewer.showExpanded(); qDebug() << "offline path is " << viewer.engine()->offlineStoragePath(); LA::OFFLINE_STORAGE_PATH = viewer.engine()->offlineStoragePath(); return app.exec(); } 

Here's a simplified class (these classes are ~ 600 lines)

 #ifndefLIGHTASSISTANT_H #define LIGHTASSISTANT_H #include <QtSql> #include <QtCore> #include <QtXml> #include <QtXmlPatterns> #include "globals.h" class LightAssistant : public QObject { Q_OBJECT public: explicit LightAssistant(QObject *parent = 0); /** * Is this running on Android? */ Q_INVOKABLE int isAndroid() { #ifdef Q_OS_ANDROID return 1; #else return 0; #endif } /** * Is this running on Android? */ Q_INVOKABLE int isIOS() { #ifdef Q_OS_IOS return 1; #else return 0; #endif } /** * @brief isMobile is this on a mobile device? * @return */ Q_INVOKABLE int isMobile() { return isIOS() + isAndroid(); } .... } #endif // LIGHTASSISTANT_H 

Theoretically, you can call this in QML as such now:

 import com.lightassistant 1.0 Item { LightAssistant { id: la } function isIos(){ return la.isIOS(); } } 

I would suggest doing something really simple to make sure there is no problem in the plumbing, and then if this works, use the method method to see if there is another call that is blocking something. My best guess without a full source is that you are probably registering the components.

+2
source share

All Articles