前言
一个挺好玩的小Demo,里面所运用到知识点也是挺常用的。
运行效果:
其中包括功能:
右键菜单:右键鼠标弹出菜单项;
添加项:既可以添加父项,也可以添加子项;
删除项:将树表中的项进行删除;
生成随机数:生成随机数用于填充第二列;并计算出总数;
其他:设置正则表达式、添加图标、控件、右侧显示点击的项名称等。
ui界面
界面虽简单,程序精髓都在代码设计上。
撸代码
知识点汇总
VS qt支持显示中文
#pragma execution_character_set("utf-8") // qt支持显示中文
新建项
QTreeWidgetItem *schoolOne = new QTreeWidgetItem(ui.treeWidget);
// 根项
QTreeWidgetItem *classOne = new QTreeWidgetItem(schoolOne);
// 子项
注意:每个项都得设置父项
设置项的勾选状态
schoolOne->setCheckState(0, Qt::CheckState::Unchecked);
第一个参数指定设置第几列。
设置文本
schoolOne->setText(0, "小学");
第一个参数指定设置第几列。
设置工具提示
schoolOne->setToolTip(0, "小学");
第一个参数指定设置第几列。
设置图标
item->setIcon(0, QIcon("E:\\QTproject\\WPS\\images\\color.ico"));
设置树表头
QStringList headList;
headList << "School/Class" << "Class/Student Count" << "总分";
//ui.treeWidget->setHeaderLabel("School/Class"); // 设置一个
ui.treeWidget->setHeaderLabels(headList); // 设置多个
隐藏下拉三角
ui.treeWidget->setRootIsDecorated(false);
隐藏表头
ui.treeWidget->setHeaderHidden(true);
设置选择模式
ui.treeWidget->setSelectionMode(QAbstractItemView::ExtendedSelection);
QAbstractItemView.SelectionMode.MultiSelection :多选(无需按ctrl)
QAbstractItemView.SelectionMode.ExtendedSelection :多选(按住ctrl,一次选一项)
QAbstractItemView.SelectionMode.ContiguousSelection :多选(一次选多项,相当于window下按住shift选文件)
设置列宽
ui.treeWidget->setColumnWidth(0, 170);
第一个参数指定设置第几列。
实例化菜单对象
this->m_menu = new QMenu;
this->m_addMenu = new QMenu("add");
this->m_addSchoolAction = new QAction("add School");
this->m_addClassAction = new QAction("add Closs");
this->m_delAction = new QAction("del");
this->m_addMenu->addAction(this->m_addSchoolAction);
this->m_addMenu->addAction(this->m_addClassAction);
this->m_menu->addMenu(this->m_addMenu);
this->m_menu->addAction(this->m_delAction);
// 为菜单项绑定槽函数
connect(this->m_addSchoolAction, SIGNAL(triggered()), this, SLOT(onAddSchool()));
connect(this->m_addClassAction, SIGNAL(triggered()), this, SLOT(onAddClass()));
connect(this->m_delAction, SIGNAL(triggered()), this, SLOT(onDelAction()));
得添加菜单右键事件
// 菜单右键事件
void contextMenuEvent(QContextMenuEvent *event);
// 右键菜单
void QTreeWidgets::contextMenuEvent(QContextMenuEvent *event) {
// 菜单出现的位置为当前鼠标的位置
this->m_menu->exec(QCursor::pos());
}
返回项的父项
item->parent()
无则返回NULL。
注意:根项是无父项的,只有子项才有父项。
显示一个输入框
bool ok = false;
QString schoolText = QInputDialog::getText(this, tr("添加学校"), tr("请输入学校名称:"), QLineEdit::Normal, "", &ok);
产生随机数
需添加头文件:#include <QTime>
QTime time;
time = QTime::currentTime(); // 获取当前系统时间(毫秒)
qsrand(time.msec() + time.second() * 1); // 种下随机种子
int classPeople = qrand() % 100; // 产生100以内的随机数
返回tree小部件中的当前项
QTreeWidgetItem *item = ui.treeWidget->currentItem();
删除子项
itemParent->removeChild(item);
删除后记得释放item内存:delete item;
删除树中给定索引处的顶级项
ui.treeWidget->takeTopLevelItem(0);
返回给定顶级项的索引
ui.treeWidget->indexOfTopLevelItem(item);
获取所有顶级项的个数
int topLeveItemCount = ui.treeWidget->topLevelItemCount();
返回给定索引的顶级项
ui.treeWidget->topLevelItem(count);
获取项的第二列和第三列的文本
QTreeWidgetItem *ParentItem;
// 获取项的子项的个数
int count = ParentItem->childCount();
for (int i = 0; i < count; i++) {
// 获得第二列和第三列的文本
QString second = ParentItem->child(i)->text(1);
QString third = ParentItem->child(i)->text(2);
}
使用正则表达式捕获字符串中的数字
// 正则表达式
QRegExp m_reg;
// 设置匹配模式
this->m_reg.setPattern("\\d*"); // 匹配任意多个数字
this->m_reg.indexIn("字符串"); // 根据正则表达式进行匹配
this->m_reg.cap(0).toInt(); // 捕获匹配到的数字
代码
有详细注释,对照着看应该可以看懂!
可将代码直接拷贝下来运行。
替换一下图标路径即可。
.h文件
#pragma once
#include <QtWidgets/QWidget>
#include "ui_QTreeWidgets.h"
#include <QMenu>
#include <QAction>
#include <QTreeWidgetItem>
class QTreeWidgets : public QWidget {
Q_OBJECT
public:
QTreeWidgets(QWidget *parent = Q_NULLPTR);
private:
void initTreeWidgetItem(); // 初始化树列表
void initQMenu(); // 初始化菜单
// 菜单右键事件
void contextMenuEvent(QContextMenuEvent *event);
// 设置父项第二列与第三列的文本
void setParentSecondAndThirdText(QTreeWidgetItem *ParentItem);
private slots:
void onSetLabelText(QTreeWidgetItem *item, int column);
void onAddSchool(); // 添加学校(父项)
void onAddClass(); // 添加班级(子项)
void onDelAction(); // 删除项
void on_determineBtn_clicked(); // 显示勾选上的父项信息
void onDeleteChildAction(QTreeWidgetItem *item, int column);
private:
Ui::QTreeWidgetsClass ui;
// 菜单
QMenu *m_menu;
QMenu *m_addMenu;
// 菜单子项
QAction *m_addSchoolAction;
QAction *m_addClassAction;
QAction *m_delAction;
// 正则表达式
QRegExp m_reg;
};
.cpp文件
#include "QTreeWidgets.h"
#include <QDebug>
#include <QInputDialog>
#include <QMessageBox>
#include <QTime>
#include <QRegExp>
#include <QAbstractItemView>
#pragma execution_character_set("utf-8") // qt支持显示中文
QTreeWidgets::QTreeWidgets(QWidget *parent)
: QWidget(parent) {
ui.setupUi(this);
// 设置匹配模式
this->m_reg.setPattern("\\d*"); // 匹配任意多个数字
ui.schoolNameLabel->setMinimumWidth(150);
ui.classNameLabel->setMinimumWidth(150);
initTreeWidgetItem();
initQMenu();
// 设置头文本
QStringList headList;
headList << "School/Class" << "Class/Student Count" << "总分";
//ui.treeWidget->setHeaderLabel("School/Class");
ui.treeWidget->setHeaderLabels(headList);
// 隐藏下拉三角
//ui.treeWidget->setRootIsDecorated(false);
// 隐藏表头
//ui.treeWidget->setHeaderHidden(true);
//QAbstractItemView.SelectionMode.MultiSelection :多选(无需按ctrl)
//QAbstractItemView.SelectionMode.ExtendedSelection :多选(按住ctrl,一次选一项)
//QAbstractItemView.SelectionMode.ContiguousSelection :多选(一次选多项,相当于window下按住shift选文件)
// 设置选择模式
ui.treeWidget->setSelectionMode(QAbstractItemView::ExtendedSelection);
// 设置列宽
ui.treeWidget->setColumnWidth(0, 170);
ui.treeWidget->setColumnWidth(1, 160);
ui.treeWidget->setColumnWidth(2, 80);
// 实现单击信号与槽的绑定
connect(ui.treeWidget, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this, SLOT(onSetLabelText(QTreeWidgetItem *, int)));
// 实现双击信号与槽的绑定
connect(ui.treeWidget, &QTreeWidget::itemDoubleClicked, this, &QTreeWidgets::onDeleteChildAction);
}
// 初始化项
void QTreeWidgets::initTreeWidgetItem() {
{
QTreeWidgetItem *schoolOne = new QTreeWidgetItem(ui.treeWidget);
schoolOne->setCheckState(0, Qt::CheckState::Unchecked);
schoolOne->setText(0, "小学");
schoolOne->setToolTip(0, "小学");
QTreeWidgetItem *classOne = new QTreeWidgetItem(schoolOne);
classOne->setText(0, "小学一班");
classOne->setText(1, "60人");
classOne->setText(2, "3600分");
classOne->setToolTip(0, "小学一班");
QTreeWidgetItem *classTwo = new QTreeWidgetItem(schoolOne);
classTwo->setText(0, "小学二班");
classTwo->setText(1, "67人");
classTwo->setText(2, "4020分");
classTwo->setToolTip(0, "小学二班");
QTreeWidgetItem *classThree = new QTreeWidgetItem(schoolOne);
classThree->setText(0, "小学三班");
classThree->setText(1, "59人");
classThree->setText(2, "3540分");
classThree->setToolTip(0, "小学三班");
setParentSecondAndThirdText(schoolOne);
}
{
QTreeWidgetItem *schoolTwo = new QTreeWidgetItem(ui.treeWidget);
schoolTwo->setCheckState(0, Qt::CheckState::Unchecked);
schoolTwo->setText(0, "初中");
schoolTwo->setToolTip(0, "初中");
QTreeWidgetItem *classOne = new QTreeWidgetItem(schoolTwo);
classOne->setText(0, "初中一班");
classOne->setText(1, "69人");
classOne->setText(2, "1200分");
classOne->setToolTip(0, "初中一班");
QTreeWidgetItem *classTwo = new QTreeWidgetItem(schoolTwo);
classTwo->setText(0, "初中二班");
classTwo->setText(1, "86人");
classTwo->setText(2, "3900分");
classTwo->setToolTip(0, "初中二班");
QTreeWidgetItem *classThree = new QTreeWidgetItem(schoolTwo);
classThree->setText(0, "初中三班");
classThree->setText(1, "76人");
classThree->setText(2, "2400分");
classThree->setToolTip(0, "初中三班");
setParentSecondAndThirdText(schoolTwo);
}
}
// 初始化菜单
void QTreeWidgets::initQMenu() {
// 实例化菜单对象
this->m_menu = new QMenu;
this->m_addMenu = new QMenu("add");
this->m_addSchoolAction = new QAction("add School");
this->m_addClassAction = new QAction("add Closs");
this->m_delAction = new QAction("del");
this->m_addMenu->addAction(this->m_addSchoolAction);
this->m_addMenu->addAction(this->m_addClassAction);
this->m_menu->addMenu(this->m_addMenu);
this->m_menu->addAction(this->m_delAction);
connect(this->m_addSchoolAction, SIGNAL(triggered()), this, SLOT(onAddSchool()));
connect(this->m_addClassAction, SIGNAL(triggered()), this, SLOT(onAddClass()));
connect(this->m_delAction, SIGNAL(triggered()), this, SLOT(onDelAction()));
}
// 右键菜单
void QTreeWidgets::contextMenuEvent(QContextMenuEvent *event) {
// 菜单出现的位置为当前鼠标的位置
this->m_menu->exec(QCursor::pos());
}
// 设置Label
void QTreeWidgets::onSetLabelText(QTreeWidgetItem *item, int column) {
// 点击的项有父亲
if (item->parent() != NULL) {
ui.schoolNameLabel->setText(item->parent()->text(column));
ui.classNameLabel->setText(item->text(column));
} else {
ui.schoolNameLabel->setText(item->text(column));
ui.classNameLabel->setText(item->text(column));
}
}
// 添加学校
void QTreeWidgets::onAddSchool() {
bool ok = false;
QString schoolText = QInputDialog::getText(this, tr("添加学校"), tr("请输入学校名称:"), QLineEdit::Normal, "", &ok);
if (ok && !schoolText.isEmpty()) {
// 新建item设置父项为数表
QTreeWidgetItem *item = new QTreeWidgetItem(ui.treeWidget);
item->setCheckState(0, Qt::CheckState::Unchecked);
item->setIcon(0, QIcon("E:\\QTproject\\WPS\\images\\color.ico"));
item->setText(0, schoolText);
item->setText(1, "0");
item->setText(2, "0");
// 设置工具提示
item->setToolTip(0, schoolText);
}
}
// 添加班级
void QTreeWidgets::onAddClass() {
// 获取选中的一项
QTreeWidgetItem *item = ui.treeWidget->currentItem();
if (item == NULL) {
QMessageBox::information(this, "提示", "请选择一项");
return;
}
// 显示输入框
bool ok = false;
QString className = QInputDialog::getText(ui.treeWidget, tr("添加班级"), tr("请输入班级名称:"), QLineEdit::Normal, "", &ok);
// 获取选中item的父项,如果父项是QTreeWidgetItem则返回该父项;如果父项是ui.treeWidget则返回NULL
QTreeWidgetItem *itemParent = item->parent();
// 选中的是子项
if (itemParent != NULL) {
QTime time;
time = QTime::currentTime(); // 获取当前系统时间
qsrand(time.msec() + time.second() * 1); // 种下随机种子
int classPeople = qrand() % 100; // 产生100以内的随机数
QTreeWidgetItem *classItem = new QTreeWidgetItem(itemParent);
//classItem->setFlags(Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsAutoTristate);
classItem->setText(0, className);
classItem->setIcon(0, QIcon("E:\\QTproject\\WPS\\images\\wps.ico"));
classItem->setText(1, QString("%1人").arg(classPeople));
classItem->setText(2, QString("%1分").arg(classPeople * 60));
classItem->setToolTip(0, className);
// 修改父项第二列与第三列的文本
setParentSecondAndThirdText(itemParent);
// 选中的是父项
} else {
// 方式一:
/*QTreeWidgetItem *classItem = new QTreeWidgetItem(item);
classItem->setText(column, className);
classItem->setToolTip(column, className);*/
QTime time;
time = QTime::currentTime(); // 获取当前系统时间
qsrand(time.msec() + time.second() * 1); // 种下随机种子
int classPeople = qrand() % 100; // 产生100以内的随机数
// 方式二:
QTreeWidgetItem *classItem = new QTreeWidgetItem;
//classItem->setFlags(Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsAutoTristate);
classItem->setText(0, className);
classItem->setIcon(0, QIcon("E:\\QTproject\\WPS\\images\\wps.ico"));
classItem->setText(1, QString("%1人").arg(classPeople));
classItem->setText(2, QString("%1分").arg(classPeople * 60));
classItem->setToolTip(0, className);
// 父项添加子项
item->addChild(classItem);
setParentSecondAndThirdText(item);
}
}
// 删除学校/班级
void QTreeWidgets::onDelAction() {
// 返回tree小部件中的当前项。
QTreeWidgetItem *item = ui.treeWidget->currentItem();
if (item == NULL) return;
QTreeWidgetItem *itemParent = item->parent();
// 删除子项
if (itemParent != NULL) {
itemParent->removeChild(item);
itemParent->setText(ui.treeWidget->currentColumn() + 1, QString("%1").arg(itemParent->childCount()));
delete item;
setParentSecondAndThirdText(itemParent);
// 删除父项
} else {
// item->childCount() 返回子项的个数
int count = item->childCount();
for (int i = 0; i < count; i++) {
item->removeChild(item->child(0)); // 删除子项
delete item->child(0); // 释放内存
}
// takeTopLevelItem:删除树中给定索引处的顶级项并返回它,否则返回0
// indexOfTopLevelItem:返回给定顶级项的索引,如果找不到该项,则返回-1
ui.treeWidget->takeTopLevelItem(ui.treeWidget->indexOfTopLevelItem(item));
delete item;
}
}
// 复选框打勾显示数据
void QTreeWidgets::on_determineBtn_clicked() {
QString showMessage = "";
// 获取所有顶级项的个数
int topLeveItemCount = ui.treeWidget->topLevelItemCount();
for (int count = 0; count < topLeveItemCount; count++) {
// 遍历所有顶级项,复选框状态未选中则跳过循环
if (ui.treeWidget->topLevelItem(count)->checkState(0) != Qt::CheckState::Checked) {
continue;
}
// ui.treeWidget->topLevelItem(count) 获取inden对应的顶级项
QString name, studentCount, score;
// 存储顶级项所有列的数据
name = ui.treeWidget->topLevelItem(count)->text(0);
studentCount = ui.treeWidget->topLevelItem(count)->text(1);
score = ui.treeWidget->topLevelItem(count)->text(2);
showMessage += name + '\n' + studentCount + '\n' + score + '\n' + "---------------" + '\n';
}
QMessageBox::information(this, "提示", showMessage);
for (int count = 0; count < topLeveItemCount; count++) {
// 遍历所有顶级项,复选框状态选中则取消勾选
if (ui.treeWidget->topLevelItem(count)->checkState(0) == Qt::CheckState::Checked) {
// 取消勾选
ui.treeWidget->topLevelItem(count)->setCheckState(0, Qt::CheckState::Unchecked);
}
}
}
// 更新根项数据
void QTreeWidgets::setParentSecondAndThirdText(QTreeWidgetItem *ParentItem) {
int classScore = 0;
int score = 0;
int count = ParentItem->childCount();
for (int i = 0; i < count; i++) {
// 获得第二列和第三列的文本
QString second = ParentItem->child(i)->text(1);
QString third = ParentItem->child(i)->text(2);
// 计算学生总人数
this->m_reg.indexIn(second);
classScore += this->m_reg.cap(0).toInt();
// 计算总分数
this->m_reg.indexIn(third); // 根据正则表达式进行匹配
score += this->m_reg.cap(0).toInt(); // 捕获匹配到的数字
}
// 刷新父项的个数
ParentItem->setText(1, QString("%1班 / %2人").arg(count).arg(classScore));
// 刷新父项总分数
ParentItem->setText(2, QString("%1分").arg(score));
}
// 双击删除子项
void QTreeWidgets::onDeleteChildAction(QTreeWidgetItem *item, int column) {
if (item->parent() == NULL) return;
QTreeWidgetItem *itemParent = item->parent();
itemParent->removeChild(item);
delete item;
setParentSecondAndThirdText(itemParent);
}
总结:
此小项目使用到的知识点还是挺多的,不过也都是挺实用的,在其他类型的项目都可以用得到。
到此,MVC三个子类控件QLiseWidget、QTableWidget、QTreeWidget都已经记录完毕。