从Qt中的类调用槽

Calling slots from a Class in Qt

本文关键字:调用 Qt      更新时间:2023-10-16

我正在尝试编程一个从服务器获取文件的应用程序。

我有一个"Window"类(mainwindow.cpp,这是一个小部件类,它将是UI),然后我还有一个"Backend"类(Backend.cpp)。

GUI有一个按钮和两个单选按钮。如果选择了单选按钮"remote",那么单击该按钮将导致从服务器获取文件。

然而,在Backend.cpp中的"connect"调用中存在一些问题,我无法解决。我得到的错误是:没有匹配的函数调用"QObject::connect(QNetworkReply*&),const char[13],Backend*const,const char[20])"

以下是代码:

答案:避免圆形夹杂物!!!!以下是更新后的代码:

主窗口.h

#ifndef WINDOW_H
#define WINDOW_H
#include <QWidget>
#include <QRadioButton>
#include <QtNetwork/QTcpSocket>
#include <QtNetwork/QHostAddress>
#include <QFile>
#include <QUrl>
#include "Backend.h"
class QGroupBox;
class Window : public QWidget
{
    Q_OBJECT
public:
    Window(QWidget *parent = 0);
    QTcpSocket *conn;
    QFile *file;
    QUrl url;
    Backend backend_inst;
private:
    QRadioButton *button_local;
    QRadioButton *button_remote;
    QGroupBox *createPushButtonGroup();

private slots:
    void onClick_button1();
    void onCheck_local();
    void onCheck_remote();
};
#endif

主窗口.c

#include <QtGui>
#include "mainwindow.h"
Window::Window(QWidget *parent)
    : QWidget(parent)
{
    QGridLayout *grid = new QGridLayout;
    grid->addWidget(createPushButtonGroup(), 1, 1);
    setLayout(grid);
    setWindowTitle(tr("File-Fetch App"));
    resize(480, 420);
}
QGroupBox *Window::createPushButtonGroup()
{
    QGroupBox *groupBox = new QGroupBox();
    QPushButton *pushButton1 = new QPushButton(tr("Fetch Files!!"));
    button_local = new QRadioButton(tr("&Download Files from Local Storage"));
    button_remote = new QRadioButton(tr("&Download Files from a Web-Server"));
    button_local->setChecked(1);

    connect(pushButton1,SIGNAL(clicked()), this, SLOT(onClick_button1()));
    QVBoxLayout *vbox = new QVBoxLayout;
    vbox->addWidget(pushButton1);
    vbox->addSpacing(50);
    vbox->addWidget(button_local);
    vbox->addWidget(button_remote);
    vbox->addStretch(1);
    groupBox->setLayout(vbox);
    return groupBox;
}
void Window::onClick_button1()
{
    QTextStream out(stdout);
    out << "fetch button clickedn";
    if (button_local->isChecked()){
        onCheck_local();
    }
    else if (button_remote->isChecked()){
         onCheck_remote();
    }
}
void Window::onCheck_local()
{
    QTextStream out(stdout);
    out << "local update button checkedn";
}
void Window::onCheck_remote()
{
    QTextStream out(stdout);
    out << "remote update button checkedn";
    QString pathname= "http://192.168.1.1:8000/example.txt";
    QUrl webaddr = pathname;
   backend_inst.FetchFile(webaddr);
}

后端.h

#ifndef BACKEND_H
#define BACKEND_H
#include <QObject>
#include <QNetworkReply>
#include <QNetworkAccessManager>
#include <QUrl>
#include <QTextStream>
class Backend : public QObject
{
    Q_OBJECT
public:
    Backend(QObject* parent=0);
    void FetchFile(QUrl fpath);
public slots:
    void getBytesFromFile();
private:
    QNetworkReply *reply;
    QNetworkAccessManager qnam;
};
#endif // BACKEND_H

后端.cpp

#include "Backend.h"

Backend::Backend(QObject* parent)
    : QObject(parent)
{
}
void Backend::FetchFile(QUrl fpath)
{
    reply = qnam.get(QNetworkRequest(fpath));
    QObject::connect(reply, SIGNAL(readyRead()),this, SLOT(getBytesFromFile()));
    //qnam = new QNetworkAccessManager;
    //QObject::connect(&qnam, SIGNAL(finished(QNetworkReply*)), this, SLOT(getBytesFromFile()));
}
void Backend::getBytesFromFile(){
    QByteArray downloadedData;
    QTextStream out(stdout);
    out << "we are loading data from URLn";
    downloadedData =reply->readAll();
    out << downloadedData;
    delete reply;
}

main.cpp

#include <QApplication>
#include "mainwindow.h"
int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    Window window;
    window.show();
    return app.exec();
}

要使用信号和插槽,您的类(包括信号和插槽)必须派生自QObject,即

#include "mainwindow.h"
#include <QObject>
class Backend : public QObject
{
    Q_OBJECT
public:
    Backend(QObject* parent=0);
[...]
Backend::Backend(QObject* parent)
    : QObject(parent)
{
}

你发布了这个:

class Backend
{
    // Q_OBJECT
public:
    Backend();
    void FetchFile(QUrl fpath);
public slots:
    void getBytesFromFile();
private:
    QNetworkReply *reply;
    QNetworkAccessManager qnam;
};

如果是的话,Q_OBJECT仍然会被注释。删除它。您正在使用信号和插槽。。

编辑:尽量避免圆形夹杂物:您在主窗口中包含了后端,反之亦然。。

注释行:

qnam = new QNetworkAccessManager;
QObject::connect(&qnam, SIGNAL(finished(QNetworkReply*)), this, SLOT(getBytesFromFile()));

是什么导致了你的问题。Connect排除指针,而不是指向指针的指针。qnam

是指针在以前版本的代码中是指针,在上面使用运算符的地址会将其变成指向指针的指针。第二个错误是,您需要对信号和插槽使用相同的签名才能调用它(否则会出现运行时错误)。所以,正确地说:
connect(qnam, SIGNAL(finished(QNetworkReply*)), this, SLOT(getBytesFromFile(QNetworkReply*)));

(显然,更改getBytesFromFile方法的实际签名)。

至于为什么尽管注释掉了代码,但您的错误仍然存在:我认为您正在运行一个旧的构建,而新的构建由于vtable问题而失败(正如您在注释线程中所描述的)。我的猜测是qmake出现了故障,这是我在将Q_OBJECT宏添加到现有类时遇到的。转到您的构建文件夹并在各处删除Makefile*。然后返回Qt创建者并重新构建项目,这将迫使qmake再次生成Makefiles。

构建机制似乎有一些问题。带有已发布代码和未评论QObject::connect(&qnam,SIGNAL(finished(QNetworkReply*)),this,SLOT(getBytesFromFile());在Backend::FetchFile函数中,您的所有代码都可以工作。运行并选中"从Web服务器下载文件",它会从getBytesFromFile打印"我们正在从URL加载数据"-这不是你想要调用的插槽吗?