QT

1.

  CONFIG += qt 的作用

  qtbase 编译

  单元测试:参考

  完整的测试代码:

/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
* Author: Alex
* mail: abnk@qq.com
* File Type: unix Name: test.cpp
* Created Time: 2021-07-23 10:15 33
*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include <QtTest/QtTest>

// 参考: https://blog.51cto.com/u_9291927/2114179
// qmake -project "QT+=testlib
// qmake && make && ./qt_test

class TestQString: public QObject
{
    Q_OBJECT
private slots:
    void toUpper();
    void toUpper_data();
};

void TestQString::toUpper()
{
    // 原来没有测试数据的时候需要将测试数据一个一个的写到代码里面。
    // QString str = "Hello";
    // QVERIFY(str.toUpper() == "HELLO");
    // QCOMPARE(str.toUpper(), QString("HELLO"));

    QFETCH(QString, lowerString);
    QFETCH(QString, upperResult);

    // 添加的数据只需要被调用一次就被批量测试完了
    QCOMPARE(lowerString.toUpper(), upperResult);
}

// 为测试函数提供数据的函数必须与该测试函数同名,并加上_data后缀
void TestQString::toUpper_data()
{
    QTest::addColumn<QString>("lowerString");
    QTest::addColumn<QString>("upperResult");

    QTest::newRow("all lower") << "hello" << "HELLO";
    QTest::newRow("mixed")     << "Hello" << "HELLO";
    QTest::newRow("all upper") << "HELLO" << "HELLO";
}

QTEST_APPLESS_MAIN(TestQString);    // 同类名
#include "test.moc"                 // 文件名+.moc
test.cpp

  Qt官方 autotest   参考

2. QScopeGuard

  析构的时候会做一些事情。

template <typename F>
class [[nodiscard]] QScopeGuard
{
public:
    explicit QScopeGuard(F &&f) noexcept
        : m_func(std::move(f))
    {
    }

    explicit QScopeGuard(const F &f) noexcept
        : m_func(f)
    {
    }

    QScopeGuard(QScopeGuard &&other) noexcept
        : m_func(std::move(other.m_func))
        , m_invoke(qExchange(other.m_invoke, false))
    {
    }

    ~QScopeGuard() noexcept
    {
        if (m_invoke)
            m_func();
    }

    void dismiss() noexcept
    {
        m_invoke = false;
    }

private:
    Q_DISABLE_COPY(QScopeGuard)

    F m_func;
    bool m_invoke = true;
};

#ifdef __cpp_deduction_guides
template <typename F> QScopeGuard(F(&)()) -> QScopeGuard<F(*)()>;
#endif

//! [qScopeGuard]
template <typename F>
[[nodiscard]] QScopeGuard<typename std::decay<F>::type> qScopeGuard(F &&f)
{
    return QScopeGuard<typename std::decay<F>::type>(std::forward<F>(f));
}
View Code

3. run in main thread (use lambda)

/*!
  rewrite from:  https://zhuanlan.zhihu.com/p/364710810
*/
#include <QtCore/QCoreApplication>
#include <QtCore/QObject>
#include <QtCore/QThread>
#include <QtCore/QDebug>
#include <QtCore/QQueue>
#include <functional>
#include <unistd.h>  // sleep

using Callback = std::function <void(QQueue <void *>)>;

class Worker : public QObject
{
    Q_OBJECT
public:
    Worker() {
        moveToThread(&m_thread);
        m_thread.start();
    }
public slots:
    void slotRunInSub() {                   // add callback
        // qDebug() << "run in sub thread slot:" << QThread::currentThreadId();
        if (m_workerCallback) {
            m_workerCallback(m_queue);
        }
        emit mSig();
    }
signals:
     void mSig();
private:
     QThread m_thread;
     QQueue <void *> m_queue;
     Callback m_workerCallback;
public:
    void setCallback(Callback &&func, void *arg) {
        m_queue.enqueue(arg);
        m_workerCallback = std::forward<Callback>(func);
    }
};

class Dummy : public QObject
{
    Q_OBJECT

public:
    Dummy(QObject* parent=0) : QObject(parent) {
        QObject::connect(this, SIGNAL(sig()), &worker, SLOT(slotRunInSub()));        // update
        QObject::connect(&worker, SIGNAL(mSig()), this, SLOT(slotRunInMain()));  // process
    }
    // template <>
    void PostToChild(Callback &&func, void *arg) {
        // m_queue.enqueue(arg);
        worker.setCallback(std::forward<Callback>(func), arg);
    }
    void PostToMain(Callback &&func, void *arg) {
        m_queue.enqueue(arg);
        m_callback = std::forward<Callback>(func);
        sigToSubThd();   // call slot, note sub thread process data
    }

public slots:
    void sigToSubThd() {
        emit sig();
    }
signals:
    void sig();

public slots:
    void slotRunInMain() {      // update
        qDebug() << "run in main: " << QThread::currentThreadId();
        if (m_callback) {
            m_callback(m_queue);
        }
    }

private:
    Worker worker;
    QQueue <void *> m_queue;
    Callback m_callback;
};

#include "main.moc"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    qDebug() << "main thread: " << QThread::currentThreadId();

    // QCoreApplication::instance()->thread();

    Dummy dummy;
    int data = 1111;

    dummy.PostToChild([](QQueue <void *> queue){            // in sub thread
        //        1. memcpy  data;
        //        2. process data;
        //        3. enqueue data;
        qDebug() << "run in sub thread slot:" << QThread::currentThreadId();
        sleep(5);
    }, (void *)&data);                               // set cb, copy data and enqueue.

    int enqueueData = 2222;
    dummy.PostToMain([](QQueue <void *> queue){         // in sub thread
        void *deData = queue.dequeue();
         qDebug() << "dequeue: " << *(int *)deData;     // dequeue data, and update???
         qDebug() << "run in main thread: " << QThread::currentThreadId();
    }, (void *)&enqueueData);

    qDebug() << "async exec";

    return a.exec();
}
View Code

  and then, add concurent,

  add ensure connect sub to main.

  add move to main thread

  add variable args function and declytype

  moveToThread has memory hosting relationship 

/*!
  rewrite from:  https://zhuanlan.zhihu.com/p/364710810
*/
#include <QtCore/QCoreApplication>
#include <QtWidgets/QApplication>
#include <QtCore/QObject>
#include <QtCore/QThread>
#include <QtCore/QDebug>
#include <QtCore/QQueue>
#include <functional>
#include <unistd.h>  // sleep
#include <thread>

#include <QStyle>
#include <QTimer>
#include <QPushButton>
#include <QMainWindow>

using Callback = std::function <void(QQueue <void *>)>;

class Worker : public QObject
{
    Q_OBJECT
public:
    Worker() {
        moveToThread(&m_thread);
        m_thread.start();
    }
    ~Worker() {
        if (m_thread.isRunning()) {
            // m_thread.deleteLater();
            // m_thread.exit(0);
            m_thread.quit();
            m_thread.wait();
        }
    }
public slots:
    void slotRunInSub() {                   // add callback
        // qDebug() << "run in sub thread slot:" << QThread::currentThreadId();
        if (m_workerCallback) {
            m_workerCallback(m_queue);
        }
        emit mSig();
    }
signals:
     void mSig();
private:
     QThread m_thread;
     QQueue <void *> m_queue;
     Callback m_workerCallback;
public:
    void setCallback(Callback &&func, void *arg) {
        m_queue.enqueue(arg);
        m_workerCallback = std::forward<Callback>(func);
    }
};

class Dummy : public QObject
{
    Q_OBJECT
public:
    Dummy(QObject* parent=0) : QObject(parent) {
        // Guranentee connect main thread to child
        if (QCoreApplication::instance() && QCoreApplication::instance()->thread()) {
            moveToThread(QCoreApplication::instance()->thread());
            QObject::connect(this, SIGNAL(signalConnectInMainToChild()), this, SLOT(slotConnectInMainToChild()));
            // qDebug() << "Dummy is constructor in main: " << QThread::currentThreadId();
        }
        emit signalConnectInMainToChild();
    }
    ~Dummy() {
//        if (worker) {
//            worker->deleteLater();
//            worker = nullptr;
//        }
    }
    // template <>
    void PostToChild(Callback &&func, void *arg) {
        // m_queue.enqueue(arg);
        worker->setCallback(std::forward<Callback>(func), arg);
    }
    void PostToMain(Callback &&func, void *arg) {
        m_queue.enqueue(arg);
        m_callback = std::forward<Callback>(func);
        sigToSubThd();   // call slot, note sub thread process data
    }

public slots:
    void sigToSubThd() {
        emit sig();
    }

    void slotConnectInMainToChild() {
        worker = new Worker;
        qDebug() << "Dummy is connect in main: " << QThread::currentThreadId();
        QObject::connect(this, SIGNAL(sig()), worker, SLOT(slotRunInSub()));        // update
        QObject::connect(worker, SIGNAL(mSig()), this, SLOT(slotRunInMain()));  // process
    }

signals:
    void sig();
    void signalConnectInMainToChild();

public slots:
    void slotRunInMain() {      // update
        qDebug() << "run in main: " << QThread::currentThreadId();
        if (m_callback) {
            m_callback(m_queue);
        }
    }

private:
    Worker *worker;
    QQueue <void *> m_queue;
    Callback m_callback;
};

#include "main.moc"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    qDebug() << "main thread: " << QThread::currentThreadId();

    // QCoreApplication::instance()->thread();

    std::thread thd([]{
        Dummy dummy;
        // dummy.signalConnectInMainToChild();
        sleep(1);
        int data = 1111;

        dummy.PostToChild([](QQueue <void *> queue){            // in sub thread
            //        1. memcpy  data;
            //        2. process data;
            //        3. enqueue data;
            qDebug() << "run in sub thread slot:" << QThread::currentThreadId();
            // sleep(5);
        }, (void *)&data);                               // set cb, copy data and enqueue.

        int enqueueData = 2222;
        dummy.PostToMain([](QQueue <void *> queue){         // in sub thread
            void *deData = queue.dequeue();
            qDebug() << "dequeue: " << *(int *)deData;     // dequeue data, and update???
            qDebug() << "run in main thread: " << QThread::currentThreadId();
        }, (void *)&enqueueData);

        qDebug() << "async exec";

        sleep(6);
        // qApp->quit();
    });

    thd.detach();



    QMainWindow w;
    QWidget central;
    QPushButton button(&central);
    w.setCentralWidget(&central);

#if 1
    // analogue render event
    QTimer timer;
    QObject::connect(&timer, &QTimer::timeout, [&button]{
        static bool flag = false;
        QStyle *style = QApplication::style();
        QIcon openPicture = style->standardIcon(QStyle::SP_TitleBarMenuButton);
        QIcon inforIron = style->standardIcon(QStyle::SP_DialogYesButton);
        button.setIcon(flag ? openPicture : inforIron);
        flag = !flag;
    });
    timer.setInterval(200);
    timer.start();
#endif

#if 0
    // single event ocupaid block
    QObject o;
    QTimer::singleShot(100, &o, [&button]{
        // while(1)
        {
            sleep(1);
            qDebug() << QThread::currentThreadId();

            static bool flag = false;
            QStyle* style = QApplication::style();
            QIcon openPicture = style->standardIcon(QStyle::SP_TitleBarMenuButton);
            QIcon inforIron = style->standardIcon(QStyle::SP_MediaSkipBackward);
            button.setIcon(flag ? openPicture : inforIron);
            flag = !flag;
        }
    });
#endif


    w.show();

    qDebug() << "enter exec";
    return a.exec();
}
View Code

4. QRunnable

  参考

4. 国际化

  参考

 

 

原文地址:https://www.cnblogs.com/abnk/p/15047607.html