15、Qt Widgets基础(上):QWidget、QLabel、QPushButton、QLineEdit、布局管理器

好,咱们今天正式进入 Qt Widgets 的世界。说实话,这部分内容是我个人觉得 Qt 最亲切的地方——你拖拖拽拽、写几行代码,一个窗口就出来了。很多初学者一上来就问我:「老师,Qt 到底难不难?」我的回答是:如果你理解了今天这几个基础控件和布局,Qt 的大门就算被你踹开了。

咱们今天要聊的,是 Qt 里最常用、最核心的几个 Widget:QWidgetQLabelQPushButtonQLineEdit,以及两个布局管理器 QHBoxLayoutQVBoxLayout。这些东西,说白了就是你写任何桌面应用都绕不开的「砖块」。

Qt Widgets 基础(上)知识体系 QWidget(基类) QLabel(标签) QPushButton(按钮) QLineEdit(输入框) QHBoxLayout(水平布局) QVBoxLayout(垂直布局) 布局管理器负责自动排列子控件,无需手动计算坐标

QWidget:一切控件的祖宗

QWidget 是 Qt 里所有用户界面对象的基类。你看到的按钮、标签、输入框,甚至整个窗口,本质上都是 QWidget 的子类。它提供了最基础的功能:绘制自己、处理鼠标键盘事件、管理子控件。

我个人习惯把 QWidget 想象成一张「白纸」。你可以在上面画东西,也可以在上面放其他控件。比如你创建一个空窗口,其实就是一个 QWidget 对象。

#include <QApplication>
#include <QWidget>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    
    QWidget window;
    window.setWindowTitle("我的第一个窗口");
    window.resize(400, 300);
    window.show();
    
    return app.exec();
}

这段代码跑起来,你会看到一个 400x300 的空白窗口。嗯,这里要注意:show() 必须调用,否则窗口不会显示。我在项目里见过新手调了半天,结果发现忘了写 show()——这种事我也干过。

小提示: QWidget 的构造函数可以传一个父对象指针。如果你传了父对象,子控件会跟随父控件一起显示、隐藏、销毁。这个机制叫「对象树」,是 Qt 内存管理的核心。

QLabel:显示文本和图片

QLabel 是 Qt 里最常用的文本显示控件。你用它来显示提示信息、标题、或者简单的富文本内容。它支持 HTML 子集,所以你可以加粗、变色、甚至插入图片。

#include <QLabel>

QLabel *label = new QLabel("Hello, Qt!", &window);
label->setText("<b>欢迎</b>来到 <font color='red'>C++与Qt</font> 的世界");
label->setAlignment(Qt::AlignCenter);
label->setGeometry(50, 50, 300, 40);

你看,setText() 里可以直接写 HTML 标签。不过要注意,QLabel 默认是不接受用户输入的——它只是个「展示者」。如果你想让它显示图片,用 setPixmap() 就行。

我曾经在做一个配置工具时,用 QLabel 显示设备状态图标。绿色表示在线,红色表示离线。配合 setPixmap() 切换图片,效果非常直观。

QPushButton:点击触发动作

按钮,不用我多说了吧?用户点击它,程序执行某个操作。QPushButton 是 Qt 里最标准的按钮控件。

#include <QPushButton>

QPushButton *btn = new QPushButton("点击我", &window);
btn->setGeometry(150, 150, 100, 40);

// 连接点击信号
QObject::connect(btn, &QPushButton::clicked, [&]() {
    label->setText("按钮被点击了!");
});

这里用到了 Qt 的信号与槽机制。clicked 是按钮点击时发出的信号,后面的 lambda 表达式就是槽函数。说白了,就是「按钮被点了,执行这段代码」。

避坑指南: 我曾经在项目里把 clicked()pressed() 搞混了。clicked 是鼠标松开时才触发,pressed 是按下去就触发。如果你要做「长按」效果,记得用 pressedreleased 组合。

QLineEdit:单行文本输入

用户输入信息,靠的就是 QLineEdit。它支持单行文本的输入、编辑、复制粘贴等操作。你还可以设置占位提示文本、输入掩码、密码模式等。

#include <QLineEdit>

QLineEdit *edit = new QLineEdit(&window);
edit->setPlaceholderText("请输入用户名...");
edit->setGeometry(50, 100, 300, 30);

// 获取输入内容
QString text = edit->text();

// 连接文本变化信号
QObject::connect(edit, &QLineEdit::textChanged, [&](const QString &text) {
    label->setText("你输入了: " + text);
});

你想想看,textChanged 信号会在用户每次输入时触发。这在做实时搜索、输入校验时非常有用。比如我做过一个登录界面,用户输入密码时,我监听 textChanged 来实时检查密码强度。

另外,setEchoMode(QLineEdit::Password) 可以把输入内容显示为圆点,适合密码输入框。

布局管理器:让控件自动排列

如果你手动用 setGeometry() 摆放控件,窗口一拉伸,控件位置就乱了。布局管理器就是来解决这个问题的。它会根据窗口大小自动调整子控件的位置和大小。

QHBoxLayout:水平布局

水平布局把控件从左到右排成一行。

#include <QHBoxLayout>

QHBoxLayout *hLayout = new QHBoxLayout();
hLayout->addWidget(new QPushButton("左"));
hLayout->addWidget(new QPushButton("中"));
hLayout->addWidget(new QPushButton("右"));

// 把布局设置到窗口上
window.setLayout(hLayout);

三个按钮会水平排列,窗口拉伸时它们会跟着调整宽度。你还可以用 addStretch() 添加弹性空间,让按钮靠左或靠右。

QVBoxLayout:垂直布局

垂直布局把控件从上到下排成一列。

#include <QVBoxLayout>

QVBoxLayout *vLayout = new QVBoxLayout();
vLayout->addWidget(new QLabel("用户名:"));
vLayout->addWidget(new QLineEdit());
vLayout->addWidget(new QPushButton("登录"));

window.setLayout(vLayout);

这样标签、输入框、按钮就垂直排列了。实际项目中,我经常把水平布局和垂直布局嵌套使用,比如外面用垂直布局,里面某一行用水平布局。

核心要点: 布局管理器可以嵌套。你可以在一个 QVBoxLayout 里放多个 QHBoxLayout,实现复杂的界面布局。而且布局管理器会自动处理控件的间距和边距,你只需要调用 setSpacing()setContentsMargins() 微调即可。

综合示例:一个简单的登录界面

咱们把今天学的知识串起来,写一个简单的登录界面。

#include <QApplication>
#include <QWidget>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QVBoxLayout>
#include <QHBoxLayout>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    
    QWidget window;
    window.setWindowTitle("登录");
    window.resize(300, 200);
    
    // 创建控件
    QLabel *userLabel = new QLabel("用户名:");
    QLineEdit *userEdit = new QLineEdit();
    userEdit->setPlaceholderText("请输入用户名");
    
    QLabel *pwdLabel = new QLabel("密码:");
    QLineEdit *pwdEdit = new QLineEdit();
    pwdEdit->setPlaceholderText("请输入密码");
    pwdEdit->setEchoMode(QLineEdit::Password);
    
    QPushButton *loginBtn = new QPushButton("登录");
    QPushButton *cancelBtn = new QPushButton("取消");
    
    // 创建布局
    QVBoxLayout *mainLayout = new QVBoxLayout();
    
    QHBoxLayout *userLayout = new QHBoxLayout();
    userLayout->addWidget(userLabel);
    userLayout->addWidget(userEdit);
    
    QHBoxLayout *pwdLayout = new QHBoxLayout();
    pwdLayout->addWidget(pwdLabel);
    pwdLayout->addWidget(pwdEdit);
    
    QHBoxLayout *btnLayout = new QHBoxLayout();
    btnLayout->addStretch();
    btnLayout->addWidget(loginBtn);
    btnLayout->addWidget(cancelBtn);
    
    mainLayout->addLayout(userLayout);
    mainLayout->addLayout(pwdLayout);
    mainLayout->addLayout(btnLayout);
    
    window.setLayout(mainLayout);
    window.show();
    
    return app.exec();
}

这个例子把标签和输入框用水平布局放在一行,按钮用水平布局靠右排列,外面再用垂直布局把三行串起来。窗口拉伸时,所有控件都会自适应——这就是布局管理器的威力。

好了,今天的内容就到这里。你掌握了 QWidgetQLabelQPushButtonQLineEdit 这四个基础控件,以及 QHBoxLayoutQVBoxLayout 两个布局管理器。这些是 Qt 桌面开发的基石,多写几个小例子,很快就能上手。

个人建议: 初学者可以先用手动 setGeometry() 的方式感受控件的位置,然后再切换到布局管理器。这样你能更深刻地理解「布局管理器到底帮我们省了什么事」。

公众号:蓝海资料掘金营,微信 deep3321