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(水平排列)。它们可以互相嵌套,实现复杂的布局。
知识体系:布局核心逻辑
实战:一个登录界面
光说不练假把式。咱们用上面学的知识,搭一个简单的登录界面。
// 创建主窗口
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基础看似简单,但它是你构建复杂界面的基石。多动手写几个小例子,比看十遍书都管用。