Qt:常用控件

devtools/2025/2/10 8:31:37/

目录

控件概述

控件体系的发展

按钮类控件

QPushButton

QRadioButton

QCheckBox

QToolButton

显示类控件

QLabel

QLCDNumber

QProgressBar

QCalendarWidget

输入类控件

QLineEdit

QTextEdit

QComboBox

QSpinBox

QDateEdit & QTimeEdit

QDial

QSlider

多元素控件

QListWidget

QTableWidget

QTreeWidget

容器类控件

QGroupBox

QTabWidget

布局管理器

QVBoxLayout

QHBoxLayout

QGridLayout

QFormLayout

间隔类控件


控件概述

Widget是Qt中的核心概念,英文原义是"小部件",此处将其翻译为"控件"。控件是构成一个图形化界面的基本要素,如按钮、列表视图、树形视图、单行输入框、多行输入框、滚动条、下拉框等都可以称为"控件"。

Qt作为一个成熟的GUI开发框架,内置了大量的常用控件。Qt也提供了"自定义控件"的能力,可以在现有控件不能满足需求时,对现有控件做出扩展,或者自定义出新的控件。


控件体系的发展

控件是 GUI 开发中的通用概念,不仅仅局限在 Qt 中。

第一阶段:

完全没有控件,此时需要通过⼀些绘图 API 手动的绘制出按钮或者输入框等内容,代码编写繁琐,例如文曲星的 Lava 平台开发。

第二阶段:

  • 只包含粗略的控件,只是提供了按钮,输⼊框,单选框,复选框等最常用的控件.
  • 例如 html 的原生控件

第三阶段:

  • 更完整的控件体系,基本可以覆盖到 GUI 开发中的⼤部分场景
  • 例如早期的 MFC,VB,C++ Builder,Qt,Delphi,后来的 Android SDK,Java FX,前端的各种 UI 库等

按钮类控件

QPushButton

Qt中使用QPushButton表示一个按钮。QPushButton继承自QAbstractButton,该类是一个抽象类,是其他按钮的父类。

在Qt Designer中也能够看到这里的继承关系

QAbstractButton中和QPushButton相关性较大的属性

属性说明
text按钮中的文本
icon按钮中的图标
iconSize按钮中图标的尺寸
shortCut按钮对应的快捷键
autoRepeat

按钮是否会重复触发,当鼠标左键按住不放时

若设为true,则会持续产生鼠标点击事件

若设为false,则必须释放鼠标后,再次点击鼠标才能产生点击事件

(类似于游戏手柄上的"连发效果")

autoRepeatDelay重复触发的延时时间(按住按钮多久,开始重复触发)
autoRepeatInterval重复触发的周期

注意:

  • QAbstractButton作为QWidget的子类,继承了QWidget的属性。QWidget里的各种属性用法,对于QAbstractButton同样适用,因此表格仅列出QAbstractButton独有的属性
  • Qt的api设计风格非常清晰,此处列出的属性都是可以获取和设置的。如:使用text()获取按钮文本,使用setText()设置文本

事实上,QPushButton的核心功能都是QAbstractButton提供的,自身提供的属性都较为简单,其中default和autoDefault影响的是按下enter时自动点击哪个按钮的行为,flat把按钮设置为扁平的样式。暂时不做过多关注。

代码示例:带有图标的按钮

创建resource.qrc文件并导入图片

在界面上创建一个按钮

修改widget.cpp

#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);//创建图标QIcon icon(":/001.png");//设置图标    ui->pushButton->setIcon(icon);//设置图标大小ui->pushButton->setIconSize(QSize(66, 66));
}Widget::~Widget()
{delete ui;
}

运行代码

代码示例:带有快捷键的按钮

在界面中拖五个按钮。五个按钮的objectName分别为pushButtonTarget 、pushButtonUp、pushButtonDown、pushButtonLeft、pushButtonRight,五个按钮的初始位置随意,其中pushButtonTarget尺寸设为100*100,其余按钮设为50*50,文本内容均清空。

创建resource.qrc并导入5个图片

修改widget.cpp,设置图标资源和快捷键,设置四个方向键的slot函数

#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);//设置图标ui->pushButtonTarget->setIcon(QIcon(":/image/dog.png"));ui->pushButtonUp->setIcon(QIcon(":/image/Up.png"));ui->pushButtonDown->setIcon(QIcon(":/image/Down.png"));ui->pushButtonLeft->setIcon(QIcon(":/image/Left.png"));ui->pushButtonRight->setIcon(QIcon(":/image/Right.png"));//设置快捷键1ui->pushButtonUp->setShortcut(QKeySequence(Qt::Key_W));ui->pushButtonDown->setShortcut(QKeySequence(Qt::Key_S));ui->pushButtonLeft->setShortcut(QKeySequence(Qt::Key_A));ui->pushButtonRight->setShortcut(QKeySequence(Qt::Key_D));//设置快捷键2
//    ui->pushButtonUp->setShortcut(QKeySequence("W"));
//    ui->pushButtonDown->setShortcut(QKeySequence("S"));
//    ui->pushButtonLeft->setShortcut(QKeySequence("A"));
//    ui->pushButtonRight->setShortcut(QKeySequence("D"));
}Widget::~Widget()
{delete ui;
}void Widget::on_pushButtonUp_clicked()
{const QRect& rect = ui->pushButtonTarget->geometry();ui->pushButtonTarget->setGeometry(rect.x(), rect.y() - 5, rect.height(), rect.width());
}
void Widget::on_pushButtonDown_clicked()
{const QRect& rect = ui->pushButtonTarget->geometry();ui->pushButtonTarget->setGeometry(rect.x(), rect.y() + 5, rect.height(), rect.width());
}
void Widget::on_pushButtonLeft_clicked()
{const QRect& rect = ui->pushButtonTarget->geometry();ui->pushButtonTarget->setGeometry(rect.x() - 5, rect.y(), rect.height(), rect.width());
}
void Widget::on_pushButtonRight_clicked()
{const QRect& rect = ui->pushButtonTarget->geometry();ui->pushButtonTarget->setGeometry(rect.x() + 5, rect.y(), rect.height(), rect.width());
}

运行程序,此时点击按钮,或者使用wasd均可让狗头移动

代码示例:按钮的重复触发

在上述案例中,按住快捷键是可以重复触发的,但是鼠标点击则不能

修改widget.cpp,在构造函数中开启重复触发

//开启鼠标重复触发
ui->pushButtonUp->setAutoRepeat(true);
ui->pushButtonDown->setAutoRepeat(true);
ui->pushButtonLeft->setAutoRepeat(true);
ui->pushButtonRight->setAutoRepeat(true);

QRadioButton

QRadioButton是单选按钮,可以在多个选项中选择一个。作为QAbstractButton和QWidget的子类,上面介绍的属性和用法对于QRadioButton同样适用

QAbstractButton中和QRadioButton关系较大的属性

属性说明
checkable是否能被选中
checked是否已经被选中,checkable时checked的前提条件
autoExclusive

是否排它

选中一个按钮之后是否会取消其他按钮的选中

对于QRadioButton而言,默认就是排它的

代码示例:选择性别

在界面上创建一个label和三个单选按钮。设置的文本如下图,三个单选按钮的objectName分别为radioButtonMale 、radioButtonFemale、radioButtonOther

修改widget.cpp,编辑三个QRadioButton的slot函数

void Widget::on_radioButtonMale_clicked()
{ui->label->setText("你选择的性别为:男");
}void Widget::on_radioButtonFemale_clicked()
{ui->label->setText("你选择的性别为:女");
}void Widget::on_radioButtonOther_clicked()
{ui->label->setText("你选择的性别为:其他");
}

修改代码,让程序启动默认选中性别男

Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);//设置默认选中该按钮ui->radioButtonMale->setChecked(true);ui->label->setText("你选择的性别为:男");
}

禁用"其他"选项

// 禁用other选项
ui->radioButtonOther->setCheckable(false);

点击"其他"按钮时,虽然不会被选中,但是可以触发点击事件,使label显示性别为其他

使用setEnabled可以更彻底的禁用按钮,此时该按钮无法被选中,也无法响应任何输入

// 禁用other选项
ui->radioButtonOther->setEnabled(false);

代码示例:clicked、pressed、released、toggled区别

  • clicked表示一次"点击"(一次按下 + 一次释放)
  • pressed表示鼠标"按下"
  • released表示鼠标"释放"
  • toggled表示按钮状态切换

在界面上创建四个单选按钮,objectName分别为radioButton、radioButton_2、radioButton_3、radioButton_4

给1创建clicked槽函数,给2创建pressed槽函数,给3创建released槽函数,给4创建toggled槽函数

void Widget::on_radioButton_clicked()
{qDebug() << "clicked";
}void Widget::on_radioButton_2_pressed()
{qDebug() << "pressed";
}void Widget::on_radioButton_3_released()
{qDebug() << "released";
}void Widget::on_radioButton_4_toggled(bool checked)
{if(checked) qDebug() << "toggled true";else qDebug() << "toggled false";
}

代码示例:单选按钮分组

在界面上创建6个单选框,用来模拟麦当劳点餐界面。objectName分别为radioButton到radioButton_6

此时直接运行程序,可以发现这六个QRadioButton之间都是排它的。但是按照正常的逻辑,应该每⼀组内部来控制排它,但是组和组之间不能排它。

引入QButtonGroup进行分组

#include "widget.h"
#include "ui_widget.h"
#include <QButtonGroup>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);//创建三个QButtonGroupQButtonGroup* group1 = new QButtonGroup(this);QButtonGroup* group2 = new QButtonGroup(this);QButtonGroup* group3 = new QButtonGroup(this);//将QRadioButton两两一组放入QButtonGroup中group1->addButton(ui->radioButton);group1->addButton(ui->radioButton_2);group2->addButton(ui->radioButton_3);group2->addButton(ui->radioButton_4);group3->addButton(ui->radioButton_5);group3->addButton(ui->radioButton_6);
}Widget::~Widget()
{delete ui;
}

再次执行程序,就可以按照正确的分组方式来进行排它了

QCheckBox

QCheckBox表示复选按钮,可以允许选中多个。和QCheckBox最相关的属性是checkable和checked,都是继承自QAbstractButton

至于QCheckBox独有的属性tristate用来实现"三态复选框",不过较为冷门,暂时不做讨论

代码示例:获取复选按钮的取值

在界面上创建三个复选按钮和一个普通按钮,objectName分别为checkBoxEat、checkBoxSleep、checkBoxPlay以及pushButton

给pushButton添加slot函数

void Widget::on_pushButton_clicked()
{QString result;if(ui->checkBoxEat->isChecked())result += ui->checkBoxEat->text();if(ui->checkBoxSleep->isChecked())result += ui->checkBoxSleep->text();if(ui->checkBoxPlay->isChecked())result += ui->checkBoxPlay->text();qDebug() << "选中的内容:" << result;
}

QToolButton

QToolButton大部分功能和QPushButton一致,但是QToolButton主要应用在工具栏、菜单等场景。


显示类控件

QLabel

QLabel可以用来显示文本和图片

核心属性

属性说明
textQLabel中的文本
textFormat

文本的格式

Qt::PlainText 纯文本

Qt::Rich Text 富文本(支持html标签)

Qt::MarkdownText markdown格式

Qt::AutoText 根据文本内容自动决定文本格式

pixmapQLabel内部包含的图片
scaledContents

设为true表示内容自动拉伸填充QLabel

设为false则不会自动拉伸

alignment对齐方式(可以设置水平方向和垂直方向如何对齐)
wordWrap

设为true内部文本会自动换行

设为false则内部文本不会自动换行

indent设置文本缩进(水平方向和垂直方向都生效)
margin内部文本与边框之间的边距
openExternalLinks

是否允许打开一个外部链接

(当QLabel的文本中包含url时涉及)

buddy

给QLabel关联一个"伙伴",按下QLabel指示的快捷键时就能激活对应的伙伴

若伙伴是一个QCheckBox,那么该QCheckBox就会被选中

代码示例:显示不同格式的文本

在界面上创建三个QLabel,objectName分别为label、label_2、label_3

修改widget.cpp,设置三个label的属性

#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);ui->label->setTextFormat(Qt::PlainText);ui->label->setText("这是一段纯文本");ui->label_2->setTextFormat(Qt::RichText);ui->label_2->setText("<b> 这是一段富文本 </b>");ui->label_3->setTextFormat(Qt::MarkdownText);ui->label_3->setText("## 这是一段MarkDown文本");
}Widget::~Widget()
{delete ui;
}

运行程序,观察效果

代码示例:显示图片

虽然QPushButton也可以通过设置图标的方式设置图片,但是并非是一个好的选择,更多的时候还是希望通过QLabel来作为一个更单纯的显示图片的方式

在界面上创建一个QLabel,objectName为label

创建resource.qrc文件并把图片导入到qrc中

修改widget.cpp,给QLabel设置图片

#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);//设置label大小与窗口大小相同ui->label->setGeometry(0, 0, 800, 600);//设置label图片QPixmap pixmap(":/huaji.png");ui->label->setPixmap(pixmap);//设置label内容拉伸ui->label->setScaledContents(true);
}Widget::~Widget()
{delete ui;
}

运行程序,观察效果,可以看到图片已经被拉伸,可以把窗口填满了。但是若拖动窗口大小,可以看到图片并不会随着窗口大小的改变而同步变化

为了解决该问题,可以在Widget中重写resizeEvent函数

void Widget::resizeEvent(QResizeEvent *event)
{ui->label->setGeometry(0, 0, event->size().width(), event->size().height());qDebug() << event->size();
}

注意:

  • 此处的resizeEvent函数没有手动调用,但是能在窗口大小变化时被自动调用。这个过程就是依赖C++中的多态来实现的,Qt框架内部管理着QWidget对象表示窗口,在窗口大小发生改变时,Qt就会自动调用resizeEvent函数
  • 但是实际上这个窗口的并非是QWidget,而是QWidget的子类,也就是自主编写的Widget。此时虽然是通过父类调用函数,但是实际上执行的是子类的函数(即重写后的resizeEvent )
  • 此处属于是多态机制的一种经典用法。通过上述过程,就可以把自定义的代码插入到框架内部执行,相当于"注册回调函数"

代码示例:文本对齐、自动换行、缩进、边距

创建四个label,objectName分别是label到label_4,并且在QFrame中设置frameShape为Box(设置边框后看起来会更清晰一些)

QFrame是QLabel的父类,其中frameShape属性用来设置边框性质

  • QFrame::Box:矩形边框
  • QFrame::Panel:带有可点击区域的面板边框
  • QFrame::WinPanel:Windows风格的边框
  • QFrame::HLine:水平线边框
  • QFrame::VLine:垂直线边框
  • QFrame::StyledPanel:带有可点击区域的面板边框,但样式取决于窗口主题

编写widget.cpp,给这四个label设置属性

#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);//设置文字居中对齐ui->label->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);ui->label->setText("垂直水平居中的文本");//设置自动换行ui->label_2->setAlignment(Qt::AlignTop | Qt::AlignLeft);ui->label_2->setWordWrap(true);ui->label_2->setText("这是一个很长的文本这是一个很长的文本这是一个很长的文本这是一个很长的文本这是一个很长的文本这是一个很长的文本");//设置首行缩进ui->label_3->setAlignment(Qt::AlignTop | Qt::AlignLeft);ui->label_3->setIndent(20);ui->label_3->setText("这是一个很长的文本这是一个很长的文本这是一个很长的文本这是一个很长的文本这是一个很长的文本这是一个很长的文本");//设置边距ui->label_4->setAlignment(Qt::AlignTop | Qt::AlignLeft);ui->label_4->setMargin(20);ui->label_4->setText("这是一个很长的文本这是一个很长的文本这是一个很长的文本这是一个很长的文本这是一个很长的文本这是一个很长的文本");
}Widget::~Widget()
{delete ui;
}
  • 第一个label垂直水平居中
  • 第二个label设置了wordWrap,能够自动动换行
  • 第三个label设置了Indent,左侧和上方和边框有间距,右侧则没有
  • 第四个label设置了margin,四个方向均有间距(图上仅体现出三个方向,下方看不出来)

代码示例:设置伙伴

创建两个label和两个radioButton,objectName分别为label、label_2、radioButton、radioButton_2

注意:

  • 此处把label中的文本设置为"快捷键 &A"这样的形式,其中&后面跟着的字符就是快捷键,可以通过alt+A的方式来触发该快捷键
  • 但是这里的快捷键和QPushButton不同,需要搭配alt和单个字母的方式才能触发

编写widget.cpp,设置buddy属性

#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);ui->label->setBuddy(ui->radioButton);ui->label_2->setBuddy(ui->radioButton_2);
}Widget::~Widget()
{delete ui;
}

QLCDNumber

QLCDNumer是一个专门用来显示数字的控件,类似于"老式计算器"的效果

核心属性

属性说明
intValueQLCDNumber显示的数字(int)
value

QLCDNumber显示的数字(double)

和intValue是联动的(如:给value设置为1.5,intValue的值就是2)

digCount显示几位数字
mode

数字显示形式

  1. QLCDNumber::Dec:十进制模式,
  2. QLCDNumber::Hex:十六进制模式
  3. QLCDNumber::Bin:二进制模式
  4. QLCDNumber::Oct:八进制模式

只有十进制时才能显示小数点后面的数字

segmentStyle

设置显示的风格

QLCDNumber::Flat:平面的显示风格,数字呈现在一个平坦的表面上

QLCDNumber::Outline:轮廓显示风格,数字具有清晰的轮廓和阴影效果

QLCDNumber::Filled:填充显示风格,数字被填充颜色并于背景区分开

smallDecimalPoint设置比较小的小数点

代码示例:倒计时

在界面上创建一个QLCDNumber,初始值设为10,objectName为lcdNumber

修改widget.cpp

#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);//创建QTimer实例timer = new QTimer(this);//QTimer会每隔⼀定的时间触发⼀个timeout信号,将timeout信号和updateTime连接起来//意味着每次触发timeout信号都会伴随updateTime函数的执⾏connect(timer, &QTimer::timeout, this, &Widget::updateTime);//启动QTimer,每个1000ms触发一次信号timer->start(1000);
}Widget::~Widget()
{delete ui;
}void Widget::updateTime()
{int value = ui->lcdNumber->intValue();if(value <= 0) {timer->stop();return;}ui->lcdNumber->display(value - 1);
}

存在问题1

上述代码若直接在Widget构造函数中,通过一个循环+sleep的方式是否可以呢?

Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);int value = ui->lcdNumber->intValue();while (true) {std::this_thread::sleep_for(std::chrono::seconds(1));if (value <= 0) break;ui->lcdNumber->display(value - 1);}
}

显然这个代码是不行的,循环会使Widget的构造函数无法执行完毕,此时界面是不能正确构造和显示的

存在问题2

上述代码若是在Widget构造函数中另起⼀个线程,在新线程中完成循环+sleep是否可以呢?

Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);std::thread t([this]() {int value = this->ui->lcdNumber->intValue();while (true) {std::this_thread::sleep_for(std::chrono::seconds(1));if (value <= 0) break;this->ui->lcdNumber->display(value - 1);}});
}

这个代码同样是不行的。Qt中规定,任何对于GUI上内容的操作必须在主线程中完成。像Widget构造函数,以及connect连接的slot函数,都是在主线程中调用的,而自主创建的线程则不是。当自主创建的线程中尝试对界面元素进行修改时,Qt程序往往会直接崩溃。

注意:

这样的约定主要是因为GUI中的状态往往是牵一发动全身的,修改一个地方就需要同步的对其他内容进行调整。如调整了某个元素的尺寸,就可能影响到内部的文字位置,或者其他元素的位置。这里一连串的修改,都是需要按照一定的顺序来完成的。由于多线程执行的顺序无法保障,因此Qt从根本上禁止了其他线程修改GUI状态,避免后续的一系列问题。

QProgressBar

Qt中使用QProgressBar表示一个进度条

核心属性

属性说明
minimum进度条最小值
maximum进度条最大值
value进度条当前值
alignment

文本在进度条中的对齐方式

  • Qt::AlignLeft:左对齐
  • Qt::AlignRight:右对齐
  • Qt::AlignCenter:居中对齐
  • Qt::AlignJustify:两端对齐
textVisible进度条的数字是否可见
orientation进度条的方向是水平还是垂直
invertAppearance是否朝反方先增长进度
format

展示的数字格式

  • %p:表示进度的百分比(0-100)
  • %v:表示进度的数值(0-100)
  • %m:表示剩余时间(以毫秒为单位)
  • %t:表示总时间(以毫秒为单位)

代码示例:设置进度条按时间增长

在界面上创建进度条,objectName为progressBar

其中最小值设为0,最大值设为100,当前值设为0

修改widget.h

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QTimer>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();void updateProgressBar();private:Ui::Widget *ui;QTimer* timer;
};
#endif // WIDGET_H

修改widget.cpp

#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);timer = new QTimer(this);connect(timer, &QTimer::timeout, this, &Widget::updateProgressBar);timer->start(100);
}Widget::~Widget()
{delete ui;
}void Widget::updateProgressBar()
{int value = ui->progressBar->value();if(value >= 100) {timer->stop();return;}ui->progressBar->setValue(value + 1);
}

代码示例:创建以个红色的进度条

QProgressBar也是QWidget的子类,因此可以使用styleSheet通过样式来修改进度条的颜色。在Qt Designer右侧的属性编辑器中,找到QWidget的styleSheet属性

QProgressBar::chunk {background-color: #FF0000;}

同时把QProcessBar的alignment属性设置为垂直水平居中

QCalendarWidget

QCalendarWidget表示一个"日历"

核心属性

属性说明
selectDate当前选中的日期
minimumDate最小日期
maximumDate最大日期
firstDayOfWeek日历的第一列是周几
gridVisible是否显示表格的边框
selectionMode是否允许选择日期
navigationBarVisible日历上方标题是否显示
horizontalHeaderFormat日历上方标题显示的日期格式
verticalHeaderFormat日历第一列显示的内容格式
dateEditEnabled是否允许日期被编辑

重要信号

属性说明
selectionChanged(const QDate&)当选中的日期发生改变时触发
activated(const QDate&)当双击一个日期或者按下回车键时触发
currentPageChanged(int, int)当年份月份发生改变时触发,形参表示改变后的新年份和新月份

代码示例:获取当前选中的日期

在界面上创建一个QCalendarWidget和一个label,objectName为calendarWidget、label

给QCalendarWidget添加slot函数

void Widget::on_calendarWidget_selectionChanged()
{QDate date = ui->calendarWidget->selectedDate();qDebug() << date;ui->label->setText(date.toString());
}

输入类控件

QLineEdit

QLineEdit用来表示单行输入框,可以输入一段文本,但是不能换行

核心属性

属性说明
text输入框中的文本
inputMask输入内容格式约束
maxLength最大长度
frame是否添加边框
echoMode

显示方式

  • QLineEdit::Normal:默认值,文本框会显示输入的文本
  • QLineEdit::Password:输入的字符会被隐藏,通常使用(*)星号或(=)等号代替
  • QLineEdit::NoEcho:文本框不会显示任何输入的字符
cursorPosition光标所在的位置
alignment文字对齐的方式,设置水平和垂直方向的对齐
dragEnabled是否允许拖拽
readOnly是否是只读的
placeHolderText当输入框为空时,显示什么样的提示信息
clearButtonEnabled是否会自动显示出"清除按钮"

核心信号

信号说明
void cursorPositionChanged(int old, int new)当鼠标移动时发出此信号,old为先前的位置,new为新位置
void editingFinished()当按下返回或者回车键时,或行编辑失去焦点时,发出此信号
void returnPress()

当返回或回车键按下时发出此信号

若设置了验证器,必须要通过验证,才能触发

void selectionChanged()当选中的文本改变时,发出此信号
void textChanged(const QString& text)

当QLineEdit中的文本改变时,发出此信号,text是新的文本

代码对文本的修改可以触发此信号

void textEdited(const QString& text)当QLineEdit中的文本改变时,发出此信号,text是新文本 代码对文本的修改不可以触发此信号

代码示例:录入个人信息

在界面上创建三个输入框和两个单选按钮,一个普通按钮。三个输入框的objectName为lineEditName、lineEditPassword、lineEditPhone,两个单选按钮的objectName为radioButtonMale、radioButtonFemale,按钮的objectName为pushButton。

#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);//初始化第一个输入框ui->lineEditName->setPlaceholderText("请输入姓名");ui->lineEditName->setClearButtonEnabled(true);//初始化第二个输入框ui->lineEditPassword->setPlaceholderText("请输入密码");ui->lineEditPassword->setClearButtonEnabled(true);ui->lineEditPassword->setEchoMode(QLineEdit::Password);//初始化第三个输入框ui->lineEditPhone->setPlaceholderText("请输入电话号码");ui->lineEditPhone->setClearButtonEnabled(true);//验证手机号必须是11位数字,并且按照"334"的格式输入ui->lineEditPhone->setInputMask("000-0000-0000");
}Widget::~Widget()
{delete ui;
}void Widget::on_pushButton_clicked()
{QString gender = ui->radioButtonMale->isChecked()? "男" : "女";qDebug() << "姓名:" << ui->lineEditName->text()<< "密码:" << ui->lineEditPassword->text()<< "性别:" << gender<< "电话:" << ui->lineEditPhone->text();
}

inputMask只能进行简单的输入格式校验。实际开发中,基于正则表达式的方式是更核心的方法

代码示例:使用正则表达式验证输入框数据

正则表达式是一种在计算机中常用的,使用特殊字符描述一个字符串的特征的机制。在进行字符串匹配时非常有用。正则表达式的语法较为复杂,一般都是随用随查,不需要背下来。

在界面上创建输入框和一个按钮

#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);//设置按钮默认是禁用状态ui->pushButton->setEnabled(false);//注册一个validatorui->lineEdit->setValidator(new QRegExpValidator(QRegExp("^1\\d{10}$")));
}Widget::~Widget()
{delete ui;
}void Widget::on_lineEdit_textEdited(const QString &arg1)
{qDebug() << arg1;QString content = arg1;int pos = 0;if(ui->lineEdit->validator()->validate(content, pos) == QValidator::Acceptable)ui->pushButton->setEnabled(true);elseui->pushButton->setEnabled(false);
}
  • 使用QRegExp创建一个正则表达式对象,"^1\\d{10}$"表示"以1开头,后面跟上任意的10个十进制数字"
  • 使用QRegExpValidator创建一个验证器对象,Qt中内置了四个主要的验证器对象

  • QRegularExpressionValidator在匹配性能上做出了一定优化,但是从使用角度讲,和QRegExpValidator差别不大
  • 通过lineEdit->validator()获取到内置的验证器
  • 通过validate方法验证文本是否符合要求
  • 第一个参数填写的是要验证的字符串。第二个参数是一个int&,是输出型参数,当验证的字符串不匹配时,返回这个字符串的长度。返回值是一个枚举,QValidator::Acceptable表示验证通过,QValidator::Invalid表示验证不通过

代码示例:验证两次输入密码一致

在界面上创建两个输入框和一个label

#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);ui->lineEdit->setEchoMode(QLineEdit::Password);ui->lineEdit_2->setEchoMode(QLineEdit::Password);
}Widget::~Widget()
{delete ui;
}void Widget::on_lineEdit_textEdited(const QString &arg1) {(void)arg1;Compare();
}
void Widget::on_lineEdit_2_textEdited(const QString &arg1) {(void)arg1;Compare();
}void Widget::Compare()
{const QString str1 = ui->lineEdit->text();const QString str2 = ui->lineEdit_2->text();if(str1.isEmpty() && str2.isEmpty())ui->label->setText("密码为空");else if(str1 == str2)ui->label->setText("两次输入密码相同");elseui->label->setText("两次输入密码不同");
}

QTextEdit

QTextEdit表示多行输入框,也是⼀个富文本&markdown编辑器,并且能在内容超出编辑框范围时自动提供滚动条

核心属性

属性说明
markdown输入框内的内容支持markdown,能自动对markdown文本进行渲染
html可以支持大部分html标签,包括img、table等
placeHolderText输入框为空时提示的内容
readOnly是否是只读的
undoRedoEnable

是否支持undo、redo功能

按下ctrl+z触发undo

按下ctrl+y触发redo

autoFormating开启自动格式化
tabstopWidth缩进占用多少空间
overwriteMode是否开辟复写模式
acceptRichText是否接收富文本内容
verticalScrollBarPolicy

垂直方向滚动条的出现策略

  • Qt::ScrollBarAsNeeded:根据内容自动决定是否需要滚动条,默认值
  • Qt::ScrollBarAlwaysOff:总是关闭滚动条
  • Qt::ScrollBarAlwaysOn:总是显示滚动条
horizontalScrollBarPolicy水平方向滚动条的出现策略

核心信号

信号说明
textChanged()文本内容改变时触发
selectionChanged()选中范围改变时触发
cursorPositionChanged()光标移动时触发
undoAvailable(bool)进行undo操作时触发
redoAvailable(bool)进行redo操作时触发
copyAvailable(bool)文本被选中/取消选中时触发

代码示例:获取多行输入框的内容

通过toPlainText方法获取到内部的文本。QTextEdit还提供了toMarkdown和toHtml,根据需要调整不同的获取方式。

#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);
}Widget::~Widget()
{delete ui;
}void Widget::on_textEdit_textChanged()
{const QString& text = ui->textEdit->toPlainText();qDebug() << text;ui->label->setText(text);
}

代码示例:验证输入框的各种信号

QTextEdit中包含了一个QTextCursor对象,通过这个对象可以获取到当前光标位置和选中的内容

#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);
}Widget::~Widget()
{delete ui;
}void Widget::on_textEdit_textChanged()
{qDebug() << "[textChanged]" << ui->textEdit->toPlainText();
}void Widget::on_textEdit_selectionChanged()
{const QTextCursor& cursor = ui->textEdit->textCursor();qDebug() << "[selectionChanged]" << cursor.selectedText();
}void Widget::on_textEdit_cursorPositionChanged()
{const QTextCursor& cursor = ui->textEdit->textCursor();qDebug() << "[cursorPositionChanged]" << cursor.position();
}void Widget::on_textEdit_undoAvailable(bool b)
{qDebug() << "[undoAvailable]" << b;
}void Widget::on_textEdit_redoAvailable(bool b)
{qDebug() << "[redoAvailable]" << b;
}void Widget::on_textEdit_copyAvailable(bool b)
{qDebug() << "[copyAvailable]" << b;
}

QComboBox

QComboBox表示下拉框

核心属性

属性说明
currentText当前选中的文本
currentIndex

当前选中的条目下标

从0开始计算,如果当前没有条目被选中,值为1

editable

是否允许修改

设为true时,QComboBox的行为就十分接近QLineEdit,也可以设置validator

iconSize下拉框图标(小三角)的大小
maxCount最多允许有多少个条目

核心方法

方法说明
addItem(const QString&)添加一个条目
currentIndex()

获取当前条目的下标

从0开始计算,若当前没有条目被选中,值为-1

currentText()获取当前条目的文本内容

核心信号

方法说明

activated(int)

activated(const QString& text)

当用户选择了一个选项时发出

这时相当于用户点开下拉框,并且鼠标划过某个选项

此时还没确认做出选择

currentIndexChanged(int)

currentIndexChanged(const QString& text)

当前选项改变时发出

此时用户已经明确的选择了一个选项

用户操作或者通过程序操作都会触发这个信号

editTextChanged(const QString& text)

当编辑框中的文本改变时发出

(editable为true时有效)

代码示例:使用下拉框模拟麦当劳点餐

在界面上创建三个下拉框和一个按钮

#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);ui->comboBox->addItem("巨无霸");ui->comboBox->addItem("麦辣鸡腿堡");ui->comboBox_2->addItem("薯条");ui->comboBox_2->addItem("麦辣鸡翅");ui->comboBox_3->addItem("可乐");ui->comboBox_3->addItem("雪碧");
}Widget::~Widget()
{delete ui;
}void Widget::on_pushButton_clicked()
{qDebug() << "汉堡选择:" << ui->comboBox->currentText();qDebug() << "小食选择:" << ui->comboBox_2->currentText();qDebug() << "饮料选择:" << ui->comboBox_3->currentText();
}

代码示例:从文件中加载下拉框的选项

#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);std::ifstream file("D:\\repositorys\\Qt\\QComboBox_2\\config.txt");std::string line;while(std::getline(file, line))ui->comboBox->addItem(QString::fromStdString(line));file.close();
}Widget::~Widget()
{delete ui;
}

Qt中也提供了QFile实现读写文件的功能。使用C++标准库的std::fstream也是完全可以的

之所以存在两套,是因为Qt诞生较早(1991年左右)此时C++还没有完成"标准化"的工作,C++标准库这样的概念自然也没有诞生。因此Qt就自己打造了⼀套库,实现了字符串、容器、文件操作、多线程、网络操作、定时器、正则表达式等内容

(由于C++标准委员会的不作为,至今仍然有些Qt提供的功能是标准库不具备的)

QSpinBox

使用QSpinBox或者QDoubleSpinBox表示"微调框",它是带有按钮的输入框,可以用来输入整数/浮点数,通过点击按钮来修改数值大小

核心属性

属性方法
value存储的数值
singleStep每次调整的步长(按下一次按钮数据变化多少)
displayInteger数字的进制
minimum最小值
maximum最大值
suffix后缀
prefix前缀
wrapping是否允许换行
frame是否带边框
alignment文字对齐方式
readOnly是否允许修改
buttonSymbol

按钮上的图标

  • UpDownArrows 上下箭头形式
  • PlusMinus 加减号形式
  • NoButtons 没有按钮
accelerated(加速的)按下按钮时是否为快速调整模式
correctionMode

    
输入有误时如何调整

  • QAbstractSpinBox::CorrectToPreviousValue:若用户输入了一个无效的值(例如在只能显示正整数的SpinBox中输入了负数),那么SpinBox会恢复为上一个有效值
  • QAbstractSpinBox::CorrectToNearestValue:若用户输入了一个无效的值,SpinBox会恢复为最接近的有效值
keyboardTrack

是否开启键盘跟踪

  • 设为true,每次在输入框中输入一个数字,都会触发一次valueChanged()和textChanged()信号
  • 设为false,只有在最终按下enter或者输入框失去焦点时才会触发valueChanged()和textChanged()信号

核心信号

信号说明
textChanged(QString)

微调框的文本发生改变时触发

参数QString带有前缀和后缀

valueChanged(int)

微调框的文本发生改变时触发

参数int代表当前的数值

#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);ui->comboBox->addItem("巨无霸");ui->comboBox->addItem("麦辣鸡腿堡");ui->comboBox_2->addItem("薯条");ui->comboBox_2->addItem("麦辣鸡翅");ui->comboBox_3->addItem("可乐");ui->comboBox_3->addItem("雪碧");ui->spinBox->setValue(1);ui->spinBox->setRange(1, 5);ui->spinBox_2->setValue(1);ui->spinBox_2->setRange(1, 5);ui->spinBox_3->setValue(1);ui->spinBox_3->setRange(1, 5);
}Widget::~Widget()
{delete ui;
}void Widget::on_pushButton_clicked()
{qDebug() << "当前下单内容:"<< ui->comboBox->currentText() << ":" << ui->spinBox->value()<< ui->comboBox_2->currentText() << ":" << ui->spinBox_2->value()<< ui->comboBox_3->currentText() << ":" << ui->spinBox_3->value();
}

QDateEdit & QTimeEdit

使用QDateEdit作为日期的微调框;使用QTimeEdit作为时间的微调框;使用QDateTimeEdit作为时间日期的微调框。这几个控件用法非常相似,下面以QDateTimeEdit为例进行介绍

QDateTimeEdit核心属性

属性说明
dateTime时间日期的值,形如 2000/1/1 0:00:00
date单纯日期的值,形如 2001/1/1
time单纯时间的值,形如 0:00:00
displayFormat

时间日期格式,形如 yyyy/M/d H:mm:ss

  • y表示年份
  • M表示月份
  • d表示日期
  • H表示小时
  • m表示分钟
  • s表示秒
minimumDateTime最小时间日期
maximumDateTime最大时间日期
timeSpec

Qt::LocalTime:显示本地时间

Qt::UTC 显示协调世界时

Qt::OffsetFromUTC:显示相对于UTC的偏移量(时差)

关于本地时间(LocalTime)和协调世界时(UTC)

UTC时间是一个基于原子钟的标准时间,不受地球的自转周期影响,和格林威治时间(GMT)是
非常接近的,科学家会通过精密的设备来测量并维护

计算机内部使用的时间就是基于UTC时间,本地时间则是基于不同的时区,对UTC时间做出了一些调整。如北京时间,位于"东八区",就需要在UTC时间基础上+8个小时的时差

核心信号

信号说明
dateChanged(QDate)日期改变时触发
dateTimeChanged(QDateTime)时间改变时触发
dateTimeChanged(QDateTime)日期时间任意一个改变时触发

代码示例:实现日期计算器

#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);
}Widget::~Widget()
{delete ui;
}void Widget::on_pushButton_clicked()
{//获取到两个时间框的时间日期QDateTime timeOld = ui->dateTimeEdit->dateTime();QDateTime timeNew = ui->dateTimeEdit_2->dateTime();//计算日期差值int days = (timeOld.secsTo(timeNew) / 3600) / 24;int hours = (timeOld.secsTo(timeNew) / 3600) % 24;//设置label的内容QString text = "计算结果为:" + QString::number(days) + "天 零 " + QString::number(hours) + "小时";ui->label->setText(text);
}

QDial

使用QDial表示一个旋钮

核心属性

属性说明
value持有的数值
minimum最小值
maximum最大值
singleStep按下方向键时改变的步长
pageStep按下pageUp/pageDown时改变的步长
sliderPosition界面上旋钮显示的初始位置
tracking

外观是否会跟踪数值变化

默认值为true,一般不需要修改

wrapping

是否允许循环调整

即数值如果超过最大值,是否允许回到最小值

(调整过程能否"套圈")

notchesVisible是否显示刻度线
notchTarget

刻度线之间的相对位置

数字越大,刻度线越稀疏

核心信号

信号说明
valueChanged(int)数值改变时触发
rangedChanged(int,int)范围改变时触发

代码示例:调整透明度

#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);//设置可以循环旋转ui->dial->setWrapping(true);//设置刻度线可见ui->dial->setNotchesVisible(true);//设置最大值为100ui->dial->setMaximum(100);//设置最小值为0ui->dial->setMinimum(0);//设置当前为100ui->dial->setValue(100);
}Widget::~Widget()
{delete ui;
}void Widget::on_dial_valueChanged(int value)
{ui->label->setText(QString("当前不透明度为:") + QString::number(value));this->setWindowOpacity((double)value / 100);
}

QSlider

使用QSlider表示一个滑动条

QSlider和QDial都是继承自QAbstractSlider,因此用法上基本相同

核心属性

属性说明
value数值
minimum最小值
maximum最大值
singleStep按下方向键时改变的步长
pageStep按下pageUp/pageDown时改变的步长
sliderPosition滑动条显示的初始位置
tracking

外观是否会跟踪数值变化

默认值为true,一般不需要修改

orientation滑动条的方向是水平还是垂直
invertedAppearance是否要翻转滑动条的方向
tickPosition刻度的位置
tickInterval刻度的密集程度

核心信号

信号说明
valueChanged(int)数值改变时触发
rangedChanged(int,int)范围变换时触发

代码示例:调整窗口大小

在界面上创建两个滑动条,分别是水平和垂直滑动条。objectName分别为horizontalSlider和verticalSlider

#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);ui->horizontalSlider->setMinimum(500);ui->horizontalSlider->setMaximum(2000);ui->horizontalSlider->setSingleStep(100);ui->horizontalSlider->setValue(800);ui->verticalSlider->setMinimum(500);ui->verticalSlider->setMaximum(1500);ui->verticalSlider->setSingleStep(100);ui->verticalSlider->setValue(600);//翻转ui->verticalSlider->setInvertedAppearance(true);
}Widget::~Widget()
{delete ui;
}void Widget::on_horizontalSlider_valueChanged(int value)
{QRect rect = this->geometry();this->setGeometry(rect.x(), rect.y(), value, rect.height());qDebug() << value;
}void Widget::on_verticalSlider_valueChanged(int value)
{QRect rect = this->geometry();this->setGeometry(rect.x(), rect.y(), rect.width(), value);qDebug() << value;
}

多元素控件

  • QListWidget
  • QListView
  • QTableWidget
  • QTableView
  • QTreeWidget
  • QTreeView

xxWidget和xxView之间的区别

以QTableWidget和QTableView为例

  • QTableView是基于MVC设计的控件,QTableView自身不持有数据,使用QTableView时需要用户创建一个Model对象(如QStandardModel),并且把Model和QTableView关联起来。后续修改Model中的数据就会影响QTableView的显示;修改QTableView的显示也会影响到Model中的数据(双向绑定)
  • QTableWidget则是QTableView的子类,对Model进行了封装,不需要用户手动创建Model对象,直接就可以往QTableWidget中添加数据了

QListWidget

使用QListWidget能够显示一个纵向的列表,每个选项都可以被选中

核心属性

属性说明
currentRow当前被选中的是第几行
count一共有多少行
sortingEnabled是否允许排序
isWrapping是否允许换行
itemAlignment元素的对齐方式
selectRectVisible被选中的元素矩形是否可见
spacing元素之间的间隔

核心方法

方法说明

addItem(const QString& label)

addItem(QListWidgetItem* item)

列表中添加元素
currentItem()返回QListWidgetItem*表示当前选中的元素
setCurrentItem(QListWidgetItem* item)设置选中哪个元素
setCurrentRow(int row)设置选中第几行的元素

insertItem(const QString& label,int row)

insertItem(QListWidgetItem* item,int row)

在指定行插入元素
item(int row)返回QListWidgetItem*表示第row行的元素
takeItem(int row)删除指定行的元素,返回QListWidgetItem*表示是哪个元素被删除了

核心信号

信号说明
currentItemChanged(QListWidgetItem* current,QListWidgetItem* old)选中不同元素时会触发,参数是当前选中的元素和之前选中的元素
currentRowChanged(int)选中不同元素时会触发,参数是当前选中元素的行数
itemClicked(QListWidgetItem* item)点击某个元素时触发
itemDoubleClicked(QListWidgetItem* item)双击某个元素时触发
itemEntered(QListWidgetItem* item)鼠标进入元素时触发

在上述介绍中,涉及到一个关键的类,QListWidgetItem。这个类表示QListWidget中的一个元素。本质上就是一个"文本+图标"构成的。

方法说明
setFont设置字体
setIcon设置图标
setHidden设置隐藏
setSizeHint设置尺寸
setSelected设置是否选中
setText设置文本
setTextAlignment设置文本对齐方式

代码示例:使用QListWidget

在界面上创建一个ListView,右键=>变形为=>QListWidget,再创建一个QLineEdit和两个按钮

注意:ListWidget是ListView的子类,功能比QListView更丰富,下面使用QListWidget即可

#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);ui->listWidget->addItem("C++");ui->listWidget->addItem("Java");ui->listWidget->addItem("Python");
}Widget::~Widget()
{delete ui;
}void Widget::on_listWidget_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous)
{if(current != nullptr && previous != nullptr)qDebug() << "当前选中:" << current->text() << ",之前选中:" << previous->text();
}void Widget::on_pushButtonAdd_clicked()
{const QString& text = ui->lineEdit->text();if(!text.isEmpty())ui->listWidget->addItem(text);
}void Widget::on_pushButtonDel_clicked()
{int row = ui->listWidget->currentRow();ui->listWidget->takeItem(row);
}

QTableWidget

使用QTableWidget表示一个表格控件,一个表格中包含若干行,每一行又包含若干列。表格中的每个单元格是一个QTableWidgetItem对象

QTableWidget核心方法

方法说明
item(int row, int column)根据行列获取指定的QTableWidgetItem*
setItem(int row, int column, QTableWidget*)根据行数列数设置表格中的元素
currentItem()返回被选中的元素QTableWidgetItem*
currentRow()返回被选中元素是第几行
currentColumn()返回被选中元素是第几列
row(QTableWidgetItem*)获取指定item是第几行
column(QTableWidgetItem*)获取指定item是第几列
rowCount()获取行数
columnCount()获取列数
insertRow(int row)在第row行处插入新行
insertColumn(int column)在第column列插入新列
removeRow(int row)删除第row行
removeColumn(int column)删除第column列
setHorizontalHeaderItem(int column, QTableWidgetItem*)设置指定列的表头
setVerticalHeaderItem(int row, QTableWidgetItem*)设置指定行的表头

QTableWidgetItem核心信号

信号说明
cellClicked(int row, int column)点击单元格时触发
cellDoubleClicked(int row, int column)双击单元格时触发
cellEntered(int row, int column)鼠标进入单元格时触发
currentCellChanged(int row, int column, int previousRow, int previousColumn)选中不同单元格时触发

QTableWidgetItem核心方法

方法说明
row()获取当前是第几行
column()获取当前是第几列
setText(const QString&)设置文本
setTextAlignment(int)设置文本对齐
setIcon(const QIcon&)设置图标
setSelected(bool)设置被选中
setSizeHints(const QSize&)设置尺寸
setFont(const QFont&)设置字体

代码示例:使用QTableWidget

在界面上创建QTableWidget和三个按钮,一个输入框

注意:QTableWidget是QTableView的子类,功能比QTableView更丰富,使用QTableWidget即可

#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);//创建3行ui->tableWidget->insertRow(0);ui->tableWidget->insertRow(1);ui->tableWidget->insertRow(2);//创建3列ui->tableWidget->insertColumn(0);ui->tableWidget->insertColumn(1);ui->tableWidget->insertColumn(2);//给3列设定列名ui->tableWidget->setHorizontalHeaderItem(0, new QTableWidgetItem("学号"));ui->tableWidget->setHorizontalHeaderItem(0, new QTableWidgetItem("姓名"));ui->tableWidget->setHorizontalHeaderItem(0, new QTableWidgetItem("年龄"));//设置初始数据ui->tableWidget->setItem(0, 0, new QTableWidgetItem("1001"));ui->tableWidget->setItem(0, 1, new QTableWidgetItem("张三"));ui->tableWidget->setItem(0, 2, new QTableWidgetItem("20"));ui->tableWidget->setItem(1, 0, new QTableWidgetItem("1002"));ui->tableWidget->setItem(1, 1, new QTableWidgetItem("李四"));ui->tableWidget->setItem(1, 2, new QTableWidgetItem("21"));ui->tableWidget->setItem(2, 0, new QTableWidgetItem("1003"));ui->tableWidget->setItem(2, 1, new QTableWidgetItem("王五"));ui->tableWidget->setItem(2, 2, new QTableWidgetItem("22"));
}Widget::~Widget()
{delete ui;
}void Widget::on_pushButtonAddRow_clicked()
{int rowCount = ui->tableWidget->rowCount();ui->tableWidget->insertRow(rowCount);
}void Widget::on_pushButtonAddColumn_clicked()
{int colCount = ui->tableWidget->columnCount();ui->tableWidget->insertColumn(colCount);const QString& name = ui->lineEdit->text();ui->tableWidget->setHorizontalHeaderItem(colCount, new QTableWidgetItem(name));
}void Widget::on_pushButtonDeleteRow_clicked()
{int currentRow = ui->tableWidget->currentRow();ui->tableWidget->removeRow(currentRow);
}void Widget::on_pushButtonDeleteColumn_clicked()
{int currentCol = ui->tableWidget->currentColumn();ui->tableWidget->removeColumn(currentCol);
}

QTreeWidget

使用QTreeWidget表示一个树形控件,里面的每个元素都是一个QTreeWidgetItem,每个QTreeWidgetItem可以包含多个文本和图标,每个文本/图标为一个列

可以给QTreeWidget设置顶层节点(顶层节点可以有多个),然后再给顶层节点添加子节点,从⽽构成树形结构

QTreeWidget核心方法

方法说明
clear清空所有子节点
addTopLevelItem(QTreeWidgetItem* item)新增顶层节点
topLevelItem(int index)获取指定下标的顶层节点
topLevelItemCount()获取顶层节点个数
indexOfTopLevelItem(QTreeWidgetItem* item)查询指定节点在顶层下标中的节点
takeTopLevelItem(int index)删除指定的顶层节点,返回QTreeWidgetItem*表示被删除的元素
currentItem()获取当前选中的节点,返回QTreeWidgetItem*
setCurrentItem(QTreeWidgetItem* item)选中指定节点
setExpanded(bool)展开/关闭节点
setHeaderLabel(const QString& text)设置QTreeWidget的header名称

QTreeWidget核心信号

信号说明
currentItemChanged(QTreeWidgetItem* current, QTreeWidgetItem* old)切换选中元素时触发
itemClicked(QTreeWidgetItem* item, int col)点击元素时触发
itemDoubleClicked(QTreeWidgetItem* item, int col)双击元素时触发
itemEntered(QTreeWidgetItem* item, int col)鼠标进入时触发
itemExpanded(QTreeWidgetItem* item)元素被展开时触发
itemCollapsend(QTreeWidgetItem* item)元素被折叠时触发

QTreeWidgetItem核心属性

属性说明
text持有的文本
textAlignment文本对齐方式
icon持有的图表
font文本字体
hidden是否隐藏
disabled是否禁用
expand是否展开
sizeHint尺寸大小
selected是否选中

QTreeWidgetItem核心方法

方法说明
addChlid(QTreeWidgetItem* child)新增子节点
childCount()子节点的个数
child(int index)获取指定下标的子节点,返回QTreeWidgetItem*
takeChild(int index)删除对应下标的子节点
removeChild(QTreeWidgetItem* child)删除对应的子节点
parent()获取该元素的父节点

代码示例:使用QTreeWidget

在界面上创建一个QTreeView,右键=>变形为=>QTreeWidget,再创建一个lineEdit和两个按钮

#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);ui->treeWidget->setHeaderLabel("动物");QTreeWidgetItem* item1 = new QTreeWidgetItem();item1->setText(0, "猫");ui->treeWidget->addTopLevelItem(item1);QTreeWidgetItem* item2 = new QTreeWidgetItem();item2->setText(0, "狗");ui->treeWidget->addTopLevelItem(item2);QTreeWidgetItem* item3 = new QTreeWidgetItem();item3->setText(0, "鸟");ui->treeWidget->addTopLevelItem(item3);
}Widget::~Widget()
{delete ui;
}void Widget::on_pushButton_clicked()
{const QString& text = ui->lineEdit->text();if(text.isEmpty()) return;QTreeWidgetItem* item = new QTreeWidgetItem();item->setText(0, text);ui->treeWidget->addTopLevelItem(item);
}void Widget::on_pushButton_2_clicked()
{const QString& text = ui->lineEdit->text();if(text.isEmpty()) return;QTreeWidgetItem* currentItem = ui->treeWidget->currentItem();if(currentItem == nullptr) return;QTreeWidgetItem* item = new QTreeWidgetItem();item->setText(0, text);currentItem->addChild(item);currentItem->setExpanded(true);
}void Widget::on_pushButton_3_clicked()
{QTreeWidgetItem* currentItem = ui->treeWidget->currentItem();if(currentItem == nullptr) return;QTreeWidgetItem* parent = currentItem->parent();if(parent == NULL) {//顶层节点int index = ui->treeWidget->indexOfTopLevelItem(currentItem);ui->treeWidget->takeTopLevelItem(index);}else parent->removeChild(currentItem);
}

容器类控件

QGroupBox

使用QGroupBox实现一个带有标题的分组框,可以把其他的控件放到里面作为一组,这样看起来更好看一些

注意:不要将QGroupBox和QButtonGroup混淆(之前在介绍QRadionButton时提到了QButtonGroup)

核心属性

属性方法
title分组框的标题
alignment分组框内部内容的对齐方式
flat是否为"扁平"模式
checkable

是否可选择

设为true,则在title前方会多出一个可勾选的部分

checked描述分组框的选择状态(前提时checkable为true)

分组框只是一个用来"美化界面"的组件,并不涉及到用户交互和业务逻辑,属于"锦上添花"

代码示例:给麦当劳案例加上分组框

在界面上创建三个分组框并且在分组框内部创建下拉框和微调框

注意:在复制粘贴控件时,一定要先选中对应的父控件再粘贴

#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);ui->comboBox->addItem("巨无霸");ui->comboBox->addItem("麦辣鸡腿堡");ui->comboBox_2->addItem("薯条");ui->comboBox_2->addItem("麦辣鸡翅");ui->comboBox_3->addItem("可乐");ui->comboBox_3->addItem("雪碧");
}Widget::~Widget()
{delete ui;
}

QTabWidget

使用QTabWidget实现一个带有标签页的控件,可以往里面添加一些widget,进一步就可以通过标签页来切换

核心属性

属性说明
tabPosition标签页所在的位置
currentIndex当前选中了第几个标签页(从0开始计算)
currentTabText当前选中的标签页的文本
currentTabName当前选中的标签页的名字
currentTabIcon当前选中的标签的图标
currentTabToolTip当前选中的标签页的提示信息
tabsCloseable标签页是否可以关闭
moveable标签页是否可以移动

核心信号

属性说明
currentChanged(int)在标签页发生切换时触发,参数为被点击的选项卡编号
tabBarClicked(int)在点击选项卡的标签条时触发,参数为被点击的选项卡编号
tabBarDoubleClicked(int)在双击选项卡的标签条时触发,参数为被点击的选项卡编号
tabCloseRequest(int)在标签页关闭时触发,参数为被关闭的选项卡编号

代码示例:使用标签页管理多组控件

在界面上创建一个QTabWidget和两个按钮

QTabWidget中的每个标签页都是一个QWidget;点击标签页就可以直接切换;右键QTabWidget可以添加标签页或者删除标签页。

#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);QLabel* label = new QLabel(ui->tab);label->setText("标签页1");label->resize(100, 50);QLabel* label2 = new QLabel(ui->tab_2);label2->setText("标签页2");label->resize(100, 50);
}Widget::~Widget()
{delete ui;
}void Widget::on_pushButtonAdd_clicked()
{//获取当前标签页的数量int count = ui->tabWidget->count();//创建新的widgetQWidget* widget = new QWidget();ui->tabWidget->addTab(widget, QString("Tab ") + QString::number(count + 1));//往widget中添加labelQLabel* label = new QLabel(widget);label->setText(QString("标签页") + QString::number(count + 1));label->resize(100, 50);//选中这个新标签页ui->tabWidget->setCurrentIndex(count);
}void Widget::on_pushButtonDel_clicked()
{int index = ui->tabWidget->currentIndex();ui->tabWidget->removeTab(index);
}

布局管理器

之前使用Qt在界面中创建的控件都是通过"绝对定位"的方式来设定的,即每个控件所在的位置都需要计算坐标,最终通过setGeometry或者move方式摆放过去。

这种设定方式其实并不方便,尤其是界面内容较多的情况,不好计算,而且一个窗口大小往往是可以调整的,按照绝对定位的方式,也无法自适应窗口大小。

因此Qt引入"布局管理器"(Layout)机制来解决上述问题。

布局管理器并非Qt独有,其他的GUI开发框架,如Android、前端等也有类似的机制。

QVBoxLayout

使用QVBoxLayout表示垂直的布局管理器,V是vertical的缩写

核心属性

属性说明
layoutLeftMargin左侧边距
layoutRightMargin右侧边距
layoutTopMargin上方边距
layoutBottomMargin下方边距
layoutSpacing相邻元素之间的间距

Layout只用于界⾯布局,并没有提供信号

代码示例:使用QVBoxLayout管理多个控件

#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);//创建三个按钮QPushButton* btn1 = new QPushButton("按钮1");QPushButton* btn2 = new QPushButton("按钮2");QPushButton* btn3 = new QPushButton("按钮3");//创建布局管理器,并将按钮添加进去//若创建时指定父元素为this,则后面不需要setLayout了QVBoxLayout* layout = new QVBoxLayout();layout->addWidget(btn1);layout->addWidget(btn2);layout->addWidget(btn3);//将布局管理器设置到widget中this->setLayout(layout);
}Widget::~Widget()
{delete ui;
}

通过上述代码的方式,只能给这个widget设定一个布局管理器,实际上也可以通过Qt Design在一个窗口中创建多个布局管理器

代码示例:创建两个QVBoxLayout

在界面上创建两个QVBoxLayout,每个QVBoxLayout各放三个按钮

运行程序可以看到这些按钮已经自动排列好,只不过这些按钮的位置不能随着窗口大小自动变化

通过Qt Designer创建的布局管理器,其实是先创建了一个widget,设置过geometry属性的,再把这个layout设置到这个widget中

实际上,一个widget只能包含一个layout,打开ui文件的原始xml,可以看到其中的端倪

这种情况下layout并非是窗口widget的布局管理器,因此不会随着窗口大小改变。

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0"><class>Widget</class><widget class="QWidget" name="Widget"><property name="geometry"><rect><x>0</x><y>0</y><width>800</width><height>600</height></rect></property><property name="windowTitle"><string>Widget</string></property><widget class="QWidget" name="verticalLayoutWidget"><property name="geometry"><rect><x>170</x><y>110</y><width>221</width><height>381</height></rect></property><layout class="QVBoxLayout" name="verticalLayout"><item><widget class="QPushButton" name="pushButton_2"><property name="text"><string>PushButton</string></property></widget></item><item><widget class="QPushButton" name="pushButton_3"><property name="text"><string>PushButton</string></property></widget></item><item><widget class="QPushButton" name="pushButton"><property name="text"><string>PushButton</string></property></widget></item></layout></widget><widget class="QWidget" name="verticalLayoutWidget_2"><property name="geometry"><rect><x>400</x><y>110</y><width>221</width><height>381</height></rect></property><layout class="QVBoxLayout" name="verticalLayout_2"><item><widget class="QPushButton" name="pushButton_5"><property name="text"><string>PushButton</string></property></widget></item><item><widget class="QPushButton" name="pushButton_6"><property name="text"><string>PushButton</string></property></widget></item><item><widget class="QPushButton" name="pushButton_4"><property name="text"><string>PushButton</string></property></widget></item></layout></widget></widget><resources/><connections/>
</ui>

QHBoxLayout

使用QHBoxLayout表示垂直的布局管理器,H是horizontal的缩写

核心属性与QVBoxLayout一致

代码示例:嵌套的layout

#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);//创建顶层layoutQVBoxLayout* layoutParent = new QVBoxLayout(this);//添加两个按钮进去QPushButton* btn1 = new QPushButton("按钮1");QPushButton* btn2 = new QPushButton("按钮2");layoutParent->addWidget(btn1);layoutParent->addWidget(btn2);//创建子layoutQHBoxLayout* layoutChild = new QHBoxLayout();//添加两个按钮进去QPushButton* btn3 = new QPushButton("按钮3");QPushButton* btn4 = new QPushButton("按钮4");layoutChild->addWidget(btn3);layoutChild->addWidget(btn4);//将子layout添加到父layout中layoutParent->addLayout(layoutChild);
}Widget::~Widget()
{delete ui;
}

QGridLayout

QGridLayout用来实现网格布局的效果,可以达到M*N的网格效果

核心属性

属性说明
layoutLeftMargin左侧边距
layoutRightMargin右侧边距
layoutTopMargin上方边距
layoutBottomMargin下方边距
layoutHorizontalSpacing相邻元素之间水平方向的间距
layoutVerticalSpacing相邻元素之间垂直方向的间距
layoutRowStretch行方向的拉伸系数
layoutColumnStretch列方向的拉伸系数

代码示例:使用QGridLayout管理元素

#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);//创建四个按钮QPushButton* btn1 = new QPushButton("按钮1");QPushButton* btn2 = new QPushButton("按钮2");QPushButton* btn3 = new QPushButton("按钮3");QPushButton* btn4 = new QPushButton("按钮4");//创建网格布局管理器,并添加元素QGridLayout* layout = new QGridLayout();layout->addWidget(btn1, 0, 0);layout->addWidget(btn2, 0, 1);layout->addWidget(btn3, 1, 0);layout->addWidget(btn4, 1, 1);//设置到layout到窗口中this->setLayout(layout);
}Widget::~Widget()
{delete ui;
}

执行代码,观察效果,可以看到当前的这几个按钮是按照2行2列的方式排列的

若调整行列坐标为下列代码

layout->addWidget(btn1, 0, 0);
layout->addWidget(btn2, 0, 1);
layout->addWidget(btn3, 0, 2);
layout->addWidget(btn4, 0, 3);

执行代码,可以看到这几个按钮都在同一行了,相当于QHBoxLayout

若调整行列坐标为下列代码

layout->addWidget(btn1, 1, 0);
layout->addWidget(btn2, 2, 0);
layout->addWidget(btn3, 3, 0);
layout->addWidget(btn4, 4, 0);

执行代码,可以看到这几个按钮都在同一列了,相当于QVBoxLayout

注意:设置行和列时,若设置的是一个很大的值,但是这个值和上一个值之间并没有其他的元素,那么并不会在中间腾出额外的空间

代码示例:设置QGridLayout中元素的大小比例

#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);// 创建 6 个按钮QPushButton* btn1 = new QPushButton("按钮1");QPushButton* btn2 = new QPushButton("按钮2");QPushButton* btn3 = new QPushButton("按钮3");QPushButton* btn4 = new QPushButton("按钮4");QPushButton* btn5 = new QPushButton("按钮5");QPushButton* btn6 = new QPushButton("按钮6");// 创建⽹格布局管理器, 并且添加元素QGridLayout* layout = new QGridLayout();layout->addWidget(btn1, 0, 0);layout->addWidget(btn2, 0, 1);layout->addWidget(btn3, 0, 2);layout->addWidget(btn4, 1, 0);layout->addWidget(btn5, 1, 1);layout->addWidget(btn6, 1, 2);// 第0列拉伸⽐例设为1layout->setColumnStretch(0, 1);// 第1列拉伸⽐例设为0, 即为固定⼤⼩, 不参与拉伸layout->setColumnStretch(1, 0);// 第2列拉伸⽐例设为3, 即为第2列的宽度是第0列的3倍layout->setColumnStretch(2, 3);// 设置layout到窗⼝中this->setLayout(layout);
}Widget::~Widget()
{delete ui;
}

QFormLayout

QFormLayout属于是QGridLayout的特殊情况,专门用于实现两列表单的布局。这种表单布局多用于让用户填写信息的场景,左侧列为提示,右侧列为输入框

代码示例:使用QFormLayout创建表单

#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);// 创建 layoutQFormLayout* layout = new QFormLayout();this->setLayout(layout);// 创建三个 labelQLabel* label1 = new QLabel("姓名");QLabel* label2 = new QLabel("年龄");QLabel* label3 = new QLabel("电话");// 创建三个 lineEditQLineEdit* lineEdit1 = new QLineEdit();QLineEdit* lineEdit2 = new QLineEdit();QLineEdit* lineEdit3 = new QLineEdit();// 创建⼀个提交按钮QPushButton* btn = new QPushButton("提交");// 把上述元素添加到 layout 中layout->addRow(label1, lineEdit1);layout->addRow(label2, lineEdit2);layout->addRow(label3, lineEdit3);layout->addRow(NULL, btn);
}Widget::~Widget()
{delete ui;
}


间隔类控件

使用布局管理器时,可能需要在控件之间,添加一段空白,就可以使用QSpacerItem来表示 

核心属性

属性说明
width宽度
height高度
hData

水平方向的sizePolicy

  • QSizePolicy::Ignored:忽略控件的尺寸,不对布局产生影响
  • QSizePolicy::Minimum:控件的最小尺寸为固定值,布局时不会小于该值
  • QSizePolicy::Maximum:控件的最大尺寸为固定值,布局时不会大于该值
  • QSizePolicy::Preferred:控件的理想尺寸为固定值,布局时会尽量接近该值
  • QSizePolicy::Expanding:控件的尺寸可以根据空间调整,尽可能占据更多的空间
  • QSizePolicy::Shrinking:控件的尺寸可以根据空间调整,尽可能缩小以适应空间
vData垂直方向的sizePolicy

代码示例:创建一组左右排列的按钮

在界面上创建一个QVBoxLayout 并添加两个按钮

#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);QHBoxLayout* layout = new QHBoxLayout();this->setLayout(layout);QPushButton* btn1 = new QPushButton("按钮1");QPushButton* btn2 = new QPushButton("按钮2");// 创建 SpacerQSpacerItem* spacer = new QSpacerItem(200, 20);layout->addWidget(btn1);// 在两个 widget 中间添加空⽩layout->addSpacerItem(spacer);layout->addWidget(btn2);
}Widget::~Widget()
{delete ui;
}


http://www.ppmy.cn/devtools/157581.html

相关文章

Spring(26) spring-security-oauth2 官方表结构解析

目录 一、什么是 spring-security-oauth2&#xff1f;二、spring-security-oauth2 的表结构2.1 oauth_client_details 客户端详细信息表2.2 oauth_access_token 认证授权Token记录表2.3 oauth_refresh_token 刷新授权Token记录表2.4 oauth_code 授权Code记录表 一、什么是 spri…

Netty:高性能网络应用框架的深度解析

引言 Netty 是由 JBoss 提供的一个开源的 Java NIO 客户端/服务器框架&#xff0c;它用以快速开发网络应用程序&#xff0c;如协议服务器和客户端。它的设计目标是提供异步事件驱动的网络应用程序框架&#xff0c;支持高效的网络通信和数据处理。Netty 在性能、可扩展性、安全…

AI眼镜-推理成本降低将加速端侧硬件智能化-AI 眼镜、AI玩具、手机AI化

机构研报指出&#xff0c;推理成本降低将加速端侧硬件智能化&#xff0c;AI端侧中 AI 眼镜、AI玩具、手机AI化、AIPC等方向均有望受益。 300735光弘科技 华为产业链消费电子 | 光弘科技9月19日进行投资者关系活动&#xff0c;称公司是华为的核心供应商&#xff0c;为客户提供包…

MoviePy,利用Python自动剪辑tiktok视频

Python剪辑视频是非常强大的&#xff0c;而且能流水线批量操作&#xff0c;可以使用MoviePy库实现。 最近看到一个Github项目&#xff0c;作者利用Python写了一个自动生成tiktok视频的脚本&#xff0c;受到热捧。 现在像抖音、tiktok上有很多流水线生产的视频&#xff0c;不少…

计算机视觉-边缘检测

一、边缘 1.1 边缘的类型 ①实体上的边缘 ②深度上的边缘 ③符号的边缘 ④阴影产生的边缘 不同任务关注的边缘不一样 1.2 提取边缘 突变-求导&#xff08;求导也是一种卷积&#xff09; 近似&#xff0c;1&#xff08;右边的一个值-自己可以用卷积做&#xff09; 该点f(x,y)…

驱动开发系列35 - Linux Graphics GEM Buffer Object 介绍

一:概述 在 Linux 内核中,DRM(Direct Rendering Manager)模块 是用于管理显示硬件和图形渲染的核心框架。它负责协调用户空间应用程序(例如 X Server、Wayland Compositors、Mesa 等)和 GPU 硬件之间的通信,是 Linux 图形子系统的重要组成部分。 GEM (Graphics Executio…

我们来学人工智能 -- 将Ollama已下载的模型从C盘迁出

题记 未配置OLLAMA_MODELS系统变量导致模型下载到了C盘 迁移步骤 退出ollama 配置OLLAMA_MODELS系统变量 OLLAMA_MODELS&#xff1a;D:\ollama\models 直接将C盘下的models目录剪切到指定目录 检查 cmd命令窗口退出重新打开

从算法到落地:DeepSeek如何突破AI工具的同质化竞争困局

&#x1f381;个人主页&#xff1a;我们的五年 &#x1f50d;系列专栏&#xff1a;Linux网络编程 &#x1f337;追光的人&#xff0c;终会万丈光芒 &#x1f389;欢迎大家点赞&#x1f44d;评论&#x1f4dd;收藏⭐文章 ​ Linux网络编程笔记&#xff1a; https://blog.cs…