简体   繁体   English

未安装模块[]-为QML注册自定义C ++包装器

[英]module [] is not installed — registering custom C++ wrapper for QML

I need to access a C++ API to work with CAN bus. 我需要访问C ++ API才能使用CAN总线。 Looks like the best solution is to write a QML wrapper to expose all the functionality I need. 看起来最好的解决方案是编写QML包装器以公开我需要的所有功能。

Here is my canservice.cpp so far: 到目前为止,这是我的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 the canservice.h I have: canservice.h我有:

#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 attempt to import the newly defined service: import can.myapp 1.0 and then I declare an instance of it: 在我的QML文件中,我首先尝试导入新定义的服务: import can.myapp 1.0 ,然后声明它的一个实例:

CANService {
    id: "myCanService"
}

When I try to run this application and load the QML file that makes the call to CANService , it does not load and I get the following error in application console: 当我尝试运行此应用程序并加载对CANService进行调用的QML文件时,该文件未加载,并且在应用CANService出现以下错误:

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

EDIT : Problem is most likely with where I am calling qmlRegisterType . 编辑 :问题最可能与我在哪里调用qmlRegisterType I am using appman so my application has no main function. 我正在使用appman所以我的应用程序没有main功能。 Where is the right place to run qmlRegisterType from? 从哪里运行qmlRegisterType的正确位置?

I'm responding because you tagged an older post as similar. 我之所以回应,是因为您将一个较旧的帖子标记为类似。

Here's a couple questions: 1) Where are you calling qmlRegisterType<MyObject>("can.myapp", 1, 0, "CANService"); 这里有几个问题:1)您在哪里调用qmlRegisterType<MyObject>("can.myapp", 1, 0, "CANService"); My understanding is that this needs to be called in the main method before you instantiate the QtQuickApplicationViewer (if you're loading it that way.) 我的理解是,在实例化QtQuickApplicationViewer之前,需要在main方法中调用它(如果以这种方式加载)。

2) Does this work with a simple example (passing a simple QString value to a function)? 2)这是否适用于简单的示例(将简单的QString值传递给函数)?

I'm not actively coding in Qt right at the moment, but hopefully this can point you in the right direction: 目前我还没有在Qt中积极编码,但希望这可以为您指明正确的方向:

Here's the "main" method from one of my applications that uses custom components (for simple Java connectivity over the command line). 这是我的一个应用程序中使用自定义组件的“主要”方法(用于通过命令行进行简单的Java连接)。

#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) 这是一个简化的类(这些类约为600行)

#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 invoke this in QML as such now: 理论上,您现在可以像这样在QML中调用它:

import com.lightassistant 1.0
Item {
  LightAssistant {
    id: la
  }

  function isIos(){
    return la.isIOS();
  }

}

I would suggest doing something really simple like this to make sure there isn't a problem in the plumbing and then, if that works, go method by method to see if there's another call that's blocking something. 我建议执行这样的简单操作,以确保管道中没有问题,然后,如果可行,请逐个方法执行操作,以查看是否有另一个调用阻塞了某个内容。 My best guess without full source is that it is probably where you're registering the components. 没有完整源代码,我的最佳猜测是您可能正在注册组件。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM