2. Qt基础控件(上):QWidget、QLabel、QPushButton、QLineEdit、QTextEdit,信号与槽机制入门

各位同学,欢迎来到第二章。这一章我们开始真正动手,接触 Qt 里最常用的一批基础控件。说实话,Qt 的控件体系非常庞大,但别怕——你只要把这几个基础控件吃透,后面再学什么 QComboBox、QTableWidget,上手会快得多。

我个人习惯把 Qt 控件分成两类:显示用的和交互用的。今天讲的五个控件,正好覆盖了这两类。我们先从最基础的 QWidget 说起。

2.1 QWidget:一切控件的根

QWidget 是所有用户界面对象的基类。说白了,你在界面上看到的任何一个按钮、标签、输入框,本质上都是一个 QWidget。它定义了窗口最基本的属性:位置、大小、可见性、鼠标事件处理等。

我在项目中遇到过一个问题:新手经常搞不清 QWidget 和 QMainWindow 的区别。简单说,QMainWindow 是 QWidget 的子类,它自带菜单栏、工具栏、状态栏这些“大件”。如果你只是做一个弹窗或者一个自定义面板,直接用 QWidget 就够了。

核心要点:

  • QWidget 是“空画布”,你可以在上面放任何子控件
  • 每个 QWidget 都可以作为独立窗口(设置 Qt::Window 标志)
  • QWidget 可以嵌套:一个 QWidget 里放另一个 QWidget,形成父子关系

来看一个最简单的例子:

// 创建一个 QWidget 作为顶层窗口
QWidget *window = new QWidget();
window->setWindowTitle("我的第一个窗口");
window->resize(400, 300);
window->show();

嗯,这里要注意:show() 必须调用,否则窗口不会显示。我刚开始学 Qt 时经常忘记这步,调试了半天发现窗口没出来——其实就是没调用 show()。

2.2 QLabel:显示文本和图片

QLabel 是 Qt 里最常用的“显示型”控件。它主要用来展示文本、图片、富文本(HTML)。你想想看,一个界面如果没有文字说明,用户根本不知道每个按钮是干嘛的。QLabel 就是干这个的。

方法 作用 示例
setText() 设置普通文本 label->setText("用户名:");
setPixmap() 设置图片 label->setPixmap(QPixmap("logo.png"));
setAlignment() 设置对齐方式 label->setAlignment(Qt::AlignCenter);
setWordWrap() 设置自动换行 label->setWordWrap(true);

小技巧:QLabel 支持简单的 HTML 标签。比如 label->setText("<b>粗体</b> <font color='red'>红色文字</font>"); 可以快速实现富文本效果,省去手动设置样式表的麻烦。

2.3 QPushButton:最常用的交互控件

QPushButton 是 Qt 里最基础的按钮控件。用户点击它,程序做出响应。它的用法极其简单,但背后涉及一个非常重要的概念——信号与槽。

先看代码:

QPushButton *btn = new QPushButton("点击我", parentWidget);
// 连接信号与槽
connect(btn, &QPushButton::clicked, this, &MainWindow::onButtonClicked);

这里 clicked 就是信号,onButtonClicked 就是槽函数。当用户点击按钮时,Qt 会自动发射 clicked 信号,然后执行对应的槽函数。

我曾经犯过一个低级错误:在 connect 时把信号和槽的参数类型写错了,结果编译通过但运行时按钮没反应。Qt 的 connect 是类型安全的,参数不匹配会静默失败。所以,如果你发现按钮点了没反应,第一件事就是检查 connect 的参数。

2.4 QLineEdit:单行文本输入

QLineEdit 是单行文本输入框。登录界面的用户名、密码输入框,搜索框,都是它。

常用功能:

  • setPlaceholderText():设置占位提示文本(灰色提示文字)
  • setEchoMode():设置回显模式,密码框用 QLineEdit::Password
  • setMaxLength():限制最大输入字符数
  • text():获取当前输入的文本

避坑指南:我曾经在做一个用户注册模块时,直接用 lineEdit->text() 获取密码,然后存入数据库。后来发现用户输入了空格和特殊字符,导致数据库报错。记住:永远不要信任用户输入。获取文本后一定要做校验和过滤。

2.5 QTextEdit:多行文本编辑器

QTextEdit 是富文本编辑器,支持多行文本、图片、表格、列表等。如果你需要做一个笔记应用、聊天窗口或者代码编辑器,QTextEdit 是首选。

与 QLineEdit 的区别很明显:

特性 QLineEdit QTextEdit
行数 单行 多行
富文本 不支持 支持(HTML)
常用场景 输入框、搜索框 编辑器、日志显示
获取内容 text() toPlainText() 或 toHtml()

我个人习惯用 QTextEdit 来显示程序运行日志。把日志追加到 QTextEdit 里,用户可以看到实时输出,比用控制台友好得多。

2.6 信号与槽机制入门

信号与槽是 Qt 最核心的机制,没有之一。它解决了对象间通信的问题——当一个对象的状态发生变化时,它需要通知其他对象。传统做法是用回调函数,但回调函数是类型不安全的,而且容易造成耦合。Qt 的信号与槽机制,说白了就是一种类型安全的观察者模式。

来看一个完整的例子:

// 定义信号(在类声明中)
signals:
    void valueChanged(int newValue);

// 定义槽(在类声明中)
public slots:
    void onValueChanged(int newValue) {
        qDebug() << "新值:" << newValue;
    }

// 连接信号与槽
connect(sender, &SenderClass::valueChanged,
        receiver, &ReceiverClass::onValueChanged);

为什么说它类型安全?因为 connect 函数在编译期就会检查信号和槽的参数是否匹配。如果信号发射 int,槽却接收 QString,编译直接报错。这比 C 语言的回调函数安全得多。

信号与槽的三种连接方式:

  1. 一对一:一个信号连接一个槽
  2. 一对多:一个信号连接多个槽,信号发射时所有槽依次执行
  3. 多对一:多个信号连接同一个槽,任意信号发射都会触发该槽

我记得有一次做项目,需要在一个按钮点击时同时更新三个界面的状态。我一开始写了三个独立的 connect,后来发现可以用一个信号连接三个槽,代码简洁多了。嗯,这就是一对多的典型应用。

2.7 知识体系总览

下面这张图把本章的核心知识点串起来了。你可以看到,QWidget 是所有控件的根,QLabel、QPushButton、QLineEdit、QTextEdit 都继承自它。而信号与槽机制,则是连接这些控件的“神经”。

Qt 基础控件与信号槽知识体系 QWidget(基类) QLabel QPushButton QLineEdit QTextEdit 信号与槽机制 类型安全的观察者模式 connect(sender, signal, receiver, slot) 一对一 1 个信号 → 1 个槽 一对多 1 个信号 → 多个槽 多对一 多个信号 → 1 个槽

从这张图你可以看到:QWidget 在最顶层,四个子控件各司其职。信号与槽机制在中间层,负责把用户的操作(点击按钮、输入文本)转换成程序可以处理的“事件”。最下面是三种连接方式,灵活组合就能实现复杂的交互逻辑。

2.8 本章小结

这一章我们学了五个基础控件和一个核心机制。说实话,这些内容在 Qt 里属于“吃饭的家伙”,几乎每个项目都会用到。我的建议是:

  • QLabel 和 QPushButton 是最简单的,先拿它们练手
  • QLineEdit 和 QTextEdit 注意区分使用场景
  • 信号与槽是 Qt 的灵魂,一定要理解“发射信号→执行槽函数”这个流程