在本教程中,我们将使用 Qt 的 QTreeWidget 控件实现一个复杂的树控件功能。该树控件包含多个层级的项目,并支持右键菜单操作。我们将详细介绍 QTreeWidget 的使用方法,包括控件布局、列设置、项目管理、查询、排序、信号处理等。以下是具体内容:
1. 效果展示
2.QTreeWidget具体接口
2.1 控件布局
在 Qt 中,可以通过 QVBoxLayout 或 QHBoxLayout 等布局管理器来布置 QTreeWidget 控件。
QVBoxLayout *layout = new QVBoxLayout();
layout->addWidget(treeWidget);
QWidget *centralWidget = new QWidget(this);
centralWidget->setLayout(layout);
setCentralWidget(centralWidget);
2.2 设置列
可以使用 setColumnCount
方法设置列数,并通过 setHeaderLabels
设置列标题。
treeWidget->setColumnCount(3);
QStringList headers;
headers << QString::fromLocal8Bit("班级")
<< QString::fromLocal8Bit("分配科目")
<< QString::fromLocal8Bit("是否达标");
treeWidget->setHeaderLabels(headers);
2.3 设置宽高
通过 resize
方法设置 QTreeWidget 的宽高。
treeWidget->resize(800, 600);
2.4 设置列表头
使用 setHeaderLabels
方法来设置 QTreeWidget 的列头。
QStringList headers;
headers << QString::fromLocal8Bit("班级")
<< QString::fromLocal8Bit("分配科目")
<< QString::fromLocal8Bit("是否达标");
treeWidget->setHeaderLabels(headers);
2.5 设置复选框
可以通过 setCheckState
方法为项目添加复选框。
QTreeWidgetItem *item = new QTreeWidgetItem(treeWidget);
item->setText(0, QString::fromLocal8Bit("某班级"));
item->setCheckState(2, Qt::Unchecked);
2.6 添加树
2.6.1 添加顶层项目
使用 addTopLevelItem
方法添加顶层项目。
QTreeWidgetItem *topLevelItem = new QTreeWidgetItem(treeWidget);
topLevelItem->setText(0, QString::fromLocal8Bit("顶层项目"));
treeWidget->addTopLevelItem(topLevelItem);
2.6.2 插入顶层项目
使用 insertTopLevelItem
方法插入顶层项目。
QTreeWidgetItem *newTopLevelItem = new QTreeWidgetItem();
newTopLevelItem->setText(0, QString::fromLocal8Bit("插入顶层项目"));
treeWidget->insertTopLevelItem(0, newTopLevelItem);
2.6.3 添加子项
使用 addChild
方法为顶层项目添加子项。
QTreeWidgetItem *childItem = new QTreeWidgetItem();
childItem->setText(0, QString::fromLocal8Bit("子项目"));
topLevelItem->addChild(childItem);
2.7 删除树
2.7.1 删除子项目
使用 removeChild
方法删除子项目。
topLevelItem->removeChild(childItem);
2.7.2 删除顶级条目
使用 takeTopLevelItem
方法删除顶层项目。
QTreeWidgetItem *removedItem = treeWidget->takeTopLevelItem(0);
delete removedItem;
2.8 查询树
2.8.1 查询对应条目
使用 findItems
方法根据条件查询条目。
QList<QTreeWidgetItem*> items = treeWidget->findItems(QString::fromLocal8Bit("查询内容"), Qt::MatchExactly);
2.8.2 查询对应序号
使用 indexOfTopLevelItem
方法获取顶层项目的索引。
int index = treeWidget->indexOfTopLevelItem(topLevelItem);
2.9 树条目操作
2.9.1 当前选中行列
使用 currentItem
方法获取当前选中的条目,并使用 currentColumn
方法获取当前选中的列。
QTreeWidgetItem *currentItem = treeWidget->currentItem();
int currentColumn = treeWidget->currentColumn();
2.9.2 设置条目选中
使用 setSelected
方法设置条目选中状态。
currentItem->setSelected(true);
2.9.3 设置选中行
使用 setCurrentItem
方法设置当前选中的条目。
treeWidget->setCurrentItem(topLevelItem);
2.9.4 设置选中列
使用 setCurrentItem
方法设置当前选中的条目和列。
treeWidget->setCurrentItem(topLevelItem, 1);
2.9.5 当前选中行 上一个选中行
使用 currentItem
和 previousItem
方法获取当前选中和上一个选中的条目。
QTreeWidgetItem *currentItem = treeWidget->currentItem(); QTreeWidgetItem *previousItem = treeWidget->itemAbove(currentItem);
2.10 树排序
2.10.1 设置自动排序
使用 setSortingEnabled
方法启用或禁用自动排序。
treeWidget->setSortingEnabled(true);
2.10.2 升序降序
使用 sortItems
方法按列进行升序或降序排序。
treeWidget->sortItems(0, Qt::AscendingOrder); treeWidget->sortItems(1, Qt::DescendingOrder);
2.11 树查找
使用 findItems
方法查找符合条件的项目。
QList<QTreeWidgetItem*> foundItems = treeWidget->findItems(QString::fromLocal8Bit("查找内容"), Qt::MatchExactly);
2.12 清空树
使用 clear
方法清空树控件中的所有项目。
treeWidget->clear();
2.13 折叠树
使用 collapseItem
方法折叠指定项目。
treeWidget->collapseItem(topLevelItem);
2.14 展开树
使用 expandItem
方法展开指定项目。
treeWidget->expandItem(topLevelItem);
2.15 滚动指定条目
使用 scrollToItem
方法滚动到指定项目。
treeWidget->scrollToItem(topLevelItem);
2.16 树单击信号
连接 itemClicked
信号以处理单击事件。
connect(treeWidget, SIGNAL(itemClicked(QTreeWidgetItem*, int)), this, SLOT(onItemClicked(QTreeWidgetItem*, int)));
2.17 树双击信号
连接 itemDoubleClicked
信号以处理双击事件。
connect(treeWidget, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)), this, SLOT(onItemDoubleClicked(QTreeWidgetItem*, int)));
2.18 树展开信号
连接 itemExpanded
信号以处理项目展开事件。
connect(treeWidget, SIGNAL(itemExpanded(QTreeWidgetItem*)), this, SLOT(onItemExpanded(QTreeWidgetItem*)));
2.19 树折叠信号
连接 itemCollapsed
信号以处理项目折叠事件。
connect(treeWidget, SIGNAL(itemCollapsed(QTreeWidgetItem*)), this, SLOT(onItemCollapsed(QTreeWidgetItem*)));
2.20 列数据变化信号
连接 itemChanged
信号以处理项目数据变化事件。
connect(treeWidget, SIGNAL(itemChanged(QTreeWidgetItem*, int)), this, SLOT(onItemChanged(QTreeWidgetItem*, int)));
3.程序源码展示
3.1main.cpp
#include <QApplication>
#include "mainwindow.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MainWindow window;
window.show();
return app.exec();
}
3.2 mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QTreeWidget>
#include <QMenu>
#include <QAction>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void onAssignSubject();
void onPromoteToKeyClass();
void onMoveToAssignedClass();
void onMoveToUnassignedKeyClass();
void onCancelPromotion();
void onContextMenuRequested(const QPoint &pos);
private:
void createTreeWidget();
void createContextMenu();
QTreeWidget *treeWidget;
QMenu *contextMenu;
QMenu *assignMenu;
QAction *promoteToKeyClassAction;
QAction *moveToAssignedClassAction;
QAction *moveToUnassignedKeyClassAction;
QAction *cancelPromotionAction;
enum Column { Class = 0, Subject, Standard };
};
#endif // MAINWINDOW_H
3.3 mainwindow.cpp
#include "mainwindow.h"
#include <QVBoxLayout>
#include <QStringList>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
treeWidget(new QTreeWidget(this)),
contextMenu(new QMenu(this)),
assignMenu(new QMenu(QString::fromLocal8Bit("分配科目"), this)),
promoteToKeyClassAction(new QAction(QString::fromLocal8Bit("提升重点班级"), this)),
moveToAssignedClassAction(new QAction(QString::fromLocal8Bit("提升"), this)),
moveToUnassignedKeyClassAction(new QAction(QString::fromLocal8Bit("提升"), this)),
cancelPromotionAction(new QAction(QString::fromLocal8Bit("取消提升"), this))
{
setWindowTitle(QString::fromLocal8Bit("班级管理"));
resize(800, 600);
createTreeWidget();
createContextMenu();
QVBoxLayout *layout = new QVBoxLayout();
layout->addWidget(treeWidget);
QWidget *centralWidget = new QWidget(this);
centralWidget->setLayout(layout);
setCentralWidget(centralWidget);
connect(treeWidget, SIGNAL(customContextMenuRequested(const QPoint&)),
this, SLOT(onContextMenuRequested(const QPoint&)));
}
MainWindow::~MainWindow() {}
void MainWindow::createTreeWidget()
{
treeWidget->setColumnCount(3);
QStringList headers;
headers << QString::fromLocal8Bit("班级")
<< QString::fromLocal8Bit("分配科目")
<< QString::fromLocal8Bit("是否达标");
treeWidget->setHeaderLabels(headers);
treeWidget->setContextMenuPolicy(Qt::CustomContextMenu);
// 创建根节点
QTreeWidgetItem *assignedClass = new QTreeWidgetItem(treeWidget, QStringList(QString::fromLocal8Bit("已分配科目班级")));
QTreeWidgetItem *unassignedKeyClass = new QTreeWidgetItem(treeWidget, QStringList(QString::fromLocal8Bit("未分配科目重点班级")));
QTreeWidgetItem *allClasses = new QTreeWidgetItem(treeWidget, QStringList(QString::fromLocal8Bit("全部班级")));
QStringList grades;
grades << QString::fromLocal8Bit("一年级")
<< QString::fromLocal8Bit("二年级")
<< QString::fromLocal8Bit("三年级")
<< QString::fromLocal8Bit("四年级")
<< QString::fromLocal8Bit("五年级");
QStringList classes;
classes << QString::fromLocal8Bit("一班")
<< QString::fromLocal8Bit("二班")
<< QString::fromLocal8Bit("三班")
<< QString::fromLocal8Bit("四班");
for (int i = 0; i < grades.size(); ++i) {
QTreeWidgetItem *gradeItem = new QTreeWidgetItem(allClasses, QStringList(grades[i]));
for (int j = 0; j < classes.size(); ++j) {
QTreeWidgetItem *classItem = new QTreeWidgetItem(gradeItem, QStringList(classes[j]));
}
}
}
void MainWindow::createContextMenu()
{
assignMenu->addAction(QString::fromLocal8Bit("语文"), this, SLOT(onAssignSubject()));
assignMenu->addAction(QString::fromLocal8Bit("数学"), this, SLOT(onAssignSubject()));
assignMenu->addAction(QString::fromLocal8Bit("英语"), this, SLOT(onAssignSubject()));
assignMenu->addAction(QString::fromLocal8Bit("体育"), this, SLOT(onAssignSubject()));
assignMenu->addAction(QString::fromLocal8Bit("思政"), this, SLOT(onAssignSubject()));
contextMenu->addMenu(assignMenu);
contextMenu->addAction(promoteToKeyClassAction);
connect(promoteToKeyClassAction, SIGNAL(triggered()), this, SLOT(onPromoteToKeyClass()));
connect(moveToAssignedClassAction, SIGNAL(triggered()), this, SLOT(onMoveToAssignedClass()));
connect(moveToUnassignedKeyClassAction, SIGNAL(triggered()), this, SLOT(onMoveToUnassignedKeyClass()));
connect(cancelPromotionAction, SIGNAL(triggered()), this, SLOT(onCancelPromotion()));
}
void MainWindow::onAssignSubject()
{
QAction *action = qobject_cast<QAction*>(sender());
if (!action)
return;
QTreeWidgetItem *currentItem = treeWidget->currentItem();
if (currentItem && currentItem->parent()) {
QString currentText = currentItem->text(Column::Subject);
QString newSubject = action->text();
if (!currentText.contains(newSubject)) {
if (!currentText.isEmpty()) {
currentText +=QString::fromLocal8Bit( "、");
}
currentText += newSubject;
currentItem->setText(Column::Subject, currentText);
}
}
}
void MainWindow::onPromoteToKeyClass()
{
QTreeWidgetItem *currentItem = treeWidget->currentItem();
if (!currentItem || !currentItem->parent())
return;
QTreeWidgetItem *itemCopy = currentItem->clone();
treeWidget->findItems(QString::fromLocal8Bit("未分配科目重点班级"), Qt::MatchExactly).first()->addChild(itemCopy);
}
void MainWindow::onMoveToAssignedClass()
{
QTreeWidgetItem *currentItem = treeWidget->currentItem();
if (!currentItem || !currentItem->parent())
return;
QTreeWidgetItem *itemCopy = currentItem->clone();
itemCopy->setCheckState(Column::Standard, Qt::Checked);
treeWidget->findItems(QString::fromLocal8Bit("已分配科目班级"), Qt::MatchExactly).first()->addChild(itemCopy);
delete currentItem;
}
void MainWindow::onMoveToUnassignedKeyClass()
{
QTreeWidgetItem *currentItem = treeWidget->currentItem();
if (!currentItem || !currentItem->parent())
return;
QTreeWidgetItem *itemCopy = currentItem->clone();
itemCopy->setCheckState(Column::Standard, Qt::Unchecked);
treeWidget->findItems(QString::fromLocal8Bit("未分配科目重点班级"), Qt::MatchExactly).first()->addChild(itemCopy);
delete currentItem;
}
void MainWindow::onCancelPromotion()
{
QTreeWidgetItem *currentItem = treeWidget->currentItem();
if (!currentItem || !currentItem->parent())
return;
QTreeWidgetItem *itemCopy = currentItem->clone();
itemCopy->setCheckState(Column::Standard, Qt::Unchecked);
treeWidget->findItems(QString::fromLocal8Bit("未分配科目重点班级"), Qt::MatchExactly).first()->addChild(itemCopy);
delete currentItem;
}
void MainWindow::onContextMenuRequested(const QPoint &pos)
{
QTreeWidgetItem *item = treeWidget->itemAt(pos);
if (!item)
return;
if (item->text(0) == QString::fromLocal8Bit("已分配科目班级") || item->text(0) == QString::fromLocal8Bit("未分配科目重点班级") || item->text(0) == QString::fromLocal8Bit("全部班级"))
return;
if (item->parent() && item->parent()->text(0) == QString::fromLocal8Bit("已分配科目班级")) {
contextMenu->clear();
contextMenu->addAction(cancelPromotionAction);
} else if (item->parent() && item->parent()->text(0) == QString::fromLocal8Bit("未分配科目重点班级")) {
contextMenu->clear();
contextMenu->addAction(moveToAssignedClassAction);
} else {
contextMenu->clear();
contextMenu->addMenu(assignMenu);
contextMenu->addAction(promoteToKeyClassAction);
}
contextMenu->exec(treeWidget->viewport()->mapToGlobal(pos));
}