Qt Writes Custom Control 46-Tree Navigation Bar

Keywords: Mobile Qt Qt5 SDK Linux

I. Preface

Tree Navigation Bar Control is the most powerful and classic one among all the controls. Among many buyers, it is also the most frequently used because it has a large collection of display effects, such as left Icon + right arrow + front icon + various color settings, etc. It covers all the code amount. It has been perfected for three years. It also provides corner signs to display text information. Throughout the market, the web and the cs framework are also good. This navigation bar is used a lot. At present, only the second-level menu is provided. If you need the third-level menu, you need to change the source code by yourself.

II. Functions of Realization

  • 1: Setting node data is quite convenient. Fill it in according to the corresponding format, separator.
  • 2: Can set whether the prompt information is displayed + width?
  • 3: Can set whether the line separator shows + height + Color
  • 4: Selected node line highlighting + Color + left right position can be set
  • 5: Selected node triangle highlighting + Color + left and right position can be set
  • 6: Set the selected color of the parent node + hover color + default color
  • 7: Set the selected color of the child node + hover color + default color
  • 8: Edge of icon + Left Distance + Font Size + Height of parent text can be set
  • 9: Icon Margin + Left Distance + Font Size + Height for Subnode Text
  • 10: Set node expansion mode, click + double click + disable


Header file code


 * Author of Tree Navigation Bar Control: feiyangqingyun(QQ:517216493) 2018-8-15
 * 1:Setting node data is quite convenient. Fill it in according to the corresponding format, separator.
 * 2:Can set whether prompt information is displayed + width
 * 3:Can set whether line separators display + height + Color
 * 4:Selected node line highlighting + Color + left and right position can be set
 * 5:Selected node triangle highlighting + Color + left and right position can be set
 * 6:Set the selected color of the parent node + hover color + default color
 * 7:Set the selected color of the child node + hover color + default color
 * 8:Icon Margin+Left Distance+Font Size+Height for Parent Node Text
 * 9:Icon Margin+Left Distance+Font Size+Height for Subnode Text
 * 10:Settable node expansion mode click + double click + disable

#include <QStyledItemDelegate>
#include <QAbstractListModel>
#include <QListView>
#include <QStringList>

class NavListView;

class NavDelegate : public QStyledItemDelegate
    NavDelegate(QObject *parent);

    QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const ;
    void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;

    NavListView *nav;
    QFont iconFont;

class NavModel : public QAbstractListModel
    NavModel(QObject *parent);

    struct TreeNode {
        int level;                  //Hierarchy, parent node-1, child node-2
        bool expand;                //Whether to open child nodes
        bool last;                  //Is it the end element?
        QChar icon;                 //Left Icon
        QString text;               //Display node text
        QString tip;                //Description on the right
        QString parentText;         //Parent Node Name
        QList<TreeNode *> children; //Set of child nodes

    struct ListNode {
        QString text;               //Node text
        TreeNode *treeNode;         //Node pointer

    int rowCount(const QModelIndex &parent) const;
    QVariant data(const QModelIndex &index, int role) const;

    QList<TreeNode *> treeNode;
    QList<ListNode> listNode;

public Q_SLOTS:
    void setItems(const QStringList &items);
    void expand(const QModelIndex &index);

    void refreshList();

#ifdef quc
#include <QtDesigner/QDesignerExportWidget>
#include <QtUiPlugin/QDesignerExportWidget>

class QDESIGNER_WIDGET_EXPORT NavListView : public QListView
class NavListView : public QListView


    Q_PROPERTY(QString items READ getItems WRITE setItems)
    Q_PROPERTY(bool rightIconVisible READ getRightIconVisible WRITE setRightIconVisible)
    Q_PROPERTY(bool tipVisible READ getTipVisible WRITE setTipVisible)
    Q_PROPERTY(int tipWidth READ getTipWidth WRITE setTipWidth)

    Q_PROPERTY(bool separateVisible READ getSeparateVisible WRITE setSeparateVisible)
    Q_PROPERTY(int separateHeight READ getSeparateHeight WRITE setSeparateHeight)
    Q_PROPERTY(QColor separateColor READ getSeparateColor WRITE setSeparateColor)

    Q_PROPERTY(bool lineLeft READ getLineLeft WRITE setLineLeft)
    Q_PROPERTY(bool lineVisible READ getLineVisible WRITE setLineVisible)
    Q_PROPERTY(int lineWidth READ getLineWidth WRITE setLineWidth)
    Q_PROPERTY(QColor lineColor READ getLineColor WRITE setLineColor)

    Q_PROPERTY(bool triangleLeft READ getTriangleLeft WRITE setTriangleLeft)
    Q_PROPERTY(bool triangleVisible READ getTriangleVisible WRITE setTriangleVisible)
    Q_PROPERTY(int triangleWidth READ getTriangleWidth WRITE setTriangleWidth)
    Q_PROPERTY(QColor triangleColor READ getTriangleColor WRITE setTriangleColor)

    Q_PROPERTY(int parentIconMargin READ getParentIconMargin WRITE setParentIconMargin)
    Q_PROPERTY(int parentMargin READ getParentMargin WRITE setParentMargin)
    Q_PROPERTY(int parentFontSize READ getParentFontSize WRITE setParentFontSize)
    Q_PROPERTY(int parentHeight READ getParentHeight WRITE setParentHeight)
    Q_PROPERTY(QColor parentBgNormalColor READ getParentBgNormalColor WRITE setParentBgNormalColor)
    Q_PROPERTY(QColor parentBgSelectedColor READ getParentBgSelectedColor WRITE setParentBgSelectedColor)
    Q_PROPERTY(QColor parentBgHoverColor READ getParentBgHoverColor WRITE setParentBgHoverColor)
    Q_PROPERTY(QColor parentTextNormalColor READ getParentTextNormalColor WRITE setParentTextNormalColor)
    Q_PROPERTY(QColor parentTextSelectedColor READ getParentTextSelectedColor WRITE setParentTextSelectedColor)
    Q_PROPERTY(QColor parentTextHoverColor READ getParentTextHoverColor WRITE setParentTextHoverColor)

    Q_PROPERTY(int childIconMargin READ getChildIconMargin WRITE setChildIconMargin)
    Q_PROPERTY(int childMargin READ getChildMargin WRITE setChildMargin)
    Q_PROPERTY(int childFontSize READ getChildFontSize WRITE setChildFontSize)
    Q_PROPERTY(int childHeight READ getChildHeight WRITE setChildHeight)
    Q_PROPERTY(QColor childBgNormalColor READ getChildBgNormalColor WRITE setChildBgNormalColor)
    Q_PROPERTY(QColor childBgSelectedColor READ getChildBgSelectedColor WRITE setChildBgSelectedColor)
    Q_PROPERTY(QColor childBgHoverColor READ getChildBgHoverColor WRITE setChildBgHoverColor)
    Q_PROPERTY(QColor childTextNormalColor READ getChildTextNormalColor WRITE setChildTextNormalColor)
    Q_PROPERTY(QColor childTextSelectedColor READ getChildTextSelectedColor WRITE setChildTextSelectedColor)
    Q_PROPERTY(QColor childTextHoverColor READ getChildTextHoverColor WRITE setChildTextHoverColor)

    Q_PROPERTY(ExpendMode expendMode READ getExpendMode WRITE setExpendMode)

    //Node Expansion Mode
    enum ExpendMode {
        ExpendMode_SingleClick = 0, //Click mode
        ExpendMode_DoubleClick = 1, //Double-click mode
        ExpendMode_NoClick = 2,     //Can't double-click

    NavListView(QWidget *parent = 0);

    NavModel *model;                //data model
    NavDelegate *delegate;          //Data delegation
    QStringList parentItem;         //Parent node data set
    QList<QStringList> childItem;   //Subnode data

    QString items;                  //Node Set
    bool rightIconVisible;          //Is the right icon displayed?
    bool tipVisible;                //Whether to display prompt information
    int tipWidth;                   //Width of prompt information

    bool separateVisible;           //Whether to display line separators
    int separateHeight;             //Line separator height
    QColor separateColor;           //Line separator color

    bool lineLeft;                  //Is it displayed on the left?
    bool lineVisible;               //Whether to display lines or not
    int lineWidth;                  //linewidth
    QColor lineColor;               //line color

    bool triangleLeft;              //Is it displayed on the left?
    bool triangleVisible;           //Whether to display triangles
    int triangleWidth;              //Triangle width
    QColor triangleColor;           //Triangle color

    int parentIconMargin;           //Parent node icon margin
    int parentMargin;               //Parent node margin
    int parentFontSize;             //Font size of parent node
    int parentHeight;               //Parent node height
    QColor parentBgNormalColor;     //Normal background color of parent node
    QColor parentBgSelectedColor;   //Select background color for parent node
    QColor parentBgHoverColor;      //Hovering background color of parent node
    QColor parentTextNormalColor;   //Normal text color of parent node
    QColor parentTextSelectedColor; //Selection of Chinese Character Color by Parent Node
    QColor parentTextHoverColor;    //Hovering text color of parent node

    int childIconMargin;            //Subnode icon margin
    int childMargin;                //Subnode margin
    int childFontSize;              //Subnode font size
    int childHeight;                //Subnode Height
    QColor childBgNormalColor;      //Normal background color of child node
    QColor childBgSelectedColor;    //Select background color for child node
    QColor childBgHoverColor;       //Hovering background color of child node
    QColor childTextNormalColor;    //Normal text color of child node
    QColor childTextSelectedColor;  //Subnode Selects Chinese Character Color
    QColor childTextHoverColor;     //Subnode Hovering Text Color

    ExpendMode expendMode;          //Node Expansion Mode Click/Double Click/Disable

private slots:
    void pressed(const QModelIndex &data);
    void setData(const QStringList &listItems);

    QString getItems()              const;
    bool getRightIconVisible()      const;
    bool getTipVisible()            const;
    int getTipWidth()               const;

    bool getSeparateVisible()       const;
    int getSeparateHeight()         const;
    QColor getSeparateColor()       const;

    bool getLineLeft()              const;
    bool getLineVisible()           const;
    int getLineWidth()              const;
    QColor getLineColor()           const;

    bool getTriangleLeft()          const;
    bool getTriangleVisible()       const;
    int getTriangleWidth()          const;
    QColor getTriangleColor()       const;

    int getParentIconMargin()       const;
    int getParentMargin()           const;
    int getParentFontSize()         const;
    int getParentHeight()           const;
    QColor getParentBgNormalColor() const;
    QColor getParentBgSelectedColor()const;
    QColor getParentBgHoverColor()  const;
    QColor getParentTextNormalColor()const;
    QColor getParentTextSelectedColor()const;
    QColor getParentTextHoverColor()const;

    int getChildIconMargin()        const;
    int getChildMargin()            const;
    int getChildFontSize()          const;
    int getChildHeight()            const;
    QColor getChildBgNormalColor()  const;
    QColor getChildBgSelectedColor()const;
    QColor getChildBgHoverColor()   const;
    QColor getChildTextNormalColor()const;
    QColor getChildTextSelectedColor()const;
    QColor getChildTextHoverColor() const;

    ExpendMode getExpendMode()      const;

    QSize sizeHint()                const;
    QSize minimumSizeHint()         const;

public Q_SLOTS:
    //Setting node data
    void setItems(const QString &items);
    //Set the selected row
    void setCurrentRow(int row);
    //Set whether the icon on the right side of the parent node is displayed
    void setRightIconVisible(bool rightIconVisible);

    //Set whether prompt information is displayed + width
    void setTipVisible(bool tipVisible);
    void setTipWidth(int tipWidth);

    //Set whether the line separator displays + height + Color
    void setSeparateVisible(bool separateVisible);
    void setSeparateHeight(int separateHeight);
    void setSeparateColor(const QColor &separateColor);

    //Set line position + visibility + width + Color
    void setLineLeft(bool lineLeft);
    void setLineVisible(bool lineVisible);
    void setLineWidth(int lineWidth);
    void setLineColor(const QColor &lineColor);

    //Set triangle position + visibility + width + Color
    void setTriangleLeft(bool triangleLeft);
    void setTriangleVisible(bool triangleVisible);
    void setTriangleWidth(int triangleWidth);
    void setTriangleColor(const QColor &triangleColor);

    //Set parent node icon margin + left margin + font size + node height + color set
    void setParentIconMargin(int parentIconMargin);
    void setParentMargin(int parentMargin);
    void setParentFontSize(int parentFontSize);
    void setParentHeight(int parentHeight);
    void setParentBgNormalColor(const QColor &parentBgNormalColor);
    void setParentBgSelectedColor(const QColor &parentBgSelectedColor);
    void setParentBgHoverColor(const QColor &parentBgHoverColor);
    void setParentTextNormalColor(const QColor &parentTextNormalColor);
    void setParentTextSelectedColor(const QColor &parentTextSelectedColor);
    void setParentTextHoverColor(const QColor &parentTextHoverColor);

    //Setting child node icon margin + left margin + font size + node height + color set
    void setChildIconMargin(int childIconMargin);
    void setChildMargin(int childMargin);
    void setChildFontSize(int childFontSize);
    void setChildHeight(int childHeight);
    void setChildBgNormalColor(const QColor &childBgNormalColor);
    void setChildBgSelectedColor(const QColor &childBgSelectedColor);
    void setChildBgHoverColor(const QColor &childBgHoverColor);
    void setChildTextNormalColor(const QColor &childTextNormalColor);
    void setChildTextSelectedColor(const QColor &childTextSelectedColor);
    void setChildTextHoverColor(const QColor &childTextHoverColor);

    //Setting Node Expansion Mode
    void setExpendMode(const ExpendMode &expendMode);

    void pressed(const QString &text, const QString &parentText);
    void pressed(int index, int parentIndex);
    void pressed(int childIndex);


V. Core Code

void NavDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
    NavModel::TreeNode *node = (NavModel::TreeNode *)index.data(Qt::UserRole).toULongLong();

    //Define variable storage areas
    QRect optionRect = option.rect;
    int x = optionRect.x();
    int y = optionRect.y();
    int width = optionRect.width();
    int height = optionRect.height();

    int fontSize = nav->getParentFontSize();

    //Separate color settings for parent and child nodes
    bool parent = (node->level == 1);

    //Set different colors according to different states: bgColor - main background color textColor - main text color tipBgColor - hint information background color tipTextColor - hint information text color
    QColor bgColor, textColor, tipBgColor, tipTextColor, iconColor;
    if (option.state & QStyle::State_Selected) {
        bgColor = parent ? nav->getParentBgSelectedColor() : nav->getChildBgSelectedColor();
        textColor = parent ? nav->getParentTextSelectedColor() : nav->getChildTextSelectedColor();
        tipBgColor = parent ? nav->getParentTextSelectedColor() : nav->getChildTextSelectedColor();
        tipTextColor = parent ? nav->getParentBgSelectedColor() : nav->getChildBgSelectedColor();
        iconColor = parent ? nav->getParentTextSelectedColor() : nav->getChildTextSelectedColor();
    } else if (option.state & QStyle::State_MouseOver) {
        bgColor = parent ? nav->getParentBgHoverColor() : nav->getChildBgHoverColor();
        textColor = parent ? nav->getParentTextHoverColor() : nav->getChildTextHoverColor();
        tipBgColor = parent ? nav->getParentTextSelectedColor() : nav->getChildTextSelectedColor();
        tipTextColor = parent ? nav->getParentBgSelectedColor() : nav->getChildBgSelectedColor();
        iconColor = parent ? nav->getParentTextHoverColor() : nav->getChildTextHoverColor();
    } else {
        bgColor = parent ? nav->getParentBgNormalColor() : nav->getChildBgNormalColor();
        textColor = parent ? nav->getParentTextNormalColor() : nav->getChildTextNormalColor();
        tipBgColor = parent ? nav->getParentBgSelectedColor() : nav->getChildBgSelectedColor();
        tipTextColor = parent ? nav->getParentTextSelectedColor() : nav->getChildTextSelectedColor();
        iconColor = parent ? nav->getParentTextNormalColor() : nav->getChildTextNormalColor();

    //Drawing Background
    painter->fillRect(optionRect, bgColor);

    //Drawing lines, currently limited to child nodes to draw, if the parent node is also required to draw, then cancel parent judgment can be
    int lineWidth = nav->getLineWidth();
    if (!parent && nav->getLineVisible() && lineWidth > 0) {
        if ((option.state & QStyle::State_Selected) || (option.state & QStyle::State_MouseOver)) {
            //Set the offset, otherwise the upper and lower parts will be a little offset.
            float offset = (float)lineWidth / 2;

            //Computing the upper and lower coordinate points
            QPointF pointTop(x, y + offset);
            QPointF pointBottom(x, height + y - offset);
            if (!nav->getLineLeft()) {

            //Set line color and width
            painter->setPen(QPen(nav->getLineColor(), lineWidth));
            painter->drawLine(pointTop, pointBottom);

    //Drawing a triangle, currently limited to child node drawing, if the parent node is also required to draw, then cancel parent judgment can be
    int triangleWidth = nav->getTriangleWidth();
    if (!parent && nav->getTriangleVisible() && triangleWidth > 0) {
        if ((option.state & QStyle::State_Selected) || (option.state & QStyle::State_MouseOver)) {
            QFont font = iconFont;
            font.setPixelSize(fontSize + triangleWidth);

            //Drawing Triangle in Graphic Font
            if (nav->getTriangleLeft()) {
                painter->drawText(optionRect, Qt::AlignLeft | Qt::AlignVCenter, QChar(0xf0da));
            } else {
                painter->drawText(optionRect, Qt::AlignRight | Qt::AlignVCenter, QChar(0xf0d9));

    //Draw line separators
    if (nav->getSeparateVisible()) {
        if (node->level == 1 || (node->level == 2 && node->last)) {
            painter->setPen(QPen(nav->getSeparateColor(), nav->getSeparateHeight()));
            painter->drawLine(QPointF(x, y + height), QPointF(x + width, y + height));

    //Draw text, not if it is empty
    QString text = node->text;
    if (!text.isEmpty()) {
        //Distance from text to left + font size
        int margin = nav->getParentMargin();
        if (node->level == 2) {
            margin = nav->getChildMargin();
            fontSize = nav->getChildFontSize();

        //Computing text areas
        QRect textRect = optionRect;
        textRect.setWidth(width - margin);
        textRect.setX(x + margin);

        QFont font;
        painter->drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, text);

    //Draw the prompt information, not if you don't need to display the prompt information or if the prompt information is empty
    QString tip = node->tip;
    if (nav->getTipVisible() && !tip.isEmpty()) {
        //If it is a number, the number over 999 will be displayed as 999.+
        //If the length of the prompt message displayed is too long, the redundancy will be displayed as an ellipsis sign.
        if (tip.toInt() > 0) {
            tip = tip.toInt() > 999 ? "999+" : tip;
        } else if (tip.length() > 2) {
            tip = tip.left(2) + " .";

        //Calculate the plotted area with a radius of one fourth of the height
        int radius = height / 4;
        QRect tipRect = optionRect;
        tipRect.setHeight(radius * 2);
        tipRect.setLeft(optionRect.right() - nav->getTipWidth() - 5);
        tipRect.setRight(optionRect.right() - 5);

        //Set font size
        QFont font;
        font.setPixelSize(fontSize - 2);

        //Drawing the background of the prompt text
        painter->drawRoundedRect(tipRect, radius, radius);

        //Draw prompt text
        painter->drawText(tipRect, Qt::AlignCenter, tip);

    //Calculate the drawing icon area
    QRect iconRect = optionRect;
    iconRect.setLeft(parent ? nav->getParentIconMargin() : nav->getChildIconMargin());

    //Setting graphics fonts and brush colors
    QFont font = iconFont;

    //Draw icons on the left, icons on the left, and if not, the parent form.+-
    if (!node->icon.isNull()) {
        painter->drawText(iconRect, Qt::AlignLeft | Qt::AlignVCenter, node->icon);
    } else if (parent) {
        if (node->expand) {
            painter->drawText(iconRect, Qt::AlignLeft | Qt::AlignVCenter, QChar(0xf067));
        } else {
            painter->drawText(iconRect, Qt::AlignLeft | Qt::AlignVCenter, QChar(0xf068));

    //Draw the icon on the right of the parent node
    iconRect.setRight(optionRect.width() - 10);
    if (!(nav->getTipVisible() && !node->tip.isEmpty()) && nav->getRightIconVisible() && parent) {
        if (node->expand) {
            painter->drawText(iconRect, Qt::AlignRight | Qt::AlignVCenter, QChar(0xf054));
        } else {
            painter->drawText(iconRect, Qt::AlignRight | Qt::AlignVCenter, QChar(0xf078));

Introduction of Control

  1. More than 150 exquisite controls, covering a variety of dashboards, progress bars, progress balls, compasses, curves, rulers, thermometers, navigation bars, navigation bars, flatui, highlighted buttons, sliding selectors, lunar calendar, etc. Far more controls than qwt integrates.
  2. Each class can be separated into a separate control, zero-coupling, each control has a header file and an implementation file, independent of other files, to facilitate the integration of a single control in the form of source code into the project, less code. The control classes of qwt are interlinked and highly coupled. If you want to use one of the controls, you must include all the code.
  3. All pure Qt writing, QWidget+QPainter drawing, support any Qt version from Qt4.6 to Qt5.12, support mingw, msvc, gcc and other compilers, support any operating system such as windows+linux+mac + embedded linux, no scrambling, can be directly integrated into Qt Creator, as with its own controls, most of the effects as long as set up. Several attributes can be used, which is very convenient.
  4. Each control has a corresponding separate DEMO containing the source code of the control, which is convenient for reference. It also provides an integrated DEMO for all controls.
  5. The source code of each control has detailed Chinese annotations, which are compiled in accordance with the unified design specifications. It is convenient to learn how to compile custom controls.
  6. Each control's default color matching and demo's corresponding color matching are very beautiful.
  7. More than 130 visible controls and 6 invisible controls.
  8. Some controls provide a variety of style choices, a variety of indicator style choices.
  9. All controls adapt to form stretching changes.
  10. Integrate custom control property designer, support drag design, WYSIWYG, support import and export xml format.
  11. With activex control demo, all controls can run directly in ie browser.
  12. Integrate fontawesome graphic fonts + hundreds of graphic fonts collected by Alibaba iconfont to enjoy the fun of graphic fonts.
  13. All controls finally generate a dll Dynamic Library file, which can be directly integrated into the qtcreator for dragging design use.
  14. At present, there is a version of qml, pyqt version will be considered later, if the user demand is large.

7. SDK Download

  • SDK Download Link: https://pan.baidu.com/s/1A5Gd77kExm8Co5ckT51vvQ Extraction code: 877p
  • The download link contains various versions of dynamic library files, header files of all controls, using demo, custom control + property designer.
  • Custom control plug-in open dynamic library dll use (permanent free), without any back door and restrictions, please feel free to use.
  • At present, 26 versions of dll have been provided, including qt5.12.3 MSVC 2017 32 + 64 MinGW 32 + 64.
  • Increase control and improve control from time to time, update SDK from time to time. Welcome to make suggestions. Thank you!
  • widget version (QQ: 517216493) qml version (QQ: 373955953) camel (QQ: 278969898).
  • The Way to Advance Qt in Taoge's Knowledge Column https://zhuanlan.zhihu.com/TaoQt
  • Welcome to pay attention to Wechat Public Number, C++/Python, learning methods, writing skills, popular technology, career development and other content, more dry goods, more benefits!
  • Qt introductory books recommend Hoyafei's Quick Start to Qt Creator, Qt5 Programming Introduction, and Qt advanced books recommend the official C++ GUI Qt4 Programming.
  • I strongly recommend programmers'self-cultivation and planning series "Talking about Programmers", "Programmers' Growth Course" and "Solution Programmers". They benefit a lot and benefit a lifetime!

Posted by mikeyca on Fri, 09 Aug 2019 00:11:37 -0700