1.
CONFIG += qt 的作用
qtbase 编译
单元测试:参考
完整的测试代码:
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * Author: Alex * mail: [email protected] * 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
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(¢ral); w.setCentralWidget(¢ral); #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. 国际化