Qt:ストリームを正しく操作するためのテンプレート-より良い実装

前回の記事では、Qtでのスレッドの適切な実装のトピックに触れ、独自のバージョンを提案しました。 コメントでは、彼らはより正しい方向を示唆した。 私はそれをやろうとしました-それは本当に簡単で美しいことが判明しました! 古い記事を修正したかったのですが、Habrがハングし、すべてが失われました。 結局、私は新しいバージョンを書くことにしました。



ここで、QThreadを基礎として、テンプレート継承者を作成します( Schleeがリハビリしました!) アプローチは次のとおりです。

  1. QThreadスレッドの作成。
  2. その中で新しいストリームの情報は現在のスレッドで準備されます ;
  3. クライアントが開始を呼び出します(優先度)...
  4. ...そして、オーバーライドされたrun()メソッドで- 新しいスレッドで -目的のオブジェクトが作成され、接続が確立され、「オブジェクトの準備ができました」というシグナルが呼び出され、メッセージ処理サイクルが開始されます。
  5. ソースストリームのクライアントは、信号と新しいオブジェクトを受け取ります。


前回と同様に、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ファイル:



 #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"
      
      








All Articles