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

时间:2016-09-07 21:33:57

标签: c++ qt qml qt-creator app-manager

我需要访问C ++ API才能使用CAN总线。看起来最好的解决方案是编写一个QML包装器来公开我需要的所有功能。

到目前为止,这是我的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);
}

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

在我的QML文件中,我首先尝试导入新定义的服务:import can.myapp 1.0,然后我声明它的一个实例:

CANService {
    id: "myCanService"
}

当我尝试运行此应用程序并加载调用CANService的QML文件时,它没有加载,我在应用程序控制台中收到以下错误:

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

修改: 问题很可能出在我打电话qmlRegisterType的地方。我正在使用appman,因此我的应用程序没有main功能。从qmlRegisterType运行的正确位置在哪里?

1 个答案:

答案 0 :(得分:2)

我之所以做出回应,是因为您将较旧的帖子标记为类似。

这里有几个问题: 1)你在哪里打电话qmlRegisterType<MyObject>("can.myapp", 1, 0, "CANService");我的理解是,在你实例化main之前,需要在QtQuickApplicationViewer方法中调用它(如果你以这种方式加载它)。

2)这是否适用于一个简单的例子(将简单的QString值传递给函数)?

我目前没有在Qt中积极编码,但希望这可以指出你正确的方向:

这里是&#34;主要&#34;我的一个应用程序使用自定义组件的方法(通过命令行进行简单的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();
}

这是一个简化的类(这些类是~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

理论上你现在可以在QML中调用它:

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

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

}

我建议做一些非常简单的事情,以确保管道中没有问题,然后,如果有效,请逐个方法查看是否有另一个电话&#39;阻止某事。我没有完全来源的最佳猜测是,它可能是您注册组件的地方。