目录
多元素控件
由多个部件或元素组成的自定义控件
Qt提供的多元素控件
- 列表:QListWidget,QListView;
- 表格:QTableWidget,QTableView;
- 树形:QTreeWidget,QTreeView
Widget和View
view是更加底层的实现,而Widget是基于View封装而来;
QListWidget
显示一个纵向的列表,列表每个元素/每一项都可以称为一个 Item,通过QListWidgetItem类表示的;
示例
创建一个ListView,右键转换成 ListWidget,
初始化
//初始化
ui->listWidget->addItem("C++");
ui->listWidget->addItem("Java");
ui->listWidget->addItem("python");
//当单行输入框为空时,显示提示输入信息
ui->lineEdit->setPlaceholderText("请输入要新增的元素名:");
//设置两个按钮的toolTip 和ToolTipDuring
ui->pushButton->setToolTip("新增一个元素");
ui->pushButton->setToolTipDuration(3000);
ui->pushButton_2->setToolTip("删除当前选中的元素");
ui->pushButton_2->setToolTipDuration(3000);
槽函数slot
编写ListWidget的槽函数:需要判定当前是否选中元素,如果没有,指针可能是NULL;
void Widget::on_listWidget_currentItemChanged(QListWidgetItem *current,
QListWidgetItem *previous)
{
//当切换不同元素时触发信号 current是新选中的元素, privious是上一次选中的元素
//当不为空,打印两个位置
if(current!=NULL && previous!=NULL)
{
qDebug()<<"当前选中: "<<current->text()
<<"之前选中: "<<previous->text();
}
}
两个按钮的slot,在删除元素后,打印下被删的元素text
void Widget::on_pushButton_clicked()
{
//新增一个元素
//获取LineText的信息,充当新加元素text,
QString name = ui->lineEdit->text();
//判断是否为空
if(name.isEmpty())
{
return;
}
//name非空,新增一个元素
ui->listWidget->addItem(name);
}
void Widget::on_pushButton_2_clicked()
{
//删除当前选中的元素
//获取当前选中的元素位置
int row = ui->listWidget->currentRow();
//记录一下被删元素的text,打印一下
QListWidgetItem* prename = ui->listWidget->currentItem();
//删除该位置元素
ui->listWidget->takeItem(row);
qDebug()<<"已经删除第"<<row<<"行元素:"<<prename->text();
}
QTableWidget
一个表格控件:一个表格中包含若干行,每一行又包含若干列
示例
与上同理,创建TableView,变形为TableWiget,添加新增行 新增列和与之删除的按钮
初始化
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//初始化
//新增行
ui->tableWidget->insertRow(0);
ui->tableWidget->insertRow(1);
ui->tableWidget->insertRow(2);
// 新增列 nsertColumn:在第column列插入新例
ui->tableWidget->insertColumn(0);
ui->tableWidget->insertColumn(1);
ui->tableWidget->insertColumn(2);
//设置列的表头
ui->tableWidget->setHorizontalHeaderItem(0,new QTableWidgetItem("学号"));
ui->tableWidget->setHorizontalHeaderItem(1,new QTableWidgetItem("姓名"));
ui->tableWidget->setHorizontalHeaderItem(2,new QTableWidgetItem("年龄"));
//设置元素信息
ui->tableWidget->setItem(0,0,new QTableWidgetItem("2020111"));
ui->tableWidget->setItem(0,1,new QTableWidgetItem("张三"));
ui->tableWidget->setItem(0,2,new QTableWidgetItem("19"));
ui->tableWidget->setItem(1,0,new QTableWidgetItem("2020112"));
ui->tableWidget->setItem(1,1,new QTableWidgetItem("李四"));
ui->tableWidget->setItem(1,2,new QTableWidgetItem("18"));
ui->tableWidget->setItem(2,0,new QTableWidgetItem("2020113"));
ui->tableWidget->setItem(2,1,new QTableWidgetItem("王五"));
ui->tableWidget->setItem(2,2,new QTableWidgetItem("19"));
}
槽函数slot
编写四个按钮的槽函数
void Widget::on_pushButton_clicked()
{
//新增行
//获取当前行数
int rowcount = ui->tableWidget->rowCount();
//在行数处插入
ui->tableWidget->insertRow(rowcount);
//打印提示下
qDebug()<<"新增一行,位置为: "<<rowcount+1;
}
void Widget::on_pushButton_3_clicked()
{
//新增一列
//1. 获取lineText的新增列名
QString nameColumn = ui->lineEdit->text();
//2.获取列数,插入在column列
int columnCount = ui->tableWidget->columnCount();
ui->tableWidget->insertColumn(columnCount);
//3.设置列表头名
ui->tableWidget->setHorizontalHeaderItem(columnCount,new QTableWidgetItem(nameColumn));
//打印提示下
qDebug()<<"新增一列,位置为: "<<columnCount;
}
void Widget::on_pushButton_2_clicked()
{
//删除选中行
//获取选中行
int curRow = ui->tableWidget->currentRow();
//删除第row行
ui->tableWidget->removeRow(curRow);
}
void Widget::on_pushButton_4_clicked()
{
//删除选中列
//获取选中列
int curColumn = ui->tableWidget->currentColumn();
//删除选中column列
ui->tableWidget->removeColumn(curColumn);
}
QTreeWidget
- 表示一个树形控件,里面每个元素都是一个QTreeWidgetItem,每个QTreeWidgetItem都可以包含多个文本和图标,每个文本/图标为一个列;
- 可以给QTreeWidget设置顶岑根节点(可以有多个),然后再给顶层节点添加子节点,从而构成树形结构
注:QTreeWidget虽然是树形结构,但是没有体现出根节点,是从根节点的下一层开始计算的,这一层也是TopLevelItem
默认创建下 QTreeWidget的header名称为1
示例
创建TreeView后变形TreeWidget,新增几个widget
初始化
设置header名称
//设置QTreeWidget的 header名称
ui->treeWidget->setHeaderLabel("动物");
增加顶层节点,且设置节点信息
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 设置QTreeWidget的 header名称
ui->treeWidget->setHeaderLabel("动物");
//设置个toplevel
QTreeWidgetItem* item1 = new QTreeWidgetItem();
item1->setText(0,"猫");
//将节点挂到treewidget上
ui->treeWidget->addTopLevelItem(item1);
QTreeWidgetItem* item2 = new QTreeWidgetItem();
item2->setText(0,"狗");
//将节点挂到treewidget上
ui->treeWidget->addTopLevelItem(item2);
QTreeWidgetItem* item3= new QTreeWidgetItem();
item3->setText(0,"鸟");
//将节点挂到treewidget上
ui->treeWidget->addTopLevelItem(item3);
// // 设置树控件的列数为2
// ui->treeWidget->setColumnCount(2);
// // 创建第一个节点并设置文本
// QTreeWidgetItem* item1 = new QTreeWidgetItem();
// item1->setText(0, "猫");
// item1->setText(1, "Meow");
// // 创建第二个节点并设置文本
// QTreeWidgetItem* item2 = new QTreeWidgetItem();
// item2->setText(0, "狗");
// item2->setText(1, "Woof");
// // 将节点添加为树控件的顶层节点
// ui->treeWidget->addTopLevelItem(item1);
// ui->treeWidget->addTopLevelItem(item2);
}
槽函数slot
添加顶层节点
void Widget::on_pushButton_clicked()
{
//获取lineText的text
const QString& name = ui->lineEdit->text();
//判断是否为空
if(name.isEmpty())
{
return;
}
//设置个toplevel
QTreeWidgetItem* item = new QTreeWidgetItem();
item->setText(0,name);
//将节点挂到treewidget上
ui->treeWidget->addTopLevelItem(item);
}
添加非顶层节点
void Widget::on_pushButton_2_clicked()
{
//添加节点到选中节点中
//获取节点名字
const QString& name = ui->lineEdit->text();
if(name.isEmpty())
{
return;
}
//获取选中节点
QTreeWidgetItem* current = ui->treeWidget->currentItem();
if(current == NULL)
{
return;
}
//创建节点
QTreeWidgetItem* item = new QTreeWidgetItem();
item->setText(0,name);
//将节点挂到选中节点中
current->addChild(item);
//展开父节点
current->setExpanded(true);
// //挂到选中节点下
// //获取选中节点,且添加item到选中节点
// ui->treeWidget->currentItem()->addChild(item);
// //展开父节点
// ui->treeWidget->currentItem()->setExpanded(true);
}
删除选中节点
这里需要注意,如果是顶层节点,就需要获取该顶层节点在treewidget的下标,如果非顶层节点,用父节点删除即可;
void Widget::on_pushButton_3_clicked()
{
//删除节点
if(ui->treeWidget->topLevelItemCount() == 0)
{
qDebug()<<"已无顶层节点";
return;
}
//删除选中节点
//获取选中节点
QTreeWidgetItem* current = ui->treeWidget->currentItem();
//判断该节点是否是顶层节点
//获取该节点的父节点,判断是否为空
//如果为空说明是顶层节点,非空就是普通节点
QTreeWidgetItem* parent = current->parent();
if(parent == NULL)
{
//获取顶层节点在顶层中的下标
int index = ui->treeWidget->indexOfTopLevelItem(current);
//删除该顶层节点
ui->treeWidget->takeTopLevelItem(index);
}
//非顶层节点
else
{
parent->removeChild(current);
}
}
XXXWidget和XXXWidgetItem
它们的关系是容器和内容的关系,类似于窗口和窗口部件的关系。
Widget
- 是一个XX控件,用于在界面上展示XX结构数据。它是一个容器类,可以包含多个QXXXWidgetItem对象。
- 提供了管理节点、展示XX数据、处理用户交互等功能。
WidgetItem
- 是用于表示XX结构中每个节点的类。
- 每个 QXXXWidgetItem对象代表XX中的一个节点,可以设置节点的文本、图标等属性,以及处理节点的操作。
关系解释
- QXXXWidget是XX控件的容器,它管理并展示多个QXXXWidgetItem对象组成的XX结构。
- QXXXWidgetItem则是 QXXXWidget中的内容,它描述了树中每个节点的属性和行为。
总结
如果你想在界面上展示一个包含多个节点的XX结构,你会创建一个 QXXXWidget对象作为整个XX控件的容器。然后,你会为每个需要展示的节点创建一个 QXXXWidgetItem对象,并将这些节点对象添加到 QXXXWidget中,从而构建整个XX结构。
总结来说,QXXXWidget是XX结构的容器,而 QXXXWidgetItem是填充到这个容器中的实际节点数据
QGroupBox
用于将其他小部件(例如按钮、文本框等)组织成一个逻辑组,并为组内的小部件提供一个可选的标题。
当页面有很多控件时,就可以把有关联的控件组织到一起
特点
- QGroupBox主要特点是提供一个可视化的边框和一个可选的标题。这个标题显示在边框的顶部,可以通过设置来控制其外观和位置。
- 可以与各种布局管理器(如垂直布局、水平布局、网格布局等)结合使用,从而可以方便地将多个控件组织在一起并根据需要进行布局调整。
- 可以通过设置 QGroupBox的启用状态来启用或禁用组内的所有小部件。
示例
创建一个麦当劳点餐,不同种类分开组件
初始化
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//初始化组件
//给combo 添加元素
ui->comboBox->addItem("安格斯牛肉堡");
ui->comboBox->addItem("双层牛肉堡");
ui->comboBox->addItem("麦乐鸡堡");
ui->comboBox_2->addItem("薯条");
ui->comboBox_2->addItem("鸡翅");
ui->comboBox_2->addItem("鸡米花");
ui->comboBox_3->addItem("雪碧");
ui->comboBox_3->addItem("可乐");
//设置spinBox
ui->spinBox->setRange(1,5);
ui->spinBox_2->setRange(1,5);
ui->spinBox_3->setRange(1,5);
}
QTabWidget
是一个带有标签页的控件,可以往里面添加一些Widget,可以通过标签页来切换
特点
- QTabWidget提供了一个选项页,每个选项页代表一个页面。用户可以通过单击选项页来切换页面,每个页面可以包含不同的控件和布局。
- 每个选项页可以使用不同的布局管理器(如垂直布局、水平布局、网格布局等)来组织和布置其内部的控件,从而实现灵活的界面设计。
- QTabWidget可以通过信号与槽(signal-slot)机制来响应用户与选项页的交互,例如在切换选项页时触发特定的操作或更新界面的内容。
示例
使用标签页管理多组控件
初始化
给两个标签页里增加label,文本提示标签页数
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//初始化
//创建label 父元素是tab /tab_2 指定父元素
QLabel* label = new QLabel(ui->tab);
label->setText("这是标签页1");
label->resize(100,50);
QLabel* label2 = new QLabel(ui->tab_2);
label2->setText("这是标签页2");
label2->resize(200,100);
}
槽函数
增加标签页:addWidget(QWidget* widget,const QString& label)
- 第一个参数widget:要添加的标签页的内容部件,通常是 QWidget 或其子类的实例。
- 第二个参数 label:要显示在标签上的文本,即标签页的标题。
在标签页里新增widget,注意父元素的添加;
函数下标基本都是从0开始;
void Widget::on_pushButton_add_clicked()
{
//第一个参数widget:要添加的标签页的内容部件,通常是 QWidget 或其子类的实例。
//第二个参数 label:要显示在标签上的文本,即标签页的标题。
//addWidget(QWidget* widget,const QString&)
//获取当前标签页的个数
int count = ui->tabWidget->count();
// qDebug()<<count;
QWidget* widget = new QWidget();
//添加标签页
ui->tabWidget->addTab(widget,QString("tab")+QString::number(count+1));
//给新的标签页增加label
QLabel* label = new QLabel(widget);
label->setText(QString("这是标签页")+QString::number(count+1));
label->resize(200,50);
//当新的标签页新增后,自动选中该页 下标从0开始
ui->tabWidget->setCurrentIndex(count);
qDebug()<<"新增标签页: "<<count+1;
}
void Widget::on_pushButton_delete_clicked()
{
//删除标签页
//获取当前选中的标签页
int index = ui->tabWidget->currentIndex();
//删除该页 下标从0开始
ui->tabWidget->removeTab(index);
qDebug()<<"删除标签页: "<<index+1;
}
当选中不同的标签页时,触发信号槽
void Widget::on_tabWidget_currentChanged(int index)
{
qDebug()<<"当前选中的标签页: "<<index;
}
布局管理器
自动化管理窗口部件(Widget)位置和大小的机制,适应不同尺寸和分辨率的屏幕,确保界面在各种环境下都能正确显示。
通过addWidget()方法将部件添加到布局中。
垂直布局(QVBoxlayout)
垂直布局管理器按照从上到下的顺序依次排列窗口部件。
示例
使用QVBoxLayout管理多个控件
初始化
创建三个按钮,父元素是verticalLayout
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//创建三个按钮
QPushButton* button1 = new QPushButton("按钮1");
QPushButton* button2 = new QPushButton("按钮2");
QPushButton* button3 = new QPushButton("按钮3");
//布局管理器在ui文件已创立,将按钮拉进去
ui->verticalLayout->addWidget(button1);
ui->verticalLayout->addWidget(button2);
ui->verticalLayout->addWidget(button3);
//将布局管理器设置到widget
this->setLayout(ui->verticalLayout);
}
可以看到三个按钮是垂直布局的,且按钮大小随着窗口尺寸变化而发生改变
示例2
在QtDeisign页面中,创建多个布局管理器;
在页面中创建两个QVBoxLayout,每个各方三个按钮;
可以看到,按钮依然垂直布局,只是不会随着窗口变化而变化
总结:一个Widget只能包含一个layout,
水平布局(QHBoxLayout)
水平布局管理器按照从左到右的顺序依次排列窗口部件
示例
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//创建水平布局管理器
QHBoxLayout* layout = new QHBoxLayout();
//设置到widget上
this->setLayout(layout);
//创建三个按钮,父元素是layou
QPushButton* button1 = new QPushButton("按钮1");
QPushButton* button2 = new QPushButton("按钮2");
QPushButton* button3 = new QPushButton("按钮3");
layout->addWidget(button1);
layout->addWidget(button2);
layout->addWidget(button3);
//将水平布局设置到widget上
this->setLayout(layout);
}
嵌套Layout
创建一个布局管理1,添加按钮进去,设置到widget后,创建另外一个布局管理2,父元素是布局管理1,同样添加按钮进去,达到不同效果
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//嵌套layout
//创建第一个layout
QVBoxLayout* layoutparent = new QVBoxLayout();
//设置到widget上
this->setLayout(layoutparent);
//创建三个按钮 添加到layoutparent上
QPushButton* button1 = new QPushButton("按钮1");
QPushButton* button2 = new QPushButton("按钮2");
QPushButton* button3 = new QPushButton("按钮3");
//
layoutparent->addWidget(button1);
layoutparent->addWidget(button2);
layoutparent->addWidget(button3);
//创建第二个layout 父元素是layoutparent
QHBoxLayout* layoutchild = new QHBoxLayout();
layoutparent->addLayout(layoutchild);
//创建两个按钮 ,父元素是layoutchild
QPushButton* button4 = new QPushButton("按钮4");
QPushButton* button5 = new QPushButton("按钮5");
//添加到layoutchild
layoutchild->addWidget(button4);
layoutchild->addWidget(button5);
}
网络布局(QGridLayout)
网格布局管理器将窗口部件放置在一个行列网格中,达到M*N的网格效果
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//创建网格布局管理
QGridLayout* layout = new QGridLayout();
//设置到widget上
this->setLayout(layout);
//添加四个按钮到 网格布局上
QPushButton* button1 = new QPushButton("按钮1");
QPushButton* button2 = new QPushButton("按钮2");
QPushButton* button3 = new QPushButton("按钮3");
QPushButton* button4 = new QPushButton("按钮4");
layout->addWidget(button1,0,0);
layout->addWidget(button2,0,1);
layout->addWidget(button3,1,0);
layout->addWidget(button4,1,1);
}
如果设置行和列的时候,哪怕设置的是一个和很大的值,但是这个值和上一个值之间并没有其它元素,那么并不会在中间腾出额外的空间
示例2
设置QGridLayout中元素比例,拉伸大小;
创建六个按钮,按照2行3列比例
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//创建六个按钮
QPushButton* button1 = new QPushButton("按钮1");
QPushButton* button2 = new QPushButton("按钮2");
QPushButton* button3 = new QPushButton("按钮3");
QPushButton* button4 = new QPushButton("按钮4");
QPushButton* button5 = new QPushButton("按钮5");
QPushButton* button6 = new QPushButton("按钮6");
//创建网络布局,添加元素
QGridLayout* layout = new QGridLayout();
layout->addWidget(button1,0,0);
layout->addWidget(button2,0,1);
layout->addWidget(button3,0,2);
layout->addWidget(button4,1,0);
layout->addWidget(button5,1,1);
layout->addWidget(button6,1,2);
//设置拉伸比例
//第0列拉伸比例为1
layout->setColumnStretch(0,1);
//第1列拉伸比例为0,即是固定大小,不参与拉伸
layout->setColumnStretch(1,0);
//第2列拉伸为3,
layout->setColumnStretch(2,3);
//设置到widget
this->setLayout(layout);
}
不仅如此,QGridLayout同样有setRowStretch设置行之间的拉伸系数,但是在次案例中,直接设置,效果不明显,要将按钮的垂直方向sizePolicy属性设置为QSizePolicy::Expanding,尽可能填满布局管理器
setSizePolicy
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//创建六个按钮
QPushButton* button1 = new QPushButton("按钮1");
QPushButton* button2 = new QPushButton("按钮2");
QPushButton* button3 = new QPushButton("按钮3");
QPushButton* button4 = new QPushButton("按钮4");
QPushButton* button5 = new QPushButton("按钮5");
QPushButton* button6 = new QPushButton("按钮6");
//设置按钮的sizePolicy
button1->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
button2->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
button3->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
button4->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
button5->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
button6->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
//创建网络布局,添加元素
QGridLayout* layout = new QGridLayout();
layout->addWidget(button1,0,0);
layout->addWidget(button2,0,1);
layout->addWidget(button3,1,0);
layout->addWidget(button4,1,1);
layout->addWidget(button5,2,0);
layout->addWidget(button6,2,1);
//设置拉伸比例
//第0行拉伸比例为1
layout->setRowStretch(0,1);
//第1行拉伸比例为0,即是固定大小,不参与拉伸
layout->setRowStretch(1,0);
//第2行拉伸为3,
layout->setRowStretch(2,3);
//设置到widget
this->setLayout(layout);
}
表单布局(QFormLayout)
是QGridLayout的特殊情况,专门用来实现两列表单的布局
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//创建表单布局
QFormLayout* layout = new QFormLayout();
this->setLayout(layout);
//创建三个label
QLabel* label1 = new QLabel("姓名");
QLabel* label2 = new QLabel("年龄");
QLabel* label3 = new QLabel("电话");
//创建三个LineEdit
QLineEdit* lineEdit1 = new QLineEdit();
QLineEdit* lineEdit2 = new QLineEdit();
QLineEdit* lineEdit3 = new QLineEdit();
QPushButton* button = new QPushButton("提交");
//将上述元素添加到layout中
layout->addRow(label1,lineEdit1);
layout->addRow(label2,lineEdit2);
layout->addRow(label3,lineEdit3);
layout->addRow(NULL,button);
}