Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Position of icon in QTreeWidgetItem

Tags:

qt

My QTreeWidget has a single column. Its items have a check box, an icon, and text. If the user clicks inside an item, I want to know whether the icon was clicked. How can I find the position and size of the icon in a QTreeWidgetItem?

Updated to add: Here is the code for my eventual solution, as requested by webclectic.

First, I sub-classed QItemDelegate so that I could access the coordinates of each part of a QTreeWidgetItem (check box, icon, and text). Here is the header file:

#include <QItemDelegate>

class MyItemDelegate : public QItemDelegate
  {
  Q_OBJECT

public:
  explicit MyItemDelegate (MyTreeWidget *parent)
    : QItemDelegate (parent), ParentView (parent) { }
  ~MyItemDelegate() { }

  void GetRects (const QModelIndex &index, QRect& CheckBox, QRect& Icon, QRect& Text) const ;

private:
  MyTreeWidget* ParentView ;
  } ;

And here is the source file:

void MyItemDelegate::GetRects (const QModelIndex &index, QRect& CheckBox, QRect& Icon, QRect& Text) const
  {
  QStyleOptionViewItem option = ParentView -> viewOptions() ;
  CheckBox = rect (option, index, Qt::CheckStateRole) ;
  Icon = rect (option, index, Qt::DecorationRole) ;
  Text = rect (option, index, Qt::DisplayRole) ;

  doLayout (option, &CheckBox, &Icon, &Text, true) ;

  QRect VisualRect = ParentView -> visualRect (index) ;
  CheckBox.translate (VisualRect.topLeft()) ;
  Icon.translate (VisualRect.topLeft()) ;
  Text.translate (VisualRect.topLeft()) ;
  }

Then I added a MyItemDelegate* member to MyTreeWidget, and set it as the item view's delegate. In the header:

class MyTreeWidget : public QTreeWidget
  {
  ...
  MyItemDelegate* Delegate ;
  ...
  } ;

In the source :

MyTreeWidget::MyTreeWidget (QObject* parent)
  {
  ...
  Delegate = new MyItemDelegate (this) ;
  setItemDelegate (ItemDelegate) ;
  }

Now, to get the coordinates of each part of a QTreeWidgetItem:

  QTreeWidgetItem* item ;
  ...
  QModelIndex ModelIndex = indexFromItem (item) ;
  QRect CheckBoxRect, IconRect, TextRect ;
  ItemDelegate -> GetRects (ModelIndex, &CheckBoxRect, &IconRect, &TextRect) ;
like image 205
TonyK Avatar asked Nov 25 '11 20:11

TonyK


1 Answers

Unfortunately there is no simple way to achieve what you want. The problem is that QTreeWidget is responsible for painting its items so the item itself has no information about the position of its elements in the view.

First of all you have to subclass QTreeWidget and reimplement the mousePressEvent (or mouseReleaseEvent if you prefer). Inside the event you should calculate the position of the icon and handle it correspondingly.

Sample code (but untested) follows:

void mousePressEvent(QMouseEvent *event)
{
   QModelIndex clickedIndex = indexAt(event->pos());
   // make sure the event was on a valid item
   if (clickedIndex.isValid() == false)
      return;

   // Get the tree widget's x position
   int treeX = header()->sectionViewportPosition(0);

   // Get the x coordinate of the root item. It is required in order to calculate
   // the identation of the item
   int rootX = visualRect(rootIndex()).x();

   // Get the rectangle of the viewport occupied by the pressed item
   QRect vrect = visualRect(clickedIndex);

   // Now we can easily calculate the x coordinate of the item
   int itemX = treeX + vrect.x() - rootX; 

   // The item is a checkbox, then an icon and finally the text. 

   // 1. Get the rect surrounding the checkbox
   QRect checkboxRect = QRect(itemX, 
                              vrect.y(), 
                              style()->pixelMetric(QStyle::PM_IndicatorWidth),
                              vrect.height()); 

   // 2. Get the rect surrounding the icon
   QRect iconRect = QRect(itemX + checkboxRect.width(),
                          vrect.y(),
                          iconSize().width(),
                          vrect.height());

   // 3. Finally get the rect surrounding the text
   QRect textRect = QRect(itemX + checkboxRect.width() + iconRect.width(),
                          vrect.y(),
                          vrect.width() - checkboxRect.width() - iconRect.width(),
                          vrect.height());       

   // Now check where the press event took place and handle it correspondingly

   if(checkboxRect.contains(event->pos())) 
   {
       qDebug() << "Checkbox pressed";
       QTreeWidget::mousePressEvent(event);
       return;
   } 
   else if (iconRect.contains(event->pos()))
   {
       qDebug() << "Icon pressed";
       QTreeWidget::mousePressEvent(event);
       return;
   }
   else
   {
       qDebug() << "Text pressed";
       QTreeWidget::mousePressEvent(event);
       return; 
   }
}

I repeat that the code is untested but you get the idea about how to achieve what you want.

like image 53
pnezis Avatar answered Oct 08 '22 16:10

pnezis