Qt编写自定义控件:绘制二叉树

关于二叉树见:《数据结构》学习记录(9):二叉树_友善啊,朋友的博客-CSDN博客

代码:

#ifndef FORM_H
#define FORM_H

#include <QWidget>

namespace Ui {
class Form;
}

class Form : public QWidget
{
    Q_OBJECT

public:
    explicit Form(QWidget *parent = nullptr);
    ~Form();

protected:
    void paintEvent(QPaintEvent *event)override;

private:
    Ui::Form *ui;
    class BTNode * root;
};

#endif // FORM_H
#include "form.h"
#include "ui_form.h"
#include <QStack>
#include <QDebug>
#include <iostream>
#include <QPainter>
#include <QPaintEvent>
#include <QRandomGenerator>

struct BTNode
{
    QChar data;
    BTNode * lchild{nullptr};
    BTNode * rchild{nullptr};
};

//创建二叉树
void CreateBTNode(BTNode * & root,QString binaryTreeBracketNotationString)
{
    root = nullptr;
    enum class processTreeType//当前字符处理的类型
    {
        leftChildTree,
        rightChildTree,
        noChildTree
    };
    processTreeType nowNodeProcessTreeType{processTreeType::noChildTree};

    BTNode * currentNode{nullptr};//当前创建的结点
    QStack<BTNode*> stack;
    for(const auto & element : qAsConst(binaryTreeBracketNotationString))
    {
        if(element == '(')//表示一棵左子树的开始,即将前面刚创建的结点作为双亲结点进栈
        {
            stack.push(currentNode);
            nowNodeProcessTreeType = processTreeType::leftChildTree;
        }
        else if(element == ')')//表示一棵子树的结束
        {
            stack.pop();
        }
        else if(element == ',')//表示一棵右子树的开始
        {
            nowNodeProcessTreeType = processTreeType::rightChildTree;
        }
        else//字母,说明应该创建一个结点
        {
            currentNode = new BTNode;
            currentNode->data = element;

            if(!root)
                root = currentNode;
            else
            {
                switch (nowNodeProcessTreeType)
                {
                    case processTreeType::leftChildTree:stack.top()->lchild = currentNode;break;
                    case processTreeType::rightChildTree:stack.top()->rchild = currentNode;break;
                    case processTreeType::noChildTree:;break;
                }
            }
        }
    }
}

//递归销毁二叉树
void DestroyBT(BTNode * & node)
{
    if (!node)
        return;
    else
    {
        DestroyBT(node->lchild);
        DestroyBT(node->rchild);
        delete node;
        node = nullptr;
    }
}

Form::Form(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Form)
{
    ui->setupUi(this);

    QString binaryTreeBracketNotationString = "A(B(D(M(N,),G(W(,H),))),C(E,F(P,Z(,K(Y,)))))";
    CreateBTNode(root,binaryTreeBracketNotationString);
}

Form::~Form()
{
    DestroyBT(root);
    delete ui;
}

QColor getRandomColor()
{
    return QColor(QRandomGenerator::global()->bounded(255),
                  QRandomGenerator::global()->bounded(255),
                  QRandomGenerator::global()->bounded(255));
}

void drawNode(BTNode * node,QPainter & painter,QPoint dataCircleCenter)
{
    static QPoint offsetPoint{20,20};
    static QPen whitePen{Qt::white,5};
    QRect rect = QRect(dataCircleCenter - offsetPoint,dataCircleCenter + offsetPoint);

    if(node->lchild)
    {
        painter.drawLine(rect.center(),dataCircleCenter + QPoint(-60,60));
        drawNode(node->lchild,painter,dataCircleCenter + QPoint(-60,60));
    }

    if(node->rchild)
    {
        painter.drawLine(rect.center(),dataCircleCenter + QPoint(60,60));
        drawNode(node->rchild,painter,dataCircleCenter + QPoint(60,60));
    }

    painter.save();
    painter.setBrush(getRandomColor());
    painter.setPen(whitePen);
    painter.drawEllipse(rect);
    painter.drawText(rect,Qt::AlignCenter,node->data);
    painter.restore();
}

void Form::paintEvent(QPaintEvent *event)
{
    static QFont font{"微软雅黑",18};
    QPainter painter(this);
    painter.setFont(font);
    painter.setRenderHint(QPainter::Antialiasing,true);
    drawNode(root,painter,QPoint(event->rect().width()/2,40));
}

效果:

  • 6
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值