Samantha Smith
Samantha Smith

Reputation: 41

QTreeView and ScrollArea size

Great Greetings. How can I find out the size of the scroll area for a QTreeView? I can get the size of the viewport, but I cannot get the size of the area over which this viewport moves. My thanks for any help! enter image description here

Upvotes: 0

Views: 1064

Answers (1)

Scheff's Cat
Scheff's Cat

Reputation: 20171

This was my recommendation per comments:

You could retrieve the QScrollBar::maximum() of QTreeView::horizontalScrollBar() and QTreeView::verticalScrollBar(). (I guess the minimum() is 0 in both cases.)

and

It might be necessary to add the view width/height. (Sorry, I didn't check in detail - just tried to give a possible direction to search into.)

As the OP had doubts about that recommendation, I made an MCVE to demonstrate my intention.

testQTreeWidgetContentsSize.cc:

// standard C++ header:
#include <string>
#include <vector>

// Qt header:
#include <QtWidgets>

class TreeWidget: public QTreeWidget {

  private:
    int _w, _h; // last determined contents size

  public:
    TreeWidget(QWidget *pQParent = nullptr);
    virtual ~TreeWidget() = default;
    TreeWidget(const TreeWidget&) = delete;
    TreeWidget& operator=(const TreeWidget&) = delete;

  protected:
    virtual void paintEvent(QPaintEvent *pQEvent) override;
};

TreeWidget::TreeWidget(QWidget *pQParent):
  QTreeWidget(pQParent), _w(0), _h(0)
{
  setHorizontalScrollMode(ScrollPerPixel);
  setVerticalScrollMode(ScrollPerPixel);
}

void TreeWidget::paintEvent(QPaintEvent *pQEvent)
{
  QTreeWidget::paintEvent(pQEvent);
  const int wView = viewport()->size().width();
  const int hView = viewport()->size().height();
  const int w = wView + horizontalScrollBar()->maximum();
  const int h = hView + verticalScrollBar()->maximum();
  if (_w == w && _h == h) return;
  _w = w; _h = h;
  qDebug() << "View Size:" << wView << "x" << hView;
  const bool wFit = horizontalScrollBar()->maximum() == 0;
  const bool hFit = verticalScrollBar()->maximum() == 0;
  qDebug() << "Contents Size:"
    << (wFit ? "<=" : "") << w << "x" << (hFit ? "<=" : "") << h;
}

struct Node {
  std::string name;
  std::vector<Node> children;
};

void populate(const Node &node, QTreeWidget &qTree);

int main(int argc, char **argv)
{
  qDebug() << "Qt Version:" << QT_VERSION_STR;
  QApplication app(argc, argv);
  // build UI
  TreeWidget qTree;
  qTree.setHeaderHidden(true);
  qTree.setWindowTitle(QString::fromUtf8("QTreeView Contents Size"));
  qTree.resize(200, 200);
  qTree.show();
  // populate tree
  Node tree = {
    "root", {
      { "child 1", {
          { "child 1-1", { } },
          { "child 1-2", { } },
          { "child 1-3", { } }
        }
      },
      { "child 2", {
          { "child 2-1", { } },
          { "child 2-2", { } },
          { "child 2-3", { } }
        }
      },
      { "child 3", {
          { "child 3-1", {
              { "child 3-1-1", { } },
              { "child 3-1-2", { } },
              { "child 3-1-3", { } }
            }
          },
          { "child 3-2", {
              { "child 3-2-1", { } },
              { "child 3-2-2", { } },
              { "child 3-2-3", { } }
            }
          },
          { "child 3-3", { } },
        }
      }
    }
  };
  populate(tree, qTree);
  //qTree.expandAll();
  // runtime loop
  return app.exec();
}

void populate(const Node &node, QTreeWidgetItem *pQParent)
{
  QTreeWidgetItem *const pQTreeItem
    = new QTreeWidgetItem(pQParent, { QString::fromStdString(node.name) });
  for (const Node &child : node.children) populate(child, pQTreeItem);
}

void populate(const Node &node, QTreeWidget &qTree)
{
  QTreeWidgetItem *const pQTreeItem
    = new QTreeWidgetItem(&qTree, { QString::fromStdString(node.name) });
  for (const Node &child : node.children) populate(child, pQTreeItem);
}

Output:

Qt Version: 5.13.0
View Size: 198 x 198
Contents Size: <= 198 x <= 198

I started to expand tree nodes interactively until tree size exceeded the view.

View Size: 181 x 198
Contents Size: <= 181 x  221

I resized the tree view a bit interactively until tree was fitting again into view.

View Size: 198 x 221
Contents Size: <= 198 x <= 221
View Size: 198 x 222
Contents Size: <= 198 x <= 222
View Size: 198 x 223
Contents Size: <= 198 x <= 223
View Size: 181 x 223
Contents Size: <= 198 x <= 223

I expanded more tree nodes interactively until tree size exceeded the view again.

View Size: 181 x 223
Contents Size: <= 181 x  272
View Size: 181 x 223
Contents Size: <= 181 x  323

snapshot of testQTreeWidgetContentsSize.exe (animated)

Notes:

This appears to be a hacky solution with some limitations.

  1. For proper results from the scroll bars, I had to use

    setHorizontalScrollMode(ScrollPerPixel);
    setVerticalScrollMode(ScrollPerPixel);
    

    Otherwise, the maximum() value would reflect some kind of item increment which would be useless for my purpose.

  2. The results got if contents is larger than the view port appear reasonable to me. If the contents fits into view port, the contents size cannot be determined this way. (This limitation might be acceptable.)

  3. I placed the contents size report in an overridden paintEvent(). That was the only idea I had ad hoc to grant that the internal layout is done when retrieving the relevant data.

    Before I tried to connect to the QTreeView::expanded() and QTreeView::collapsed() signals but with this I got outdated results, and moving it in a separate event via QTimer::singleShot() didn't fix it (although this is my usual, reliable “Swiss Army Knife” for such issues).

Before sending my answer, I spent a certain time to scroll through the Qt doc. for

I struggled to believe that there isn't any way offered to retrieve the contents size.

Usually, when I use any class derived from QAbstractScrollArea then I either don't care about contents size (in full trust to the automatisms inside the Qt widgets) or I define it in my own code so that I have access to it.

Either I didn't search carefully enough or the Qt guys just couldn't imagine that a Qt using developer will ever need this data.

If I had to research further I probably would have a look onto the source code (e.g. on woboq.org) to see how the contents size is managed and where.

Upvotes: 1

Related Questions