新建工程与界面介绍
新建文件,不要选错成Application (Qt for python)了


这里选择QDialog

新建之后可以点开看到文件夹中的dialog.cpp
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文件代码如下:
cpp
#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
#include <QSerialPort>
#include <QSerialPortInfo>
QT_BEGIN_NAMESPACE
namespace Ui { class Dialog; }
QT_END_NAMESPACE
class Dialog : public QDialog
{
Q_OBJECT
public:
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代码如下:
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代码如下:
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代码如下:
cpp
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}") # 应为TRUE
set(PROJECT_SOURCES
main.cpp
dialog.cpp
dialog.h
dialog.ui # 确保包含.ui文件
)
if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)
qt_add_executable(Text1004Test
MANUAL_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 PRIVATE
Qt${QT_VERSION_MAJOR}::Widgets
Qt${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 TRUE
WIN32_EXECUTABLE TRUE
)
include(GNUInstallDirs)
install(TARGETS Text1004Test
BUNDLE DESTINATION .
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)
if(QT_VERSION_MAJOR EQUAL 6)
qt_finalize_executable(Text1004Test)
endif()
然后再下个串口调试助手,开一对虚拟串口,两个互选一下试试互发消息

能互相收到就成功了,这个简单的例子可以用来熟悉一下这种"控件+代码"的设计模式