zoukankan      html  css  js  c++  java
  • QT blockingmaster例子学习

    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:"
                                 "
    
    -request: %2"
                                 "
    
    -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]
    }
    无欲速,无见小利。欲速,则不达;见小利,则大事不成。
  • 相关阅读:
    【无私分享:从入门到精通ASP.NET MVC】从0开始,一起搭框架、做项目(8) 权限管理,自定义权限,扩展权限
    致博客园网友
    【无私分享:从入门到精通ASP.NET MVC】从0开始,一起搭框架、做项目(7.2) 模块管理,模块的添加、修改、删除
    【无私分享:从入门到精通ASP.NET MVC】从0开始,一起搭框架、做项目(7.1) 模块管理,验证权限,展示模块列表
    【无私分享:从入门到精通ASP.NET MVC】从0开始,一起搭框架、做项目(6) 控制器基类 主要做登录用户、权限认证、日志记录等工作
    【无私分享:从入门到精通ASP.NET MVC】从0开始,一起搭框架、做项目(5.5) 登录功能的实现,完善登录功能
    【C#公共帮助类】 WebHelper帮助类
    【无私分享:从入门到精通ASP.NET MVC】从0开始,一起搭框架、做项目(5.4) 登录功能的实现,创建与登录用户相关的接口和实现类
    【无私分享:从入门到精通ASP.NET MVC】从0开始,一起搭框架、做项目(5.3) 登录功能的实现,丰富数据表、建立关联
    【无私分享:从入门到精通ASP.NET MVC】从0开始,一起搭框架、做项目(5.2) 登录功能的实现,接口注入、log4net的使用
  • 原文地址:https://www.cnblogs.com/ch122633/p/7497379.html
Copyright © 2011-2022 走看看