4、Qt Widgets基础:QWidget属性、QPushButton、QLabel、QLineEdit、布局管理器

说实话,很多新手学Qt一上来就怼信号槽、怼多线程,结果连个按钮都摆不整齐。我个人觉得,Widgets基础才是Qt桌面开发的根。你想想看,一个窗口里放几个控件,怎么对齐、怎么缩放,这些基本功不扎实,后面写再多逻辑也是白搭。

这一章,咱们就踏踏实实把QWidget、QPushButton、QLabel、QLineEdit这几个最常用的家伙摸透,再配上布局管理器,让你能快速搭出一个像样的界面。

核心要点:所有可视化控件都继承自QWidget,布局管理器决定它们怎么排,而不是你手动去算坐标。

4.1 QWidget:一切控件的爹

QWidget是所有用户界面对象的基类。说白了,你看到的每个按钮、标签、输入框,本质上都是一个QWidget。它提供了窗口最基本的能力:大小、位置、可见性、鼠标事件等等。

我刚开始学Qt时,总喜欢直接new一个QWidget出来当窗口用。后来发现,其实QWidget本身就是一个空白窗口,你往上面放东西就行。

常用属性一览

属性 类型 说明
geometry QRect 控件的位置和大小(相对于父控件)
minimumSize / maximumSize QSize 控件允许的最小/最大尺寸
sizePolicy QSizePolicy 控件在布局中的伸缩策略
enabled bool 控件是否可用(灰色不可点)
visible bool 控件是否可见
windowTitle QString 窗口标题(仅顶层窗口有效)

这里我特别想提一下sizePolicy。我在项目中遇到过一个问题:两个按钮放在水平布局里,一个想固定宽度,另一个想自动拉伸。折腾了半天,最后发现就是sizePolicy没设对。记住:Expanding表示尽量占满空间,Fixed表示保持固定大小。

// 设置一个按钮固定宽度,另一个自动拉伸
QPushButton *btnFixed = new QPushButton("固定");
btnFixed->setFixedWidth(100);

QPushButton *btnStretch = new QPushButton("拉伸");
btnStretch->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);

4.2 QPushButton:最常用的交互控件

按钮嘛,谁都会用。但你真的了解它吗?QPushButton除了显示文字,还能显示图标、设置快捷键、甚至模拟点击。

我个人习惯,在写按钮时一定会设置setFocusPolicy。为什么?因为默认情况下按钮可以获取焦点,按空格就能触发。这在某些场景下会误操作。我曾经在一个数据录入界面里,用户按空格想输入空格,结果把按钮触发了……嗯,从那以后我养成了好习惯。

QPushButton *btn = new QPushButton("保存(&S)", this);
btn->setIcon(QIcon(":/icons/save.png"));
btn->setFocusPolicy(Qt::NoFocus);  // 不让按钮抢焦点
// 快捷键 Alt+S 可以直接触发这个按钮

小技巧:按钮文字中的&S会显示为带下划线的S,配合Alt键就是快捷键。这个在菜单和按钮上都很实用。

4.3 QLabel:不只是显示文字

QLabel最基础的功能是显示文本,但它还能显示图片、富文本(HTML)、甚至动画。你想想看,一个简单的状态提示,用QLabel就够了。

我记得有一次做监控软件,需要在界面上显示设备状态。用QLabel配合setPixmap,直接放一个红绿灯图标,比画自定义控件省事多了。

QLabel *label = new QLabel("欢迎使用本系统", this);
label->setAlignment(Qt::AlignCenter);
label->setStyleSheet("font-size: 18px; color: #333;");

// 显示图片
QLabel *imageLabel = new QLabel(this);
QPixmap pix(":/images/logo.png");
imageLabel->setPixmap(pix.scaled(200, 100, Qt::KeepAspectRatio));

注意:QLabel默认不会自动缩放图片。如果你想让图片自适应标签大小,需要手动调用scaled(),或者在标签大小变化时重新设置。我曾经踩过这个坑,图片显示不全,排查了半天。

4.4 QLineEdit:单行文本输入

QLineEdit是用户输入文本的主要方式。它支持占位符、密码模式、输入验证、自动补全等特性。

这里我重点说两个点:输入掩码和验证器。输入掩码适合固定格式,比如电话号码、日期;验证器适合动态规则,比如只能输入数字。

QLineEdit *phoneEdit = new QLineEdit(this);
phoneEdit->setPlaceholderText("请输入手机号");
phoneEdit->setInputMask("000-0000-0000");  // 固定格式

QLineEdit *ageEdit = new QLineEdit(this);
ageEdit->setValidator(new QIntValidator(0, 150, this));  // 只能输入0-150的整数

你想想看,如果没有这些限制,用户随便输入一串字母,你后端还得做一堆校验。直接在输入层就卡住,省心多了。

4.5 布局管理器:让界面自动适应

布局管理器是Qt界面设计的灵魂。没有它,你就要手动计算每个控件的位置和大小,窗口一缩放就乱套。

常用的就两个:QVBoxLayout(垂直排列)和QHBoxLayout(水平排列)。它们可以互相嵌套,实现复杂的布局。

知识体系:布局核心逻辑

Qt 布局管理器核心逻辑 布局管理器 (QLayout) QVBoxLayout (垂直) QHBoxLayout (水平) QPushButton QLabel QLineEdit 其他QWidget 布局管理器自动计算控件位置和大小 支持嵌套:水平里套垂直,垂直里套水平

实战:一个登录界面

光说不练假把式。咱们用上面学的知识,搭一个简单的登录界面。

// 创建主窗口
QWidget *window = new QWidget;
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->setEchoMode(QLineEdit::Password);  // 密码模式
pwdEdit->setPlaceholderText("请输入密码");

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);
mainLayout->addStretch();  // 底部弹簧

window->setLayout(mainLayout);
window->show();

经验之谈:布局里加addStretch()是个好习惯。它相当于一个弹性弹簧,能把控件推到一边。没有它,控件可能会被拉伸得很难看。

你看,整个界面没有写一行坐标代码,全靠布局管理器自动排列。窗口缩放时,控件会自适应。这就是布局的魅力。

4.6 避坑指南

最后,分享几个我踩过的坑,希望能帮你省点时间。

  • 布局嵌套层级别太深:我曾经嵌套了五六层布局,结果界面卡得要死。一般三层以内就够了。
  • 记得给父控件设置布局:setLayout()这一步很容易忘。不设置的话,控件不会自动排列。
  • QLineEdit的密码模式:设置setEchoMode(QLineEdit::Password)后,输入的内容会显示为圆点。但注意,这个只是显示隐藏,数据本身还是明文,传输时记得加密。
  • QLabel的富文本:如果你用setText("<b>粗体</b>"),记得先调用setTextFormat(Qt::RichText),否则可能不生效。

嗯,这一章的内容就到这里。Widgets基础看似简单,但它是你构建复杂界面的基石。多动手写几个小例子,比看十遍书都管用。

可可精品资料库