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. QStyledItemDelegate highlighting Indentation space on focus?
Forum Updated to NodeBB v4.3 + New Features

QStyledItemDelegate highlighting Indentation space on focus?

Scheduled Pinned Locked Moved Solved General and Desktop
qt c++delegatehelpproblemqtreeview
19 Posts 5 Posters 2.5k Views 2 Watching
  • 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 StudentScripter

    So i created my QStyledItemDelegate and actually highlighting the delegate does work, but the identation space of my QTreeView stays white. I want the identationspace to get highlighted too.

    Here is how it looks like right now: febae6c7-5d1c-4ead-acc5-fb2bb0a8a9fa-image.png

    Ps: it would be even better if the identation space would be gone if there is no item grouped below, but still the whole entry should be highlighted blue.

    Here is my code for the delegate, please help me:
    .cpp:

    #include "ViewLayerItemDelegate.h"
    #include <QStyledItemDelegate>
    #include <QPainter>
    #include <QApplication>
    
    
    
    
    ViewLayerItemDelegate::ViewLayerItemDelegate(QObject *parent)
        : QStyledItemDelegate{parent}
    {
    
    }
    
    
    
    QWidget *ViewLayerItemDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
    {
        qDebug() << "Editor created";
        
        LineEditCheckBoxWidget *editor = new LineEditCheckBoxWidget(parent);
        if (option.state & QStyle::State_Selected) {
            //editor->setStyleSheet("background-color: lightblue;");
        }
    
       // Verbinden Sie das textChanged() Signal des LineEdits mit Ihrem Slot
        connect(editor->lineEdit, &QLineEdit::textChanged, this, &ViewLayerItemDelegate::onLineEditTextChanged);
    
    
    
        return editor;
    }
    
    
    
    
    void ViewLayerItemDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
    {
    
        
        LineEditCheckBoxWidget *widget = static_cast<LineEditCheckBoxWidget *>(editor);
    
        // Setzen Sie die Werte der SpinBox und CheckBox basierend auf den Modellwerten
        QString lineEditvalue = index.model()->data(index, Qt::EditRole).toString();
        bool checkBoxValue = index.model()->data(index, Qt::CheckStateRole).toBool();
    
        widget->lineEdit->setText(lineEditvalue);
        widget->checkBox->setChecked(checkBoxValue);
        
        
    
    
        widget->lineEdit->setFocus(Qt::MouseFocusReason); // Editor aktivieren
        widget->lineEdit->setStyleSheet("");
        widget->iconLabel->setAttribute(Qt::WA_TranslucentBackground);
        widget->setStyleSheet("background: white");
            
    }
    
    
    
    
    void ViewLayerItemDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
    {
        
        
        LineEditCheckBoxWidget *widget = static_cast<LineEditCheckBoxWidget *>(editor);
    
        
    
        // Speichern Sie die Werte der SpinBox und CheckBox im Modell
        QString lineEditvalue = widget->lineEdit->text();
        bool checkBoxValue = widget->checkBox->isChecked();
    
        model->setData(index, lineEditvalue, Qt::EditRole);
        model->setData(index, checkBoxValue ? Qt::Checked : Qt::Unchecked, Qt::CheckStateRole);
        
        qDebug() << "Model data set";
    }
    
    
    
    
    void ViewLayerItemDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
    {
        editor->setGeometry(option.rect);
    }
    
    
    
    
    QSize ViewLayerItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
    {
        
        QSize size = QStyledItemDelegate::sizeHint(option, index);
            size.setHeight(40); // Setzen Sie hier die gewünschte Höhe
        return size;
    }
    
    
    
    
    
    
    void ViewLayerItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
    {
        QStyleOptionViewItem opt = option;
        initStyleOption(&opt, index);
    
        LineEditCheckBoxWidget widget;
    
        // Setzen Sie die Werte der SpinBox und CheckBox basierend auf den Modellwerten
        QString lineEditvalue = index.model()->data(index, Qt::EditRole).toString();
        bool checkBoxValue = index.model()->data(index, Qt::CheckStateRole).toBool();
    
        widget.lineEdit->setText(lineEditvalue);
        widget.checkBox->setChecked(checkBoxValue);
    
        // Laden Sie das Icon und setzen Sie es auf das QLabel
        QPixmap iconPixmap("://resource/quick.png"); // Ersetzen Sie dies durch den Pfad zu Ihrer Icon-Datei
        QPixmap scaledPixmap = iconPixmap.scaled(32, 32, Qt::KeepAspectRatio, Qt::SmoothTransformation);
        widget.iconLabel->setPixmap(scaledPixmap);
    
       
    
        // Passen Sie das Aussehen des Widgets basierend auf der QStyleOptionViewItem an
        if (opt.state & QStyle::State_Selected) {
        
            widget.setStyleSheet("background-color: lightblue;");
            
        }else{
        qDebug() << "Test"; 
        widget.setStyleSheet("background-color: white");
        }
    
        widget.resize(option.rect.size()); // Stellen Sie sicher, dass die Größe des Widgets der Größe des Elements entspricht
    
        // Rendern Sie das Widget in den Painter
        QPixmap pixmap(widget.size());
        widget.render(&pixmap);
    
        // Zeichnen Sie das Pixmap mit dem QPainter
        painter->drawPixmap(option.rect.topLeft(), pixmap);
    }
    
    
    
    
    // Slot-Implementierung
    void ViewLayerItemDelegate::onLineEditTextChanged(const QString &text)
    {
        // Hier können Sie die gewünschte Aktion ausführen, wenn der Text im LineEdit bearbeitet wird
        qDebug() << "LineEdit text changed to:" << text;
    }
    
    
    
    
    
    
    
    
    
    void LineEditCheckBoxWidget::mousePressEvent(QMouseEvent *event)
    {
        qDebug() << "Test clicked";
    
        QWidget::mousePressEvent(event);
    }
    
    

    and here delegate.h:

    #ifndef VIEWLAYERITEMDELEGATE_H
    #define VIEWLAYERITEMDELEGATE_H
    
    #include <QStyledItemDelegate>
    #include <QModelIndex>
    #include <QObject>
    #include <QSize>
    #include <QLineEdit>
    #include <QStandardItemModel>
    #include <QCheckBox>
    #include <QFormLayout>
    #include <QLabel>
    #include <QPushButton>
    
    
    
    
    // Definieren Sie das benutzerdefinierte Widget
    class LineEditCheckBoxWidget : public QWidget {
        Q_OBJECT
    public:
        QLineEdit *lineEdit;
        QCheckBox *checkBox;
        QLabel *iconLabel;
    
    
        LineEditCheckBoxWidget(QWidget *parent = nullptr) : QWidget(parent) {
            QHBoxLayout *layout = new QHBoxLayout(this);
            layout->setContentsMargins(10,0,20,0);
            layout->setSpacing(0);
            lineEdit = new QLineEdit(this);
            checkBox = new QCheckBox(this);
            iconLabel = new QLabel(this);
    
    
            // Laden Sie das Icon und setzen Sie es auf das QLabel
            QPixmap iconPixmap("://resource/quick.png"); // Ersetzen Sie dies durch den Pfad zu Ihrer Icon-Datei
            QPixmap scaledPixmap = iconPixmap.scaled(32, 32, Qt::KeepAspectRatio, Qt::SmoothTransformation);
            iconLabel->setPixmap(scaledPixmap);
    
    
    
            layout->addWidget(iconLabel);
            layout->addSpacing(10);
            layout->addWidget(lineEdit);
            layout->addStretch(1);
            layout->addWidget(checkBox);
    
            // Zugriff auf das QLineEdit-Widget und setzen Sie den Hintergrund transparent
            lineEdit->setStyleSheet("background: transparent;");
            lineEdit->setFrame(false);
            lineEdit->setPlaceholderText("<Empty>");
    
            checkBox->setStyleSheet("background: transparent");
        }
        
        // QWidget interface
    protected:
        void mousePressEvent(QMouseEvent *event) override;
        
    signals:
    
    };
    
    
    
    
    
    
    
    class ViewLayerItemDelegate : public QStyledItemDelegate
    {
        Q_OBJECT
    public:
        explicit ViewLayerItemDelegate(QObject *parent = nullptr);
        
        
        
        QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
        void setEditorData(QWidget *editor, const QModelIndex &index) const override;
        void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override;
        void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
        
        QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override;
        void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
        
        
        
    public slots:
        
        void onLineEditTextChanged(const QString &text);
    
    
    signals:
        
        
        
        
        
        
    
    };
       
    
    #endif // VIEWLAYERITEMDELEGATE_H
    
    

    Thanks for helping, really really appreciate that. <3

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

    @StudentScripter Have you tried a simple stylesheet such as this:

    QTreeView::item:selected
    {
        background-color: red;
    }
    
    QTreeView::branch:selected
    {
        background-color: red;
    }
    

    No need to handle the painting manually.

    S 1 Reply Last reply
    0
    • qwasder85Q qwasder85

      @StudentScripter Have you tried a simple stylesheet such as this:

      QTreeView::item:selected
      {
          background-color: red;
      }
      
      QTreeView::branch:selected
      {
          background-color: red;
      }
      

      No need to handle the painting manually.

      S Offline
      S Offline
      StudentScripter
      wrote on last edited by StudentScripter
      #8

      @qwasder85 Yes thank you, i tried it but you have to know that i have implemented a paint methode for my delegate in order to display the controls as pixmap, even when the editor is not open:

      delegate.cpp:

      void ViewLayerItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
      {
          QStyleOptionViewItem opt = option;
          initStyleOption(&opt, index);
      
          LineEditCheckBoxWidget widget;
      
      
          QString lineEditvalue = index.model()->data(index, Qt::EditRole).toString();
          bool checkBoxValue = index.model()->data(index, Qt::CheckStateRole).toBool();
      
          widget.lineEdit->setText(lineEditvalue);
          widget.checkBox->setChecked(checkBoxValue);
      
      
          QPixmap iconPixmap("://resource/quick.png"); // Ersetzen Sie dies durch den Pfad zu Ihrer Icon-Datei
          QPixmap scaledPixmap = iconPixmap.scaled(32, 32, Qt::KeepAspectRatio, Qt::SmoothTransformation);
          widget.iconLabel->setPixmap(scaledPixmap);
      
         
      
          if (opt.state & QStyle::State_Selected) {
          
          widget.setStyleSheet("background-color: lightblue;");
              
          }else{
      
          widget.setStyleSheet("background-color: white");
          }
      
          widget.resize(option.rect.size()); 
      
      
          QPixmap pixmap(widget.size());
          widget.render(&pixmap);
      
          painter->drawPixmap(option.rect.topLeft(), pixmap);
      }
      
      

      implementing a stylesheet for branch highlighting in the treeview like this:

      QTreeView.cpp

      
      ViewLayerList::ViewLayerList(CustomGraphicsScene *scene, QWidget *parent)
          : QTreeView{parent}, scene_durchgereicht(scene)
      {
      
       // Setzen Sie das Stylesheet für den ausgewählten Zweig hier
          setStyleSheet("QTreeView::item:selected { background-color: yellow; }");
      }
      

      (i also tried branch, row .... isn't cutting it) always ends up looking like:
      5d4e95c2-c4fa-4f55-9f1f-a45a8b1bc58d-image.png

      vs. this with my delegate code: (so it looks like it should look like) but as @Chris-Kawa mentioned, thats not a good way to do it, so im looking for a better way instead of painting the highlight twice, once in my delegate and once in my QTreeView
      66ea05a2-eead-4a97-ab47-9926a3b3d181-image.png

      Chris KawaC 1 Reply Last reply
      0
      • S StudentScripter

        @qwasder85 Yes thank you, i tried it but you have to know that i have implemented a paint methode for my delegate in order to display the controls as pixmap, even when the editor is not open:

        delegate.cpp:

        void ViewLayerItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
        {
            QStyleOptionViewItem opt = option;
            initStyleOption(&opt, index);
        
            LineEditCheckBoxWidget widget;
        
        
            QString lineEditvalue = index.model()->data(index, Qt::EditRole).toString();
            bool checkBoxValue = index.model()->data(index, Qt::CheckStateRole).toBool();
        
            widget.lineEdit->setText(lineEditvalue);
            widget.checkBox->setChecked(checkBoxValue);
        
        
            QPixmap iconPixmap("://resource/quick.png"); // Ersetzen Sie dies durch den Pfad zu Ihrer Icon-Datei
            QPixmap scaledPixmap = iconPixmap.scaled(32, 32, Qt::KeepAspectRatio, Qt::SmoothTransformation);
            widget.iconLabel->setPixmap(scaledPixmap);
        
           
        
            if (opt.state & QStyle::State_Selected) {
            
            widget.setStyleSheet("background-color: lightblue;");
                
            }else{
        
            widget.setStyleSheet("background-color: white");
            }
        
            widget.resize(option.rect.size()); 
        
        
            QPixmap pixmap(widget.size());
            widget.render(&pixmap);
        
            painter->drawPixmap(option.rect.topLeft(), pixmap);
        }
        
        

        implementing a stylesheet for branch highlighting in the treeview like this:

        QTreeView.cpp

        
        ViewLayerList::ViewLayerList(CustomGraphicsScene *scene, QWidget *parent)
            : QTreeView{parent}, scene_durchgereicht(scene)
        {
        
         // Setzen Sie das Stylesheet für den ausgewählten Zweig hier
            setStyleSheet("QTreeView::item:selected { background-color: yellow; }");
        }
        

        (i also tried branch, row .... isn't cutting it) always ends up looking like:
        5d4e95c2-c4fa-4f55-9f1f-a45a8b1bc58d-image.png

        vs. this with my delegate code: (so it looks like it should look like) but as @Chris-Kawa mentioned, thats not a good way to do it, so im looking for a better way instead of painting the highlight twice, once in my delegate and once in my QTreeView
        66ea05a2-eead-4a97-ab47-9926a3b3d181-image.png

        Chris KawaC Offline
        Chris KawaC Offline
        Chris Kawa
        Lifetime Qt Champion
        wrote on last edited by
        #9

        @StudentScripter For painting the selection I simply meant this, without adjusting the area at all:

        if (selectionModel()->isSelected(index)) {
           painter->fillRect(options.rect, QColor(173, 216, 230));
        }
        

        The widget (or the picture of it) in the item is displayed "above" the row, so it covers whatever the view painted for the row. If you'd like to go with the approach that only view paints selection then make sure that the widget (and the picture of it) has transparent background, so the underlying row is visible.

        S 1 Reply Last reply
        1
        • Chris KawaC Chris Kawa

          @StudentScripter For painting the selection I simply meant this, without adjusting the area at all:

          if (selectionModel()->isSelected(index)) {
             painter->fillRect(options.rect, QColor(173, 216, 230));
          }
          

          The widget (or the picture of it) in the item is displayed "above" the row, so it covers whatever the view painted for the row. If you'd like to go with the approach that only view paints selection then make sure that the widget (and the picture of it) has transparent background, so the underlying row is visible.

          S Offline
          S Offline
          StudentScripter
          wrote on last edited by
          #10

          @Chris-Kawa Yes thank you very much, i have done this now. Sadly and i don't know why, suddenly the intendation space isn't painted highlighted anymore:

          69fd9d57-0953-423b-bd21-0bc3195f3162-image.png

          void ViewLayerList::drawRow(QPainter *painter, const QStyleOptionViewItem &options, const QModelIndex &index) const
          {
             
              if (selectionModel()->isSelected(index)) {
              
              // Zeichnen Sie den Einzugsbereich (Indentation) mit Ihrer gewünschten Farbe
                      QRect indentRect = visualRect(index);
                      painter->fillRect(indentRect, QColor(173, 216, 230)); // "lightblue" Hervorhebungsfarbe*/
                      
                 
                      
                  
              }
          
              
               QTreeView::drawRow(painter, options, index); // Rufen Sie die Basisimplementierung auf, um die Standardzeichnung durchzuführen
          }
          
          

          it only works when adding the stylesheet solution to the treeview constructor, but i guess thats not what you meant:
          d18bde15-6933-492c-94db-c7d1549a60d2-image.png

          
          ViewLayerList::ViewLayerList(CustomGraphicsScene *scene, QWidget *parent)
              : QTreeView{parent}, scene_durchgereicht(scene)
          {
          
          // Setzen Sie das Stylesheet für den ausgewählten Zweig hier
              setStyleSheet("QTreeView::item:selected { background-color: lightblue; }");
          
          Chris KawaC 1 Reply Last reply
          0
          • S StudentScripter

            @Chris-Kawa Yes thank you very much, i have done this now. Sadly and i don't know why, suddenly the intendation space isn't painted highlighted anymore:

            69fd9d57-0953-423b-bd21-0bc3195f3162-image.png

            void ViewLayerList::drawRow(QPainter *painter, const QStyleOptionViewItem &options, const QModelIndex &index) const
            {
               
                if (selectionModel()->isSelected(index)) {
                
                // Zeichnen Sie den Einzugsbereich (Indentation) mit Ihrer gewünschten Farbe
                        QRect indentRect = visualRect(index);
                        painter->fillRect(indentRect, QColor(173, 216, 230)); // "lightblue" Hervorhebungsfarbe*/
                        
                   
                        
                    
                }
            
                
                 QTreeView::drawRow(painter, options, index); // Rufen Sie die Basisimplementierung auf, um die Standardzeichnung durchzuführen
            }
            
            

            it only works when adding the stylesheet solution to the treeview constructor, but i guess thats not what you meant:
            d18bde15-6933-492c-94db-c7d1549a60d2-image.png

            
            ViewLayerList::ViewLayerList(CustomGraphicsScene *scene, QWidget *parent)
                : QTreeView{parent}, scene_durchgereicht(scene)
            {
            
            // Setzen Sie das Stylesheet für den ausgewählten Zweig hier
                setStyleSheet("QTreeView::item:selected { background-color: lightblue; }");
            
            Chris KawaC Offline
            Chris KawaC Offline
            Chris Kawa
            Lifetime Qt Champion
            wrote on last edited by
            #11

            @StudentScripter You're painting the wrong rectangle. Look at the code you posted and the one I did.

            S 1 Reply Last reply
            0
            • Chris KawaC Chris Kawa

              @StudentScripter You're painting the wrong rectangle. Look at the code you posted and the one I did.

              S Offline
              S Offline
              StudentScripter
              wrote on last edited by
              #12

              @Chris-Kawa Well, what a pitty, i indeed missed this. 😅 Thanks for your patience with me.

              May can i bother you again with another question related to this widget:
              I know about the setEditTriggers() but still when i set:

              setEditTriggers(QAbstractItemView::AllEditTriggers);
              

              cc121d67-2642-4c81-99ea-903f2190f42d-image.png
              Like it is now i have to doubleclick to create the editor and click a third time again to focus the line edit, thats pretty user unfriendly and wierd.

              Instead i want to double click onto the position where my lineedit is to select and focus/write into it.
              Also with the checkbox i would like to click on it and it should be ticked instantly on the first click. I guess i have to implement this logic somehow myself into QTreeView mousePressEvent, but i have no good idea on how to do that? Maybe with openpersitentEditor and than somehow set focus to the widget depending on what is under the clicked mouse position?

              Also can't say it often enough thanks for your help and the help of the others. I really doubt i would have gotten this far without. :D Also have to admit this photoeditor clone is my first big project that i set myself, of course only with basic features, but i really want to tweak them to be useful in a real world scenario.

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

                No, check the editorEvent function.

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

                S 2 Replies Last reply
                0
                • SGaistS SGaist

                  No, check the editorEvent function.

                  S Offline
                  S Offline
                  StudentScripter
                  wrote on last edited by
                  #14

                  @SGaist thanks that seems the right direction, however i cant get the mouse position to be into the checkbox. Visually it looks like i click into the check box but my debug says its not clicking into the checkbox. I tried mapping to global in order to align both positions but i had no luck with this:

                  
                  
                  bool ViewLayerItemDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index)
                  {
                      if(event->type() == QEvent::MouseButtonPress)
                      {
                          QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
                          
                          QWidget *parentWidget = qobject_cast<QWidget*>(parent());
                          if(parentWidget)
                          {
                              
                              QWidget *editor = createEditor(parentWidget, option, index);
                             
                                  LineEditCheckBoxWidget *widget = qobject_cast<LineEditCheckBoxWidget*>(editor);
                                  if(widget)
                                  {   
                                 
                                      
                                  QPoint mousePosition = widget->checkBox->mapFromGlobal(mouseEvent->globalPos());
                                  QRect checkboxGeometry = widget->checkBox->geometry();
                                  QRect globalCheckboxGeometry;
                                  globalCheckboxGeometry.setTopLeft(widget->checkBox->mapToGlobal(checkboxGeometry.topLeft()));
                                  globalCheckboxGeometry.setBottomRight(widget->checkBox->mapToGlobal(checkboxGeometry.bottomRight()));
                  
                  
                                     qDebug() << "Checkboxdata: " << globalCheckboxGeometry;
                  
                                     qDebug() << "MousePostion: " << mousePosition;
                  
                  
                                      /*
                                       //IGNORE: later i want to check here if the positon 
                                       //is the same in order to perform further actions
                                      bool checked = widget->checkBox->isChecked();
                                      widget->checkBox->setChecked(!checked);
                                      setModelData(editor, model, index);
                                      return true; 
                                      */
                                  }
                          }
                  
                        
                     
                      }
                      
                      return QStyledItemDelegate::editorEvent(event, model, option, index);
                  }
                  
                  

                  I get for example:
                  Checkboxdata: QRect(1095,302 100x30)
                  MousePostion: QPoint(215,21)

                  1 Reply Last reply
                  0
                  • SGaistS SGaist

                    No, check the editorEvent function.

                    S Offline
                    S Offline
                    StudentScripter
                    wrote on last edited by
                    #15

                    @SGaist Bumping this up. Guess you are busy but may you have a second the next days or so to may answer my last question. Sorry for the interuption. :)

                    Chris KawaC 1 Reply Last reply
                    0
                    • S StudentScripter

                      @SGaist Bumping this up. Guess you are busy but may you have a second the next days or so to may answer my last question. Sorry for the interuption. :)

                      Chris KawaC Offline
                      Chris KawaC Offline
                      Chris Kawa
                      Lifetime Qt Champion
                      wrote on last edited by
                      #16

                      @StudentScripter There's multiple problems in your code.

                      First this is wrong: QWidget *parentWidget = qobject_cast<QWidget*>(parent());.
                      A delegate can be shared between multiple views and there's no requirement that any of those views was a parent of that delegate. There's also no requirement that the parent of the delegate is a QWidget or that the delegate even has any parent. In case of sharing delegate between views the parent might not even be the widget the event occurred in.
                      The proper way to retrieve the widget the event happened in is through option.widget parameter.

                      Next, you should not call createEditor. This is a callback method that the view calls when editing of an item is requested via view->edit(index). The way you have it you create a new widget every time an item is clicked. you never show or delete that widget, but you do give it a parent, so after 1000 clicks you have 1000 instances of that widget created, invisible and living until you the view is destroyed.

                      The event gives you press position in view's viewport coordinates. To convert it to item's coordinates you can get the item coords in the viewport and do the math e.g.

                      if(event->type() == QEvent::MouseButtonPress)
                      {
                          QMouseEvent* mouseEvt = static_cast<QMouseEvent*>(event);
                          
                          if ( const QTreeView* view = qobject_cast<const QTreeView*>(option.widget))
                          {
                              const QRect itemRect = view->visualRect(index);
                              QPointF itemPos = mouseEvt->position() - itemRect.topLeft(); // press position in item's coords
                      

                      You should not create and destroy a widget every time you want to paint or check a position in it. That's an enormous overhead that defeats the whole point of delegates.

                      Calculate where your checkbox is without instantiating a widget. For example you can assume it's always in a right aligned square of your item, so you can calculate its position from the item dimensions.

                      When painting the item you also shouldn't instantiate a widget and take a screenshot of it like you're doing now. Use style()->drawControl(...) to draw a picture of a checkbox or line edit without actually instantiating them. That's the idea of delegates - provide a lightweight proxy for the items and only instantiating an actual widget when editing of an item starts.

                      When painting an item don't load any resources e.g. QPixmap iconPixmap("://resource/quick.png"); in the paint event. That is reading from disk and can stall and make your app unresponsive if you have many items or slow disk access. Load the image once e.g. in the delegate's constructor and store it in a class member. Also if you're doing any transformation on it, like scaled(...) do it once on load and store and reuse the result. Keep in mind that the paining is called every time a user moves a mouse over an item, so it's potentially hundreds of events a second. Painting should be as speedy as possible.

                      Don't use stylesheets to draw a colored rectangle. It's like shooting a fly with a canon. Just use a QPainter and paint a rectangle.

                      S 3 Replies Last reply
                      3
                      • Chris KawaC Chris Kawa

                        @StudentScripter There's multiple problems in your code.

                        First this is wrong: QWidget *parentWidget = qobject_cast<QWidget*>(parent());.
                        A delegate can be shared between multiple views and there's no requirement that any of those views was a parent of that delegate. There's also no requirement that the parent of the delegate is a QWidget or that the delegate even has any parent. In case of sharing delegate between views the parent might not even be the widget the event occurred in.
                        The proper way to retrieve the widget the event happened in is through option.widget parameter.

                        Next, you should not call createEditor. This is a callback method that the view calls when editing of an item is requested via view->edit(index). The way you have it you create a new widget every time an item is clicked. you never show or delete that widget, but you do give it a parent, so after 1000 clicks you have 1000 instances of that widget created, invisible and living until you the view is destroyed.

                        The event gives you press position in view's viewport coordinates. To convert it to item's coordinates you can get the item coords in the viewport and do the math e.g.

                        if(event->type() == QEvent::MouseButtonPress)
                        {
                            QMouseEvent* mouseEvt = static_cast<QMouseEvent*>(event);
                            
                            if ( const QTreeView* view = qobject_cast<const QTreeView*>(option.widget))
                            {
                                const QRect itemRect = view->visualRect(index);
                                QPointF itemPos = mouseEvt->position() - itemRect.topLeft(); // press position in item's coords
                        

                        You should not create and destroy a widget every time you want to paint or check a position in it. That's an enormous overhead that defeats the whole point of delegates.

                        Calculate where your checkbox is without instantiating a widget. For example you can assume it's always in a right aligned square of your item, so you can calculate its position from the item dimensions.

                        When painting the item you also shouldn't instantiate a widget and take a screenshot of it like you're doing now. Use style()->drawControl(...) to draw a picture of a checkbox or line edit without actually instantiating them. That's the idea of delegates - provide a lightweight proxy for the items and only instantiating an actual widget when editing of an item starts.

                        When painting an item don't load any resources e.g. QPixmap iconPixmap("://resource/quick.png"); in the paint event. That is reading from disk and can stall and make your app unresponsive if you have many items or slow disk access. Load the image once e.g. in the delegate's constructor and store it in a class member. Also if you're doing any transformation on it, like scaled(...) do it once on load and store and reuse the result. Keep in mind that the paining is called every time a user moves a mouse over an item, so it's potentially hundreds of events a second. Painting should be as speedy as possible.

                        Don't use stylesheets to draw a colored rectangle. It's like shooting a fly with a canon. Just use a QPainter and paint a rectangle.

                        S Offline
                        S Offline
                        StudentScripter
                        wrote on last edited by StudentScripter
                        #17
                        This post is deleted!
                        1 Reply Last reply
                        0
                        • Chris KawaC Chris Kawa

                          @StudentScripter There's multiple problems in your code.

                          First this is wrong: QWidget *parentWidget = qobject_cast<QWidget*>(parent());.
                          A delegate can be shared between multiple views and there's no requirement that any of those views was a parent of that delegate. There's also no requirement that the parent of the delegate is a QWidget or that the delegate even has any parent. In case of sharing delegate between views the parent might not even be the widget the event occurred in.
                          The proper way to retrieve the widget the event happened in is through option.widget parameter.

                          Next, you should not call createEditor. This is a callback method that the view calls when editing of an item is requested via view->edit(index). The way you have it you create a new widget every time an item is clicked. you never show or delete that widget, but you do give it a parent, so after 1000 clicks you have 1000 instances of that widget created, invisible and living until you the view is destroyed.

                          The event gives you press position in view's viewport coordinates. To convert it to item's coordinates you can get the item coords in the viewport and do the math e.g.

                          if(event->type() == QEvent::MouseButtonPress)
                          {
                              QMouseEvent* mouseEvt = static_cast<QMouseEvent*>(event);
                              
                              if ( const QTreeView* view = qobject_cast<const QTreeView*>(option.widget))
                              {
                                  const QRect itemRect = view->visualRect(index);
                                  QPointF itemPos = mouseEvt->position() - itemRect.topLeft(); // press position in item's coords
                          

                          You should not create and destroy a widget every time you want to paint or check a position in it. That's an enormous overhead that defeats the whole point of delegates.

                          Calculate where your checkbox is without instantiating a widget. For example you can assume it's always in a right aligned square of your item, so you can calculate its position from the item dimensions.

                          When painting the item you also shouldn't instantiate a widget and take a screenshot of it like you're doing now. Use style()->drawControl(...) to draw a picture of a checkbox or line edit without actually instantiating them. That's the idea of delegates - provide a lightweight proxy for the items and only instantiating an actual widget when editing of an item starts.

                          When painting an item don't load any resources e.g. QPixmap iconPixmap("://resource/quick.png"); in the paint event. That is reading from disk and can stall and make your app unresponsive if you have many items or slow disk access. Load the image once e.g. in the delegate's constructor and store it in a class member. Also if you're doing any transformation on it, like scaled(...) do it once on load and store and reuse the result. Keep in mind that the paining is called every time a user moves a mouse over an item, so it's potentially hundreds of events a second. Painting should be as speedy as possible.

                          Don't use stylesheets to draw a colored rectangle. It's like shooting a fly with a canon. Just use a QPainter and paint a rectangle.

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

                          @Chris-Kawa thank you very much. That definitely helped a lot. :)

                          I have done the manual positioning now, so all delegates line up with the actual widget. :)

                          
                          void ViewLayerItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
                          {
                              
                              
                              QStyleOptionViewItem opt = option;
                              initStyleOption(&opt, index);
                          
                          
                              // Überprüfen Sie, ob der aktuelle Index bearbeitet wird
                                  if (index == currentlyEditedIndex) {
                                     
                                      return;
                                  }
                          
                          
                          
                              // Setzen Sie die Werte der SpinBox und CheckBox basierend auf den Modellwerten
                              QString lineEditvalue = index.model()->data(index, Qt::EditRole).toString();
                              bool checkBoxValue = index.model()->data(index, Qt::CheckStateRole).toBool();
                          
                              // Laden Sie das Icon und skalieren Sie es
                              QPixmap iconPixmap("://resource/quick.png"); // Ersetzen Sie dies durch den Pfad zu Ihrer Icon-Datei
                              QPixmap scaledPixmap = iconPixmap.scaled(32, 32, Qt::KeepAspectRatio, Qt::SmoothTransformation);
                              
                              // Berechnen Sie die Position für das Icon
                              int centerY = option.rect.top() + option.rect.height() / 2;
                              int iconY = centerY - scaledPixmap.height() / 2;
                              QPoint iconPos = QPoint(option.rect.left() + 10, iconY);
                              
                              // Zeichnen Sie das Pixmap mit dem QPainter
                              painter->drawPixmap(iconPos, scaledPixmap);
                          
                          
                              // Berechnen Sie die Position und Größe für das LineEdit
                              QRect lineEditRect = option.rect;
                              lineEditRect.setLeft(iconPos.x() + scaledPixmap.width() + 10); // Adjust as needed
                              lineEditRect.setRight(option.rect.right() - 10); // Adjust as needed
                          
                              // Erstellen Sie ein QStyleOptionFrame für das LineEdit
                              QStyleOptionFrame lineEditOption;
                              lineEditOption.lineWidth = 1; // Setzen Sie die Liniendicke auf 1
                              lineEditOption.rect = lineEditRect;
                          
                              // Zeichnen Sie das LineEdit
                              QApplication::style()->drawControl(QStyle::CE_ShapedFrame, &lineEditOption, painter);
                          
                              // Zeichnen Sie den Text des LineEdits
                              painter->drawText(lineEditOption.rect.adjusted(2,0,0,0), Qt::AlignLeft | Qt::AlignVCenter, lineEditvalue);
                          
                              // Berechnen Sie die Position und Größe für die CheckBox
                              QRect checkBoxRect = option.rect;
                              checkBoxRect.setLeft(lineEditRect.right() - 22); // Adjust as needed
                              checkBoxRect.setRight(option.rect.right() - 10); // Adjust as needed
                          
                              // Erstellen Sie ein QStyleOptionButton für die CheckBox
                              QStyleOptionButton checkBoxOption;
                              checkBoxOption.state = checkBoxValue ? QStyle::State_On : QStyle::State_Off;
                              checkBoxOption.rect = checkBoxRect;
                          
                              // Zeichnen Sie die CheckBox
                              QApplication::style()->drawControl(QStyle::CE_CheckBox, &checkBoxOption, painter);
                          }
                          
                          1 Reply Last reply
                          0
                          • Chris KawaC Chris Kawa

                            @StudentScripter There's multiple problems in your code.

                            First this is wrong: QWidget *parentWidget = qobject_cast<QWidget*>(parent());.
                            A delegate can be shared between multiple views and there's no requirement that any of those views was a parent of that delegate. There's also no requirement that the parent of the delegate is a QWidget or that the delegate even has any parent. In case of sharing delegate between views the parent might not even be the widget the event occurred in.
                            The proper way to retrieve the widget the event happened in is through option.widget parameter.

                            Next, you should not call createEditor. This is a callback method that the view calls when editing of an item is requested via view->edit(index). The way you have it you create a new widget every time an item is clicked. you never show or delete that widget, but you do give it a parent, so after 1000 clicks you have 1000 instances of that widget created, invisible and living until you the view is destroyed.

                            The event gives you press position in view's viewport coordinates. To convert it to item's coordinates you can get the item coords in the viewport and do the math e.g.

                            if(event->type() == QEvent::MouseButtonPress)
                            {
                                QMouseEvent* mouseEvt = static_cast<QMouseEvent*>(event);
                                
                                if ( const QTreeView* view = qobject_cast<const QTreeView*>(option.widget))
                                {
                                    const QRect itemRect = view->visualRect(index);
                                    QPointF itemPos = mouseEvt->position() - itemRect.topLeft(); // press position in item's coords
                            

                            You should not create and destroy a widget every time you want to paint or check a position in it. That's an enormous overhead that defeats the whole point of delegates.

                            Calculate where your checkbox is without instantiating a widget. For example you can assume it's always in a right aligned square of your item, so you can calculate its position from the item dimensions.

                            When painting the item you also shouldn't instantiate a widget and take a screenshot of it like you're doing now. Use style()->drawControl(...) to draw a picture of a checkbox or line edit without actually instantiating them. That's the idea of delegates - provide a lightweight proxy for the items and only instantiating an actual widget when editing of an item starts.

                            When painting an item don't load any resources e.g. QPixmap iconPixmap("://resource/quick.png"); in the paint event. That is reading from disk and can stall and make your app unresponsive if you have many items or slow disk access. Load the image once e.g. in the delegate's constructor and store it in a class member. Also if you're doing any transformation on it, like scaled(...) do it once on load and store and reuse the result. Keep in mind that the paining is called every time a user moves a mouse over an item, so it's potentially hundreds of events a second. Painting should be as speedy as possible.

                            Don't use stylesheets to draw a colored rectangle. It's like shooting a fly with a canon. Just use a QPainter and paint a rectangle.

                            S Offline
                            S Offline
                            StudentScripter
                            wrote on last edited by StudentScripter
                            #19
                            This post is deleted!
                            1 Reply Last reply
                            0
                            • S StudentScripter has marked this topic as solved on

                            • Login

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