美文网首页
Qt 官方示例 | 简单几步,小白也能制作一个串口终端

Qt 官方示例 | 简单几步,小白也能制作一个串口终端

作者: 老吴的嵌入式之旅 | 来源:发表于2021-04-22 18:35 被阅读0次

    大家好,我是老吴。

    我又成功写了一篇小文章,每当我没动力写文章的时候,我就会把写文章的门槛降低,这其实是很好的一个技巧,把一个大目标切成很多小目标,是对付拖延症的一个好方法。

    正巧最近看了一些讨论敏捷开发的文章,或者是不是可以考虑一下怎么敏捷学习?

    某个项目的长时间开发会消磨开发人员的耐心,长时间学习某样东西同样也会打击人的信心。

    再说了,你怎么知道现在学习的东西将来是否会在工作上用得上。

    所以,我的结论是:学到的知识尽量马上用。能用一点是一点,不够用了再回头补!

    回到正题,学习 Qt 的最佳途径是阅读官方的手册和示例。

    今天要分享的是 Qt 官方示例:terminal。

    一个简易的串口终端工具:

    点击查看大图

    它演示了如何创建一个终端,并使用 QSerialPort 进行串口通讯。

    源码文件:

    terminal/
    ├── console.cpp
    ├── console.h
    ├── images/
    ├── main.cpp
    ├── mainwindow.cpp
    ├── mainwindow.h
    ├── mainwindow.ui
    ├── settingsdialog.cpp
    ├── settingsdialog.h
    ├── settingsdialog.ui
    ├── terminal.pro
    └── terminal.qrc

    接下来,跟我一起来实现这个小工具吧。

    正文目录:

    1. 新建 Qt Widgets Application
    2. 设计主界面
    3. 实现主界面的功能
    4. 设计设置界面
    5. 实现设置界面的功能
    6. 相关参考

    1. 新建 Qt Widgets Application

    在 Qt Creator 里 点击File > New File or Project > Applications > Qt Widgets Application > Choose:

    点击查看大图

    以 QMainWindow 作为基类,子类名为 MainWindow:

    新建完成后会得到下列文件:

    terminal/
    ├── main.cpp
    ├── mainwindow.cpp
    ├── mainwindow.h
    ├── mainwindow.ui
    ├── terminal.pro
    └── terminal.qrc

    运行效果:

    点击查看大图

    此时只有跟 QMainWindow 一样的界面,还没有任何串口终端相关的功能。

    2. 设计主界面

    主界面分为 4 部分:

    点击查看大图

    1、菜单栏,用 QMenuBar 实现,用于提供串口终端的核心操作功能;

    2、工具栏,用 QToolBar 实现,用于提供快捷操作;

    3、中间区域留空,待会在 C++ 中通过继承 QPlainTextEdit 来实现,用于输入和输出串口信息;

    4、状态栏,用 QstatusBar 实现,用于显示当前的连接状态。

    在 Qt Designer 里执行下列操作:

    1、菜单栏里添加 Calls、Tools 菜单项:

    在 Calls 里添加子菜单项 Connect、Disconnect,分别对应连接和断开串口的功能。

    在 Tools 里添加子菜单项 Configure、Clear,分别对应打开设置窗口、清空终端信息的功能。

    2、工具栏里添加 Connect、Disconnect、Configure、Clear 按钮;

    3、添加 Setting 对话框:

    使用 Dialog without Buttions 模板,新建名为 "SettingsDialog" 的对话框。

    运行效果:

    点击查看大图

    此时,菜单栏和工具栏里的菜单项并没有任何实际功能。

    3. 实现 Setting 功能

    由于连接串口前需要先设置参数,所以我们需要先实现 Setting 界面里的功能。

    设计界面:

    点击查看大图

    此时,还没有实际的功能。

    支持选择串口设备:

    // 文件:settingsdialog.cpp
    void SettingsDialog::fillPortsInfo(){
        ...
        // 拿到系统当前所有可用的串口设备列表
        const auto infos = QSerialPortInfo::availablePorts();

        // 初始化组合框
        for (const QSerialPortInfo &info : infos) {
            QStringList list;
            description = info.description();
            manufacturer = info.manufacturer();
            serialNumber = info.serialNumber();
            list << info.portName();
            ...
            m_ui->serialPortInfoListBox->addItem(list.first(), list);
        }
    }

    在 Qt 里,可以通过 QSerialPortInfo 来获取系统当前可用的串口设备列表,我们拿到串口信息后,就用它来初始化Serial Port 组合框。

    当选择不同的串口设备时,要切换设备的描述信息:

    connect(m_ui->serialPortInfoListBox,
    QOverload<int>::of(&QComboBox::currentIndexChanged), this,&SettingsDialog::showPortInfo);

    运行效果:

    点击查看大图

    支持设置串口参数:

    // 文件:settingsdialog.cpp
    void SettingsDialog::fillPortsParameters(){
        // 添加可选的波特率、数据位数等串口参数
        m_ui->baudRateBox->addItem(QStringLiteral("9600"), QSerialPort::Baud9600);
        m_ui->baudRateBox->addItem(QStringLiteral("19200"), QSerialPort::Baud19200);
        m_ui->baudRateBox->addItem(QStringLiteral("38400"), QSerialPort::Baud38400);
        m_ui->baudRateBox->addItem(QStringLiteral("115200"), QSerialPort::Baud115200);

        ...
    }

    在 Qt 里,串口相关的功能由 qtserialport 模块负责实现,只要就是 QSerialPort 和 QSerialPortInfo 这两个类。

    运行效果:

    点击查看大图

    支持保存设置:

    // 文件:settingsdialog.cpp
    void SettingsDialog::apply(){
        updateSettings();
        hide();
    }

    // 将串口参数保存在变量 m_currentSettings 中
    void SettingsDialog::updateSettings(){
        m_currentSettings.name = m_ui->serialPortInfoListBox->currentText();

        m_currentSettings.baudRate = static_cast<QSerialPort::BaudRate>(m_ui->baudRateBox->itemData(m_ui->baudRateBox->currentIndex()).toInt());

        ...
    }

    当点击 Apply 按钮时,就会调用到 apply(),进而将界面上的串口参数保存在 struct Settings m_currentSettings 中。

    运行效果:

    点击查看大图

    4. 实现串口 Connect 功能

    // 文件:mainwindow.cpp
    void MainWindow::openSerialPort(){
        const SettingsDialog::Settings p = m_settings->settings();
        // 要打开哪个串口设备?
        m_serial->setPortName(p.name);
        ...

        // 仍然是那个熟悉的 open()
        if (m_serial->open(QIODevice::ReadWrite)) {
            m_console->setEnabled(true);
            m_ui->actionConnect->setEnabled(false);
            m_ui->actionDisconnect->setEnabled(true);
            m_ui->actionConfigure->setEnabled(false);
            ...
        }
    }

    当点击 Connect 按钮时,就会调用到 openSerialPort(),进而将执行到 QSerialPort 的 open()。

    m_console 是一个 QPlainTextEdit 类型的对象,它负责显示串口。

    运行效果:

    点击查看大图

    此时已经能打开串口设备了,但是还无法显示串口数据。

    5. 实现串口读写功能

    支持从串口读数据:

    // 文件:mainwindow.cpp
    void MainWindow::readData(){
        // 从串口硬件中读数据
        const QByteArray data = m_serial->readAll();
        // 显示在文本框中
        m_console->putData(data);
    }

    打开串口后,当串口有数据时,就调用 MainWindow::readData() 将数据读出来并显示到界面上。putData() 会调用

    QPlainTextEdit::insertPlainText() 将数据显示在文本框里。

    支持向串口写数据:

    // 文件:console.cpp
    void Console::keyPressEvent(QKeyEvent *e){
        switch (e->key()) {
        // 不处理某些按键
        case Qt::Key_Backspace:
        ...
            break;
        default:
            // 发送接收到用户输入的信号
            emit getData(e->text().toLocal8Bit());
        }
    }

    当用户通过键盘输入时,m_console 会捕获该事件并发出信号,主界面接收到该信号后,会执行真正的写串口操作:

    // 文件:mainwindow.cpp
    MainWindow::MainWindow(QWidget *parent)
        : ...
    {
        ...
        connect(m_console, &Console::getData, this, &MainWindow::writeData);
    }

    void MainWindow::writeData(const QByteArray &data){
        // 熟悉的 write()
        m_serial->write(data);
    }

    运行效果:

    点击查看大图

    到此,这个 Qt 的官方示例子 terminal 的核心功能就实现完毕啦。

    感兴趣的小伙伴们请自行阅读 Qt example 里的完整代码吧。

    相关参考

    《Qt 官方文档》

    《C++ GUI Qt4 编程 (第二版)》

    《Qt5 编程入门 (第二版)》

    《Qt Creator 快速入门》

    —— The End ——

    相关文章

      网友评论

          本文标题:Qt 官方示例 | 简单几步,小白也能制作一个串口终端

          本文链接:https://www.haomeiwen.com/subject/ulufrltx.html