基于QTreeWidget实现多级组织结构以及带Checkbox的选择树
采用基于QWidget+Mingw实现的原生的消息气泡
通过QTreeWidget控件实现的多级组织结构树。
基于QTreeWidget实现多级组织结构代码已上传到【https://gitee.com/duyanjun/bubbleChat.git】
目录
- 基于QTreeWidget实现多级组织结构以及带Checkbox的选择树
- 1、效果图
- 2、运行
- 2.1、从git导入
- 2.2、修改头像图片的路径
- 2.3、运行
- 2.4、实现
1、效果图
2、运行
2.1、从git导入
文件 -> 新建文件或项目 -> Import Project -> Git Clone
【https://gitee.com/duyanjun/QT_treeDemo.git】
2.2、修改头像图片的路径
运行本Demo需要修改mainwindow.cpp第130行代码中的images目录的绝对路径;
2.3、运行
2.4、实现
1)、主画面部局
在画面添加QTreeWidget控件
2)、人员节点部局
整体部局采用横向部局,依次是头像和(姓名+心情),(姓名+心情)采用纵向部局
3)、main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
4)、MainWindow类
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QTreeWidgetItem>
#include <QPixmap>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void onItemExpanded(QTreeWidgetItem * item);
void onItemCollapsed(QTreeWidgetItem * item);
void onItemClicked(QTreeWidgetItem * item, int column);
private:
void initTree();
QTreeWidgetItem* addChildNode(QTreeWidgetItem *parent, int index, QString namePre);
QTreeWidgetItem* addChildEmpNode(QTreeWidgetItem *parent, int index);
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "departnodeitem.h"
#include "EmployeeNodeItem.h"
#include <QList>
#include <QPainter>
#include <QDebug>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
initTree();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::onItemExpanded(QTreeWidgetItem *item)
{
bool bIsChild = item->data(0, Qt::UserRole).toBool();
if (!bIsChild) {
DepartNodeItem *departNode = dynamic_cast<DepartNodeItem*>(ui->tree->itemWidget(item, 0));
if (departNode) {
departNode->setExpanded(true);
}
}
}
void MainWindow::onItemCollapsed(QTreeWidgetItem *item)
{
bool bIsChild = item->data(0, Qt::UserRole).toBool();
if (!bIsChild) {
DepartNodeItem *departNode = dynamic_cast<DepartNodeItem*>(ui->tree->itemWidget(item, 0));
if (departNode) {
departNode->setExpanded(false);
}
}
}
void MainWindow::onItemClicked(QTreeWidgetItem *item, int column)
{
bool bIsChild = item->data(0, Qt::UserRole).toBool();
if (!bIsChild)
{
item->setExpanded(!item->isExpanded());
}
}
void MainWindow::initTree()
{
ui->tree->setHeaderHidden(true);
//展开和收缩时信号,以达到变更我三角图片;
connect(ui->tree, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this, SLOT(onItemClicked(QTreeWidgetItem *, int)));
connect(ui->tree, SIGNAL(itemExpanded(QTreeWidgetItem *)), this, SLOT(onItemExpanded(QTreeWidgetItem *)));
connect(ui->tree, SIGNAL(itemCollapsed(QTreeWidgetItem *)), this, SLOT(onItemCollapsed(QTreeWidgetItem *)));
for(int i = 0; i < 10; i++){
// 一级部门节点
QTreeWidgetItem *pRootDeptItem = new QTreeWidgetItem();
pRootDeptItem->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator);
//设置Data用于区分,Item是分组节点还是子节点,0代表分组节点,1代表子节点
pRootDeptItem->setData(0, Qt::UserRole, 0);
DepartNodeItem *pItemName = new DepartNodeItem(ui->tree);
pItemName->setLevel(0);
int nMyFriendNum = 6;
QString qsGroupName = QString("一级部门%3 [%1/%2]").arg(0).arg(nMyFriendNum).arg(i);
pItemName->setText(qsGroupName);
//插入分组节点
ui->tree->addTopLevelItem(pRootDeptItem);
ui->tree->setItemWidget(pRootDeptItem, 0, pItemName);
for(int j = 0; j < 5; j++){
addChildEmpNode(pRootDeptItem, j);
}
for(int j = 0; j < 5; j++){
QString name = QString("二级部门%1").arg(j);
QTreeWidgetItem *childItem = addChildNode(pRootDeptItem, i * 10 + j,name);
for(int g = 0; g < 5; g++){
addChildEmpNode(childItem, g);
}
}
}
}
QTreeWidgetItem* MainWindow::addChildNode(QTreeWidgetItem *parent, int index, QString namePre)
{
QTreeWidgetItem *pDeptItem = new QTreeWidgetItem();
pDeptItem->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator);
//设置Data用于区分,Item是分组节点还是子节点,0代表分组节点,1代表子节点
pDeptItem->setData(0, Qt::UserRole, 0);
DepartNodeItem *pItemName = new DepartNodeItem(ui->tree);
int level = 0;
DepartNodeItem *departNode = dynamic_cast<DepartNodeItem*>(ui->tree->itemWidget(parent, 0));
if (departNode) {
level = departNode->getLevel();
level ++;
}
pItemName->setLevel(level);
int nMyFriendNum = 6;
QString qsGroupName = QString("%4%3 [%1/%2]").arg(0).arg(nMyFriendNum).arg(index).arg(namePre);
pItemName->setText(qsGroupName);
//擦入分组节点
parent->addChild(pDeptItem);
ui->tree->setItemWidget(pDeptItem, 0, pItemName);
return pDeptItem;
}
QTreeWidgetItem *MainWindow::addChildEmpNode(QTreeWidgetItem *parent, int index)
{
QTreeWidgetItem *pDeptItem = new QTreeWidgetItem();
//设置Data用于区分,Item是分组节点还是子节点,0代表分组节点,1代表子节点
pDeptItem->setData(0, Qt::UserRole, 1);
int level = 0;
DepartNodeItem *departNode = dynamic_cast<DepartNodeItem*>(ui->tree->itemWidget(parent, 0));
if (departNode) {
level = departNode->getLevel();
level ++;
}
EmployeeNodeItem *pItemName = new EmployeeNodeItem(ui->tree);
pItemName->setLevel(level);
// 加载本地文件,需要修改成本地的路径
pItemName->setHeadPath(QString("D:/work/Qt/workspace/QT_treeDemo/images/pic/%1.jpg").arg(index));
QString qfullName = QString("人员%1").arg(index);
pItemName->setFullName(qfullName);
pItemName->setSign(QString("欢迎访问杜燕军工作号-test!!!"));
//擦入分组节点
parent->addChild(pDeptItem);
ui->tree->setItemWidget(pDeptItem, 0, pItemName);
return pDeptItem;
}
5)、DepartNodeItem类
departnodeitem.h
#ifndef DEPARTNODEITEM_H
#define DEPARTNODEITEM_H
#include <QLabel>
#include <QPaintEvent>
#include <QPropertyAnimation>
#define INDENTATION 20
class DepartNodeItem : public QLabel
{
Q_OBJECT
Q_PROPERTY(int rotation READ rotation WRITE setRotation)
public:
DepartNodeItem(QWidget *parent = 0);
~DepartNodeItem();
void setText(const QString& title);
void setExpanded(bool expand);
int getIndentation();
void setLevel(int level);
int getLevel();
private:
int rotation();
void setRotation(int rotation);
private:
void paintEvent(QPaintEvent *event);
private:
QPropertyAnimation *m_animation;
// 部门名称
QString m_name;
// 部门ID
QString m_id;
// 旋转角度
int m_rotation;
// 当前节点缩进距离
int m_indentation;
// 当前节点的深度(级数)
int m_level;
};
#endif // DEPARTNODEITEM_H
departnodeitem.cpp
#include "departnodeitem.h"
#include <QPainter>
#include <QDebug>
DepartNodeItem::DepartNodeItem(QWidget *parent)
: QLabel(parent),
m_rotation(0),
m_level(0),
m_indentation(0)
{
setFixedHeight(32);
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
m_animation = new QPropertyAnimation(this, "rotation");
m_animation->setDuration(50);
m_animation->setEasingCurve(QEasingCurve::InQuad);
}
DepartNodeItem::~DepartNodeItem()
{
m_animation = NULL;
delete m_animation;
}
void DepartNodeItem::setText(const QString &title)
{
m_name = title;
update();
}
void DepartNodeItem::setExpanded(bool expand)
{
if (expand) {
m_animation->setEndValue(90);
} else {
m_animation->setEndValue(0);
}
m_animation->start();
}
int DepartNodeItem::getIndentation()
{
return this->m_indentation;
}
void DepartNodeItem::setLevel(int level)
{
this->m_level = level;
this->m_indentation = this->m_level * INDENTATION;
}
int DepartNodeItem::getLevel()
{
return this->m_level;
}
int DepartNodeItem::rotation()
{
return m_rotation;
}
void DepartNodeItem::setRotation(int rotation)
{
m_rotation = rotation;
update();
}
void DepartNodeItem::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
{
painter.setRenderHint(QPainter::TextAntialiasing, true);
QFont font;
font.setPointSize(10);
painter.setFont(font);
int txtX = m_indentation + 24;
painter.drawText(txtX, 0, this->width() - txtX, this->height(), Qt::AlignLeft | Qt::AlignVCenter, m_name);
}
{
painter.setRenderHint(QPainter::SmoothPixmapTransform, true);
painter.save();
QPixmap pixmap(":/tree/Resources/arrow.png");
QPixmap tmpPixmap(pixmap.size());
tmpPixmap.fill(Qt::transparent);
QPainter p(&tmpPixmap);
p.setRenderHint(QPainter::SmoothPixmapTransform, true);
// 旋转m_rotation角度
p.translate(pixmap.width() /2, pixmap.height() /2);
p.rotate(m_rotation);
p.drawPixmap(0 - pixmap.width() /2, 0 - pixmap.height() / 2,pixmap);
painter.drawPixmap(m_indentation+6, (this->height() - pixmap.height()) / 2, tmpPixmap);
painter.restore();
}
QLabel::paintEvent(event);
}
6)、EmployeeNodeItem类
EmployeeNodeItem.h
#ifndef EMPLOYEENODEITEM_H
#define EMPLOYEENODEITEM_H
#include <QWidget>
#include <QPaintEvent>
#include <QPixmap>
#include <QSize>
#define INDENTATION 20
#define HEAD_LABEL_WIDTH 40
namespace Ui {
class EmployeeNodeItem;
}
class EmployeeNodeItem : public QWidget
{
Q_OBJECT
public:
EmployeeNodeItem(QWidget *parent = 0);
~EmployeeNodeItem();
public:
void setFullName(const QString& fullName);
void setSign(const QString& sign);
void setHeadPixmap(const QPixmap& headPath);
void setHeadPath(const QString& headPath);
QSize getHeadLabelSize() const;
int getIndentation();
int getLevel();
void setLevel(int level);
private:
void initControl();
QPixmap getRoundImage(const QPixmap &src, QPixmap& mask, QSize masksize);
private:
void paintEvent(QPaintEvent *event);
private:
Ui::EmployeeNodeItem *ui;
// 当前节点缩进距离
int m_indentation;
// 当前节点的深度(级数)
int m_level;
// 头像Label的宽度
int m_headLabelWidth;
};
#endif // EMPLOYEENODEITEM_H
EmployeeNodeItem.cpp
#include "EmployeeNodeItem.h"
#include "ui_EmployeeNodeItem.h"
#include <QDebug>
#include <QPainter>
EmployeeNodeItem::EmployeeNodeItem(QWidget *parent) :
QWidget(parent),
ui(new Ui::EmployeeNodeItem),
m_headLabelWidth(0),
m_level(0),
m_indentation(0)
{
ui->setupUi(this);
initControl();
}
EmployeeNodeItem::~EmployeeNodeItem()
{
delete ui;
}
void EmployeeNodeItem::setFullName(const QString &fullName)
{
ui->lbFullName->setText(fullName);
}
void EmployeeNodeItem::setSign(const QString &sign)
{
ui->lbSign->setText(sign);
}
void EmployeeNodeItem::setHeadPixmap(const QPixmap &headPath)
{
ui->lbHeadPic->setPixmap(headPath);
}
void EmployeeNodeItem::setHeadPath(const QString &headPath)
{
/*
ui->lbHeadPic->setScaledContents(true);
QString style = ui->lbHeadPic->styleSheet();
style.append("image:url(").append(headPath).append(");");
qDebug() << style;
ui->lbHeadPic->setStyleSheet(style);
*/
// 方式3.加载QPixmap
QPixmap pixmap1;
pixmap1.load(headPath);
QPixmap pixmap2;
pixmap2.load(":/tree/Resources//head_mask.png");
//qDebug() << "m_level:" << m_level << " m_indentation:" << m_indentation << " m_headLabelWidth:" << m_headLabelWidth << " " << HEAD_LABEL_WIDTH;
QPixmap roundPic = this->getRoundImage(pixmap1, pixmap2, QSize(m_headLabelWidth,HEAD_LABEL_WIDTH));
this->setHeadPixmap(roundPic);
}
QSize EmployeeNodeItem::getHeadLabelSize() const
{
return ui->lbHeadPic->size();
}
int EmployeeNodeItem::getIndentation()
{
return this->m_indentation;
}
int EmployeeNodeItem::getLevel()
{
return this->m_level;
}
void EmployeeNodeItem::setLevel(int level)
{
this->m_level = level;
this->m_indentation = this->m_level * INDENTATION;
this->m_headLabelWidth = this->m_indentation + HEAD_LABEL_WIDTH;
ui->lbHeadPic->setMinimumWidth(m_indentation);
}
void EmployeeNodeItem::initControl()
{
}
QPixmap EmployeeNodeItem::getRoundImage(const QPixmap &src, QPixmap &mask, QSize masksize)
{
if (masksize == QSize(0, 0))
{
masksize = mask.size();
}
else
{
mask = mask.scaled(masksize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
}
QImage resultImage(masksize, QImage::Format_ARGB32_Premultiplied);
QPainter painter(&resultImage);
painter.setCompositionMode(QPainter::CompositionMode_Source);
painter.fillRect(resultImage.rect(), Qt::transparent);
painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
painter.drawPixmap(m_indentation, 0, mask);
painter.setCompositionMode(QPainter::CompositionMode_SourceIn);
painter.drawPixmap(m_indentation, 0, src.scaled(masksize, Qt::KeepAspectRatio, Qt::SmoothTransformation));
painter.end();
return QPixmap::fromImage(resultImage);
}
void EmployeeNodeItem::paintEvent(QPaintEvent *event)
{
QWidget::paintEvent(event);
}