QT各种类|QT各种类 2020-11-07

  • QThread
  • QMutexLocker
  • QWaitCondition
  • QLocalServer
  • QLocalSocket
  • QUdpSocket
  • QTimer
  • QHostAddress
  • QDnsLookup
  • QHostInfo
  • QNetworkReply
  • QNetworkInterface
注意事项
  • 继承自QThread的类,如果添加多个数据成员,在修改/读取数据成员时,为了保障数据一致性,需要使用QMutex 锁起来.
  • 线程的启动/运行中等待/退出
    • 启动使用start(),
    • 运行中表示方法run()还没有运行完毕,可以使用isRunning()查询状态
    • 要想退出,需要让run()访问退出,一般要破坏掉run()方法中的while循环条件(如果其中还有其他的暂停等待的功能实现,例如使用了QWaitCondition,让线程处于暂行等待的状态,也需要满足等待条件(调用QWaitCondition::wakeOne())),然后调用wait()方法等待run()运行完成.
其他注意事项
  • 类的构造函数如果只有一个参数,一般要使用 explicit 关键字,防止类型转换
  • Qt中资源的释放,大多靠构造时传入的parent(QObject *parent = nullptr)参数的析构函数,所以在构造类实例时尽可能传入parent参数.
  • 根据对代码运行结果的分析,如果widget(例如QLabel)在new时没有传入parent,但是该widget被加入layout,当调用setLayout后,没有parent的widget也有了widget.
  • 在继承QWidget时,如果有些子Widget不需要在多个成员方法中用到,可以不用把这些widget作为类的成员,只需要在构造界面的函数中直接使用.
  • 当不在main函数中,想要获取命令行参数的方法:
    QStringList args = QCoreApplication::instance()->arguments(); args.takeFirst(); // 需要注意,第一个参数时应用的名称,跳过

  • QCoreApplication的正确使用方式是:
    int main(int argc, char **argv) { using namespace std; QCoreApplication app(argc, argv); QStringList arguments = app.arguments(); arguments.takeFirst(); // remove the first argument, which is the program's nameif (arguments.isEmpty()) { printf("Qt Download example\n" "Usage: downloadmanager url1 [url2... urlN]\n" "\n" "Downloads the URLs passed in the command-line to the local directory\n" "If the target file already exists, a .0, .1, .2, etc. is appended to\n" "differentiate.\n"); return 0; }DownloadManager manager; manager.append(arguments); QObject::connect(&manager, &DownloadManager::finished, &app, &QCoreApplication::quit); ///<<-=-=-==-=-=-=-=-=-=-=这里是重点 return app.exec(); }

QUdpSocket的使用
  • 一般使用方法就是先调用bind()方法, 然后调用 writeDatagram() / readDatagram() / receiveDatagram() 传输数据.
  • 如果只是发送数据报, 不必调用bind()方法.
  • 如果想使用 QIODevice 中的 read(), readLine(), write(),等方法,首先必须调用connectToHost().
  • 每次数据报发送完成后,都会触发信号: bytesWritten()
  • 当收到数据报时,会触发信号: readyRead() ,此时 hasPendingDatagrams() 返回 true. 调用 pendingDatagramSize() 可以获得第一个数据报的大小, 然后可以调用 readDatagram() 或者 receiveDatagram() 读取数据报内容.
  • qint64 QUdpSocket::readDatagram(char *data, qint64 maxSize, QHostAddress *address = nullptr, quint16 *port = nullptr)
  • QNetworkDatagram QUdpSocket::receiveDatagram(qint64 maxSize = -1)
QTimer的使用
  • 类似于interval
QTimer *timer = new QTimer(this); connect(timer, &QTimer::timeout, this, QOverload<>::of(&AnalogClock::update)); timer->start(1000);

  • 一次性的闹钟
setSingleShot(true)


QTimer::singleShot(200, this, &Foo::updateCaption);

QTimer使用注意事项
  • 在多线程应用中,QTimer可以在任何有 an event loop的线程中使用.
  • 在非GUI应用中,可以通过调用QThread::exec()来开启event loop.
  • 调用QTimer的start(), stop(),都必须在其所在的线程中.
  • 其他的timer
    1. Qt::PreciseTimer 精度:1毫秒
    2. Qt::CoarseTimer 精度: 5% of the interval
    3. Qt::VeryCoarseTimer 精度:500 ms
    4. 调用QObject::startTimer() / QObject::killTimer()
    5. QBasicTimer
QHostAddress 使用
  • 【QT各种类|QT各种类 2020-11-07】QHostAddress 可以用于IPv4 和IP v6的地址
  • 不解析dns. 想要解析域名,需要使用QHostInfo
  • 包含一些常用的主机地址
    • QHostAddress::Null
      The null address object. Equivalent to QHostAddress(). See also QHostAddress::isNull().
    • QHostAddress::LocalHost
      The IPv4 localhost address. Equivalent to QHostAddress("127.0.0.1").
    • QHostAddress::LocalHostIPv6
      The IPv6 localhost address. Equivalent to QHostAddress("::1").
    • QHostAddress::Broadcast
      The IPv4 broadcast address. Equivalent to QHostAddress("255.255.255.255").
    • QHostAddress::AnyIPv4
      The IPv4 any-address. Equivalent to QHostAddress("0.0.0.0"). A socket bound with this address will listen only on IPv4 interfaces.
    • QHostAddress::AnyIPv6
      The IPv6 any-address. Equivalent to QHostAddress("::"). A socket bound with this address will listen only on IPv6 interfaces.
    • QHostAddress::Any
      The dual stack any-address. A socket bound with this address will listen on both IPv4 and IPv6 interfaces.
QDnsLookup 使用 使用步骤如下:
  1. new一个QDnsLookup
  2. connect finished() signal
  3. 设置type, 调用setType()
    包括:
    • QDnsLookup::A
      IPv4 address records.
    • QDnsLookup::AAAA
      IPv6 address records.
    • QDnsLookup::ANY
      any records.
    • QDnsLookup::CNAME
      canonical name records.
    • QDnsLookup::MX
      mail exchange records.
    • QDnsLookup::NS
      name server records.
    • QDnsLookup::PTR
      pointer records.
    • QDnsLookup::SRV
      service records.
    • QDnsLookup::TXT
      text records.
  4. 设置name,调用setName()
  5. 调用lookup()
  6. 在处理finished信号的函数中,根据type不同,调用不同的函数
    • QList canonicalNameRecords() const
    • QList hostAddressRecords() const
    • QList mailExchangeRecords() const
    • QList nameServerRecords() const
    • QHostAddress nameserver() const
    • QList pointerRecords() const
    • QList serviceRecords() const
    • QList textRecords() const
实例代码
void MyObject::lookupServers() { dns = new QDnsLookup(this); connect(dns, SIGNAL(finished()), this, SLOT(handleServers())); dns->setType(QDnsLookup::A); dns->setName("www.baidu.com"); dns->lookup(); } void MyObject::handleServers() { // Check the lookup succeeded. if (dns->error() != QDnsLookup::NoError) { qWarning("DNS lookup failed"); dns->deleteLater(); return; }// Handle the results. const auto records = dns->hostAddressRecords(); for (auto record : records) { //... } dns->deleteLater(); }

QHostInfo 使用
  • 异步方式(通过signal/slot接收结果)
// To find the IP address of qt-project.org QHostInfo::lookupHost("qt-project.org", this, SLOT(printResults(QHostInfo))); // To find the host name for 4.2.2.1 QHostInfo::lookupHost("4.2.2.1", this, SLOT(printResults(QHostInfo))); //在printResults() 函数中 调用addresses() 或者hostName() 获取结果

  • 在获取结果过程中,可以调用QHostInfo::abortHostLookup(int id) 取消操作.
  • 同步方式
QHostInfo info = QHostInfo::fromName("qt-project.org");

  • 还有本地信息:
    • 获取主机名称: QHostInfo::localHostName()
    • 获取主机域名: QHostInfo::localDomainName()
QNetworkReply 使用
  • 常规的使用方式如下:
    QNetworkRequest request(url); currentDownload = manager.get(request); connect(currentDownload, &QNetworkReply::downloadProgress, this, &DownloadManager::downloadProgress); connect(currentDownload, &QNetworkReply::finished, this, &DownloadManager::downloadFinished); connect(currentDownload, &QNetworkReply::readyRead, this, &DownloadManager::downloadReadyRead); void DownloadManager::downloadProgress(qint64 bytesReceived, qint64 bytesTotal){ } void DownloadManager::downloadFinished(){ } void DownloadManager::downloadReadyRead() { output.write(currentDownload->readAll()); }

  • 从QNetworkReply获取statusCode
    bool DownloadManager::isHttpRedirect(QNetworkReply *reply) { int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); return statusCode == 301 || statusCode == 302 || statusCode == 303 || statusCode == 305 || statusCode == 307 || statusCode == 308; }

  • 从中获取302跳转的新地址(Location头的值)
    QVariant target = currentDownload->attribute(QNetworkRequest::RedirectionTargetAttribute); if (!target.isValid()) return; QUrl redirectUrl = target.toUrl(); if (redirectUrl.isRelative()) redirectUrl = requestUrl.resolved(redirectUrl);

  • 使用完毕后,要delete
    reply->deleteLater();

QNetworkInterface的使用
  • 获取本机所有的网卡
    QList ipAddressesList = QNetworkInterface::allAddresses();

    推荐阅读