QML Connections在Qt6中不能正常运行

QML Connections cannot run normally in Qt6

QML 连接问题

qrc:/main.qml:12:5: QML Connections: Detected function "onTop" in Connections element. This is probably intended to be a signal handler but no signal of the target matches the name.
qrc:/main.qml:13: ReferenceError: classA is not defined

如图所示,我不能link我的Qt Signal 问题是 QML 无法识别我的 Qt 信号 void onTop(),我该如何解决?在 Qt 6 中 感觉QML问题多,不如传统QWidget好用,相关资料也少

头文件

#pragma once
#include <QOBject>
#include <QUdpSocket>
class CupSingleHelper : public QObject
{
    Q_OBJECT
    Q_PROPERTY(NOTIFY onTop)
public:
    CupSingleHelper(QObject *parent = nullptr);
    ~CupSingleHelper();
public:
    void initSocket();
    void setAppPid(qint64 app_pid);
    void readData();
    Q_INVOKABLE void printStr2();
public:
    QUdpSocket* udp_socket = nullptr;
    qint64 pid;
public slots:
    void printStr();

signals:
    void onTop();
};

cpp 文件

#include "CupSingleHelper.h"
#include <QNetWorkDatagram>
#include <qmessagebox.h>
#include <QDebug>
CupSingleHelper::CupSingleHelper(QObject* parent)
{
    
}

void CupSingleHelper::printStr()
{
    qDebug() << "1111111";
}
void CupSingleHelper::printStr2()
{
    qDebug() << "22222";
}

void CupSingleHelper::setAppPid(qint64 app_pid)
{
    this->pid = app_pid;
}

void CupSingleHelper::initSocket()
{
    QString data = ":start";
    data.insert(0, QString::number(pid));

    QByteArray byte_data = data.toLatin1();

    udp_socket = new QUdpSocket(this);
    bool sStatus = false;
    sStatus = udp_socket->bind(QHostAddress::LocalHost, 8898);
    if (sStatus == false) { udp_socket->writeDatagram(byte_data, QHostAddress::LocalHost, 8889); exit(1); }
    connect(udp_socket, &QUdpSocket::readyRead, this, &CupSingleHelper::readData);

    udp_socket->writeDatagram(byte_data, QHostAddress::LocalHost, 8889);
}

void CupSingleHelper::readData()
{
    while (udp_socket->hasPendingDatagrams())
    {
        QNetworkDatagram datagram = udp_socket->receiveDatagram();
        QString receive_data = datagram.data().data();
        QString temp = receive_data.section(":", 0, 0);
        if (temp.toInt() == pid)
        {
            break;
        }
        temp = receive_data.section(":", 1, 1);
        if (temp.compare("start") == 0)
        {
            emit  onTop();
        }
    }
}

CupSingleHelper::~CupSingleHelper()
{
    if(udp_socket != nullptr)
    {
        delete[]udp_socket;
    }
}

main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QTranslator>
#include <QLocale>
#include "CupSingleHelper.h"

int main(int argc, char *argv[])
{
#if defined(Q_OS_WIN)
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif
    QGuiApplication app(argc, argv);

    CupSingleHelper cup_single_helper;
    qint64 app_pid = QCoreApplication::applicationPid();
    cup_single_helper.setAppPid(app_pid); //set process id
    cup_single_helper.initSocket();//init udpsocket to listen


    QTranslator t;
    QLocale ql;
    //Check system language and load
    if (ql.language() == QLocale::Chinese)
    {
        bool status = t.load(":/x64/Debug/cuptools_zh.qm");
    }
    if (ql.language() != QLocale::English)
    {
        app.installTranslator(&t);
    }


    QQmlApplicationEngine engine;
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    if (engine.rootObjects().isEmpty())
        return -1;
    
    QQmlContext* rootContext = engine.rootContext();
    rootContext->setContextProperty("classA",&cup_single_helper);

    return app.exec();
}

main.qml

import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Controls 2.2

Window {
    visible: true
    width: 500
    height: 720
    title: qsTr("CupTools") 
    property var strd: "22222"
    
    Connections {
       target: classA
         function onTop(){ 
           label12.text = strd 
         }
    }

    Text {
     id: label12
     anchors {
        top: parent.top
        horizontalCenter: parent.horizontalCenter
        topMargin: 20
     }
     text:"11111"
    }

    Button {
         id: mbutton
         anchors.centerIn:parent
         text: "Click"
         onClicked: classA.printStr()
    }
}

您的代码存在以下问题:

  • 如果你要声明一个信号,那么你不应该使用 Q_PROPERTY。删除 Q_PROPERTY(NOTIFY onTop).

  • 您必须在加载 .qml 之前建立上下文属性,否则在加载时 objects 将不会被定义。

  • 如果你想连接一个信号那么语法是on<signal>其中<signal>必须是驼峰格式,在你的情况下它必须是onOnTop。

  • 在 Qt6 中,不需要 QML 模块的版本。

  • 因为 udp_socket 是 class 的 child 那么没有必要消除它,因为它会导致分段错误,因为你正在消除指针 2 次。

#ifndef CUPSINGLEHELPER_H
#define CUPSINGLEHELPER_H

#include <QObject>

class QUdpSocket;

class CupSingleHelper : public QObject
{
    Q_OBJECT
public:
    CupSingleHelper(QObject *parent = nullptr);
    ~CupSingleHelper();
public:
    void initSocket();
    void setAppPid(qint64 app_pid);
    void readData();
    Q_INVOKABLE void printStr2();
public:
    QUdpSocket* udp_socket = nullptr;
    qint64 pid;
public slots:
    void printStr();

signals:
    void onTop();
};

#endif // CUPSINGLEHELPER_H
#include "cupsinglehelper.h"

#include <QNetworkDatagram>
#include <QUdpSocket>

CupSingleHelper::CupSingleHelper(QObject* parent):QObject(parent)
{

}

void CupSingleHelper::printStr()
{
    qDebug() << "1111111";
}
void CupSingleHelper::printStr2()
{
    qDebug() << "22222";
}

void CupSingleHelper::setAppPid(qint64 app_pid)
{
    this->pid = app_pid;
}

void CupSingleHelper::initSocket()
{
    QString data = ":start";
    data.insert(0, QString::number(pid));

    QByteArray byte_data = data.toLatin1();

    udp_socket = new QUdpSocket(this);
    bool sStatus = false;
    sStatus = udp_socket->bind(QHostAddress::LocalHost, 8898);
    if (sStatus == false) { udp_socket->writeDatagram(byte_data, QHostAddress::LocalHost, 8889); exit(1); }
    connect(udp_socket, &QUdpSocket::readyRead, this, &CupSingleHelper::readData);

    udp_socket->writeDatagram(byte_data, QHostAddress::LocalHost, 8889);
}

void CupSingleHelper::readData()
{
    while (udp_socket->hasPendingDatagrams())
    {
        QNetworkDatagram datagram = udp_socket->receiveDatagram();
        QString receive_data = QString::fromUtf8(datagram.data());
        QString temp = receive_data.section(":", 0, 0);
        if (temp.toInt() == pid)
        {
            break;
        }
        temp = receive_data.section(":", 1, 1);
        if (temp.compare("start") == 0)
        {
            emit  onTop();
        }
    }
}

CupSingleHelper::~CupSingleHelper()
{
}
#include "cupsinglehelper.h"

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>


int main(int argc, char *argv[])
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif

    QGuiApplication app(argc, argv);

    CupSingleHelper cup_single_helper;
    qint64 app_pid = QCoreApplication::applicationPid();
    cup_single_helper.setAppPid(app_pid); //set process id
    cup_single_helper.initSocket();//init udpsocket to listen

    QQmlApplicationEngine engine;
    const QUrl url(QStringLiteral("qrc:/main.qml"));
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                     &app, [url](QObject *obj, const QUrl &objUrl) {
        if (!obj && url == objUrl)
            QCoreApplication::exit(-1);
    }, Qt::QueuedConnection);

    QQmlContext* rootContext = engine.rootContext();
    rootContext->setContextProperty("classA",&cup_single_helper);

    engine.load(url);

    return app.exec();
}
import QtQuick
import QtQuick.Window
import QtQuick.Controls

Window {
    visible: true
    width: 500
    height: 720
    title: qsTr("CupTools")
    property string strd: "22222"

    Connections {
        target: classA
        function onOnTop(){
            label12.text = strd
        }
    }

    Text {
        id: label12
        anchors {
            top: parent.top
            horizontalCenter: parent.horizontalCenter
            topMargin: 20
        }
        text:"11111"
    }

    Button {
        id: mbutton
        anchors.centerIn:parent
        text: "Click"
        onClicked: classA.printStr()
    }
}