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. QTreeView ghost select parent if child selected?

QTreeView ghost select parent if child selected?

Scheduled Pinned Locked Moved Solved General and Desktop
qtreeview
9 Posts 3 Posters 2.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.
  • D Offline
    D Offline
    Dariusz
    wrote on last edited by
    #1

    Hey

    I'd like to implement the behavior in the topic... any idea? at all? I'm lost O_O

    Right now if I select items programmatically, I would not know that they are selected because if their parent is not expanded there is no indication of any selection... What can I do?

    TIA

    1 Reply Last reply
    0
    • SGaistS Offline
      SGaistS Offline
      SGaist
      Lifetime Qt Champion
      wrote on last edited by
      #2

      Hi,

      What about expending the branch of your programmatically selected items ?

      Interested in AI ? www.idiap.ch
      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

      D 1 Reply Last reply
      0
      • SGaistS SGaist

        Hi,

        What about expending the branch of your programmatically selected items ?

        D Offline
        D Offline
        Dariusz
        wrote on last edited by
        #3

        @SGaist Sadly that wont do. User may not want to expand the items, Only see which parent groups they in perhaps?

        1 Reply Last reply
        0
        • SGaistS Offline
          SGaistS Offline
          SGaist
          Lifetime Qt Champion
          wrote on last edited by
          #4

          Can you explain how such a selection may happen ?

          Interested in AI ? www.idiap.ch
          Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

          D 1 Reply Last reply
          0
          • SGaistS SGaist

            Can you explain how such a selection may happen ?

            D Offline
            D Offline
            Dariusz
            wrote on last edited by
            #5

            @SGaist said in QTreeView ghost select parent if child selected?:

            Can you explain how such a selection may happen ?

            Hey

            Its implemented in quite few 3d apps. One of them Autodesk Maya > https://youtu.be/8gRBwGafHfg?t=96

            You can see if child is selected the parent is then "half" selected...

            I have some rough ideas on how to handle it but they all sound pretty bad so far...

            1 Reply Last reply
            0
            • VRoninV Offline
              VRoninV Offline
              VRonin
              wrote on last edited by VRonin
              #6
              #include <QApplication>
              #include <QTreeWidget>
              #include <QStyledItemDelegate>
              #include <QItemSelectionModel>
              class ChildSelectDelegate : public QStyledItemDelegate{
                  //Q_OBJECT
                  Q_DISABLE_COPY(ChildSelectDelegate)
              public:
                  explicit ChildSelectDelegate(QObject *parent = Q_NULLPTR)
                      :QStyledItemDelegate(parent)
                      ,m_selModel(Q_NULLPTR)
                  {}
                  void setSelectionModel(QItemSelectionModel* selModel){m_selModel=selModel;}
                  void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE{
                      Q_ASSERT(index.isValid());
                      QStyleOptionViewItem opt = option;
                      initStyleOption(&opt, index);
                      const QWidget *widget = option.widget;
                      if(!(opt.state & QStyle::State_Selected) && m_selModel && m_selModel->model() == index.model()){
                          if(childrenSelected(index)){
                              const QPalette::ColorGroup cg = (widget ? widget->isEnabled() : (opt.state & QStyle::State_Enabled)) ? QPalette::Normal : QPalette::Disabled;
                              QBrush darkHighLight = opt.palette.brush(cg, QPalette::Highlight);
                              const QColor oldCol = darkHighLight.color();
                              darkHighLight.setColor(QColor(oldCol.red()*3/4,oldCol.green()*3/4,oldCol.blue()*3/4,oldCol.alpha()));
                              opt.backgroundBrush = darkHighLight;
                          }
                      }
                      QStyle *style =  widget ? widget->style() : QApplication::style();
                      style->drawControl(QStyle::CE_ItemViewItem, &opt, painter, widget);
                  }
              private:
                  QItemSelectionModel* m_selModel;
                  bool childrenSelected(const QModelIndex &index) const{
                      Q_ASSERT(m_selModel);
                      Q_ASSERT(m_selModel->model() == index.model());
                      for(int i=0, maxRow = index.model()->rowCount(index);i<maxRow;++i){
                          for(int j=0, maxCol = index.model()->columnCount(index);j<maxCol;++j){
                              const QModelIndex currIdx = index.model()->index(i,j,index);
                              if(m_selModel->isSelected(currIdx))
                                  return true;
                              if(index.model()->hasChildren(currIdx)){
                                  if(childrenSelected(currIdx))
                                      return true;
                              }
                          }
                      }
                      return false;
                  }
              };
              
              int main(int argc, char **argv)
              {
                  QApplication app(argc,argv);
                  QTreeWidget wid;
                  wid.model()->insertRows(0,2);
                  const QModelIndex parentIdx = wid.model()->index(0,0);
                  wid.model()->setData(parentIdx,"Thomas");
                  wid.model()->insertRows(0,2,parentIdx);
                  wid.model()->setData(wid.model()->index(0,0,parentIdx),"Bob");
                  wid.model()->setData(wid.model()->index(1,0,parentIdx),"Alice");
                  wid.model()->setData(wid.model()->index(1,0),"Richard");
              
                  ChildSelectDelegate* deleg = new ChildSelectDelegate(&wid);
                  deleg->setSelectionModel(wid.selectionModel());
                  wid.setItemDelegate(deleg);
                  QObject::connect(wid.selectionModel(),&QItemSelectionModel::selectionChanged,&wid,[&wid](const QItemSelection &selected,const QItemSelection &deselected)->void{
                      for (const QItemSelection &itemSelection : {selected,deselected} ){
                          const QModelIndexList itemSelectionIdx = itemSelection.indexes();
                          for(const QModelIndex& idx : itemSelectionIdx){
                              for (QModelIndex parIdx = idx.parent();parIdx.isValid();parIdx=parIdx.parent())
                                  wid.update(parIdx);
                          }
              
                      }
                  });
                  wid.show();
                  return app.exec();
              }
              

              2 notes:

              • the line darkHighLight.setColor... is the one that determines the color of the half-selection
              • You should move ChildSelectDelegate in its own header/source files. if you do, uncomment Q_OBJECT

              "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
              ~Napoleon Bonaparte

              On a crusade to banish setIndexWidget() from the holy land of Qt

              D 1 Reply Last reply
              2
              • VRoninV VRonin
                #include <QApplication>
                #include <QTreeWidget>
                #include <QStyledItemDelegate>
                #include <QItemSelectionModel>
                class ChildSelectDelegate : public QStyledItemDelegate{
                    //Q_OBJECT
                    Q_DISABLE_COPY(ChildSelectDelegate)
                public:
                    explicit ChildSelectDelegate(QObject *parent = Q_NULLPTR)
                        :QStyledItemDelegate(parent)
                        ,m_selModel(Q_NULLPTR)
                    {}
                    void setSelectionModel(QItemSelectionModel* selModel){m_selModel=selModel;}
                    void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE{
                        Q_ASSERT(index.isValid());
                        QStyleOptionViewItem opt = option;
                        initStyleOption(&opt, index);
                        const QWidget *widget = option.widget;
                        if(!(opt.state & QStyle::State_Selected) && m_selModel && m_selModel->model() == index.model()){
                            if(childrenSelected(index)){
                                const QPalette::ColorGroup cg = (widget ? widget->isEnabled() : (opt.state & QStyle::State_Enabled)) ? QPalette::Normal : QPalette::Disabled;
                                QBrush darkHighLight = opt.palette.brush(cg, QPalette::Highlight);
                                const QColor oldCol = darkHighLight.color();
                                darkHighLight.setColor(QColor(oldCol.red()*3/4,oldCol.green()*3/4,oldCol.blue()*3/4,oldCol.alpha()));
                                opt.backgroundBrush = darkHighLight;
                            }
                        }
                        QStyle *style =  widget ? widget->style() : QApplication::style();
                        style->drawControl(QStyle::CE_ItemViewItem, &opt, painter, widget);
                    }
                private:
                    QItemSelectionModel* m_selModel;
                    bool childrenSelected(const QModelIndex &index) const{
                        Q_ASSERT(m_selModel);
                        Q_ASSERT(m_selModel->model() == index.model());
                        for(int i=0, maxRow = index.model()->rowCount(index);i<maxRow;++i){
                            for(int j=0, maxCol = index.model()->columnCount(index);j<maxCol;++j){
                                const QModelIndex currIdx = index.model()->index(i,j,index);
                                if(m_selModel->isSelected(currIdx))
                                    return true;
                                if(index.model()->hasChildren(currIdx)){
                                    if(childrenSelected(currIdx))
                                        return true;
                                }
                            }
                        }
                        return false;
                    }
                };
                
                int main(int argc, char **argv)
                {
                    QApplication app(argc,argv);
                    QTreeWidget wid;
                    wid.model()->insertRows(0,2);
                    const QModelIndex parentIdx = wid.model()->index(0,0);
                    wid.model()->setData(parentIdx,"Thomas");
                    wid.model()->insertRows(0,2,parentIdx);
                    wid.model()->setData(wid.model()->index(0,0,parentIdx),"Bob");
                    wid.model()->setData(wid.model()->index(1,0,parentIdx),"Alice");
                    wid.model()->setData(wid.model()->index(1,0),"Richard");
                
                    ChildSelectDelegate* deleg = new ChildSelectDelegate(&wid);
                    deleg->setSelectionModel(wid.selectionModel());
                    wid.setItemDelegate(deleg);
                    QObject::connect(wid.selectionModel(),&QItemSelectionModel::selectionChanged,&wid,[&wid](const QItemSelection &selected,const QItemSelection &deselected)->void{
                        for (const QItemSelection &itemSelection : {selected,deselected} ){
                            const QModelIndexList itemSelectionIdx = itemSelection.indexes();
                            for(const QModelIndex& idx : itemSelectionIdx){
                                for (QModelIndex parIdx = idx.parent();parIdx.isValid();parIdx=parIdx.parent())
                                    wid.update(parIdx);
                            }
                
                        }
                    });
                    wid.show();
                    return app.exec();
                }
                

                2 notes:

                • the line darkHighLight.setColor... is the one that determines the color of the half-selection
                • You should move ChildSelectDelegate in its own header/source files. if you do, uncomment Q_OBJECT
                D Offline
                D Offline
                Dariusz
                wrote on last edited by
                #7

                @VRonin Wow this is incredible!!!

                Will test it asap!

                Thanks so much @_@

                1 Reply Last reply
                0
                • VRoninV Offline
                  VRoninV Offline
                  VRonin
                  wrote on last edited by
                  #8

                  easier but requires your model to support multiple roles:

                  #include <QApplication>
                  #include <QTreeWidget>
                  #include <QItemSelectionModel>
                  int main(int argc, char **argv)
                  {
                      QApplication app(argc,argv);
                      QTreeWidget wid;
                      wid.model()->insertRows(0,2);
                      const QModelIndex parentIdx = wid.model()->index(0,0);
                      wid.model()->setData(parentIdx,"Thomas");
                      wid.model()->insertRows(0,2,parentIdx);
                      wid.model()->setData(wid.model()->index(0,0,parentIdx),"Bob");
                      wid.model()->setData(wid.model()->index(1,0,parentIdx),"Alice");
                      wid.model()->setData(wid.model()->index(1,0),"Richard");
                  
                      QObject::connect(wid.selectionModel(),&QItemSelectionModel::selectionChanged,&wid,[&wid](const QItemSelection &selected,const QItemSelection &deselected)->void{
                          const QBrush ghostBrush(Qt::lightGray);
                          QModelIndexList itemSelectionIdx = selected.indexes();
                          for(const QModelIndex& idx : qAsConst(itemSelectionIdx)){
                              for (QModelIndex parIdx = idx.parent();parIdx.isValid();parIdx=parIdx.parent()){
                                  if(!wid.selectionModel()->isSelected(parIdx))
                                      wid.model()->setData(parIdx,ghostBrush,Qt::BackgroundRole);
                              }
                          }
                          itemSelectionIdx = deselected.indexes();
                          for(const QModelIndex& idx : qAsConst(itemSelectionIdx)){
                              for (QModelIndex parIdx = idx.parent();parIdx.isValid();parIdx=parIdx.parent())
                                  wid.model()->setData(parIdx,QVariant(),Qt::BackgroundRole);
                          }
                      });
                      wid.show();
                      return app.exec();
                  }
                  

                  "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
                  ~Napoleon Bonaparte

                  On a crusade to banish setIndexWidget() from the holy land of Qt

                  1 Reply Last reply
                  2
                  • D Offline
                    D Offline
                    Dariusz
                    wrote on last edited by
                    #9

                    Well my ASAP took a lot longer than I thought... anyway I went with Method 1 and it works like charm! Thank you so much!

                    The only thing I had to tweak was to call update() at the end of mouse release, as apparently, the selection flag in my scenario was happening after selection, so when the painter was painting items the child was not marked selected... after that it all tick!

                    TIA!

                    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