Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Highlighting selected row to be Bold in QTreeView
QtWS25 Last Chance

Highlighting selected row to be Bold in QTreeView

Scheduled Pinned Locked Moved Solved General and Desktop
21 Posts 5 Posters 3.6k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • S Offline
    S Offline
    sogo
    wrote on last edited by
    #1

    Hi,
    I'm working on highlighting a selected row in QTreeView bold when double clicked or to be specific through using index of that row selected. As this is an old issue and there are multiple solutions online that I found, I started using QStyledItemDelegate by sub-classing it and using it's paint function.
    In my main window, I have separate class "TreeView" which holds QTreeView widget and in that I'm calling another class "FileSystem" that has sub-classed QStyleItemDelegate.
    Here is the code of TreeView:
    TreeView.h

    #include <QFileSystemModel>
    #include <QModelIndex>
    #include <QDebug>
    #include <QStyledItemDelegate>
    
    #include "filesystem.h"
    namespace Ui {
    class TreeView;
    }
    
    class TreeView : public QWidget
    {
        Q_OBJECT
    
    public:
        explicit TreeView(QWidget *parent = nullptr);
        ~TreeView();
        void openFile(const QString& folderPath);
        QFileSystemModel *myModel;
        FileSystem *ite;
    
    public slots:
        void onClick(const QModelIndex&);
    
    private:
        Ui::TreeView *ui;
    };
    
    #endif // TREEVIEW_H
    

    TreeView.cpp

    #include "TreeView.h"
    #include "ui_TreeView.h"
    
    TreeView::TreeView(QWidget *parent) :
        QWidget(parent),
        ui(new Ui::TreeView)
    {
        ui->setupUi(this);
        myModel = new QFileSystemModel;
        ite = new FileSystem;
        connect( ui->treeView, SIGNAL(doubleClicked(const QModelIndex&)), this, SLOT( onClick(const QModelIndex&) ) );
    }
    
    TreeView::~TreeView()
    {
        delete ui;
        delete ite;
        delete myModel;
    }
    
    void TreeView::openFile(const QString& folderPath)
    
    {
    myModel->setRootPath(folderPath);
    QModelIndex index = myModel->index(folderPath);
    myModel->setFilter(QDir::NoDotAndDotDot | QDir::AllDirs);
    ui->treeView->setModel(myModel);
    ui->treeView->setRootIndex(index);
    ui->treeView -> expand(index);
    
    }
    
    void TreeView::onClick(const QModelIndex &index)
    {
        ui->treeView->setItemDelegateForRow(index.row(),ite);
    }
    

    FileSystem.h

    #ifndef FILESYSTEM_H
    #define FILESYSTEM_H
    #include <QFileSystemModel>
    #include <QStyledItemDelegate>
    class FileSystem: public QStyledItemDelegate
    {
    public:
        FileSystem();
        QStyledItemDelegate *item;
        void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
    };
    
    #endif // FILESYSTEM_H
    
    

    FileSystem.cpp

    #include "filesystem.h"
    #include <QFont>
    #include <QDebug>
    #include <QBrush>
    FileSystem::FileSystem()
    {
      item = new QStyledItemDelegate;
    }
    
    void FileSystem::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
    {
        QStyleOptionViewItem opt = option;
        initStyleOption(&opt, index);
        opt.font.setBold(true);
    
        QStyledItemDelegate::paint(painter, opt, index);
    }
    

    So I'm using QAbstractItemView's function "setItemDelegateForRow(index.row(), ite)" to set custom style item delegate for that specific row. Now their are two problems I'm facing:
    1- As I'm using index.row(), it returns integer number of row which is same for the treeView child rows and all those child rows also get highlighted. Is there any option that can segregate parent from their child rows, please see image below
    1.PNG

    2- When I select another row, the previous one selected needs to get un-bold or back to default view. Is their a way to unset my custom item delegate on previously selected row

    I'm not sure if this is the best way to do it so I'm open to suggestions also. Thanks

    eyllanescE 1 Reply Last reply
    0
    • sierdzioS Offline
      sierdzioS Offline
      sierdzio
      Moderators
      wrote on last edited by
      #2

      You can probably simply use Qt::ItemDataRole::FontRole and return a bold font (in model::data() method) for the row you want to be bold..

      (Z(:^

      qwasder85Q 1 Reply Last reply
      4
      • S Offline
        S Offline
        sogo
        wrote on last edited by sogo
        #3

        @sierdzio Thanks for your quick response, do you mean that to sub-class QFileSystemModel and use it's QFileSystemModel::data function to implement QT:FontRole?

        Update: corrected typo, changed QT::DisplayRole to QT::FontRole

        sierdzioS 1 Reply Last reply
        0
        • S sogo

          @sierdzio Thanks for your quick response, do you mean that to sub-class QFileSystemModel and use it's QFileSystemModel::data function to implement QT:FontRole?

          Update: corrected typo, changed QT::DisplayRole to QT::FontRole

          sierdzioS Offline
          sierdzioS Offline
          sierdzio
          Moderators
          wrote on last edited by
          #4

          @sogo said in Highlighting selected row to be Bold in QTreeView:

          @sierdzio Thanks for your quick response, do you mean that to sub-class QFileSystemModel and use it's QFileSystemModel::data function to implement QT:FontRole?

          Update: corrected typo, changed QT::DisplayRole to QT::FontRole

          Yes, exactly.

          (Z(:^

          1 Reply Last reply
          0
          • S Offline
            S Offline
            sogo
            wrote on last edited by
            #5

            @sierdzio I also looked into it here to see how I can sub-class and modify QFileSystemModel::data() method Model/View Tutorial and tried changing my FileSystem class in this way:
            FileSystem.h

            #ifndef FILESYSTEM_H
            #define FILESYSTEM_H
            #include <QFileSystemModel>
            
            class FileSystem: public QFileSystemModel
            {
            public:
                FileSystem();
                QVariant data(const QModelIndex &index, int role) const;
                QFileSystemModel *model;
            };
            
            #endif // FILESYSTEM_H
            

            FileSystem.cpp

            #include "filesystem.h"
            #include <QFont>
            #include <QDebug>
            #include <QBrush>
            FileSystem::FileSystem()
            {
              model = new QFileSystemModel;
            }
            
            QVariant FileSystem::data(const QModelIndex &index, int role) const
            {
                int row = index.row();
                int col = index.column();
                // generate a log message when this method gets called
                qDebug() << QString("row %1, col%2, role %3")
                        .arg(row).arg(col).arg(role);
            
                switch (role) {
                case Qt::DisplayRole:
                    if (row == 0 && col == 1) return QString("<--left");
                    if (row == 1 && col == 1) return QString("right-->");
            
                    return QString("Row%1, Column%2")
                            .arg(row + 1)
                            .arg(col +1);
                case Qt::FontRole:
                    if (row == 0 && col == 0) { //change font only for cell(0,0)
                        QFont boldFont;
                        boldFont.setBold(true);
                        return boldFont;
                    }
                    break;
                }
                return QVariant();
            }
            
            
            Now I have changed in my TreeView.h class to use FileSystem as the model. The issue with this one is I'm operating on separate rows, isn't the model applied to whole TreeView? The advantage I saw style item delegate was that I can do it for one row. Also do I have to re-implement all the QFileSystem:data() method as if I remove the QT::DisplayRole from above code, the output treeView shows empty with just arrow icons.
            1 Reply Last reply
            0
            • sierdzioS Offline
              sierdzioS Offline
              sierdzio
              Moderators
              wrote on last edited by sierdzio
              #6

              @sogo said in Highlighting selected row to be Bold in QTreeView:

              Now I have changed in my TreeView.h class to use FileSystem as the model. The issue with this one is I'm operating on separate rows, isn't the model applied to whole TreeView?

              The model is all QTreeView "knows", that's where it gets all the data from.

              The data() method is called by the view per item when it needs to read data. So, whenever you scroll, highlight, modify, update the view (or change the model), data() will be called - multiple times. View calls it foe every cell which was affected by the change.

              The advantage I saw style item delegate was that I can do it for one row. Also do I have to re-implement all the QFileSystem:data() method as if I remove the QT::DisplayRole from above code, the output treeView shows empty with just arrow icons.

              No you don't need to reimplement QFileSystem:data(), just simply call it ;-)

              QVariant FileSystem::data(const QModelIndex &index, int role) const
              {
                const bool shouldBeBold = (row == 0 && col == 0);
                if (role == Qt::FontRole && shouldBeBold) {
                  Font boldFont;
                  boldFont.setBold(true);
                  return boldFont;
                } else {
                  return QFileSystem::data(index, role); // This will call the original QFileSystem::data method
                }
              }
              

              (Z(:^

              JonBJ 1 Reply Last reply
              3
              • sierdzioS sierdzio

                @sogo said in Highlighting selected row to be Bold in QTreeView:

                Now I have changed in my TreeView.h class to use FileSystem as the model. The issue with this one is I'm operating on separate rows, isn't the model applied to whole TreeView?

                The model is all QTreeView "knows", that's where it gets all the data from.

                The data() method is called by the view per item when it needs to read data. So, whenever you scroll, highlight, modify, update the view (or change the model), data() will be called - multiple times. View calls it foe every cell which was affected by the change.

                The advantage I saw style item delegate was that I can do it for one row. Also do I have to re-implement all the QFileSystem:data() method as if I remove the QT::DisplayRole from above code, the output treeView shows empty with just arrow icons.

                No you don't need to reimplement QFileSystem:data(), just simply call it ;-)

                QVariant FileSystem::data(const QModelIndex &index, int role) const
                {
                  const bool shouldBeBold = (row == 0 && col == 0);
                  if (role == Qt::FontRole && shouldBeBold) {
                    Font boldFont;
                    boldFont.setBold(true);
                    return boldFont;
                  } else {
                    return QFileSystem::data(index, role); // This will call the original QFileSystem::data method
                  }
                }
                
                JonBJ Offline
                JonBJ Offline
                JonB
                wrote on last edited by
                #7

                @sierdzio
                Before you confuse @sogo, you accidentally omitted the return in front of QFileSystem:data(index, role); :)

                sierdzioS 1 Reply Last reply
                3
                • JonBJ JonB

                  @sierdzio
                  Before you confuse @sogo, you accidentally omitted the return in front of QFileSystem:data(index, role); :)

                  sierdzioS Offline
                  sierdzioS Offline
                  sierdzio
                  Moderators
                  wrote on last edited by
                  #8

                  @JonB said in Highlighting selected row to be Bold in QTreeView:

                  @sierdzio
                  Before you confuse @sogo, you accidentally omitted the return in front of QFileSystem:data(index, role); :)

                  Good catch, thanks :D

                  (Z(:^

                  1 Reply Last reply
                  0
                  • sierdzioS sierdzio

                    You can probably simply use Qt::ItemDataRole::FontRole and return a bold font (in model::data() method) for the row you want to be bold..

                    qwasder85Q Offline
                    qwasder85Q Offline
                    qwasder85
                    wrote on last edited by
                    #9

                    @sierdzio This. Do this.

                    sierdzioS 1 Reply Last reply
                    0
                    • qwasder85Q qwasder85

                      @sierdzio This. Do this.

                      sierdzioS Offline
                      sierdzioS Offline
                      sierdzio
                      Moderators
                      wrote on last edited by
                      #10

                      @qwasder85 said in Highlighting selected row to be Bold in QTreeView:

                      @sierdzio This. Do this.

                      Hm?

                      (Z(:^

                      1 Reply Last reply
                      1
                      • S Offline
                        S Offline
                        sogo
                        wrote on last edited by
                        #11

                        Hi @sierdzio Oh this is new for me, please give me sometime to check and play with it a little and see how can I implement bold row on double click on any row and if I have any question, I'll ping here. Here is the updated code, were some issues in there:

                        QVariant FileSystem::data(const QModelIndex &index, int role) const
                        {
                          int row = index.row();
                          int col = index.column();
                          const bool shouldBeBold = (row == 0 && col == 0);
                          if (role == Qt::FontRole && shouldBeBold) {
                            QFont boldFont;
                            boldFont.setBold(true);
                            return boldFont;
                          } else {
                            return QFileSystemModel::data(index, role); // This will call the original QFileSystem::data method
                          }
                        }
                        

                        @JonB thanks for your update too

                        I have one question though, I was reading the QFileSystemModel source code and I didn't see any case of QT::FontRole in qfilesystemmodel.cpp "::data" method. What confuses me is that in this code this statement "if (role == QT::FontRole && shouldBeBold)", how is it checking this.

                        sierdzioS JonBJ 2 Replies Last reply
                        0
                        • S sogo

                          Hi @sierdzio Oh this is new for me, please give me sometime to check and play with it a little and see how can I implement bold row on double click on any row and if I have any question, I'll ping here. Here is the updated code, were some issues in there:

                          QVariant FileSystem::data(const QModelIndex &index, int role) const
                          {
                            int row = index.row();
                            int col = index.column();
                            const bool shouldBeBold = (row == 0 && col == 0);
                            if (role == Qt::FontRole && shouldBeBold) {
                              QFont boldFont;
                              boldFont.setBold(true);
                              return boldFont;
                            } else {
                              return QFileSystemModel::data(index, role); // This will call the original QFileSystem::data method
                            }
                          }
                          

                          @JonB thanks for your update too

                          I have one question though, I was reading the QFileSystemModel source code and I didn't see any case of QT::FontRole in qfilesystemmodel.cpp "::data" method. What confuses me is that in this code this statement "if (role == QT::FontRole && shouldBeBold)", how is it checking this.

                          sierdzioS Offline
                          sierdzioS Offline
                          sierdzio
                          Moderators
                          wrote on last edited by
                          #12

                          @sogo said in Highlighting selected row to be Bold in QTreeView:

                          I have one question though, I was reading the QFileSystemModel source code and I didn't see any case of QT::FontRole in qfilesystemmodel.cpp "::data" method.

                          In general, this flag is rarely used. I think most of the time, delegates just take default font from QPalette / QSS.

                          What confuses me is that in this code this statement "if (role == QT::FontRole && shouldBeBold)", how is it checking this.

                          I don't understand your question, sorry. How is what checking this?

                          (Z(:^

                          1 Reply Last reply
                          0
                          • S sogo

                            Hi @sierdzio Oh this is new for me, please give me sometime to check and play with it a little and see how can I implement bold row on double click on any row and if I have any question, I'll ping here. Here is the updated code, were some issues in there:

                            QVariant FileSystem::data(const QModelIndex &index, int role) const
                            {
                              int row = index.row();
                              int col = index.column();
                              const bool shouldBeBold = (row == 0 && col == 0);
                              if (role == Qt::FontRole && shouldBeBold) {
                                QFont boldFont;
                                boldFont.setBold(true);
                                return boldFont;
                              } else {
                                return QFileSystemModel::data(index, role); // This will call the original QFileSystem::data method
                              }
                            }
                            

                            @JonB thanks for your update too

                            I have one question though, I was reading the QFileSystemModel source code and I didn't see any case of QT::FontRole in qfilesystemmodel.cpp "::data" method. What confuses me is that in this code this statement "if (role == QT::FontRole && shouldBeBold)", how is it checking this.

                            JonBJ Offline
                            JonBJ Offline
                            JonB
                            wrote on last edited by JonB
                            #13

                            @sogo
                            Every model inherits https://doc.qt.io/qt-5/qabstractitemmodel.html#data. The Qt infrastructure (e.g. QTreeView) calls the model's data() method multiple times (behind the scenes), passing in the various roles listed in https://doc.qt.io/qt-5/qt.html#ItemDataRole-enum, to get all the information it wants from the model to display each item as desired. One of the roles it passes in is FontRole. Your override of data() returns a bold font if and only if you want it to be bold. In the code proposed, that is when row == 0 && col == 0, so that item (only) comes out in bold.

                            1 Reply Last reply
                            2
                            • S Offline
                              S Offline
                              sogo
                              wrote on last edited by
                              #14

                              What I mean't is we are not giving "role" as argument to call the function "QFileSystemModel::data", how does the program knows if role is equal to Qt::FontRole. Does the QFileSystemModel:data function goes to check through all the Qt::ItemDataRole?

                              JonBJ sierdzioS 2 Replies Last reply
                              0
                              • S sogo

                                What I mean't is we are not giving "role" as argument to call the function "QFileSystemModel::data", how does the program knows if role is equal to Qt::FontRole. Does the QFileSystemModel:data function goes to check through all the Qt::ItemDataRole?

                                JonBJ Offline
                                JonBJ Offline
                                JonB
                                wrote on last edited by JonB
                                #15

                                @sogo
                                Your post has crossed with my latest. Read that and see if you follow now? Yes, behind the scenes it calls your data() many times, with different values for role. You can put in a qDebug() statement, to see how many times it is called, with which row/column and with various values for role.

                                1 Reply Last reply
                                0
                                • S Offline
                                  S Offline
                                  sogo
                                  wrote on last edited by
                                  #16

                                  Hi @JonB
                                  Yea, now I get it. Thanks a lot for clarification

                                  1 Reply Last reply
                                  0
                                  • S sogo

                                    What I mean't is we are not giving "role" as argument to call the function "QFileSystemModel::data", how does the program knows if role is equal to Qt::FontRole. Does the QFileSystemModel:data function goes to check through all the Qt::ItemDataRole?

                                    sierdzioS Offline
                                    sierdzioS Offline
                                    sierdzio
                                    Moderators
                                    wrote on last edited by
                                    #17

                                    @sogo said in Highlighting selected row to be Bold in QTreeView:

                                    What I mean't is we are not giving "role" as argument to call the function "QFileSystemModel::data", how does the program knows if role is equal to Qt::FontRole. Does the QFileSystemModel:data function goes to check through all the Qt::ItemDataRole?

                                    const QModelIndex &index, int role role is there, it's the second argument.

                                    If you call data() manually and skip the role, it defaults to Qt::DisplayRole. But the view (QTreeView and others) will call data() with other roles, too, don't worry. If you want to force it (as you should in case of your double click thingy), emit dataChanged() for the row which should be bold.

                                    (Z(:^

                                    S 1 Reply Last reply
                                    0
                                    • sierdzioS sierdzio

                                      @sogo said in Highlighting selected row to be Bold in QTreeView:

                                      What I mean't is we are not giving "role" as argument to call the function "QFileSystemModel::data", how does the program knows if role is equal to Qt::FontRole. Does the QFileSystemModel:data function goes to check through all the Qt::ItemDataRole?

                                      const QModelIndex &index, int role role is there, it's the second argument.

                                      If you call data() manually and skip the role, it defaults to Qt::DisplayRole. But the view (QTreeView and others) will call data() with other roles, too, don't worry. If you want to force it (as you should in case of your double click thingy), emit dataChanged() for the row which should be bold.

                                      S Offline
                                      S Offline
                                      sogo
                                      wrote on last edited by
                                      #18

                                      @sierdzio said in Highlighting selected row to be Bold in QTreeView:

                                      If you call data() manually and skip the role, it defaults to Qt::DisplayRole.

                                      I'm not sure but whenever I have to call it manually, I have to give Qt::ItemDataRole as arg.. For now this is what I tried in my TreeView.cpp code:

                                      #include "TreeView.h"
                                      #include "ui_TreeView.h"
                                      
                                      TreeView::TreeView(QWidget *parent) :
                                          QWidget(parent),
                                          ui(new Ui::TreeView)
                                      {
                                          ui->setupUi(this);
                                          myModel = new FileSystem;
                                          connect( ui->treeView, SIGNAL(doubleClicked(const QModelIndex&)), this, SLOT( onClick(const QModelIndex&) ) );
                                      }
                                      
                                      TreeView::~TreeView()
                                      {
                                          delete ui;
                                      }
                                      
                                      void TreeView::openFile(const QString& folderPath)
                                      
                                      {
                                      myModel->setRootPath(folderPath);
                                      QModelIndex index = myModel->index(folderPath);
                                      myModel->setFilter(QDir::NoDotAndDotDot | QDir::AllDirs);
                                      ui->treeView->setModel(myModel);
                                      ui->treeView->setRootIndex(index);
                                      ui->treeView -> expand(index);
                                      }
                                      
                                      void TreeView::onClick(const QModelIndex &index)
                                      {
                                          myModel->data(index,Qt::DisplayRole);
                                      
                                      }
                                      

                                      @sierdzio said in Highlighting selected row to be Bold in QTreeView:

                                      will call data() with other roles, too, don't worry. If you want to force it (as you should in case of your double click thingy), emit dataChanged() for the row which should be bold

                                      I also tried tried creating new signal which will emit dataChanged(const QModelIndex&) and emit when double clicked signal:

                                      void TreeView::onClick(const QModelIndex &index)
                                      {
                                         emit dataChanged(index);
                                      }
                                      

                                      I'm not sure how to catch this signal in my FileSystem class so that I can connect it with data function. Another issue is if I change hard code row and columns in FileSystem::data function, it calls it everytime to populate tree view which causes rows and columns to be bold out when directory is loaded. This part.

                                      int row = index.row();
                                        int col = index.column();
                                        const bool shouldBeBold = (row && col);
                                        if (role == Qt::FontRole && shouldBeBold) {
                                      
                                      1 Reply Last reply
                                      0
                                      • sierdzioS Offline
                                        sierdzioS Offline
                                        sierdzio
                                        Moderators
                                        wrote on last edited by
                                        #19

                                        You need to change the way you think about the view and the model a bit, I think.

                                        In Qt model-view framework, there is a clear separation: the model is "the boss". The view is just a dumb "output" for data provided by the model.

                                        So for example, do not do this:

                                        void TreeView::onClick(const QModelIndex &index)
                                        {
                                            myModel->data(index,Qt::DisplayRole);
                                        }
                                        

                                        The data has not changed, so calling data() here is pointless! Instead, tell the model which row was clicked and update the data inside of the model. I mean something like:

                                        // view
                                        void TreeView::onClick(const QModelIndex &index)
                                        {
                                            myModel->rowClicked(index);
                                        }
                                        
                                        // model
                                        
                                        void FileModel::rowClicked(const QModelIndex &index)
                                        {
                                          // m_boldRow is some private member variable you add to your model class
                                          // Probably better to use QPersistentIndex here!
                                          m_boldRow = index; 
                                          emit dataChanged(index, index, Qt::FontRole);
                                        }
                                        
                                        QVariant FileSystem::data(const QModelIndex &index, int role) const
                                        {
                                          const bool shouldBeBold = (index == m_boldRow);
                                          if (role == Qt::FontRole && shouldBeBold) {
                                            QFont boldFont;
                                            boldFont.setBold(true);
                                            return boldFont;
                                          } else {
                                            return QFileSystemModel::data(index, role); // This will call the original QFileSystem::data method
                                          }
                                        }
                                        

                                        (Z(:^

                                        1 Reply Last reply
                                        3
                                        • S Offline
                                          S Offline
                                          sogo
                                          wrote on last edited by
                                          #20

                                          I see, I was trying something similar next i.e. catching the QModelIndex in FileSystem class in separate function and changing the condition inside the data function but I wasn't sure how to update the model. If I'm not wrong, the emit dataChanged() signal is doing that. Thanks for this, this is working. Closing this thread

                                          1 Reply Last reply
                                          0

                                          • Login

                                          • Login or register to search.
                                          • First post
                                            Last post
                                          0
                                          • Categories
                                          • Recent
                                          • Tags
                                          • Popular
                                          • Users
                                          • Groups
                                          • Search
                                          • Get Qt Extensions
                                          • Unsolved