Qt4_写FTP客户端

2023-11-05

写FTP客户端

QFtp类在Qt中实现了FTP协议的客户端程序,它提供了非常多的函数来执行多数常见的FTP操作,同时还可以执行任意的FTP指令。

QFtp类是异步工作的。若调用一个像get()或者put()这样的函数,它会立即返回并且仅在控制权回到Qt的事件循环时才发生数据传输。这样就确保了在执行FTP指令时,用户界面可以保持响应。

我们将从如何使用get()函数获取一个单一文件的例子 开始讲起。该例子是一个名为ftpget的控制台应用程序,它可以下载指定命令行上的远程文件。首先看看main()主函数:

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);
    QStringList args = QCoreApplication::arguments();

    if (args.count() != 2) {
        std::cerr << "Usage: ftpget url" << std::endl
                  << "Example:" << std::endl
                  << "    ftpget ftp://ftp.trolltech.com/mirrors"
                  << std::endl;
        return 1;
    }

    FtpGet getter;
    if (!getter.getFile(QUrl(args[1])))
        return 1;

    QObject::connect(&getter, SIGNAL(done()), &app, SLOT(quit()));

    return app.exec();
}

我们要创建一个QCoreApplication而不是它的子类QAplication,以避免连接到QtGui库。QCoreApplication::arguments()函数返回命令行参数作为一个QStingList列表,采用第一项作为程序被调用时的名称,同时删除掉诸如-style型的所有Qt指定的参数。main()函数的核心是构建FtpGet对象和getFile()调用。如果该函数调用成功,就会让事件循环一直运行下去,直到下载完毕。

FtpGet子类完成了所有的工作,其子类的定义如下:

class FtpGet : public QObject
{
    Q_OBJECT

public:
    FtpGet(QObject *parent = 0);

    bool getFile(const QUrl &url);

signals:
    void done();

private slots:
    void ftpDone(bool error);

private:
    QFtp ftp;
    QFile file;
};

这个类有一个公有函数getFile(),可用来获取由URL指定的文件。QUrl 类提供了一个高级接口,用来提取URL的不同部分,如文件名称、路径、协议和端口。

FtpGet有一个私有槽fitpDone(),当文件传输完成时,就会调用它;而当文件下载完成后,它将发送一个done()信号。这个类还有两个私有变量:ftp变量和file变量,前者的类型为QFtp,封装一个到FTP服务器的连接;后者用来向磁盘写入所下载的文件。

FtpGet::FtpGet(QObject *parent)
    : QObject(parent)
{
    connect(&ftp, SIGNAL(done(bool)), this, SLOT(ftpDone(bool)));
}

在构造函数中,我们把QFtp::done( bool)信号与ftpDone( bool)私有槽连接起来。当所有的请求都已处理完时,QFtp就发射done( bool)信号,bool参数指明是否有错误发生。

bool FtpGet::getFile(const QUrl &url)
{
    if (!url.isValid()) {
        std::cerr << "Error: Invalid URL" << std::endl;
        return false;
    }

    if (url.scheme() != "ftp") {
        std::cerr << "Error: URL must start with 'ftp:'" << std::endl;
        return false;
    }

    if (url.path().isEmpty()) {
        std::cerr << "Error: URL has no path" << std::endl;
        return false;
    }

    QString localFileName = QFileInfo(url.path()).fileName();
    if (localFileName.isEmpty())
        localFileName = "ftpget.out";

    file.setFileName(localFileName);
    if (!file.open(QIODevice::WriteOnly)) {
        std::cerr << "Error: Cannot write file "
                  << qPrintable(file.fileName()) << ": "
                  << qPrintable(file.errorString()) << std::endl;
        return false;
    }

    ftp.connectToHost(url.host(), url.port(21));
    ftp.login();
    ftp.get(url.path(), &file);
    ftp.close();
    return true;
}

getFile()函数首先检查传人的URL。如果遇到问题,该函数将打印出一条出错信息到cerr,同时返回false以表明下载失败。

通过对ftpget.out的备份,我们可以试图利用URL自身创建一个合理的本地文件名而不是让用户自己虚构一个文件名。如果打开文件失败,就会打印出错信息并返回false。

接着,利用QFtp对象执行一个含4个FTP指令的序列。url.port(21)调用返回在URL中指定的端口号;如果在URL中并未指定任何端口号,则返回端口21。因为没有给login()函数任何用户名或者密码,所以此处需要一个匿名登录。get()中的第二个参数指定了输出信号的I/O设备。

这些FTP指令在Qt的事件循环中排队并等待执行。QFtp 的done(bool)信号表明这些指令的完成情况,构造函数中已经把这个信号与ftpDone(bool)连接起来了。

void FtpGet::ftpDone(bool error)
{
    if (error) {
        std::cerr << "Error: " << qPrintable(ftp.errorString())
                  << std::endl;
    } else {
        std::cerr << "File downloaded as "
                  << qPrintable(file.fileName()) << std::endl;
    }
    file.close();
    emit done();
}

这些FTP指令一旦得以执行,就可以关闭相应的文件并且发射我们自己的done()信号。在此处关闭文件而不在getFile()函数最后通过调用ftp.close()来关闭文件,显得有些不同寻常;但是请牢记:在返回getFile()函数之后,FTP指令会异步执行并且整个执行过程会非常顺利。

QFtp提供了一些FTP指令,包括connectToHost()、login()、close()、list()、cd()、get()、put()、remove()、mkdir()、rmdir()和rename()。所有这些函数都可以调度一个 FTP指令,并且可以返回一个标识这个指令的ID号。对于传输模式(默认为被动模式)和传输类型(默认为二进制数据)的控制,也是可能的。

使用rawCommand()可以执行任意的FTP指令。例如,以下是如何执行一个SITE CHMOD指令的代码:
ftp. rawCommand(“SITE CHMOD 755 fortune”);
当QFtp开始执行一个指令的时候,它发射commandStarted(int)信号,而当这个指令完成的时候,它发射commandFinished(int, bool)信号。int 参数是标识一个指令的ID号。如果对个别指令的结果感兴趣,则当调用这些指令的时候,可以保存这些ID号。了解并记录这些ID号可以为用户提供详细的反馈信息。例如:

bool FtpGet::getFile(const QUrl &url)
{
    ...
    connectId = ftp.connectToHost(url.host(), url.port(21));
    loginId = ftp.login();
    getId = ftp.get(url.path(), &file);
    closeId = ftp.close();
    return true;
}

void FtpGet::ftpCommandStarted(int id)
{
    if(id == connectId)
    {
        std::cerr << "Connecting..." << std::endl;
    }
    else if(id == loginId)
    {
        std::cerr << "Logging in..." << std::endl;
    }
    ...
}

ftpget.h

#ifndef FTPGET_H
#define FTPGET_H

#include <QFile>
#include <QFtp>

class QUrl;

class FtpGet : public QObject
{
    Q_OBJECT

public:
    FtpGet(QObject *parent = 0);

    bool getFile(const QUrl &url);

signals:
    void done();

private slots:
    void ftpDone(bool error);

private:
    QFtp ftp;
    QFile file;
};

#endif

ftpget.cpp

#include <QtCore>
#include <QtNetwork>
#include <iostream>

#include "ftpget.h"

FtpGet::FtpGet(QObject *parent)
    : QObject(parent)
{
    connect(&ftp, SIGNAL(done(bool)), this, SLOT(ftpDone(bool)));
}

bool FtpGet::getFile(const QUrl &url)
{
    if (!url.isValid()) {
        std::cerr << "Error: Invalid URL" << std::endl;
        return false;
    }

    if (url.scheme() != "ftp") {
        std::cerr << "Error: URL must start with 'ftp:'" << std::endl;
        return false;
    }

    if (url.path().isEmpty()) {
        std::cerr << "Error: URL has no path" << std::endl;
        return false;
    }

    QString localFileName = QFileInfo(url.path()).fileName();
    if (localFileName.isEmpty())
        localFileName = "ftpget.out";

    file.setFileName(localFileName);
    if (!file.open(QIODevice::WriteOnly)) {
        std::cerr << "Error: Cannot write file "
                  << qPrintable(file.fileName()) << ": "
                  << qPrintable(file.errorString()) << std::endl;
        return false;
    }

    ftp.connectToHost(url.host(), url.port(21));
    ftp.login();
    ftp.get(url.path(), &file);
    ftp.close();
    return true;
}

void FtpGet::ftpDone(bool error)
{
    if (error) {
        std::cerr << "Error: " << qPrintable(ftp.errorString())
                  << std::endl;
    } else {
        std::cerr << "File downloaded as "
                  << qPrintable(file.fileName()) << std::endl;
    }
    file.close();
    emit done();
}

main.cpp

#include <QtCore>
#include <iostream>

#include "ftpget.h"

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);
    QStringList args = QCoreApplication::arguments();

    if (args.count() != 2) {
        std::cerr << "Usage: ftpget url" << std::endl
                  << "Example:" << std::endl
                  << "    ftpget ftp://ftp.trolltech.com/mirrors"
                  << std::endl;
        return 1;
    }

    FtpGet getter;
    if (!getter.getFile(QUrl(args[1])))
        return 1;

    QObject::connect(&getter, SIGNAL(done()), &app, SLOT(quit()));

    return app.exec();
}

在这里插入图片描述
提供反馈的另一种方式是与QFtp的stateChanged()信号连接,只要连接进入了一个新状态(QFtp::Connecting、QFtp::Connected、QFtp::LoggedIn,等等),就会发射stateChanged()信号。

在绝大多数应用程序中,我们仅仅对整个指令序列的结果而不是对其中某个特别的指令感兴趣。这时,可以只简单地连接done(bool)信号,一旦指令队列变空,就会发射这个信号。

当错误发生时,QFtp会自动清空指令队列。也就是说,如果这次连接或者登录失败,位于队列后面的指令将不会执行。但如果在错误发生之后使用同一个QFtp对象调用新的指令序列,那么这些指令将会排队等待执行。

在应用程序的.pro文件中,需要如下的命令行来连接到QtNetwork数据库:

QT += network

现在来看一个更高级的例子。Spider 命令行程序下载一个FTP目录下的所有文件,它将从所有目录的子目录中递归下载这些文件。在Spider类中体现了网络的逻辑联系:

#ifndef SPIDER_H
#define SPIDER_H

#include <QFtp>
#include <QStringList>

class QFile;

class Spider : public QObject
{
    Q_OBJECT

public:
    Spider(QObject *parent = 0);

    bool getDirectory(const QUrl &url);

signals:
    void done();

private slots:
    void ftpDone(bool error);
    void ftpListInfo(const QUrlInfo &urlInfo);

private:
    void processNextDirectory();

    QFtp ftp;
    QList<QFile *> openedFiles;
    QString currentDir;
    QString currentLocalDir;
    QStringList pendingDirs;
};

#endif

我们将开始目录指定为QUrl,并且使用getDirectory()来设置开始目录:

Spider::Spider(QObject *parent)
    : QObject(parent)
{
    connect(&ftp, SIGNAL(done(bool)), this, SLOT(ftpDone(bool)));
    connect(&ftp, SIGNAL(listInfo(const QUrlInfo &)),
            this, SLOT(ftpListInfo(const QUrlInfo &)));
}

在构造函数中,建立了两个信号-槽的连接。当为所获取的每一个文件请求一个目录列表[在getDirectory()中]时,QFtp 就会发射listInfo(const QUrlInfo &)信号。这个信号被连接到一个名为ftpListInfo()的槽,它会下载与URL相关的给定文件。

bool Spider::getDirectory(const QUrl &url)
{
    if (!url.isValid()) {
        std::cerr << "Error: Invalid URL" << std::endl;
        return false;
    }

    if (url.scheme() != "ftp") {
        std::cerr << "Error: URL must start with 'ftp:'" << std::endl;
        return false;
    }

    ftp.connectToHost(url.host(), url.port(21));
    ftp.login();

    QString path = url.path();
    if (path.isEmpty())
        path = "/";

    pendingDirs.append(path);
    processNextDirectory();

    return true;
}

当调用getDirectory()函数时,它首先要做一些检查,如果一切正常,就试图建立一个 FTP连接。它对必须要处理的路径进行跟踪,并调用processNextDirectory(),以开始下载根目录中的文件。

void Spider::processNextDirectory()
{
    if (!pendingDirs.isEmpty()) {
        currentDir = pendingDirs.takeFirst();
        currentLocalDir = "downloads/" + currentDir;
        QDir(".").mkpath(currentLocalDir);

        ftp.cd(currentDir);
        ftp.list();
    } else {
        emit done();
    }
}

processNextDirectory()函数从pendingDirs列表中取出第一个远程目录,同时在本地文件系统中创建一个相应的目录。然后它告诉QFtp对象将目录更改为被取出的目录并列出其中的文件。对于list()处理的每一个文件,它都将发射一个促使ftpListInfo()槽被调用的listInfo()信号 。

如果没有需要处理的目录了,该函数将发射done()信号以表明下载完成。

void Spider::ftpListInfo(const QUrlInfo &urlInfo)
{
    if (urlInfo.isFile()) {
        if (urlInfo.isReadable()) {
            QFile *file = new QFile(currentLocalDir + "/"
                                    + urlInfo.name());

            if (!file->open(QIODevice::WriteOnly)) {
                std::cerr << "Warning: Cannot write file "
                          << qPrintable(QDir::toNativeSeparators(
                                        file->fileName()))
                          << ": " << qPrintable(file->errorString())
                          << std::endl;
                return;
            }

            ftp.get(urlInfo.name(), file);
            openedFiles.append(file);
        }
    } else if (urlInfo.isDir() && !urlInfo.isSymLink()) {
        pendingDirs.append(currentDir + "/" + urlInfo.name());
    }
}

ftpListInfo()槽的urlInfo参数提供了有关一个远程文件的详细信息。如果这个文件只是一个可读的普通文件(而不是目录),就调用get()来下载它。这个用于下载的QFile对象是利用new函数以及一个指向它在openedFiles 列表中存储的指针来分配的。

如果QUlInfo持有一个不是符号连接的远程目录的细节信息,就将这个目录加到pendingDirs列表中。之所以要跳过符号连接,是因为它容易导致无穷递归循环。

void Spider::ftpDone(bool error)
{
    if (error) {
        std::cerr << "Error: " << qPrintable(ftp.errorString())
                  << std::endl;
    } else {
        std::cout << "Downloaded " << qPrintable(currentDir) << " to "
                  << qPrintable(QDir::toNativeSeparators(
                                QDir(currentLocalDir).canonicalPath()));
    }

    qDeleteAll(openedFiles);
    openedFiles.clear();

    processNextDirectory();
}

当所有这些FIP指令都完成后,或者如果有错误发生时,就会调用ftpDone()槽。我们删除QFile对象以防止内存泄漏,同时也关闭每一个文件。最后,调用processNextDirectory()。如果还有需要处理的目录,整个过程将从列表中的下一个目录重新开始;否则,下载过程停止并且发射done()信号。

如果没有错误发生,FTP指令和信号的序列如下:

connectToHost(host, port)
login()
cd(directory_1)
list()
    emit listInfo(file_1_2)
        get(file_1_1)
    emit listInfo(file_1_2)
        get(file_1_2)
    ...
emit done()
...
cd(directory_N)
list()
    emit listInfo(file_N_1)
        get(file_N_1)
    emit listInfo(file_N_2)
        get(file_N_2)
    ...
emit done()

如果打开的文件实际上是一个目录,它将被加入到pendingDirs列表中。在当前list()指令中的最后一个文件被下载完时,就将发出一个新的cd()指令以及下一个待处理目录的list()指令,而整个过程将随一个新目录重新开始。这个过程不断重复,既有新文件被下载也有新目录被添加到pendingDirs列表,直到每一目录下的文件都被下载完,这时pendingDirs 列表也最终将变空。

如果要下载一个目录下的20个文件,当下载到第5个文件的时候,网络发生错误,那么剩下的文件将不会被下载。如果想下载尽可能多的文件,一个解决方案是一次只调用一个GET操作来下载一个文件,并且在调用下一个新的GET操作之前等待done( bool)信号。在listInfo()中,将简单地把文件名追加到一个QStringList中,而不是立即调用get(),而且在done(bool)中,我们将对下一个文件调用get()函数以在QStringList中下载。于是,整个执行顺序看起来可以归结如下:

connectToHost(host, port)
login()
cd(directory_1)
list()
...
cd(directory_N)
list()
    emit listInfo(file_1_2)
    emit listInfo(file_1_2)
    ...
    emit listInfo(file_N_1)
    emit listInfo(file_N_2)
    ...
emit done()
get(file_1_1)
emit done()
get(file_1_2)
emit done()
...
get(file_N_1)
emit done()
get(file_N_2)
...

另外一个解决方案是对每一个文件使用一个QFtp对象。这样可以通过一些单独的FTP连接来并行下载这些文件。

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);
    QStringList args = QCoreApplication::arguments();

    if (args.count() != 2) {
        std::cerr << "Usage: spider url" << std::endl
                  << "Example:" << std::endl
                  << "    spider ftp://ftp.trolltech.com/freebies/"
                  << "leafnode" << std::endl;
        return 1;
    }

    Spider spider;
    if (!spider.getDirectory(QUrl(args[1])))
        return 1;

    QObject::connect(&spider, SIGNAL(done()), &app, SLOT(quit()));

    return app.exec();
}

main()函数完成了这个程序。如果用户没有在命令行中指定一个URL,就给出一个出错信息并终止程序。

在这两个FTP实例中,利用get()函数获得的数据都被写入QFile 中。但这样的做法并不是必需的。如果想把这些数据放到内存中,则可以使用QBuffer,它是一个在QByteAray上操作的QIODevice的子类。例如:

QBuffer *buffer = new QBuffer;
buffer->open(QIODevice::WriteOnly);
ftp.get(urlInfo.name(), buffer);

也可以省略get()中的输入/输出(I/O)设备参数,或者只传递一个空指针。然后每次当有新数据可读的时候,QFtp类就会发射一个readyRead()信号,并且可以使用read()或者readAIl()来读取这些数据。

spider.h

#ifndef SPIDER_H
#define SPIDER_H

#include <QFtp>
#include <QStringList>

class QFile;

class Spider : public QObject
{
    Q_OBJECT

public:
    Spider(QObject *parent = 0);

    bool getDirectory(const QUrl &url);

signals:
    void done();

private slots:
    void ftpDone(bool error);
    void ftpListInfo(const QUrlInfo &urlInfo);

private:
    void processNextDirectory();

    QFtp ftp;
    QList<QFile *> openedFiles;
    QString currentDir;
    QString currentLocalDir;
    QStringList pendingDirs;
};

#endif

spider.cpp

#include <QtCore>
#include <QtNetwork>
#include <iostream>

#include "spider.h"

Spider::Spider(QObject *parent)
    : QObject(parent)
{
    connect(&ftp, SIGNAL(done(bool)), this, SLOT(ftpDone(bool)));
    connect(&ftp, SIGNAL(listInfo(const QUrlInfo &)),
            this, SLOT(ftpListInfo(const QUrlInfo &)));
}

bool Spider::getDirectory(const QUrl &url)
{
    if (!url.isValid()) {
        std::cerr << "Error: Invalid URL" << std::endl;
        return false;
    }

    if (url.scheme() != "ftp") {
        std::cerr << "Error: URL must start with 'ftp:'" << std::endl;
        return false;
    }

    ftp.connectToHost(url.host(), url.port(21));
    ftp.login();

    QString path = url.path();
    if (path.isEmpty())
        path = "/";

    pendingDirs.append(path);
    processNextDirectory();

    return true;
}

void Spider::ftpDone(bool error)
{
    if (error) {
        std::cerr << "Error: " << qPrintable(ftp.errorString())
                  << std::endl;
    } else {
        std::cout << "Downloaded " << qPrintable(currentDir) << " to "
                  << qPrintable(QDir::toNativeSeparators(
                                QDir(currentLocalDir).canonicalPath()));
    }

    qDeleteAll(openedFiles);
    openedFiles.clear();

    processNextDirectory();
}

void Spider::ftpListInfo(const QUrlInfo &urlInfo)
{
    if (urlInfo.isFile()) {
        if (urlInfo.isReadable()) {
            QFile *file = new QFile(currentLocalDir + "/"
                                    + urlInfo.name());

            if (!file->open(QIODevice::WriteOnly)) {
                std::cerr << "Warning: Cannot write file "
                          << qPrintable(QDir::toNativeSeparators(
                                        file->fileName()))
                          << ": " << qPrintable(file->errorString())
                          << std::endl;
                return;
            }

            ftp.get(urlInfo.name(), file);
            openedFiles.append(file);
        }
    } else if (urlInfo.isDir() && !urlInfo.isSymLink()) {
        pendingDirs.append(currentDir + "/" + urlInfo.name());
    }
}

void Spider::processNextDirectory()
{
    if (!pendingDirs.isEmpty()) {
        currentDir = pendingDirs.takeFirst();
        currentLocalDir = "downloads/" + currentDir;
        QDir(".").mkpath(currentLocalDir);

        ftp.cd(currentDir);
        ftp.list();
    } else {
        emit done();
    }
}

main.cpp

#include <QtCore>
#include <iostream>

#include "spider.h"

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);
    QStringList args = QCoreApplication::arguments();

    if (args.count() != 2) {
        std::cerr << "Usage: spider url" << std::endl
                  << "Example:" << std::endl
                  << "    spider ftp://ftp.trolltech.com/freebies/"
                  << "leafnode" << std::endl;
        return 1;
    }

    Spider spider;
    if (!spider.getDirectory(QUrl(args[1])))
        return 1;

    QObject::connect(&spider, SIGNAL(done()), &app, SLOT(quit()));

    return app.exec();
}

在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Qt4_写FTP客户端 的相关文章

  • 包含 Qt 标头的正确方法是什么?

    到目前为止我知道几种方法 includeQt 类 include
  • QChart 对大数据集无响应

    我的这段代码适用于高达 1000 的数据大小 现在我用 65536 个点对其进行了测试 series new QLineSeries QList
  • 如何在 Qt-Creator 中添加自定义构建步骤?

    构建我的应用程序后 我想将其复制到特定目录 在 Windows 7 上 自定义构建步骤 cmd exe c k copy MyPlugin dll HostApp Debug plugins 但我有错误 Can t run process
  • QObject多重继承

    我正在尝试在 C Qt 类中使用 mix 来提供一大堆具有通用接口的小部件 该接口是以这样的方式定义的 如果它被定义为其他小部件类的基类 那么小部件本身将具有这些信号 class SignalInterface public QObject
  • 如何在不同的QT线程中创建一个窗口?

    我有一个应用程序 其中每个线程 主线程除外 都需要创建自己的窗口 我尝试创建一个线程然后调用this gt exec in the run功能 然而 在我接到那个电话之前我就收到了一个错误 ASSERT failure in QWidget
  • QFileDialog 作为 TableView 的编辑器:如何获取结果?

    我正在使用一个QFileDialog作为某些专栏的编辑QTableView 这基本上有效 对一些焦点问题取模 请参阅here https stackoverflow com questions 22854242 qfiledialog as
  • 如何在Qt3D中优化点云渲染

    我正在尝试使用 Qt3D 显示大型点云 20M pts 我第一次发现这个图书馆https github com MASKOR Qt3DPointcloudRenderer https github com MASKOR Qt3DPointc
  • 如何重写(重新实现)QFileSystemModel 中的成员函数

    我已经为此苦苦挣扎了一段时间 Qt s QFileSystemModel由于图标获取算法非常糟糕 在获取数百个文件时速度非常慢 我想完全禁用图标 它们被提取到QFileSystemModel data方法不是虚拟的 QFileSystemM
  • 在信号/槽处理期间删除 QObject

    我知道从槽处理中删除 QObject 可能会使应用程序崩溃 因为它可能有其他排队的事件 因此 我将使用 obj gt deleteLater 而不是使用 delete obj 据我所知 obj 等待处理所有排队的事件 然后 删除 obj Q
  • Qt - QProcess 不工作

    我尝试启动 Internet Explorer 所以我使用下面的代码 QProcess process new QProcess this QString temp C Program Files Internet Explorer iex
  • PySide6.1 与 matplotlib 3.4 不兼容

    当我只安装PySide6时 GUI程序运行良好 但是一旦我安装了matplotlib及其依赖包 包括pyqt5 则GUI程序将无法运行并输出以下错误消息 This application failed to start because no
  • Qt 码头调整大小事件

    有没有办法在 Qt 中捕捉码头的调整大小事件 我需要能够检测到扩展坞何时调整大小 而不仅仅是其位置或 功能 发生变化时 看起来 QDockWidget 没有 调整大小 信号 如果您不希望子类化以仅获得调整大小事件控件 您可以安装事件过滤器
  • Qmake 不支持源目录下的构建目录

    我创建了一个可以在 OS X 上编译和运行的应用程序 我现在想开始让它在 Windows 上运行 首先 我将项目复制到 Windows 机器上并尝试编译 但收到此错误 警告 Qmake不支持源目录下的构建目录 有任何想法吗 将影子构建目录设
  • PyQt:使用 alpha 通道创建 QPixmap,而不是预乘颜色通道

    我想创建一个 QPixmap 来使用 QPainter 进行绘制 QPixmap 应支持透明度 而不使用预乘颜色通道 目前 我通过创建具有所需尺寸的 QPixmap 并用每个通道 包括 alpha 设置为零的 QColor 填充它来实现此目
  • 使用信号和槽更新指针

    我对 Qt 很陌生 请帮我解决这个问题 我正在使用线程在后台执行密集操作 同时我想更新 UI 所以我使用 SIGNALS 和 SLOTS 为了更新 UI 我发出一个信号并更新 UI 让我们考虑下面的示例代码 struct sample QS
  • 更改显示的 DPI 缩放大小使 Qt 应用程序的字体大小渲染得更大

    我使用 Qt 创建了一些 GUI 应用程序 我的 GUI 应用程序包含按钮和单选按钮等控件 当我运行应用程序时 按钮内的按钮和字体看起来正常 当我将显示器的 DPI 缩放大小从 100 更改为 150 或 200 时 无论分辨率如何 控件的
  • 在 Qt 中构建 Android 项目不再有效

    所以我对 Android SDK NDK 和 Apache Ant 进行了一些更新 现在我无法构建任何 Android 项目 我收到一条警告 然后它说找不到 build xml 文件 错误 Warning Android platform
  • 将 QMAKE_CXXFLAGS += -std=c++11 添加到 qt 中的 .pro 文件不起作用(在 linux 12.04 上)

    编译器输出 main o 错误 1 cc1plus 错误 无法识别的命令行选项 std c 11 解决方案是更新系统上的旧 gcc 版本 事实上 我很惊讶你的 12 04 Ubuntu 变体上有这么旧的版本 默认情况下应该有 4 6 3 您
  • 在未安装 Qt VS Tools 的情况下以 Qt/MsBuild 格式编译 Qt 项目

    我在 Visual Studio 中有很多 Qt 项目 使用新的 Qt MsBuild 格式 https blog qt io blog 2018 02 16 qt visual studio improving performance 由
  • 如何搭建qtwayland?

    我花了一整天的时间尝试使用QtWayland Compositor 1 0在 Qt 创建者中 我已经遵循了从那里开始的所有步骤https wiki qt io QtWayland https wiki qt io QtWayland但我收到

随机推荐

  • Go使用Redis 发布和订阅消息

    发布消息 在Go中 Redis客户端库可以提供一个Publish方法来实现消息的发布 不同的Redis客户端库可能有不同的API和方法命名 此处以 v8 为例 v8 版本以下不需要context 下面是一个示例使用go redis库进行Pu
  • 中国佛学66句震撼世界的禅语

    author skate time 2010 06 10 中国佛学66句震撼世界的禅语 1 人之所以痛苦 在于追求错误的东西 2 如果你不给自己烦恼 别人也永远不可能给你烦恼 因为你自己的内心 你放不下 3 你永远要感谢给你逆境的众生 4
  • VM虚拟机桥接模式无法联网解决办法

    1 背景介绍 桥接模式 使虚拟机客户机可以和主机在同一网段 这样 和主机同局域网内的其他主机就也可以ping到虚拟机了 因此 虚拟机设置为桥接模式 且设为静态IP 这样以后就可以方便的使用虚拟机了 2 问题描述 桥接模式之前是好用的 但是主
  • 大话linux运用层访问到硬件驱动层过程

    维哥简述 面试就这么答就OK 今天面试居然忘记了 老司机也翻车 唉 概论流程图 如下图所示 1 当运用程序调用open dev path mode 时 2 虚拟文件系统 vfs 的sys open 函数就会被调用 该函数会在dev path
  • SQLServer中使用加密函数,解密函数

    加密函数 加密 password 要加密的字段 Salt 盐值 pwd 加密后的数据 Create FUNCTION dbo EncryptByPassPhrasePwd password nvarchar 200 Salt nvarcha
  • Unity5.4 Assetbundles官方说明七(在AssetBundle中存储和加载二进制数据)

    转 https blog csdn net u010377179 article details 52922717 第一步是用 bytes 的扩展名保存二进制文件 Unity将把这个文件作为一个TextAsset文本资源 这样就可以打包成A
  • Linux中chown与chmod两个命令的区别详解

    今天小编就为大家分享一篇关于Linux中chown与chmod两个命令的区别详解 小编觉得内容挺不错的 现在分享给大家 具有很好的参考价值 需要的朋友一起跟随小编来看看吧 在linux系统中 chmod和chown命令都可以来设置权限 但他
  • vue项目Error:Cannot find module ‘xxx’ 类报错的解决方法

    现发现只要是报错Error Cannot find module xxx 例如 Error Cannot find module webpack 这类的问题都可以用下面的方法解决 报错内容如下 运行cnpm install没问题 运行cnp
  • 高通平台 Display 杂记

    一 代码位置 User space SurfaceTexture frameworks native libs gui SurfaceFlinger frameworks native services surfaceflinger Gra
  • 【python之argparse模块学习】简单入门

    目录 0 前言 1 入门程序 2 参数 2 1 位置参数 2 2 可选参数 2 3 矛盾选项 3 总结 4 参考文献 0 前言 该模块地位 Python 标准库中推荐的命令行解析模块 类比linux命令ls来理解该模块功能 与该命令类似的
  • 杂音 & pop 音的解决方法

    杂音 pop 音的解决方法 1 喇叭有严重的 吱吱 破音 绝大多数的原因有可能在于V out 电压不稳定 所以最好测一下无负载时的输出电压 同时也可以测量 VCC 即boost 的输出 输入电压 正常的VCC 可以通过客户的 反馈电阻和 V
  • 解决Error:Kotlin: Module was compiled with an incompatible version of Kotlin. The binary version of ..

    文章目录 1 问题 2 分析问题 3 升级kotlin插件版本 3 1 升级方法1 3 1 升级方法2 4 其他问题 4 1 方法1中的Cannot download Read timed out问题 4 2 方法2中的Plugin Kot
  • 23种常用设计模式(C++)

    Part One Methods for constrcting a new object 1 Factory method 我们把简单工厂方法归类到工厂方法中 工厂方法的目的是用来解决具有同一接口 基类 派生类对象的生成问题 尽管可以通过
  • vray渲染白屏卡死_3DMAX使用VRay渲染的时候,在building embree static这一步最后一点卡死...

    DMAX使用vray渲染的时候 在building embree static这一步最后一点卡死是参数设置错误 解决方法如下 1 在我们为场景打好vray灯光以后 要设置vray渲染的参数 按 F10 打开vray渲染编辑器 在 公用 下栏
  • react-Suspense工作原理分析

    Suspense 基本应用 Suspense 目前在 react 中一般配合 lazy 使用 当有一些组件需要动态加载 例如各种插件 时可以利用 lazy 方法来完成 其中 lazy 接受类型为 Promise lt gt default
  • 大数据从入门到精通文章体系

    大数据知识可谓是多而杂 大数据相关的组件更是数不胜数 但是我们每一次的感受到学习的累 就足以证明我们在认真的学习 每感到到一次累的同时 就应该感受到一次进步 所以不要让自己停下来 各位小伙伴冲冲冲 大数据系列资源链接 名称 链接 提取码 H
  • PS笔记2

    第01堂课 出识Ps 图像处理软件 学习ps要做到三点 了解基本概念 掌握操作规律 开发扩展思维 第02堂课 软件安装 百度搜索ps 下载 会发现两种下载情况 第一种不需要安装 解压后在文件里直接找到PS图标 打开就可以了 第二种安装包 安
  • 织梦网站调用变量失败_织梦dedecms无法调用新添加变量的解决办法

    织梦dedecms无法调用新添加变量 在项目中使用了几次织梦cms程序 感觉越来越好用 以前刚接触dedecms时一看后台界面 如此之乱 使我心乱如麻 不知从何下手 后来因为工作逐渐就熟悉了它的后台 特别是一些客户的特殊要求 靠dede自带
  • Ubuntu配置国内源

    Ubuntu配置国内源 Ubuntu源 使用配置生成器 安装依赖包 打开apt源配置文件 国内apt源 中科大源 阿里源 Ubuntu源 每个 Ubuntu 版本都有自己的一组四个官方存储库 Main Canonical 支持的自由开源软件
  • Qt4_写FTP客户端

    写FTP客户端 QFtp类在Qt中实现了FTP协议的客户端程序 它提供了非常多的函数来执行多数常见的FTP操作 同时还可以执行任意的FTP指令 QFtp类是异步工作的 若调用一个像get 或者put 这样的函数 它会立即返回并且仅在控制权回