ここで、QThreadを基礎として、テンプレート継承者を作成します( Schleeがリハビリしました!) アプローチは次のとおりです。
- QThreadスレッドの作成。
- その中で、新しいストリームの情報は現在のスレッドで準備されます ;
- クライアントが開始を呼び出します(優先度)...
- ...そして、オーバーライドされたrun()メソッドで- 新しいスレッドで -目的のオブジェクトが作成され、接続が確立され、「オブジェクトの準備ができました」というシグナルが呼び出され、メッセージ処理サイクルが開始されます。
- ソースストリームのクライアントは、信号と新しいオブジェクトを受け取ります。
前回と同様に、MOCはテンプレートクラスを処理できないことに注意してください。「MOCでは、C ++のすべての機能を使用できません。 主な問題は、 クラステンプレートにシグナルまたはスロットを含めることができないことです。
実装
作成されたクラスのコードを考慮します(すべてが画面に収まるように、コメントを削除しました)。
// ** // ** // ** class ThreadedObjectBase: public QThread { Q_OBJECT protected: const char *_finished_signal; const char *_terminate_slot; bool _to_delete_later_object; void initObject (QObject *obj) { bool res; if (_finished_signal) { res = connect (obj, _finished_signal, this, SLOT (quit ())); Q_ASSERT_X (res, "connect", "connection is not established"); } if (_terminate_slot) { res = connect (this, SIGNAL (finished ()), obj, _terminate_slot); Q_ASSERT_X (res, "connect", "connection is not established"); } if (_to_delete_later_object && _finished_signal) { res = connect (obj, _finished_signal, obj, SLOT (deleteLater ())); Q_ASSERT_X (res, "connect", "connection is not established"); } emit objectIsReady (); } public: ThreadedObjectBase (QObject *parent = 0): QThread (parent), _finished_signal (0), _terminate_slot (0), _to_delete_later_object (true) {} signals: void objectIsReady (void); }; // ** // ** // ** template <class T> class ThreadedObject: public ThreadedObjectBase { protected: T *_obj; public: ThreadedObject (QObject *parent = 0): ThreadedObjectBase (parent), _obj (0) {} void starting ( const char *FinishedSignal = 0, const char *TerminateSlot = 0, QThread::Priority Priority = QThread::InheritPriority, bool ToDeleteLaterThread = true, bool ToDeleteLaterObject = true) { _finished_signal = FinishedSignal; _terminate_slot = TerminateSlot; _to_delete_later_object = ToDeleteLaterObject; start (Priority); } void run (void) { initObject (_obj = new T); exec (); } bool objectIsCreated (void) const { return _obj != 0; } T* ptr (void) { return reinterpret_cast <T*> (_obj); } const T* cptr (void) const { return reinterpret_cast <const T*> (_obj); } operator T* (void) { return ptr (); } T* operator -> (void) { return ptr (); } operator const T* (void) const { return cptr (); } const T* operator -> (void) const { return cptr (); } };
ここで、メインメソッドが開始されます。これは、信号とスロットの名前を記憶し、メソッドの遅延除去を設定します。 objectIsCreated()メソッドは、オブジェクトが既に作成されている場合にtrueを返します。 複数のオーバーロードにより、ThreadedObject <T>をスマートポインターとして使用できます。
これらのクラスを使用する簡単な例を次に示します。
ThreadedObject <Operation> _obj; QObject::connect (&_obj, SIGNAL (objectIsReady ()), this, SLOT (connectObject ())); _obj.starting (SIGNAL (finished ()), SLOT (terminate ()), QThread::HighPriority);
実際の例を以下に添付します-メインスレッドにボタンが作成されます。 int変数は、新しいスレッドで作成され、タイマーからのシグナルとタイマーイベントも作成されます。 これらのタイマーは両方ともint変数の値を減らします;ゼロに達すると、 QCoreApplication :: quit()スロットが呼び出されます。 一方、アプリケーションを閉じると、スレッドが停止します。 WinXPでテストされた例。 Linux、MacOS、Android、およびその他のサポートされているプラットフォームでの成功したテストについてのコメントを聞きたいです 。
例+クラス
ThreadedObjectファイル:
Main.cppファイル:
#include <QtCore> // ** // ** // ** class ThreadedObjectBase: public QThread { Q_OBJECT protected: const char *_finished_signal; // " " const char *_terminate_slot; // " " bool _to_delete_later_object; // // . void initObject (QObject *obj) { bool res; if (_finished_signal) // " "? { res = connect (obj, _finished_signal, this, SLOT (quit ())); Q_ASSERT_X (res, "connect", "connection is not established"); } // if (_terminate_slot) // " "? { res = connect (this, SIGNAL (finished ()), obj, _terminate_slot); Q_ASSERT_X (res, "connect", "connection is not established"); } // " " if (_to_delete_later_object && _finished_signal) // ? { res = connect (obj, _finished_signal, obj, SLOT (deleteLater ())); Q_ASSERT_X (res, "connect", "connection is not established"); } // emit objectIsReady (); // } public: ThreadedObjectBase (QObject *parent = 0): QThread (parent){} signals: void objectIsReady (void); // " " }; // class ThreadedObject // ** // ** // ** template <class T> class ThreadedObject: public ThreadedObjectBase { protected: T *_obj; // , public: ThreadedObject (QObject *parent = 0): ThreadedObjectBase (parent), _obj (0) {} // . void starting (const char *FinishedSignal = 0, const char *TerminateSlot = 0, QThread::Priority Priority = QThread::InheritPriority, bool ToDeleteLaterThread = true, bool ToDeleteLaterObject = true) // { _finished_signal = FinishedSignal; // " " _terminate_slot = TerminateSlot; // " " _to_delete_later_object = ToDeleteLaterObject; // start (Priority); // } void run (void) { initObject (_obj = new T); exec (); } // // . bool objectIsCreated (void) const { return _obj != 0; } // ? T* ptr (void) { return reinterpret_cast <T*> (_obj); } // const T* cptr (void) const { return reinterpret_cast <const T*> (_obj); } // // . operator T* (void) { return ptr (); } // T* operator -> (void) { return ptr (); } // operator const T* (void) const { return cptr (); } // const T* operator -> (void) const { return cptr (); } // }; // class ThreadedObject
Main.cppファイル:
#include <QtGui> #include <QtWidgets> #include <QtCore> #include "ThreadedObject.h" // ** // ** // ** class Operation: public QObject { Q_OBJECT int *Int; // QTimer _tmr; // int _int_timer; // public: Operation (void) { Int = new int (5); } // ~Operation (void) { if (Int) delete Int; } // signals: void addText(const QString &txt); // " " void finished (); // " " public slots: void terminate () // { killTimer (_int_timer); // _tmr.stop (); // delete Int; // Int = 0; // emit finished (); // } void doAction (void) // { bool res; emit addText (QString ("- %1 -"). arg (*Int)); res = QObject::connect (&_tmr, &QTimer::timeout, this, &Operation::timeout); Q_ASSERT_X (res, "connect", "connection is not established"); // _tmr.start (2000); // thread()->sleep (1); // 1 ... timeout (); // ... ... startTimer (2000); // ... } protected: void timerEvent (QTimerEvent *ev) { timeout (); } // private slots: void timeout (void) { if (!Int || !*Int) // ? return; // ... --*Int; // emit addText (QString ("- %1 -"). arg (*Int)); // if (!Int || !*Int) // ? emit finished (); // ... } }; // ** // ** , // ** class App: public QObject { Q_OBJECT ThreadedObject <Operation> _obj; // - QPushButton _btn; // protected: void timerEvent (QTimerEvent *ev) { bool res; // - killTimer (ev->timerId ()); // res = QObject::connect (&_obj, SIGNAL (objectIsReady ()), this, SLOT (connectObject ())); Q_ASSERT_X (res, "connect", "connection is not established"); // _obj.starting (SIGNAL (finished ()), SLOT (terminate ()), QThread::HighPriority); // } private slots: void setText (const QString &txt) { _btn.setText (txt); } // void connectObject (void) // { bool res; // - res = QObject::connect (this, &App::finish, _obj, &Operation::terminate); Q_ASSERT_X (res, "connect", "connection is not established"); // res = QObject::connect (this, &App::startAction, _obj, &Operation::doAction); Q_ASSERT_X (res, "connect", "connection is not established"); // res = QObject::connect (_obj, &Operation::finished, this, &App::finish); Q_ASSERT_X (res, "connect", "connection is not established"); // res = QObject::connect (_obj, &Operation::addText, this, &App::setText); Q_ASSERT_X (res, "connect", "connection is not established"); // res = QObject::connect (&_btn, &QPushButton::clicked, _obj, &Operation::terminate); Q_ASSERT_X (res, "connect", "connection is not established"); // _btn.show (); // emit startAction (); // } public slots: void terminate (void) { emit finish (); } // signals: void startAction (void); // " " void finish (void); // " " }; // ** // ** // ** int main (int argc, char **argv) { QApplication app (argc, argv); // App a; // bool res; // a.startTimer (0); // res = QObject::connect (&a, SIGNAL (finish ()), &app, SLOT (quit ())); Q_ASSERT_X (res, "connect", "connection is not established"); // res = QObject::connect (&app, SIGNAL (lastWindowClosed ()), &a, SLOT (terminate ())); Q_ASSERT_X (res, "connect", "connection is not established"); // return app.exec(); // } #include "main.moc"