草庐IT

Qt 学习笔记 - 第三章 - Qt的三驾马车之一 - 串口编程 + 程序打包成Windows软件

Dandelion 2023-03-28 原文

Qt 学习笔记全系列传送门:

1、创建项目

实现串口助手

  • 创建 Qt Widgets Application 项目 seial

  • 基类选择 Widget

2、UI

  • UI设计

    1. 接收框组件,在分类 Input Widgets 中,Plain Text Edit 组件(QPlainTextEdit),双击可以编辑选项,置顶项为默认选择属性,勾选组件的只读属性 readOnly
    2. 属性选择,在分类 Input Widgets 中,Combo Box 组件(QComboBox)
    3. 发送框,在分类在 Input Widgets 中,Line Edit 组件(QLineEdit)
    4. 信息框,写个广告之类的可以使用,在分类 中,Group Box 组件(QGroupBox)
    5. 控件改名
  • UI代码展示

    <?xml version="1.0" encoding="UTF-8"?>
    <ui version="4.0">
     <class>Widget</class>
     <widget class="QWidget" name="Widget">
      <property name="geometry">
       <rect>
        <x>0</x>
        <y>0</y>
        <width>800</width>
        <height>480</height>
       </rect>
      </property>
      <property name="windowTitle">
       <string>Widget</string>
      </property>
      <widget class="QWidget" name="layoutWidget">
       <property name="geometry">
        <rect>
         <x>31</x>
         <y>31</y>
         <width>737</width>
         <height>385</height>
        </rect>
       </property>
       <layout class="QGridLayout" name="gridLayout_3">
        <item row="0" column="0">
         <widget class="QPlainTextEdit" name="recvEdit">
          <property name="readOnly">
           <bool>true</bool>
          </property>
         </widget>
        </item>
        <item row="1" column="0">
         <spacer name="verticalSpacer">
          <property name="orientation">
           <enum>Qt::Vertical</enum>
          </property>
          <property name="sizeHint" stdset="0">
           <size>
            <width>20</width>
            <height>40</height>
           </size>
          </property>
         </spacer>
        </item>
        <item row="2" column="0">
         <layout class="QGridLayout" name="gridLayout_2">
          <item row="0" column="0">
           <layout class="QGridLayout" name="gridLayout">
            <item row="0" column="0">
             <widget class="QLabel" name="label_2">
              <property name="text">
               <string>波特率</string>
              </property>
             </widget>
            </item>
            <item row="0" column="1">
             <widget class="QComboBox" name="baundrateCb">
              <item>
               <property name="text">
                <string>4800</string>
               </property>
              </item>
              <item>
               <property name="text">
                <string>9600</string>
               </property>
              </item>
              <item>
               <property name="text">
                <string>115200</string>
               </property>
              </item>
             </widget>
            </item>
            <item row="1" column="0">
             <widget class="QLabel" name="label">
              <property name="text">
               <string>串口号</string>
              </property>
             </widget>
            </item>
            <item row="1" column="1">
             <widget class="QComboBox" name="serialCb"/>
            </item>
            <item row="2" column="0">
             <widget class="QLabel" name="label_5">
              <property name="text">
               <string>数据位</string>
              </property>
             </widget>
            </item>
            <item row="2" column="1">
             <widget class="QComboBox" name="dataCb">
              <item>
               <property name="text">
                <string>5</string>
               </property>
              </item>
              <item>
               <property name="text">
                <string>6</string>
               </property>
              </item>
              <item>
               <property name="text">
                <string>7</string>
               </property>
              </item>
              <item>
               <property name="text">
                <string>8</string>
               </property>
              </item>
             </widget>
            </item>
            <item row="3" column="0">
             <widget class="QLabel" name="label_4">
              <property name="text">
               <string>停止位</string>
              </property>
             </widget>
            </item>
            <item row="3" column="1">
             <widget class="QComboBox" name="stopCb">
              <item>
               <property name="text">
                <string>1</string>
               </property>
              </item>
              <item>
               <property name="text">
                <string>1.5</string>
               </property>
              </item>
              <item>
               <property name="text">
                <string>2</string>
               </property>
              </item>
             </widget>
            </item>
            <item row="4" column="0">
             <widget class="QLabel" name="label_3">
              <property name="text">
               <string>校验位</string>
              </property>
             </widget>
            </item>
            <item row="4" column="1">
             <widget class="QComboBox" name="checkCb">
              <item>
               <property name="text">
                <string>none</string>
               </property>
              </item>
             </widget>
            </item>
           </layout>
          </item>
          <item row="0" column="1">
           <spacer name="horizontalSpacer_4">
            <property name="orientation">
             <enum>Qt::Horizontal</enum>
            </property>
            <property name="sizeHint" stdset="0">
             <size>
              <width>40</width>
              <height>20</height>
             </size>
            </property>
           </spacer>
          </item>
          <item row="0" column="2">
           <layout class="QVBoxLayout" name="verticalLayout_2">
            <item>
             <widget class="QGroupBox" name="groupBox">
              <property name="title">
               <string>欢迎使用,这是一个信息框</string>
              </property>
              <widget class="QLabel" name="label_6">
               <property name="geometry">
                <rect>
                 <x>120</x>
                 <y>30</y>
                 <width>161</width>
                 <height>21</height>
                </rect>
               </property>
               <property name="text">
                <string>demo info...</string>
               </property>
              </widget>
             </widget>
            </item>
            <item>
             <widget class="QLineEdit" name="sendEdit"/>
            </item>
            <item>
             <layout class="QHBoxLayout" name="horizontalLayout_6">
              <item>
               <widget class="QPushButton" name="openBt">
                <property name="text">
                 <string>打开串口</string>
                </property>
               </widget>
              </item>
              <item>
               <spacer name="horizontalSpacer">
                <property name="orientation">
                 <enum>Qt::Horizontal</enum>
                </property>
                <property name="sizeHint" stdset="0">
                 <size>
                  <width>40</width>
                  <height>20</height>
                 </size>
                </property>
               </spacer>
              </item>
              <item>
               <widget class="QPushButton" name="closeBt">
                <property name="text">
                 <string>关闭串口</string>
                </property>
               </widget>
              </item>
              <item>
               <spacer name="horizontalSpacer_2">
                <property name="orientation">
                 <enum>Qt::Horizontal</enum>
                </property>
                <property name="sizeHint" stdset="0">
                 <size>
                  <width>40</width>
                  <height>20</height>
                 </size>
                </property>
               </spacer>
              </item>
              <item>
               <widget class="QPushButton" name="sendBt">
                <property name="text">
                 <string>发送</string>
                </property>
               </widget>
              </item>
              <item>
               <spacer name="horizontalSpacer_3">
                <property name="orientation">
                 <enum>Qt::Horizontal</enum>
                </property>
                <property name="sizeHint" stdset="0">
                 <size>
                  <width>40</width>
                  <height>20</height>
                 </size>
                </property>
               </spacer>
              </item>
              <item>
               <widget class="QPushButton" name="clearBt">
                <property name="text">
                 <string>清空</string>
                </property>
               </widget>
              </item>
             </layout>
            </item>
           </layout>
          </item>
         </layout>
        </item>
       </layout>
      </widget>
     </widget>
     <layoutdefault spacing="6" margin="11"/>
     <resources/>
     <connections/>
    </ui>
    

3、逻辑功能

  1. 在工程文件中引入serialport

    QT       += core gui serialport
    
  2. 获取串口信息并展示到页面上,在目前 UI 对应的 cpp 的构造中进行

    说明:需要连接单片机才能显示串口号

    Widget::Widget(QWidget *parent) :
        QWidget(parent),
        ui(new Ui::Widget)
    {
        ui->setupUi(this);
        QStringList serialNamePorts;
    
        // QSerialPort 是串口信息类,用于存放串口信息
        // QSerialPortInfo::availablePorts() 自动搜索可用串口,返回串口信息类对象的数组
        foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts()) {
    
            // 将得到的串口信息的串口号加入到 QStringList 中
            serialNamePorts<<info.portName();
        }
    
        // 将可用串口的列表显示到页面的下拉框中
        ui->serialCb->addItems(serialNamePorts);
    }
    
  3. 其他控件的逻辑功能

    • 点击打开串口时对串口进行初始化

      • 对串口的声明和创建

        • 头文件

          #ifndef WIDGET_H
          #define WIDGET_H
          
          #include <QWidget>
          #include <QSerialPort>
          
          namespace Ui {
          class Widget;
          }
          
          class Widget : public QWidget
          {
              Q_OBJECT
          
          public:
              explicit Widget(QWidget *parent = 0);
              ~Widget();
              // 声明QSerialPort *serialPort
              QSerialPort *serialPort;
          
          private slots:
              void on_openBt_clicked();
          
              void on_closeBt_clicked();
          
              void on_sendBt_clicked();
              
              void on_clearBt_clicked();
              
          private:
              Ui::Widget *ui;
          };
          
          #endif // WIDGET_H
          
          
        • Cpp文件

          #include "widget.h"
          #include "ui_widget.h"
          #include <QSerialPortInfo>
          #include <QMessageBox>
          
          Widget::Widget(QWidget *parent) :
              QWidget(parent),
              ui(new Ui::Widget)
          {
              ui->setupUi(this);
              // ...
          
              serialPort = new QSerialPort(this);
          
              // ... 
          }
          
          Widget::~Widget()
          {
              delete serialPort;
              delete ui;
          }
          
      • 打开按钮单击信号的槽函数

        // 点击打开串口时将数据设置进串口并打开串口
        void Widget::on_openBt_clicked()
        {
            QSerialPort::BaudRate baudReat;
            QSerialPort::DataBits dataBits;
            QSerialPort::StopBits stopBits;
            QSerialPort::Parity checkBits;
        
            // 获取界面上的值
            switch(ui->baundrateCb->currentText().toInt()) {
            case QSerialPort::Baud4800:
                baudReat = QSerialPort::Baud4800;
                break;
            case QSerialPort::Baud9600:
                baudReat = QSerialPort::Baud9600;
                break;
            case QSerialPort::Baud115200:
                baudReat = QSerialPort::Baud115200;
                break;
            }
        
            switch(ui->dataCb->currentText().toInt()) {
            case QSerialPort::Data5:
                dataBits = QSerialPort::Data5;
                break;
            case QSerialPort::Data6:
                dataBits = QSerialPort::Data6;
                break;
            case QSerialPort::Data7:
                dataBits = QSerialPort::Data7;
                break;
            case QSerialPort::Data8:
                dataBits = QSerialPort::Data8;
                break;
            }
        
            int stopTmp = ui->stopCb->currentText().toInt();
            if (stopTmp == QSerialPort::OneStop) {
                stopBits = QSerialPort::OneStop;
            } else if (stopTmp == QSerialPort::OneAndHalfStop) {
                stopBits = QSerialPort::OneAndHalfStop;
            } else if (stopTmp == QSerialPort::TwoStop) {
                stopBits = QSerialPort::TwoStop;
            }
        
            if (ui->checkCb->currentText() == "none") {
                checkBits = QSerialPort::NoParity;
            }
        
            // 使用获取到的数据设置串口
            serialPort->setPortName(ui->serialCb->currentText());
            serialPort->setBaudRate(baudReat);
            serialPort->setDataBits(dataBits);
            serialPort->setStopBits(stopBits);
            serialPort->setParity(checkBits);
        
            // 打开串口,需要先判断串口是否打开成功
            if (serialPort->open(QIODevice::ReadWrite) == true) {
                QMessageBox::information(this, "提示", "success!");
            } else {
                QMessageBox::critical(this, "提示", "failed!");
            }
        }
        
      • 关闭按钮单击信号槽函数

        void Widget::on_closeBt_clicked()
        {
            serialPort->close();
        }
        
      • 发送按钮单击信号槽函数

        void Widget::on_sendBt_clicked()
        {
            // 将UI发送的QString转换为char* 类型,写入到serialPort
            serialPort->write(ui->sendEdit->text().toLocal8Bit().data());
        }
        
      • 串口有东西可读时,在接收框中进行展示

        • 定义槽函数,在头文件中

          #ifndef WIDGET_H
          #define WIDGET_H
          
          #include <QWidget>
          #include <QSerialPort>
          
          namespace Ui {
          class Widget;
          }
          
          class Widget : public QWidget
          {
              Q_OBJECT
          
          // ...
          
          private slots:
          	// ...
              // 定义串口有东西可读时触发的槽函数
              void serialPortReadyRead_Slot();
          
          // ...
          };
          
          #endif // WIDGET_H
          
        • 手动绑定可读信号与槽函数,在构造中

          Widget::Widget(QWidget *parent) :
              QWidget(parent),
              ui(new Ui::Widget)
          {
              ui->setupUi(this);
              QStringList serialNamePorts;
          
              serialPort = new QSerialPort(this);
          
              // 手动关联读信号与自定义槽函数serialPortReadyRead_Slot(),串口有东西可读时触发槽函数
              connect(serialPort, SIGNAL(readyRead()), this, SLOT(serialPortReadyRead_Slot()));
          
          	// ...
          }
          
        • 实现槽函数

          // 串口有东西可读时产生信号,触发槽函数
          void Widget::serialPortReadyRead_Slot()
          {
              // 接收UI中输入框的数据
              QString buffer = QString(serialPort->readAll());
              // 将接收到的数据显示到UI的recvEdit中
              ui->recvEdit->appendPlainText(buffer);
          
          }
          
      • 清除按钮单击信号槽函数

        void Widget::on_clearBt_clicked()
        {
            ui->recvEdit->clear();
        }
        

4、程序打包和部署

  1. 切换到 Release 模式进行编译

    由于缺少动态库,打包好的程序暂时还无法运行

    • 导出文件位置:位于项目目录所在路径下,文件名以 Release 结尾,如:build-seial-Desktop_Qt_5_11_1_MinGW_32bit-Release

    • 图示:

  2. 为打包好的程序更换图标

    需要使用.ico格式的图片

    • 将图标拷贝到工程目录下

    • 在工程文件中添加如下代码,再重新编译即可

      RC_ICONS = serial_icon.ico
      
  3. 封包操作,需要用到 Qt 的控制台

    • 创建一个新的目录,用于存放封包好的文件,不能包含中文路径

    • 将打包好的.exe文件拷贝到新的目录下

    • 从控制台进入新目录中cd /d C:\xxx\xxx

      D:\Tools\Qt\Qt5.11.1\5.11.1\mingw53_32>cd /d C:\Users\Dandelion\Desktop\SerialTools
      
      C:\Users\Dandelion\Desktop\SerialTools>dir
       驱动器 C 中的卷是 OS
       卷的序列号是 EAE6-1E0A
      
       C:\Users\Dandelion\Desktop\SerialTools 的目录
      
      2023/03/10  02:22    <DIR>          .
      2023/03/10  02:20    <DIR>          ..
      2023/03/10  02:17            48,640 seial.exe
                     1 个文件         48,640 字节
                     2 个目录 63,272,501,248 可用字节
      
      C:\Users\Dandelion\Desktop\SerialTools>
      
    • 使用windeployqt工具将动态库加到当前目录下:windeployqt seial.exe

      C:\Users\Dandelion\Desktop\SerialTools>windeployqt seial.exe
      C:\Users\Dandelion\Desktop\SerialTools\seial.exe 32 bit, release executable
      Adding Qt5Svg for qsvgicon.dll
      Skipping plugin qtvirtualkeyboardplugin.dll due to disabled dependencies (Qt5Qml Qt5Quick).
      Direct dependencies: Qt5Core Qt5Gui Qt5SerialPort Qt5Widgets
      All dependencies   : Qt5Core Qt5Gui Qt5SerialPort Qt5Widgets
      To be deployed     : Qt5Core Qt5Gui Qt5SerialPort Qt5Svg Qt5Widgets
      Updating Qt5Core.dll.
      Updating Qt5Gui.dll.
      Updating Qt5SerialPort.dll.
      Updating Qt5Svg.dll.
      Updating Qt5Widgets.dll.
      Updating libGLESV2.dll.
      Updating libEGL.dll.
      Updating D3Dcompiler_47.dll.
      Updating opengl32sw.dll.
      Updating libgcc_s_dw2-1.dll.
      Updating libstdc++-6.dll.
      Updating libwinpthread-1.dll.
      Patching Qt5Core.dll...
      Creating directory C:/Users/Dandelion/Desktop/SerialTools/iconengines.
      Updating qsvgicon.dll.
      Creating directory C:/Users/Dandelion/Desktop/SerialTools/imageformats.
      Updating qgif.dll.
      Updating qicns.dll.
      Updating qico.dll.
      Updating qjpeg.dll.
      Updating qsvg.dll.
      Updating qtga.dll.
      Updating qtiff.dll.
      Updating qwbmp.dll.
      Updating qwebp.dll.
      Creating directory C:/Users/Dandelion/Desktop/SerialTools/platforms.
      Updating qwindows.dll.
      Creating directory C:/Users/Dandelion/Desktop/SerialTools/styles.
      Updating qwindowsvistastyle.dll.
      Creating C:\Users\Dandelion\Desktop\SerialTools\translations...
      Creating qt_ar.qm...
      Creating qt_bg.qm...
      Creating qt_ca.qm...
      Creating qt_cs.qm...
      Creating qt_da.qm...
      Creating qt_de.qm...
      Creating qt_en.qm...
      Creating qt_es.qm...
      Creating qt_fi.qm...
      Creating qt_fr.qm...
      Creating qt_gd.qm...
      Creating qt_he.qm...
      Creating qt_hu.qm...
      Creating qt_it.qm...
      Creating qt_ja.qm...
      Creating qt_ko.qm...
      Creating qt_lv.qm...
      Creating qt_pl.qm...
      Creating qt_ru.qm...
      Creating qt_sk.qm...
      Creating qt_uk.qm...
      
      C:\Users\Dandelion\Desktop\SerialTools>
      

有关Qt 学习笔记 - 第三章 - Qt的三驾马车之一 - 串口编程 + 程序打包成Windows软件的更多相关文章

  1. ruby - 在 Ruby 程序执行时阻止 Windows 7 PC 进入休眠状态 - 2

    我需要在客户计算机上运行Ruby应用程序。通常需要几天才能完成(复制大备份文件)。问题是如果启用sleep,它会中断应用程序。否则,计算机将持续运行数周,直到我下次访问为止。有什么方法可以防止执行期间休眠并让Windows在执行后休眠吗?欢迎任何疯狂的想法;-) 最佳答案 Here建议使用SetThreadExecutionStateWinAPI函数,使应用程序能够通知系统它正在使用中,从而防止系统在应用程序运行时进入休眠状态或关闭显示。像这样的东西:require'Win32API'ES_AWAYMODE_REQUIRED=0x0

  2. ruby - 在 Windows 机器上使用 Ruby 进行开发是否会适得其反? - 2

    这似乎非常适得其反,因为太多的gem会在window上破裂。我一直在处理很多mysql和ruby​​-mysqlgem问题(gem本身发生段错误,一个名为UnixSocket的类显然在Windows机器上不能正常工作,等等)。我只是在浪费时间吗?我应该转向不同的脚本语言吗? 最佳答案 我在Windows上使用Ruby的经验很少,但是当我开始使用Ruby时,我是在Windows上,我的总体印象是它不是Windows原生系统。因此,在主要使用Windows多年之后,开始使用Ruby促使我切换回原来的系统Unix,这次是Linux。Rub

  3. Vscode+Cmake配置并运行opencv环境(Windows和Ubuntu大同小异) - 2

    之前在培训新生的时候,windows环境下配置opencv环境一直教的都是网上主流的vsstudio配置属性表,但是这个似乎对新生来说难度略高(虽然个人觉得完全是他们自己的问题),加之暑假之后对cmake实在是爱不释手,且这样配置确实十分简单(其实都不需要配置),故斗胆妄言vscode下配置CV之法。其实极为简单,图比较多所以很长。如果你看此文还配不好,你应该思考一下是不是自己的问题。闲话少说,直接开始。0.CMkae简介有的人到大二了都不知道cmake是什么,我不说是谁。CMake是一个开源免费并且跨平台的构建工具,可以用简单的语句来描述所有平台的编译过程。它能够根据当前所在平台输出对应的m

  4. Qt Designer的简单使用 - 2

    在前面两节的例子中,主界面窗口的尺寸和标签控件显示的矩形区域等,都是用C++代码编写的。窗口和控件的尺寸都是预估的,控件如果多起来,那就不好估计每个控件合适的位置和大小了。用C++代码编写图形界面的问题就是不直观,因此Qt项目开发了专门的可视化图形界面编辑器——QtDesigner(Qt设计师)。通过QtDesigner就可以很方便地创建图形界面文件*.ui,然后将ui文件应用到源代码里面,做到“所见即所得”,大大方便了图形界面的设计。本节就演示一下QtDesigner的简单使用,学习拖拽控件和设置控件属性,并将ui文件应用到Qt程序代码里。使用QtDesigner设计界面在开始菜单中找到「Q

  5. STM32读取串口传感器数据(颗粒物传感器,主动上传) - 2

    文章目录1.开发板选择*用到的资源2.串口通信(个人理解)3.代码分析(注释比较详细)1.主函数2.串口1配置3.串口2配置以及中断函数4.注意问题5.源码链接1.开发板选择我用的是STM32F103RCT6的板子,不过代码大概在F103系列的板子上都可以运行,我试过在野火103的霸道板上也可以,主要看一下串口对应的引脚一不一样就行了,不一样的就更改一下。*用到的资源keil5软件这里用到了两个串口资源,采集数据一个,串口通信一个,板子对应引脚如下:串口1,TX:PA9,RX:PA10串口2,TX:PA2,RX:PA32.串口通信(个人理解)我就从串口采集传感器数据这个过程说一下我自己的理解,

  6. LC滤波器设计学习笔记(一)滤波电路入门 - 2

    目录前言滤波电路科普主要分类实际情况单位的概念常用评价参数函数型滤波器简单分析滤波电路构成低通滤波器RC低通滤波器RL低通滤波器高通滤波器RC高通滤波器RL高通滤波器部分摘自《LC滤波器设计与制作》,侵权删。前言最近需要学习放大电路和滤波电路,但是由于只在之前做音乐频谱分析仪的时候简单了解过一点点运放,所以也是相当从零开始学习了。滤波电路科普主要分类滤波器:主要是从不同频率的成分中提取出特定频率的信号。有源滤波器:由RC元件与运算放大器组成的滤波器。可滤除某一次或多次谐波,最普通易于采用的无源滤波器结构是将电感与电容串联,可对主要次谐波(3、5、7)构成低阻抗旁路。无源滤波器:无源滤波器,又称

  7. CAN协议的学习与理解 - 2

    最近在学习CAN,记录一下,也供大家参考交流。推荐几个我觉得很好的CAN学习,本文也是在看了他们的好文之后做的笔记首先是瑞萨的CAN入门,真的通透;秀!靠这篇我竟然2天理解了CAN协议!实战STM32F4CAN!原文链接:https://blog.csdn.net/XiaoXiaoPengBo/article/details/116206252CAN详解(小白教程)原文链接:https://blog.csdn.net/xwwwj/article/details/105372234一篇易懂的CAN通讯协议指南1一篇易懂的CAN通讯协议指南1-知乎(zhihu.com)视频推荐CAN总线个人知识总

  8. 深度学习部署:Windows安装pycocotools报错解决方法 - 2

    深度学习部署:Windows安装pycocotools报错解决方法1.pycocotools库的简介2.pycocotools安装的坑3.解决办法更多Ai资讯:公主号AiCharm本系列是作者在跑一些深度学习实例时,遇到的各种各样的问题及解决办法,希望能够帮助到大家。ERROR:Commanderroredoutwithexitstatus1:'D:\Anaconda3\python.exe'-u-c'importsys,setuptools,tokenize;sys.argv[0]='"'"'C:\\Users\\46653\\AppData\\Local\\Temp\\pip-instal

  9. ruby - 我正在学习编程并选择了 Ruby。我应该升级到 Ruby 1.9 吗? - 2

    我完全不是程序员,正在学习使用Ruby和Rails框架进行编程。我目前正在使用Ruby1.8.7和Rails3.0.3,但我想知道我是否应该升级到Ruby1.9,因为我真的没有任何升级的“遗留”成本。缺点是什么?我是否会遇到与普通gem的兼容性问题,或者甚至其他我不太了解甚至无法预料的问题? 最佳答案 你应该升级。不要坚持从1.8.7开始。如果您发现不支持1.9.2的gem,请避免使用它们(因为它们很可能不被维护)。如果您对gem是否兼容1.9.2有任何疑问,您可以在以下位置查看:http://www.railsplugins.or

  10. ruby - 如何在 Ruby 中执行 Windows CLI 命令? - 2

    我在目录“C:\DocumentsandSettings\test.exe”中有一个文件,但是当我用单引号编写命令时`C:\DocumentsandSettings\test.exe(我无法在此框中显示),用于在Ruby中执行命令,我无法这样做,我收到的错误是找不到文件或目录。我尝试用“//”和“\”替换“\”,但似乎没有任何效果。我也使用过系统、IO.popen和exec命令,但所有的努力都是徒劳的。exec命令还使程序退出,这是我不想发生的。提前致谢。 最佳答案 反引号环境就像双引号,所以反斜杠用于转义。此外,Ruby会将空格解

随机推荐