Brak połączenia QML'a z C++ (QT)

0

Cześć!
Próbuje w Qt połączyć moją bibliotekę "serialportreader" z jednym z przykładów (Planets w Canvas 3D). Gdy dodaje do projektu swoją bibliotekę, to plik main.cpp ją widzi, koloruje składnie itp. ale niestety plik planets.qml już jej nie rozpoznaję i pokazuje błąd:

qrc:/planets.qml5: QML Connections: Cannot assign to non-existent property "onCommandReceived"
qrc:/planets.qml ReferenceError: serialPortReader is not defined>

Dodam, że ten błąd nie pojawiał mi się wcześniej i biblioteka działała normalnie z tym przykładem.
Zapewne nie jest to błąd w kodzie, tylko ja coś źle robię przy dodawaniu tych plików :)
Naprawę szukałem rozwiązania cały dzień i straciłem już cierpliwość.
Może miał ktoś podobny problem?

Z góry dzięki za pomoc.

Kod:

serialportreader.h


#ifndef SERIALPORTREADER_H
#define SERIALPORTREADER_H

#include <QByteArray>
#include <QSerialPort>
#include <QTextStream>
#include <QTimer>


class SerialPortReader : public QObject
{
    Q_OBJECT

public:
    explicit SerialPortReader(QSerialPort *serialPort, QObject *parent = nullptr);

private slots:
    void handleReadyRead();
    void handleTimeout();
    void handleError(QSerialPort::SerialPortError error);

private:
    QSerialPort *m_serialPort = nullptr;
    QByteArray m_readData;
    QString serialBuffer;
    QTextStream m_standardOutput;
    QTimer m_timer;

signals:
    void commandReceived(QString planetNumber, QString mass);
};

#endif // SERIALPORTREADER_H

serialportreader.cpp

#include "serialportreader.h"

#include <QCoreApplication>

SerialPortReader::SerialPortReader(QSerialPort *serialPort, QObject *parent) :
    QObject(parent),
    m_serialPort(serialPort),
    m_standardOutput(stdout)
{
    connect(m_serialPort, &QSerialPort::readyRead, this, &SerialPortReader::handleReadyRead);
    connect(m_serialPort, &QSerialPort::errorOccurred, this, &SerialPortReader::handleError);
    connect(&m_timer, &QTimer::timeout, this, &SerialPortReader::handleTimeout);

    m_timer.start(1000);
    serialBuffer = "";
}

void SerialPortReader::handleReadyRead()
{
  QStringList bufferSplit = serialBuffer.split(",");
  if(bufferSplit.length() < 3){
      m_readData = m_serialPort->readAll();
      serialBuffer += QString::fromStdString(m_readData.toStdString());
  } else {
      m_standardOutput << bufferSplit[1] << endl;
      QStringList commandList = bufferSplit[1].split(" ");
      emit commandReceived(commandList[0], commandList[1]);
      serialBuffer = "";
  }

    if (!m_timer.isActive())
        m_timer.start(1000);
}

void SerialPortReader::handleTimeout()
{
    if (m_readData.isEmpty()) {
        m_standardOutput << QObject::tr("No data was currently available "
                                        "for reading from port %1 %2")
                            .arg(m_serialPort->portName())
                            .arg(m_serialPort->errorString())
                         << endl;
    } else {
        m_standardOutput << QObject::tr("Data successfully received from port %1")
                           .arg(m_serialPort->portName())
                         << endl;
    }

    //QCoreApplication::quit();
}

void SerialPortReader::handleError(QSerialPort::SerialPortError serialPortError)
{
    if (serialPortError == QSerialPort::ReadError) {
        m_standardOutput << QObject::tr("An I/O error occurred while reading "
                                        "the data from port %1, error: %2")
                            .arg(m_serialPort->portName())
                            .arg(m_serialPort->errorString())
                         << endl;
        QCoreApplication::exit(1);
    }
}

main.cpp

#include <QtGui/QGuiApplication>
#include <QtCore/QDir>
#include <QtQuick/QQuickView>
#include <QtQml/QQmlEngine>

#include <QStringList>
#include <QTextStream>

#include <QSerialPort>
#include <QSerialPortInfo>
#include <QStringList>
#include <QTextStream>

#include "serialportreader.h"

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

    //---------------------------------------------------------
    QSerialPort serialPort;
    QSerialPortInfo serialPortInfo;

    bool nano_is_connected = false;

    QString serialPortName;

    foreach(const QSerialPortInfo &serialPortInfo, QSerialPortInfo::availablePorts()){
        if(serialPortInfo.hasProductIdentifier() && serialPortInfo.hasVendorIdentifier()){
            if(serialPortInfo.productIdentifier() == 0 && serialPortInfo.vendorIdentifier() == 0){
                nano_is_connected = true;
                serialPortName = serialPortInfo.portName();
            }
        }
    }
    if(nano_is_connected){
    serialPort.setPortName(serialPortName);
    serialPort.open(QSerialPort::ReadOnly);
    serialPort.setBaudRate(9600);
    //serialPort.setDataBits(QSerialPort::Data8);
   // serialPort.setParity(QSerialPort::NoParity);
   // serialPort.setStopBits(QSerialPort::OneStop);
   // serialPort.setFlowControl(QSerialPort::NoFlowControl);
    SerialPortReader serialPortReader(&serialPort);
    }
    //------------------------------------------------------------



    QQuickView viewer;

    // The following are needed to make examples run without having to install the module
    // in desktop environments.
#ifdef Q_OS_WIN
    QString extraImportPath(QStringLiteral("%1/../../../../%2"));
#else
    QString extraImportPath(QStringLiteral("%1/../../../%2"));
#endif
    viewer.engine()->addImportPath(extraImportPath.arg(QGuiApplication::applicationDirPath(),
                                                       QString::fromLatin1("qml")));

    viewer.setSource(QUrl("qrc:/planets.qml"));

    viewer.setTitle(QStringLiteral("Qt Canvas 3D Examples - Planets"));
    viewer.setResizeMode(QQuickView::SizeRootObjectToView);
    viewer.setColor(Qt::black);
    viewer.showFullScreen();

    return app.exec();
}

planets.qml

import QtQuick 2.0
import QtCanvas3D 1.0

import "planets.js" as GLCode

Item {
    id: mainview
    width: 1280
    height: 768
    visible: true
    property int focusedPlanet: 100
    property int oldPlanet: 0
    property real xLookAtOffset: 0
    property real yLookAtOffset: 0
    property real zLookAtOffset: 0
    property real xCameraOffset: 0
    property real yCameraOffset: 0
    property real zCameraOffset: 0
    property real cameraNear: 0
    property int sliderLength: (width < height) ? width / 2 : height / 2
    property real textSize: (sliderLength < 320) ? (sliderLength / 20) : 16
    property real planetButtonSize: (height < 768) ? (height / 11) : 70


    property int mansMass: 0 

    Connections {
        target: serialPortReader // <------w tym miejscu pokazuje błąd
        onCommandReceived: {
           switch (planetNumber){
            case "1":
                mainview.focusedPlanet = 1
                break
            case "2":
                mainview.focusedPlanet = 2
                break
            case "3":
                mainview.focusedPlanet = 3
                break
            case "4":
                mainview.focusedPlanet = 4
                break
            case "5":
                mainview.focusedPlanet = 5
                break
            case "6":
                mainview.focusedPlanet = 6
                break
            case "7":
                mainview.focusedPlanet = 7
                break
            case "8":
                mainview.focusedPlanet = 8
                break
            case "9":
                mainview.focusedPlanet = 9
                break
            case "0":
                mainview.focusedPlanet = 0
                break
            default:
                mainview.focusedPlanet = 100
                break
            }
            mansMass = parseInt(mass)
        }
    }
...
1

Jeśli korzystasz z Qt Creatora dobrze przyjrzyj się plikowi .pro, zapewne niepoprawnie podpiąłeś swoje pliki źródłowe.

0

@MasterBLB:
Plik .pro wygląda tak ale nadal nie ma połączenia.

TEMPLATE = app

QT += qml quick \
    serialport
target.path = $$[QT_INSTALL_EXAMPLES]/canvas3d/threejs/$$TARGET
INSTALLS += target

HEADERS += \
    serialportreader.h

SOURCES += \
    main.cpp \
    serialportreader.cpp

OTHER_FILES += *.qml \
               planets.js \
               doc/src/* \
               doc/images/*

RESOURCES += planets.qrc

ios {
    ios_icon.files = $$files($$PWD/ios/AppIcon*.png)
    QMAKE_BUNDLE_DATA += ios_icon
    QMAKE_INFO_PLIST = ios/Info.plist
}

EXAMPLE_FILES += \
    ios

0

To serialport to tylko te 2 pliki h i cpp, czy dodatkowo jakiś .lib?
Ponadto popatrz w Qt Assistancie co piszą na temat budowania aplikacji QML, a zwłaszcza używaniu własnych klas. Niestety, sam takich aplikacji nie tworzyłem ale mam podejrzenia, że i do pliku qml musisz odpowiednio serialporta zaimportować.

0

@MasterBLB:
Nie, te pliki to jedyne pliki tej biblioteki. Co ciekawe, to biblioteka łączy się normalnie z przykładem Planets w QML (działa komunikacja i nie ma tego błędu) ale nie łączy się z przykładem w Canvas3D (tego na którym mi zależy).

0

Po pierwsze serialPortReader istnieje tylko przez moment. Po wyjsciu ze scope przestaje istniec. Proponuje cos takiego:

SerialPortReader *serialPortReader = nullptr;
if(nano_is_connected){
...
    serialPortReader = new(&serialPort);
}

Po drugie chyba zapomniales o ustawieniu context property. Doaj cos takieg przed zaladowaniem qmla:

viewer.rootContext()->setContextProperty("serialPortReader", serialPortReader);

Edit: Zastanow sie co w ogole program powinien robic jesli nano_is_connected == false. Bo wtedy bedziesz mial w qmlu serialPortReader nulla.

0

@git:
Dzięki już sam znalazłem problem. Miałem tutaj o tym napisać jak wrócę do domu ale mnie ubiegłeś :) Właśnie zapomniałem dodać tej linijki do kodu i dlatego nie działało (wcześniej dodałem ją do przykładu z QML'a i działało ale zapomniałem o niej w przykładzie z Canvasem 3D ;) ) Dodatkowo należało dodać bibliotekę QQmlContext. Teraz działa wszystko ładnie. Serio czasem oderwanie się od kodu na kawę wystarczy i człowiek od razu dostrzega błąd ;)
Kod:

#include <QtGui/QGuiApplication>
#include <QtCore/QDir>
#include <QtQuick/QQuickView>
#include <QtQml/QQmlEngine>

#include <QStringList>
#include <QTextStream>
#include <QQmlContext> //------------------------------------zapomniałem o tym------------------------------

#include <QSerialPort>
#include <QSerialPortInfo>
#include <QStringList>
#include <QTextStream>

#include "serialportreader.h"

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

    //---------------------------------------------------------
    QSerialPort serialPort;
    QSerialPortInfo serialPortInfo;

    bool nano_is_connected = false;

    QString serialPortName;

    foreach(const QSerialPortInfo &serialPortInfo, QSerialPortInfo::availablePorts()){
        if(serialPortInfo.hasProductIdentifier() && serialPortInfo.hasVendorIdentifier()){
            if(serialPortInfo.productIdentifier() == 0x7523 && serialPortInfo.vendorIdentifier() == 0x1a86){
                nano_is_connected = true;
                serialPortName = serialPortInfo.portName();
            }
        }
    }
    if(nano_is_connected){
    serialPort.setPortName(serialPortName);
    serialPort.open(QSerialPort::ReadOnly);
    serialPort.setBaudRate(9600);
    //serialPort.setDataBits(QSerialPort::Data8);
   // serialPort.setParity(QSerialPort::NoParity);
   // serialPort.setStopBits(QSerialPort::OneStop);
   // serialPort.setFlowControl(QSerialPort::NoFlowControl);
    }
    //------------------------------------------------------------


    QQuickView viewer;

    SerialPortReader serialPortReader(&serialPort);

    //-----------------------------------------------------------------------------------
    viewer.rootContext()->setContextProperty("serialPortReader", &serialPortReader); // -----zapomniałem o tym-----
    //-----------------------------------------------------------------------------------

    // The following are needed to make examples run without having to install the module
    // in desktop environments.
#ifdef Q_OS_WIN
    QString extraImportPath(QStringLiteral("%1/../../../../%2"));
#else
    QString extraImportPath(QStringLiteral("%1/../../../%2"));
#endif
    viewer.engine()->addImportPath(extraImportPath.arg(QGuiApplication::applicationDirPath(),
                                                       QString::fromLatin1("qml")));

    viewer.setSource(QUrl("qrc:/planets.qml"));

    viewer.setTitle(QStringLiteral("Qt Canvas 3D Examples - Planets"));
    viewer.setResizeMode(QQuickView::SizeRootObjectToView);
    viewer.setColor(Qt::black);
    viewer.showFullScreen();

    return app.exec();
}

I tak dzięki wielkie za pomoc chłopaki.
Pozdrawiam.

1 użytkowników online, w tym zalogowanych: 0, gości: 1