基于QTreeWidget实现多级组织结构

基于QTreeWidget实现多级组织结构以及带Checkbox的选择树

采用基于QWidget+Mingw实现的多级组织结构树

通过QTreeWidget控件实现的多级组织结构树。

Qt相关系列文章:
一、Qt实现的聊天画面消息气泡
二、基于QTreeWidget实现多级组织结构
三、基于QTreeWidget实现带Checkbox的多级组织结构选择树

基于QTreeWidget实现多级组织结构代码已上传到【https://gitee.com/duyanjun/bubbleChat.git】

目录

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

c 复制代码
#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

c 复制代码
#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

c 复制代码
#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

c 复制代码
#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

c 复制代码
#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

c 复制代码
#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

c 复制代码
#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);
}
相关推荐
用户805533698034 天前
不止三件套:QObject 属性系统全关键字与运行时反射!
c++·qt
xcyxiner4 天前
DicomViewer (vcpkg Windows和ubuntu编译)7
qt
Quz9 天前
QML Hello World 入门示例
qt
xcyxiner12 天前
DicomViewer (dcmtk读取dcm文件)5
qt
xcyxiner13 天前
DicomViewer (后台线程处理文件)4
qt
xcyxiner13 天前
DicomViewer (添加模型类)3
qt
xcyxiner14 天前
DicomViewer (目录调整) 2
qt
xcyxiner14 天前
dcmtk vtk vtk-dicom(gdcm) 编译(debug) v2
qt
桥田智能16 天前
桥田智能 QT-650S:面向白车身焊装的 800kg 重载快换解决方案
开发语言·qt·系统架构
森G16 天前
75、服务器源码解析---------云视频服务项目
linux·服务器·网络·c++·qt