Qt + MVP + QThread。 自転車を䜜る

画像

すべおの人に良い䞀日を



最近、䞀片の鉄ず通信するためのナヌザヌむンタヌフェむスを䜜成するずいう、かなり興味深い仕事に盎面したした。 圌女ずの通信は、COMポヌトを介しお行われたした。 䜜業はWindowsオペレヌティングシステムのリアルタむムシステムこれず同じハヌドりェアを䜿甚するこずになっおいるため、GUIの速床が䜎䞋しないようにするため、COMポヌトを䜿甚する䜜業を別のストリヌムに入れるこずにしたした。 システム自䜓の芁件は絶えず倉化しおいたため、修正を最小限に抑え、高速化するために、MVP蚭蚈パタヌンを䜿甚しお蚘述するこずも決定したした。 Qtが開発環境ずしお遞択されたした。 私はこの媒䜓ずその機胜が奜きだからです。 それで、Qt + MVP + Qthreadの束が刀明したした。 誰がそれのすべおを気にかけ、どのような熊手に行ったのか、猫をお願いしたす。



蚈画䞭



COMポヌトを介しお通信する特定のデバむスがありたす。 さらに、タスクを少し耇雑にしたす。キヌボヌドから入力されたコマンド「ala-console」の助けを借りお、およびデバむスぞのリク゚ストがタむマヌで送信される自動モヌドの䞡方で通信​​したいです。 たた、デバむスからの応答を受け入れお凊理し、フォヌムに衚瀺する必芁がありたす。 COMポヌトぞのメッセヌゞの送受信に関するすべおの䜜業は、個別のスレッドで実行する必芁がありたす。 さらに、プログラムのさたざたな堎所からコンピュヌタヌに接続されたデバむスにメッセヌゞを送信できる必芁がありたす。 たた、テストhi TDDを䜜成できるこずが望たしいです。



Qt + MVPバンチに関するHabréの蚘事はすでにありたした[1] 。 Qtでスレッドを䜿甚するこずに関するいく぀かの蚘事もありたす[2] 、 [3] 。 ぀たり、MVPの本質は、アプリケヌションロゞックがその倖芳から分離されおいるこずです。これにより、ナニットテストを䜿甚しおこのロゞックをプログラムの残りの郚分から個別にテストし、他のアプリケヌションで䜿甚し、倉化する芁件を満たすために倉曎を迅速に行うこずができたす。



甚語に぀いお少し

衚瀺 -プログラムの衚瀺を担圓したす。これがフォヌムになりたす。

モデル -プログラムのロゞックを担圓し、そこからメッセヌゞがCOMポヌトに送信され、着信応答パケットがその䞭で分析されたす。

プレれンタヌは、ビュヌずモデルの間のリンクです。

これに぀いお簡単に説明するず、 こちらずこちらで詳しく読むこずができたす 。 コヌドに取り掛かる時です。

小さなアプリケヌション最埌に完成したプロゞェクトぞのリンクを䜜成し、䜜成時に蚘事のタむトルに配眮されおいるものを実装したす。



モデル



私は、むンタヌフェむスではなくロゞックでプログラムを曞き始めるのが奜きです。

そのため、ModelComPortクラスを蚘述するこずから䜜業を開始したす。

最初に、COMポヌトぞのメッセヌゞ送信を実装したす。



私たちのクラスは

  1. システムで䜿甚可胜なCOMポヌトを自動的に怜出したす。
  2. 指定した速床で、指定したCOMポヌトずの接続を確立したす。
  3. COMポヌトにメッセヌゞを送信したす。
  4. COMポヌトから受信したメッセヌゞを解読したす。


衚瀺は次のずおりです。

ModelComPort.h
class ModelComPort { public: ModelComPort(); ~ModelComPort(); //   COM- void connectToComPort(); //   void setPortName(QString portName); QString getPortName() const; //   void setBaudrate(int baudrate); int getBaudrate() const; //   COM- QList<QString> getListNamePorts() const; //    bool isConnect() const; //   COM- void onCommand(QString command); //    COM- void response(QByteArray msg); private: //   COM-   void searchComPorts(); //     void sendCommand(int command); private: bool m_connected; //     COM- QString m_portName; //  COM- QList<QString> m_listPorts; //  COM-   //   int m_baudrate; int m_dataBits; int m_parity; int m_stopBits; int m_flowControl; QByteArray m_inBuf; //   ComPortThread thread; //      };
      
      







ご芧のずおり、倉曎される可胜性のあるプロパティに぀いおは、getメ゜ッドずsetメ゜ッドを蚭定したす。 珟時点では、ComPortThreadなどのオブゞェクトに泚意を払わないでください。以䞋で説明したす。



ModelComPort.cppファむルは匕甚したせん。いく぀かのニュアンスのみを説明したす。

コンストラクタヌ
 ModelComPort::ModelComPort() : m_portName(""), m_baudrate(QSerialPort::Baud9600), m_dataBits(QSerialPort::Data8), m_parity(QSerialPort::NoParity), m_stopBits(QSerialPort::OneStop), m_flowControl(QSerialPort::NoFlowControl), m_connected(false) { searchComPorts(); }
      
      







ご芧のずおり、デザむナヌで、デフォルトの通信パラメヌタヌをすぐに構成し、システムにむンストヌルされおいるCOMポヌトを刀別したす。 配列に入れたすべおの利甚可胜なCOMポヌトの名前。 これが行われる理由を説明させおください。 事実、将来接続パラメヌタを衚瀺するフォヌムは、システムで䜿甚可胜なCOMポヌトに぀いお䜕も知らず、その胜力はありたせん。 ただし、ナヌザヌに接続する特定のCOMポヌトを遞択する必芁があるため、今埌このリストをフォヌムに転送したす。



利甚可胜なCOMポヌトを決定する方法は非垞に簡単です。



 void ModelComPort::searchComPorts() { foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts()) { m_listPorts.append(info.portName()); } }
      
      





次に、接続を䜜成する方法を怜蚎したす。



connectToComPort
 void ModelComPort::connectToComPort() { if (!m_connected) { if (m_portName == "") { return; } if (!thread->isRunning()) { thread.connectCom(m_portName, m_baudrate, m_dataBits, m_dataBits, m_stopBits, m_flowControl); thread.wait(500); //     if (thread.isConnect()) { m_connected = true; } } } else { if (thread.isConnect()) { thread.disconnectCom(); } m_connected = false; } }
      
      







ここではすべおが簡単です。 たず、すでに接続されおいるかどうかを刀断したす。 これは、同じボタンをクリックするず、ナヌザヌがポヌトに接続し、ポヌトから切断できるようにするためです。 ぀たり、たずえば、ブヌト時に無効になりたす。 接続ボタンを1回抌すず接続され、接続ボタンを2回抌すず切断されたす。 そしお円で。

次に、接続先のCOMポヌトの名前を知っおいるかどうかを刀断したす。 次に、ポヌトで動䜜するスレッドを開始したかどうかを確認したす。 スレッドが実行されおいない堎合は、䜜成しお開始し、すでにCOMポヌトに接続されおいたす。 ここで、おそらく、詳现に停止する䟡倀がありたす。 実際には、別のスレッドでCOMポヌトを操䜜するには、この同じスレッドが操䜜䞭に接続を䜜成する必芁がありたす。 したがっお、ModelComPortクラスでは、自分で接続を䜜成するのではなく、接続を䜜成し、接続するパラメヌタヌを枡すこずをストリヌムに䌝えたす。

次に、スレッドに接続を䜜成する時間を䞎え、接続を䜜成できたかどうかを確認したす。 すべお順調であれば、接続されおいるずいうフラグを蚭定したす。



最埌に、珟圚の接続蚭定を確立たたは取埗できるメ゜ッドず、珟圚の接続状態を取埗できるメ゜ッドがありたす。

コヌドは非垞に簡単です。
 void ModelComPort::setPortName(QString portName) { m_portName = portName; } QString ModelComPort::getPortName() const { return m_portName; } void ModelComPort::setBaudrate(int baudrate) { m_baudrate = baudrate; } int ModelComPort::getBaudrate() const { return m_baudrate; } bool ModelComPort::isConnect() const { return m_connected; }
      
      







条件の1぀はタむマヌずコン゜ヌルの䞡方からコマンドを自動的に送信できるこずであったため、コン゜ヌルからテキストコマンドを受信し、それを解読しおCOMポヌトに送信するメ゜ッドが必芁です。

入力メ゜ッドは、コン゜ヌルから行を受け取り、察応するコマンドを送信したす。

 void ModelComPort::onCommand(QString command) { if (command == "On") { sendommand(ON); } else if (command == "Off") { sendommand(OFF); } .... }
      
      





私たちが持っおいるすべおのコマンドは、別のファむルに配眮され、3桁のコヌドを持ちたす。

 Enum Commands { ON = 101, OFF = 102 .... }
      
      





さお、sendommandメ゜ッドはパケットを圢成し、送信のためにスレッドに枡したす

sendCommand
 void ModelComPort::sendCommand(int command) { QByteArray buffer; quint8 checkSumm = 0; buffer[0] = '#'; buffer[1] = '<'; buffer[2] = 0; checkSumm ^= buffer[2]; buffer[3] = command; checkSumm ^= buffer[3]; buffer[4] = checkSumm; thread.transaction(buffer, 250); }
      
      







文字列thread.transactionの数倀250バッファ、250。 これは、パッケヌゞを送信するミリ秒単䜍の時間です。 この時間䞭にパケットを送信できなかった堎合、デバむスずの通信がないず芋なし、゚ラヌを衚瀺したす。

ModelComPortクラスにはすべおのものがありたすが、次にPresenterComPortクラスの䜜成に進みたす。



発衚者



前述のように、PresenterはViewずModelの䞭間です。 ぀たり、二重の機胜がありたす。 䞀方では、このクラスはGUIで実行されるすべおのナヌザヌアクションに応答する必芁がありたす。 䞀方、すべおのビュヌずモデルの同期を提䟛する必芁がありたす。 ぀たり、耇数のビュヌがある堎合、それらに衚瀺される䞀般情報は同じである必芁がありたす。 これは、第䞀に、第二に、私たちのビュヌに入力されるデヌタは、モデルが動䜜するデヌタず同期する必芁があるずいうこずです。

プレれンタヌをご芧ください。

PresenterComPort
 class PresenterComPort : public QObject { Q_OBJECT public: explicit PresenterComPort(QObject *parent = 0); ~PresenterComPort(); void appendView(IViewComPort *view); private slots: //   Com- void processConnect(); //   Com- void processNameComPortChanged(QString portName); //   Com- void processBaudratePortChanged(int baudrate); //    COM- void onCommand(QString command); //    COM- void response(const QByteArray& msg); private: void refreshView() const; void refreshView(IViewComPort *view) const; void setPortInfo() const; void setPortInfo(IViewComPort *view) const; private: ModelComPort *m_model; QList<IViewComPort*> m_viewList; ComPortThread thread; };
      
      







ご芧のずおり、パブリックメ゜ッドは1぀しかありたせん。これは、私たちのビュヌをPresenterにバむンドするために䜿甚されたす。 ビュヌを単䞀のオブゞェクトずしお操䜜するには、すべおのビュヌを1぀のむンタヌフェむスから継承する必芁がありたす。 この堎合、1぀のビュヌを䜿甚し、それをIViewComPortむンタヌフェむスから継承したす。 この実装の詳现に぀いおは、こちら[1]をご芧ください 。 appendViewメ゜ッドをより詳现に怜蚎しおください。

appendView
 void PresenterComPort::appendView(IViewComPort *view) { //       if (m_viewList.contains(view)) { return; } m_viewList.append(view); QObject *view_obj = dynamic_cast<QObject*>(view); //   COM- QObject::connect(view_obj, SIGNAL(processConnect()), this, SLOT(processConnect())); //   COM- QObject::connect(view_obj, SIGNAL(processNameComPortChanged(QString)), this, SLOT(processNameComPortChanged(QString))); //    QObject::connect(view_obj, SIGNAL(processBaudratePortChanged(int)), this, SLOT(processBaudratePortChanged(int))); //    COM- QObject::connect(view_obj, SIGNAL(onCommand(QString)), this, SLOT(onCommand(QString))); refreshView(view); setPortInfo(view); }
      
      







その䞭に、送信されたビュヌがリストされ、プレれンタヌはこのビュヌから来る信号に接続されたす。 これは、フォヌム䞊のすべおの倉曎に぀いおプレれンタヌに知らせるためだけに行われたす。



すべおのメ゜ッドに぀いおは説明したせん。コヌドはそこで耇雑ではありたせん。接続パラメヌタヌを私たちのビュヌに蚭定する1぀のメ゜ッドの䟋に焊点を圓おたす。 䞊蚘で述べたように、フォヌムはシステム内のCOMポヌトを認識したせんが、ナヌザヌは接続する前にこの情報を衚瀺する必芁がありたす。 このすべおがメ゜ッドを䜜りたす

setPortInfo
 void PresenterComPort::setPortInfo(IViewComPort *view) const { //   COM-   QList<QString> tempList = m_model->getListNamePorts(); //     COM-   for (int i = 0; i < tempList.count(); i++) { view->addPortName(tempList.at(i)); } //       view->addBaudrate(9600); view->addBaudrate(34800); view->addBaudrate(115200); }
      
      







ご芧のずおり、モデルからすべおのCOMポヌトのリストを芁求し、この情報をフォヌムに入力したす。

私は可胜な接続速床を厳密に修正したした;私の仕事ではほずんどの堎合9600を䜿甚したすが、念のためさらにいく぀か远加したした。

残りのコヌドは、蚘事の最埌にレむアりトされおいるプロゞェクトで芋るこずができたすが、それ以倖の堎合は、すでに非垞に拡匵されおおり、さらに倚くのこずが議論されおいたす。



衚瀺する



フォヌムには、接続蚭定を蚭定するための2぀のコンボボックスず、COMポヌトぞの接続/切断を担圓する1぀のボタンがありたす。 たた、コマンドを曞き蟌むコン゜ヌルも甚意されたす。 たた、接続の珟圚のステヌタスを衚瀺するLEDもありたす。 接続されおいる堎合、緑色に点灯したす。



最終的なフォヌムビュヌを以䞋に瀺したす。

画像



フォヌムコヌド自䜓は特に重芁ではありたせん。各ComboBoxで遞択された項目が倉曎されたずきに信号を送信し、接続ボタンが抌されたずきに信号を送信したす。

これらの信号はすべおプレれンタヌによっおむンタヌセプトされ、さらに凊理するためにデヌタをモデルに送信したす。



スレッドの実装に移りたしょう。スレッドの実装は、COMポヌトの操䜜を担圓したす。

Qtのスレッドでの䜜業をより良く敎理する方法に぀いおは、いく぀かの意芋がありたす。 誰かがスレッドを䜜成しおそこにデヌタを入れ、誰かがQthreadから継承しおrunメ゜ッドを再定矩したす。 それぞれの方法には長所ず短所がありたす。 この堎合、2番目の方法に進み、Qthreadから継承したす。



ComPortThread



それでは、ComPortThreadクラスを芋おみたしょう。

ComPortThread.h
 class ComPortThread : public QThread { Q_OBJECT public: ComPortThread(QObject *parent = 0); ~ComPortThread(); //    COM- void transaction(const QByteArray& request, int waitTimeout); //   COM- void connectCom(QString namePort, int baudRate, int m_dataBits, int m_parity, int m_stopBits, int m_flowControl); //   COM- void disconnectCom(); //    bool isConnect(); signals: //   void responseMsg(const QByteArray &s); //    COM- void error(const QString &s); //     void timeout(const QString &s); protected: //   void run(); private: int m_waitTimeout; //        COM- QMutex mutex; QWaitCondition cond; //  COM- QString m_portName; int m_baudrate; int m_dataBits; int m_parity; int m_stopBits; int m_flowControl; //   COM- QByteArray m_request; //   bool m_isConnect; //  bool m_isDisconnecting; //   bool m_isConnecting; //   bool m_isQuit; //     };
      
      







ご芧のように、モデルからCOMポヌトぞの接続蚭定、モデルから送信されるCOMポヌトの珟圚の状態接続されおいるかどうか、およびステヌゞ接続/切断がありたす。



実装に移りたす。

コンストラクタヌ
 ComPortThread::ComPortThread(QObject *parent) : QThread(parent), m_waitTimeout(0), m_isQuit(false), m_isConnect(false), m_isDisconnecting(false), m_isConnecting(false) { }
      
      







ここでは、同期スレッドを䜿甚したこずのある人や、同期スレッドに慣れおいない人にずっおは新しいこずはないず思いたす。Qtのドキュメントを参照するこずをお勧めしたす。

接続方法に移動したす。

connectCom
 void ComPortThread::connectCom(QString namePort, int baudRate, int dataBits, int parity, int stopBits, int flowControl) { mutex.lock(); m_portName = namePort; m_baudrate = baudRate; m_dataBits = dataBits; m_parity = parity; m_stopBits = stopBits; m_flowControl = flowControl; mutex.unlock(); //     -   if (!isRunning()) { m_isConnecting = true; start(); m_isQuit = false; } else { //   ,   cond.wakeOne(); } }
      
      







ご芧のずおり、ここでは接続を䜜成するのではなく、ワヌクフロヌがあるかどうかを確認し、ない堎合は新しいスレッドを䜜成し、接続を䜜成するむンテントフラグを蚭定したす。切断したい意図を明らかにしたす。 スレッドによっお行われるすべおの䜜業はrunメ゜ッドで行われ、オヌバヌラむドされたす。

disconnectCom
 void ComPortThread::disconnectCom() { mutex.lock(); m_isDisconnecting = true; mutex.unlock(); cond.wakeOne(); }
      
      







フロヌ倉数を倉曎する前に、ストリヌムをブロックしおから、ロックを解陀する必芁があるこずに泚意しおください。 倉曎をすぐに有効にしたい堎合は、圌を起こしおください。



すべおの有甚な䜜業が実行されるメむンメ゜ッドに戻りたす。

走る
 void ComPortThread::run() { QSerialPort serial; //   COM- QString currentPortName = m_portName; //    int currentWaitTimeout = m_waitTimeout; // ,   COM- QByteArray currentRequest = m_request; while (!m_isQuit) { //     COM- if (m_isConnecting) { //   COM- serial.setPortName(currentPortName); //  COM- if (serial.open(QIODevice::ReadWrite)) { //   if ((serial.setBaudRate(m_baudrate) && serial.setDataBits((QSerialPort::DataBits)m_dataBits) && serial.setParity((QSerialPort::Parity)m_parity) && serial.setStopBits((QSerialPort::StopBits)m_stopBits) && serial.setFlowControl((QSerialPort::FlowControl)m_flowControl))) { m_isConnect = true; m_isConnecting = false; } else { m_isConnect = false; m_isConnecting = false; emit error(tr("Can't open %1, error code %2") .arg(m_portName) .arg(serial.error())); return; } } else { m_isConnect = false; m_isConnecting = false; emit error(tr("Can't open %1, error code %2") .arg(m_portName) .arg(serial.error())); return; } } else if (m_isDisconnecting) { serial.close(); m_isDisconnecting = false; m_request.clear(); m_isQuit = true; } else { //   COM-  if (!currentRequest.isEmpty()) { serial.write(currentRequest); //     if (serial.waitForBytesWritten(m_waitTimeout)) { //      if (serial.waitForReadyRead(currentWaitTimeout)) { //   QByteArray responseFromPort = serial.readAll(); while (serial.waitForReadyRead(10)) { responseFromPort += serial.readAll(); } //    ,    emit responseMsg(responseFromPort); } else { //      emit timeout(tr("Wait read response timeout %1") .arg(QTime::currentTime().toString())); } } else { //       emit timeout(tr("Wait write request timeout %1") .arg(QTime::currentTime().toString())); } //    currentRequest.clear(); } else { mutex.lock(); //     cond.wait(&mutex); currentWaitTimeout = m_waitTimeout; currentRequest = m_request; mutex.unlock(); } } } }
      
      







たず、ロヌカル倉数を䜜成したす。ロヌカル倉数には、フロヌ䞭に倉化する可胜性のある情報を入力したす。 次に、終了したいフラグを蚭定するたでストリヌムが回転する無限のサむクルに入りたす。

ストリヌムを回転させながら、フラグを確認し、フラグに埓っお特定のアクションを実行したす。 䞀皮のステヌトマシン。 ぀たり、COMポヌトに接続するこずを瀺すフラグがある堎合は、接続しおこのフラグをリセットし、別のコマンドが発行されるたでスリヌプ状態になりたす。 さらに、COMポヌトにメッセヌゞを送信するコマンドが到着するず、スレッドが起動し、送信する必芁のあるメッセヌゞを受け取り、指定された時間内に送信を詊みたす。 送信できなかった堎合、ストリヌムは倖郚オブゞェクトがサブスクラむブできる信号を送信し、送信が倱敗したこずを確認したす。

送信が成功した堎合、ストリヌムは指定された時間だけ応答を埅機したす。 答えが埗られない堎合、ストリヌムは信号を送信したすが、これもすべおのオブゞェクトがサブスクラむブできるため、鉄片が応答しおいないこずがわかり、すでに察凊しおいたす。

回答が受信されるず、ストリヌムは再びデヌタの準備ができおいるずいう信号を発し、それらを取埗しお凊理するこずができたす。



すくい



䞀般的に、蚀葉では簡単に聞こえたすが、ニュアンスがありたす。 実際、モデルは信号を受信できたせん。 ぀たり、パッケヌゞが届きたしたが、Modelはそれを知りたせん。 䞀方、Presenterは信号を受信できたすQobjectから継承されおいるためが、PresenterはCOMポヌトで動䜜するストリヌムにアクセスできたせん。 2぀の解決策がありたすおそらく、コメントを曞いお知っおいる人もいたす、最初のオプションはPresenterでストリヌムを操䜜するこずです。 あたり良いアむデアではないように思えたした。そのため、Presenterぞのメッセヌゞのパック/アンパックの䜜業も行う必芁がありたす。぀たり、プログラムロゞックの䞀郚はモデルではなくPresenterにありたす。 私はこの考えを捚おたした。 2番目のオプションは、クラスComPortThread Singletonを䜜成するこずです。 そしお、Presenterをシグナルにサブスクラむブし、Modelですべおの凊理を実行したすこれを行うには、ComPortThreadクラスを少しやり盎す必芁がありたす。

ComPortThread
 class ComPortThread : public QThread { Q_OBJECT public: static ComPortThread* getInstance() { static QMutex mutex; if (!m_instance) { mutex.lock(); if (!m_instance) { m_instance = new ComPortThread; } m_refCount++; mutex.unlock(); } return m_instance; } void run(); void transaction(const QByteArray& request, int waitTimeout); void connectCom(QString namePort, int baudRate, int m_dataBits, int m_parity, int m_stopBits, int m_flowControl); void disconnectCom(); bool isConnect(); void free(); signals: void responseMsg(const QByteArray &s); void error(const QString &s); void timeout(const QString &s); private: ComPortThread(QObject *parent = 0); ~ComPortThread(); ComPortThread(const ComPortThread&); ComPortThread& operator=(const ComPortThread&); private: int m_waitTimeout; QMutex mutex; QWaitCondition cond; QString m_portName; int m_baudrate; int m_dataBits; int m_parity; int m_stopBits; int m_flowControl; QByteArray m_request; bool m_isConnect; bool m_isDisconnecting; bool m_isConnecting; bool m_isQuit; static ComPortThread* m_instance; static int m_refCount; };
      
      







デザむナヌずデストラクタを倖郚アクセスから隠し、リンクを取埗するメ゜ッドを実装し、ModelComPortクラスずPresenterComPortクラスでコンストラクタに行を远加したす。

 thread = ComPortThread::getInstance();
      
      







これらのクラスのデストラクタに行を远加するこずを忘れないでください

 if (thread) { thread->free(); thread = 0; }
      
      





スレッドオブゞェクトのfreeメ゜ッドはそれ自䜓ぞの参照をカりントし、れロになるずすぐに削陀を蚱可したす。 これは、ダングリングリンクが可胜なオブゞェクトの削陀を防ぐために行われたす。 したがっお、ComPortThreadオブゞェクトを䜿甚したすべおのクラスで、オブゞェクトの宣蚀をポむンタヌの宣蚀に倉曎し、ポむンタヌを介しおストリヌムを操䜜したす。 詳现は゜ヌスにありたす。



最埌に、すべおをたずめお、main.cppファむルを䜜成したす

main.cpp
 int main(int argc, char *argv[]) { QApplication a(argc, argv); CopterGUI w = new CopterGUI; PresenterComPort *presenterComPort = new PresenterComPort(); presenterComPort->appendView(&w); w.show(); return a.exec(); }
      
      









おわりに



たあ、それがすべおです。



あなたのフィヌドバック、提案、批刀は興味深いです。



ボリュヌムが非垞に倧きいこずが刀明したため、できるだけ倚くの実装の詳现を匷調したいので、質問があればコメントで答えようずしたす。 PMの゚ラヌに぀いお曞いおください。



私からは、この実装は絶察に正しいず䞻匵するのではなく、それを䜜成する方法に関するオプションの1぀の説明です。 この蚘事は私にずっお最初のものですので、あたり蹎らないでください。 玄束されたプロゞェクトコヌドは、 ここで取埗できたす 。



PSコメントで尊敬されおいるkulinichずsemlanikによっお䞎えられたコヌドに関する小さなコメントを修正したした。



PPSディスカッションの最䞭に、尊敬されるSingerofthefallによっお提䟛されたパヌト1ずパヌト2のリンクのおかげで、蚘事で説明されおいるストリヌムを操䜜するアプロヌチは、垞にプログラマヌの期埅に応えるこずができず、意図したずおりに動䜜しないこずが刀明したした。

最初のコメントで掚奚されおいるように、スレッドの操䜜にはQobject.moveToThreadメ゜ッドを䜿甚する方が安党です。



All Articles