1. 程式人生 > >QT blockingmaster例子學習

QT blockingmaster例子學習

qwidget 等待 cit 數據 nec 為什麽 star nullptr 同步

dialog.h:

#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>

#include "masterthread.h"
//這裏的寫法有點。。為什麽不直接加頭文件
QT_BEGIN_NAMESPACE

class QLabel;
class QLineEdit;
class QSpinBox;
class QPushButton;
class QComboBox;

QT_END_NAMESPACE

class Dialog : public QDialog
{
    Q_OBJECT

public:
    explicit
Dialog(QWidget *parent = nullptr); private slots: void transaction(); void showResponse(const QString &s); void processError(const QString &s); void processTimeout(const QString &s); private: void setControlsEnabled(bool enable); private: int transactionCount; QLabel
*serialPortLabel;                  //聲明了各類控件 QComboBox *serialPortComboBox; QLabel *waitResponseLabel; QSpinBox *waitResponseSpinBox; QLabel *requestLabel; QLineEdit *requestLineEdit; QLabel *trafficLabel; QLabel *statusLabel; QPushButton *runButton; MasterThread thread;                    //創建了一個線程類 };
#endif // DIALOG_H

masterthread.h:

#ifndef MASTERTHREAD_H
#define MASTERTHREAD_H

#include <QThread>
#include <QMutex>
#include <QWaitCondition>

//! [0]
class MasterThread : public QThread
{
    Q_OBJECT

public:
    explicit MasterThread(QObject *parent = nullptr);
    ~MasterThread();

    void transaction(const QString &portName, int waitTimeout, const QString &request);        //用來傳遞GUI界面的信息函數
    void run() Q_DECL_OVERRIDE;                                         //線程運行函數

signals:
    void response(const QString &s);                                      //一些信號:響應、錯誤、時間
    void error(const QString &s);
    void timeout(const QString &s);

private:
    QString portName;                                               //需要操作記錄的私有變量
    QString request;
    int waitTimeout;
    QMutex mutex;                                                                                    //互斥鎖,保護上面的私有變量
    QWaitCondition cond;                                                                             //條件變量,用來同步
    bool quit;
};
//! [0]

#endif // MASTERTHREAD_H

dialog.cpp:

#include "dialog.h"

#include <QLabel>
#include <QLineEdit>
#include <QComboBox>
#include <QSpinBox>
#include <QPushButton>
#include <QGridLayout>

#include <QtSerialPort/QSerialPortInfo>

QT_USE_NAMESPACE

Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
    , transactionCount(0)
    , serialPortLabel(new QLabel(tr("Serial port:")))
    , serialPortComboBox(new QComboBox())
    , waitResponseLabel(new QLabel(tr("Wait response, msec:")))
    , waitResponseSpinBox(new QSpinBox())
    , requestLabel(new QLabel(tr("Request:")))
    , requestLineEdit(new QLineEdit(tr("Who are you?")))
    , trafficLabel(new QLabel(tr("No traffic.")))
    , statusLabel(new QLabel(tr("Status: Not running.")))
    , runButton(new QPushButton(tr("Start")))
{
    const auto infos = QSerialPortInfo::availablePorts();
    for (const QSerialPortInfo &info : infos)
        serialPortComboBox->addItem(info.portName());

    waitResponseSpinBox->setRange(0, 10000);
    waitResponseSpinBox->setValue(1000);

    auto mainLayout = new QGridLayout;
    mainLayout->addWidget(serialPortLabel, 0, 0);
    mainLayout->addWidget(serialPortComboBox, 0, 1);
    mainLayout->addWidget(waitResponseLabel, 1, 0);
    mainLayout->addWidget(waitResponseSpinBox, 1, 1);
    mainLayout->addWidget(runButton, 0, 2, 2, 1);
    mainLayout->addWidget(requestLabel, 2, 0);
    mainLayout->addWidget(requestLineEdit, 2, 1, 1, 3);
    mainLayout->addWidget(trafficLabel, 3, 0, 1, 4);
    mainLayout->addWidget(statusLabel, 4, 0, 1, 5);
    setLayout(mainLayout);

    setWindowTitle(tr("Blocking Master"));
    serialPortComboBox->setFocus();

    connect(runButton, &QPushButton::clicked, this, &Dialog::transaction);
    connect(&thread, &MasterThread::response, this, &Dialog::showResponse);
    connect(&thread, &MasterThread::error, this, &Dialog::processError);
    connect(&thread, &MasterThread::timeout, this, &Dialog::processTimeout);
}

void Dialog::transaction()
{
    setControlsEnabled(false);
    statusLabel->setText(tr("Status: Running, connected to port %1.")
                         .arg(serialPortComboBox->currentText()));
    thread.transaction(serialPortComboBox->currentText(),
                       waitResponseSpinBox->value(),
                       requestLineEdit->text());
}

void Dialog::showResponse(const QString &s)
{
    setControlsEnabled(true);
    trafficLabel->setText(tr("Traffic, transaction #%1:"
                             "\n\r-request: %2"
                             "\n\r-response: %3")
                          .arg(++transactionCount).arg(requestLineEdit->text()).arg(s));
}

void Dialog::processError(const QString &s)
{
    setControlsEnabled(true);
    statusLabel->setText(tr("Status: Not running, %1.").arg(s));
    trafficLabel->setText(tr("No traffic."));
}

void Dialog::processTimeout(const QString &s)
{
    setControlsEnabled(true);
    statusLabel->setText(tr("Status: Running, %1.").arg(s));
    trafficLabel->setText(tr("No traffic."));
}

void Dialog::setControlsEnabled(bool enable)
{
    runButton->setEnabled(enable);
    serialPortComboBox->setEnabled(enable);
    waitResponseSpinBox->setEnabled(enable);
    requestLineEdit->setEnabled(enable);
}

masterthread.cpp:

#include "masterthread.h"

#include <QtSerialPort/QSerialPort>

#include <QTime>

QT_USE_NAMESPACE

MasterThread::MasterThread(QObject *parent)
    : QThread(parent), waitTimeout(0), quit(false)
{
}

//! [0]
MasterThread::~MasterThread()
{
    mutex.lock();
    quit = true;
    cond.wakeOne();
    mutex.unlock();
    wait();
}
//! [0]

//! [1] //! [2]
void MasterThread::transaction(const QString &portName, int waitTimeout, const QString &request)
{
    //! [1]
    QMutexLocker locker(&mutex);                            //用QMutexLocker鎖住函數內的操作
    this->portName = portName;
    this->waitTimeout = waitTimeout;
    this->request = request;
    //! [3]
    if (!isRunning())                                  //判斷線程是否啟動
        start();
    else
        cond.wakeOne();                                 //已經啟動則喚醒線程
}
//! [2] //! [3]

//! [4]
void MasterThread::run()
{
    bool currentPortNameChanged = false;          //臨時變量

    mutex.lock();
    //! [4] //! [5]
    QString currentPortName;                  //臨時變量
    if (currentPortName != portName) {
        currentPortName = portName;
        currentPortNameChanged = true;
    }

    int currentWaitTimeout = waitTimeout;
    QString currentRequest = request;
    mutex.unlock();                      //到這裏把私有信息傳遞進去了
    //! [5] //! [6]
    QSerialPort serial;                    //創建了一個串口類

    while (!quit) {
        //![6] //! [7]
        if (currentPortNameChanged) {            //如果改了名字
            serial.close();
            serial.setPortName(currentPortName);      //重新打開

            if (!serial.open(QIODevice::ReadWrite)) {        //判斷是否打開成功
                emit error(tr("Can‘t open %1, error code %2")
                           .arg(portName).arg(serial.error()));
                return;
            }
        }
        //! [7] //! [8]
        // write request
        QByteArray requestData = currentRequest.toLocal8Bit();      //請求的消息轉成byte格式
        serial.write(requestData);                      //發送數據
        if (serial.waitForBytesWritten(waitTimeout)) {           //等待waitTimeout時間發送數據
            //! [8] //! [10]
            // read response
            if (serial.waitForReadyRead(currentWaitTimeout)) {      //等待waitTimeout時間讀取串口數據
                QByteArray responseData = serial.readAll();        //將讀取數據寫到responseData中
                while (serial.waitForReadyRead(10))             //再等10秒
                    responseData += serial.readAll();            //寫進responseData中

                QString response(responseData);               //這裏又轉成QString類型了
                //! [12]
                emit this->response(response);               //發送response信號
                //! [10] //! [11] //! [12]
            } else {
                emit timeout(tr("Wait read response timeout %1")
                             .arg(QTime::currentTime().toString()));    //發送響應延時信號
            }
            //! [9] //! [11]
        } else {
            emit timeout(tr("Wait write request timeout %1")
                         .arg(QTime::currentTime().toString()));         //發送寫延時信號
        }
        //! [9]  //! [13]
        mutex.lock();
        cond.wait(&mutex);                           //這裏又等待了?怎麽喚醒?第二次按按鈕時喚醒,這是一個循環。再次點擊又運行一次
        if (currentPortName != portName) {
            currentPortName = portName;
            currentPortNameChanged = true;
        } else {
            currentPortNameChanged = false;
        }
        currentWaitTimeout = waitTimeout;
        currentRequest = request;
        mutex.unlock();
    }
    //! [13]
}

QT blockingmaster例子學習