c++ QT 开发第二天,用ui按钮点亮实体led

#include "mainwindow.h"

#include <QDebug>

#include <QGuiApplication>

#include <QScreen>

#include <QRect>

MainWindow::MainWindow(QWidget *parent)

: QMainWindow(parent)

{

/* 获取屏幕的分辨率,Qt官方建议使用这

* 种方法获取屏幕分辨率,防上多屏设备导致对应不上

* 注意,这是获取整个桌面系统的分辨率

*/

QList <QScreen *> list_screen = QGuiApplication::screens();

/* 如果是ARM平台,直接设置大小为屏幕的大小 */

#if arm

/* 重设大小 */

this->resize(list_screen.at(0)->geometry().width(),

list_screen.at(0)->geometry().height());

/* 默认是出厂系统的LED心跳的触发方式,想要控制LED,

* 需要改变LED的触发方式,改为none,即无 */

system("echo none > /sys/class/leds/sys-led/trigger");

#else

/* 否则则设置主窗体大小为800x480 */

this->resize(800, 480);

#endif

pushButton = new QPushButton(this);

/* 居中显示 */

pushButton->setMinimumSize(200, 50);

pushButton->setGeometry((this->width() - pushButton->width()) /2 ,

(this->height() - pushButton->height()) /2,

pushButton->width(),

pushButton->height()

);

/* 开发板的LED控制接口 */

file.setFileName("/sys/devices/platform/leds/leds/sys-led/brightness");

if (!file.exists())

/* 设置按钮的初始化文本 */

pushButton->setText("未获取到LED设备!");

/* 获取LED的状态 */

getLedState();

/* 信号槽连接 */

connect(pushButton, SIGNAL(clicked()),

this, SLOT(pushButtonClicked()));

}

MainWindow::~MainWindow()

{

}

void MainWindow::setLedState()

{

/* 在设置LED状态时先读取 */

bool state = getLedState();

/* 如果文件不存在,则返回 */

if (!file.exists())

return;

if(!file.open(QIODevice::ReadWrite))

qDebug()<<file.errorString();

QByteArray buf[2] = {"0", "1"};

/* 写0或1 */

if (state)

file.write(buf[0]);

else

file.write(buf[1]);

/* 关闭文件 */

file.close();

/*重新获取LED的状态 */

getLedState();

}

bool MainWindow::getLedState()

{

/* 如果文件不存在,则返回 */

if (!file.exists())

return false;

if(!file.open(QIODevice::ReadWrite))

qDebug()<<file.errorString();

QTextStream in(&file);

/* 读取文件所有数据 */

QString buf = in.readLine();

/* 打印出读出的值 */

qDebug()<<"buf: "<<buf<<endl;

file.close();

if (buf == "1") {

pushButton->setText("LED点亮");

return true;

} else {

pushButton->setText("LED熄灭");

return false;

}

}

void MainWindow::pushButtonClicked()

{

/* 设置LED的状态 */

setLedState();

}


一、这整个程序是干什么的?

👉 一句话概括:

用 Qt 做一个窗口,窗口中只有一个按钮

点击按钮 → 通过 /sys/class/leds/.../brightness
控制开发板 LED 的亮 / 灭


二、整体结构(先有个全局概念)

复制代码
MainWindow
│
├── QPushButton *pushButton     // 界面上的按钮
├── QFile file                  // 指向 LED 亮度文件
│
├── 构造函数 MainWindow()       // 创建界面、按钮、初始化
├── setLedState()               // 设置 LED 亮/灭
├── getLedState()               // 读取 LED 当前状态
└── pushButtonClicked()         // 按钮点击槽函数

三、构造函数 MainWindow(最重要)

复制代码
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{

1️⃣ 调用父类构造函数

复制代码
: QMainWindow(parent)
  • MainWindow 继承自 QMainWindow

  • 这句是 初始化父类

  • parent 一般是 nullptr


2️⃣ 获取屏幕分辨率(Qt 官方推荐)

复制代码
QList<QScreen *> list_screen = QGuiApplication::screens();
  • 获取所有屏幕

  • 防止多屏设备分辨率不一致

  • list_screen.at(0) 是主屏幕


3️⃣ ARM 和 PC 平台区分(宏判断)

复制代码
#if __arm__

ARM 平台(开发板)

复制代码
this->resize(list_screen.at(0)->geometry().width(),
             list_screen.at(0)->geometry().height());

👉 窗口大小 = 屏幕大小(全屏)

复制代码
system("echo none > /sys/class/leds/sys-led/trigger");

🔴 非常关键的一句:

  • Linux 默认 LED 是 心跳闪烁

  • 想手动控制 LED

  • 必须把触发方式改成 none


非 ARM(PC 上调试)

复制代码
#else
this->resize(800, 480);
#endif

👉 PC 上就固定窗口大小


4️⃣ 创建按钮(重点)

复制代码
pushButton = new QPushButton(this);
  • 动态创建按钮

  • this 是父对象 → 自动内存管理

  • 按钮会显示在主窗口中


5️⃣ 设置按钮大小和位置(居中)

复制代码
pushButton->setMinimumSize(200, 50);

按钮最小尺寸:200 × 50

复制代码
pushButton->setGeometry(
    (this->width() - pushButton->width()) / 2,
    (this->height() - pushButton->height()) / 2,
    pushButton->width(),
    pushButton->height()
);

👉 这段数学计算的目的只有一个:

让按钮在窗口正中间


6️⃣ 设置 LED 控制文件路径(Linux 核心)

复制代码
file.setFileName("/sys/devices/platform/leds/leds/sys-led/brightness");

这个文件:

  • "0" → LED 灭

  • "1" → LED 亮

👉 Qt 本质上就是在读写 Linux 文件


7️⃣ 判断 LED 文件是否存在

复制代码
if (!file.exists())
    pushButton->setText("未获取到LED设备!");
  • 如果不是在开发板上运行

  • 或路径不对

  • 按钮提示错误信息


8️⃣ 读取 LED 初始状态

复制代码
getLedState();
  • 启动程序时

  • 自动读取 LED 是亮还是灭

  • 同时更新按钮文字


9️⃣ 信号槽(Qt 核心机制)

复制代码
connect(pushButton, SIGNAL(clicked()),
        this, SLOT(pushButtonClicked()));

意思是:

按钮被点击 → 自动调用 pushButtonClicked()


四、析构函数(为什么是空的)

复制代码
MainWindow::~MainWindow()
{
}

为什么不 delete pushButton

👉 因为:

  • pushButton 的父对象是 MainWindow

  • Qt 会 自动释放所有子对象

  • 所以这里什么都不用写


五、setLedState() ------ 设置 LED 状态

复制代码
void MainWindow::setLedState()
{

1️⃣ 先读当前状态

复制代码
bool state = getLedState();
  • true → 当前是亮

  • false → 当前是灭

👉 点击按钮后是 取反操作


2️⃣ 文件不存在直接返回

复制代码
if (!file.exists())
    return;

3️⃣ 打开 LED 文件

复制代码
file.open(QIODevice::ReadWrite);
  • 必须 ReadWrite

  • sysfs 文件读写都走这里


4️⃣ 写入 0 / 1

复制代码
QByteArray buf[2] = {"0", "1"};

if (state)
    file.write(buf[0]);  // 原来亮 → 写0 → 关灯
else
    file.write(buf[1]);  // 原来灭 → 写1 → 开灯

👉 按钮就是一个"开关"


5️⃣ 关闭文件 + 重新读取状态

复制代码
file.close();
getLedState();

六、getLedState() ------ 获取 LED 状态

复制代码
bool MainWindow::getLedState()
{

1️⃣ 文件检查 + 打开

复制代码
if (!file.exists())
    return false;

2️⃣ 读取文件内容

复制代码
QTextStream in(&file);
QString buf = in.readLine();
  • buf 可能是 "0""1"

3️⃣ 打印调试信息

复制代码
qDebug() << "buf: " << buf;

4️⃣ 根据值更新按钮文字

复制代码
if (buf == "1") {
    pushButton->setText("LED点亮");
    return true;
} else {
    pushButton->setText("LED熄灭");
    return false;
}

👉 一个函数干三件事:

  1. 读 LED 状态

  2. 改按钮文字

  3. 返回 LED 状态


七、pushButtonClicked() ------ 槽函数

复制代码
void MainWindow::pushButtonClicked()
{
    setLedState();
}

非常简单:

按钮点一下 → 切换 LED 状态


八、完整运行流程(面试级总结)

复制代码
程序启动
  ↓
创建窗口
  ↓
创建按钮 + 居中
  ↓
绑定 LED 文件
  ↓
读取 LED 当前状态
  ↓
用户点击按钮
  ↓
读取当前状态
  ↓
写入相反状态 (0/1)
  ↓
更新按钮文字

信号 / 槽


一、先忘掉"信号 / 槽"这两个词

我们先把它们换成你熟悉的东西:

Qt 名字 用"人话"理解
信号 (signal) 某件事发生了
槽 (slot) 这件事发生后要执行的函数

👉 信号 = 事件通知

👉 槽 = 事件处理函数


二、用"按钮"做最直观的类比

想象现实中的一个按钮:

复制代码
你按下按钮
   ↓
按钮告诉系统:我被按了!
   ↓
系统执行你写好的代码

在 Qt 里:

复制代码
clicked()     ←------ 信号(按钮被点了)
pushButtonClicked() ←------ 槽(你要干什么)

三、你这行代码到底在干什么?(重点)

复制代码
connect(pushButton, SIGNAL(clicked()),
        this, SLOT(pushButtonClicked()));

我帮你逐个翻译成中文

当 pushButton 这个按钮

发出 clicked() 这个信号时

就调用 this(MainWindow)里的 pushButtonClicked() 函数

一句话白话版:

"按钮被点 → 自动执行 pushButtonClicked()"


四、拆开 connect 的四个参数

复制代码
connect(  A,        B,
          C,        D );
参数 你的代码 人话解释
A pushButton 谁发出信号
B clicked() 发生了什么事
C this 谁来处理
D pushButtonClicked() 具体干什么

五、为什么不直接在按钮里写代码?

你可能会想:

为什么不写:
pushButton->clicked() { setLedState(); }

原因很重要:

Qt 的设计思想是:

"谁触发" 和 "干什么" 完全分离

好处:

  • 按钮不用知道 LED 是什么

  • LED 不关心是按钮、定时器还是网络控制

  • 程序结构非常清晰


六、槽函数到底是什么?

你这个槽函数:

复制代码
void MainWindow::pushButtonClicked()
{
    setLedState();
}

说白了:

  • 它就是一个 普通成员函数

  • 只是被 Qt 在合适的时候自动调用

👉 没有魔法

👉 没有线程

👉 没有中断


七、没有信号槽,程序会发生什么?

你现在的程序逻辑是:

复制代码
程序启动
  ↓
什么都不会发生
  ↓
除非你点击按钮

👉 点击按钮本身 什么都不会做

只有因为这句:

复制代码
connect(...)

Qt 才知道:

"哦,按钮点了要去干这件事"


八、换一个你熟悉的"嵌入式"类比(关键)

你是电子 / 嵌入式方向的,这样理解更快 👇

Qt 信号槽 ≈ STM32 中断回调

STM32 Qt
按键中断 clicked() 信号
EXTI 触发 信号发出
中断服务函数 槽函数
HAL_GPIO_EXTI_Callback() pushButtonClicked()

👉 中断来了 → 自动执行回调

👉 信号发了 → 自动执行槽


九、你可以做的最简单实验(强烈建议)

把槽函数改成这样:

复制代码
void MainWindow::pushButtonClicked()
{
    qDebug() << "按钮被点击了!";
}

运行后:

  • 不点按钮 → 什么都不会打印

  • 点按钮 → 控制台出现文字

👉 这一步你一定能"顿悟"


十、用一句话彻底记住信号槽

connect 的本质:

"当某个对象发生某件事时,自动调用另一个对象的某个函数"


相关推荐
2501_941882481 天前
在开普敦跨区域部署环境中构建高可靠分布式配置中心的设计思路与实现实践
开发语言·c#
一只小小Java1 天前
Java面试场景高频题
java·开发语言·面试
Ljubim.te1 天前
inline介绍,宏定义的注意事项以及nullptr
c语言·开发语言·c++
亓才孓1 天前
多态:编译时看左边,运行时看右边
java·开发语言
小白探索世界欧耶!~1 天前
用iframe实现单个系统页面在多个系统中复用
开发语言·前端·javascript·vue.js·经验分享·笔记·iframe
2501_941878741 天前
在奥克兰云原生实践中构建动态配置中心以支撑系统稳定演进的工程经验总结
开发语言·python
weixin_443297881 天前
Python打卡训练营第31天
开发语言·python
围炉聊科技1 天前
Vibe Kanban:Rust构建的AI编程代理编排平台
开发语言·rust·ai编程
hqwest1 天前
码上通QT实战04--主窗体布局
开发语言·css·qt·布局·widget·layout·label