QT(c++)开发自学笔记:1.串口
新建工程与界面介绍
新建文件,不要选错成Application (Qt for python)了
这里选择QDialog
新建之后可以点开看到文件夹中的dialog.cpp
#include "dialog.h"
#include "./ui_dialog.h"Dialog::Dialog(QWidget *parent): QDialog(parent), ui(new Ui::Dialog)
{ui->setupUi(this);
}Dialog::~Dialog()
{delete ui;
}
Dialog::Dialog(QWidget *parent)
:这是成员函数的定义,使用作用域解析运算符::
指定函数属于Dialog类。函数名与类名相同,表示构造函数。参数列表(QWidget *parent)
定义了一个指针参数parent
,类型为QWidget*
(Qt的窗口部件基类指针),用于传递父窗口指针。: QDialog(parent)
:这是初始化列表(Initializer List)的开始,以冒号:
开头,用于在函数体执行前初始化基类和成员变量。格式为: 成员/基类(参数)
。调用基类QDialog的构造函数,传递parent
参数。QDialog是Qt的对话框基类,这里实现继承初始化。, ui(new Ui::Dialog)
:初始化列表的延续,以逗号,
分隔多个初始化项。初始化成员变量ui
(在头文件中声明为Ui::Dialog *ui;
),使用new
动态分配内存,创建Ui::Dialog对象的实例。Ui::Dialog
是命名空间Ui
下的类(Qt UI生成)。{ ui->setupUi(this); }
:函数体,用花括号{}
包围。内部语句ui->setupUi(this);
:ui->
:使用箭头运算符->
访问指针ui
指向的对象成员。setupUi(this)
:调用Ui::Dialog类的成员函数setupUi
,参数this
是当前对象指针(Dialog*),用于将UI控件绑定到当前对话框。
Dialog::~Dialog()
:表示析构函数(Destructor),销毁对话框。无参数列表()
,且无返回值类型。{ delete ui; }
:函数体,用{}
包围。内部语句delete ui;
:delete
是C++运算符,用于释放动态分配的内存(对应构造函数中的new
)。ui
是指针变量,delete ui
会调用Ui::Dialog的析构函数并释放内存。
一些快捷键
ctrl+B:编译
ctrl+R:运行
F4:再.h和.cpp直接切换
添加控件的基本形式
新建之后,点开dialog.ui
新建一个ComBox
点击该框,右下角可以改名
注意左下角的控件
报错问题:当前QT版本不支持串口
运行完程序之后,会自动弹出QT支持包,选择一个版本功能中有”Serial Port“功能的进行安装(比如我6.9.2不支持串口,但是6.9.3可以),然后再到左侧框”项目“选项中把6.9.3相关的全部运行,6.9.2的给关掉
注意:只开前两个,后面两个不要开(我这样之后仍然报错,仍未解决) 所以采用以下方法:
直接打开Qt维护工具,也就是MaintenanceTool.exe
把6.9.2给全部取消勾选,点下一步
然后等移除之后,新建一个工程,刚才那个工程的东西全部复制过来算了
完整添加控件和代码
添加以下控件,并精确设置objectName(在属性编辑器中,右上角的Property Editor):
控件类型 | objectName(名称) | 布局建议位置 |
---|---|---|
QComboBox | comboBoxPort | 上方,选择串口 |
QComboBox | comboBoxBaud | 上方,选择波特率 |
QPushButton | pushButtonOpen | 中间,打开/关闭按钮 |
QLineEdit | lineEditSend | 下方,发送输入框 |
QPushButton | pushButtonSend | 下方,发送按钮 |
QTextEdit | textEditReceive | 最下方,接收显示区(设置readOnly=true,便于只读) |
最终布局类似于这样:
dialog.h文件代码如下:
#ifndef DIALOG_H
#define DIALOG_H#include <QDialog>
#include <QSerialPort>
#include <QSerialPortInfo>QT_BEGIN_NAMESPACE
namespace Ui { class Dialog; }
QT_END_NAMESPACEclass Dialog : public QDialog
{Q_OBJECTpublic:Dialog(QWidget *parent = nullptr);~Dialog();private slots:void openSerialPort();void closeSerialPort();void sendData();void readData();private:Ui::Dialog *ui;QSerialPort *serial;
};#endif // DIALOG_H
dialog.cpp代码如下:
#include "dialog.h"
#include "./ui_dialog.h"
#include <QDebug>
#include <QMessageBox>Dialog::Dialog(QWidget *parent): QDialog(parent), ui(new Ui::Dialog), serial(new QSerialPort(this))
{ui->setupUi(this);// 假设UI元素:ui->comboBoxPort (QComboBox for ports), ui->comboBoxBaud (QComboBox for baud rates),// ui->pushButtonOpen (QPushButton for open/close), ui->textEditReceive (QTextEdit for received data),// ui->lineEditSend (QLineEdit for send data), ui->pushButtonSend (QPushButton for send).// 填充可用串口for (const QSerialPortInfo &info : QSerialPortInfo::availablePorts()) {ui->comboBoxPort->addItem(info.portName());}// 填充常见波特率ui->comboBoxBaud->addItems({"9600", "19200", "38400", "57600", "115200"});// 连接信号槽connect(ui->pushButtonOpen, &QPushButton::clicked, this, &Dialog::openSerialPort);connect(ui->pushButtonSend, &QPushButton::clicked, this, &Dialog::sendData);connect(serial, &QSerialPort::readyRead, this, &Dialog::readData);connect(serial, QOverload<QSerialPort::SerialPortError>::of(&QSerialPort::errorOccurred),this, [](QSerialPort::SerialPortError error) {if (error != QSerialPort::NoError) {qDebug() << "Serial port error:" << error;}});serial->setBaudRate(QSerialPort::Baud9600); // 默认波特率serial->setDataBits(QSerialPort::Data8);serial->setParity(QSerialPort::NoParity);serial->setStopBits(QSerialPort::OneStop);serial->setFlowControl(QSerialPort::NoFlowControl);
}Dialog::~Dialog()
{if (serial->isOpen()) {serial->close();}delete ui;
}void Dialog::openSerialPort()
{if (serial->isOpen()) {closeSerialPort();} else {serial->setPortName(ui->comboBoxPort->currentText());serial->setBaudRate(ui->comboBoxBaud->currentText().toInt());if (serial->open(QIODevice::ReadWrite)) {ui->pushButtonOpen->setText("关闭串口");QMessageBox::information(this, "成功", "串口打开成功");} else {QMessageBox::warning(this, "错误", "无法打开串口: " + serial->errorString());}}
}void Dialog::closeSerialPort()
{if (serial->isOpen()) {serial->close();ui->pushButtonOpen->setText("打开串口");QMessageBox::information(this, "成功", "串口关闭成功");}
}void Dialog::sendData()
{if (serial->isOpen() && !ui->lineEditSend->text().isEmpty()) {QByteArray data = ui->lineEditSend->text().toUtf8();serial->write(data);ui->lineEditSend->clear();} else {QMessageBox::warning(this, "错误", "串口未打开或发送数据为空");}
}void Dialog::readData()
{if (serial->bytesAvailable()) {QByteArray data = serial->readAll();ui->textEditReceive->append(data);}
}
main.cpp代码如下:
#include "dialog.h"#include <QApplication>int main(int argc, char *argv[])
{QApplication a(argc, argv);Dialog w;w.show();return a.exec();
}
CMakeLists.txt代码如下:
cmake_minimum_required(VERSION 3.16)project(Text1004Test VERSION 0.1 LANGUAGES CXX)# 手动指定Qt 6.9.3完整路径(用正斜杠,无空格;替换为您的确切路径,例如 D:/QTWorks/6.9.3/mingw_64)
set(CMAKE_PREFIX_PATH "D:/QTWorks/6.9.3/mingw_64")set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)# 临时调试:启用详细查找日志(构建后移除)
# set(CMAKE_FIND_DEBUG_MODE TRUE)# 查找Qt 6(优先),包含Widgets和SerialPort组件
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets SerialPort)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets SerialPort)# 调试输出:打印找到的Qt路径和组件状态
message(STATUS "Qt Version: ${QT_VERSION_MAJOR}.${QT_VERSION_MINOR}")
message(STATUS "Qt Install Prefix: ${Qt6_DIR}/..")
message(STATUS "SerialPort Found: ${Qt6SerialPort_FOUND}") # 应为TRUEset(PROJECT_SOURCESmain.cppdialog.cppdialog.hdialog.ui # 确保包含.ui文件
)if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)qt_add_executable(Text1004TestMANUAL_FINALIZATION${PROJECT_SOURCES})
else()if(ANDROID)add_library(Text1004Test SHARED${PROJECT_SOURCES})else()add_executable(Text1004Test${PROJECT_SOURCES})endif()
endif()# 链接Widgets和SerialPort
target_link_libraries(Text1004Test PRIVATEQt${QT_VERSION_MAJOR}::WidgetsQt${QT_VERSION_MAJOR}::SerialPort
)# iOS/macOS捆绑设置
if(${QT_VERSION} VERSION_LESS 6.1.0)set(BUNDLE_ID_OPTION MACOSX_BUNDLE_GUI_IDENTIFIER com.example.Text1004Test)
endif()
set_target_properties(Text1004Test PROPERTIES${BUNDLE_ID_OPTION}MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}MACOSX_BUNDLE TRUEWIN32_EXECUTABLE TRUE
)include(GNUInstallDirs)
install(TARGETS Text1004TestBUNDLE DESTINATION .LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)if(QT_VERSION_MAJOR EQUAL 6)qt_finalize_executable(Text1004Test)
endif()
然后再下个串口调试助手,开一对虚拟串口,两个互选一下试试互发消息
能互相收到就成功了,这个简单的例子可以用来熟悉一下这种”控件+代码“的设计模式