PDA

View Full Version : How to get scrollbars in QTreeWidget



Arthur
14th April 2006, 12:58
Hello,

I use a QTreeWidget (target platform Win32) and set the horizontal scroll bar policy to to Qt::ScrollBarAsNeeded. However I never get a scrollbar.

Does anyone know how to fix this?

Arthur

wysota
14th April 2006, 13:09
Maybe you never need it? :)

Can you provide a minimal compilable example which reproduces the problem?

Arthur
14th April 2006, 13:55
Here it is

fullmetalcoder
14th April 2006, 15:08
maybe we do need it!!! I got exactly the same problem with DevQt project manager (all those who tested may have noticed) and I didn't find any way to fix it! Looks like a Qt issue (maybe only on M$ Win but still a Qt issue)... :(

wysota
14th April 2006, 16:26
Here it is

This is not a minimal compilable example. One can hardly to anything with a complex, yet not using layouts window.

SkripT
14th April 2006, 17:16
I comment how I solve this problem: I declare one additional column at the end of the tree widget and I let it empty (it's a bit ugly but in this way always appears the scroll bar when is needed and also if you hide the header it's not noticed ;) )

wysota
14th April 2006, 22:52
It should be achievable if you resize the column. Either by calling resizeColumnToContents (or something like that) or QHeaderView::resizeSection(). One of them will probably fix the issue. Qt behaviour is fine -- it is not the view contents which doesn't fit on the viewport (which would mean a scrollbar has to be added), it is the column which is too narrow to fit contents.

Arthur
14th April 2006, 23:41
This is not a minimal compilable example. One can hardly to anything with a complex, yet not using layouts window.

Well, this is exactly nothing more than a simple project containing the widget layout where the problem occurs. If I just put a treeview on a form, it will probably work...

wysota
15th April 2006, 00:48
Well, this is exactly nothing more than a simple project containing the widget layout where the problem occurs. If I just put a treeview on a form, it will probably work...

There is no layout there. Try resizing the window. The form (and other widgets too) is completely unnecessary, it would be better if there was only the treewidget there:


#include <QApplication>
#include <QTreeWidget>
#include <QStringList>

int main(int argc, char **argv){
QApplication app(argc, argv);
QTreeWidget tw;
// ... some lines here, like:
tw.insertTopLevelItem(0,
new QTreeWidgetItem( QStringList() << "col1" << "col2" )
);
tw.show();
return app.exec();
}

That's a minimal compilable example :)

minorpan
30th April 2006, 12:04
I hope I can help you by providing you the following example code.

class MyTreeWidget: public QTreeWidget
{

Q_OBJECT
public:
MyTreeWidget(QWidget* parent = 0): QTreeWidget(parent)
{

setObjectName(QString::fromUtf8("objectView"));
setGeometry(QRect(10, 20, 120, 150));
setColumnCount(2);
header()->resizeSection(0, 0);
setItemHidden(headerItem(), true);

QObject::connect(this, SIGNAL(itemChanged(QTreeWidgetItem*, int)), this, SLOT(updateColumnWidth()));
QObject::connect(this, SIGNAL(itemExpanded(QTreeWidgetItem*)), this, SLOT(updateColumnWidth()));
QObject::connect(this, SIGNAL(itemCollapsed(QTreeWidgetItem*)), this, SLOT(updateColumnWidth()));
}

protected slots:
void updateColumnWidth()
{

header()->resizeSection(0, 0);
resizeColumnToContents(0);
}

};

To make your tree widget support horizontal scroll bar and resize automatically to fit the width of the contents that are displaying, you may create your own tree widget class derived from QTreeWidget, and "make it work well" at the constructor.
Take a look at the highlighted code, we have to make it have at least two columns (just as SkripT said) by adding setColumnCount(2), and initialize the width of column 0 to 0 (or the scroll bar will appear even it contains nothing).
Then, to make it resize automatically when the content displaying on the widget has changed, we add the function updateColumnWidth() as a slot, which is connected by three signals: itemChanged, itemExpanded and itemCollapsed, since the content displayed on the widget may be changed when one of the signals is emitted.

And in function updateColumnWidth(),
header()->resizeSection(0, 0);
resizeColumnToContents(0);
are called sequentially. The function resizeColumnToContents(column) resizes the column to fit the contents that are displaying, but it will only grow when the width increases (will not shrink when the width decreases), therefore we have to reset the width of the column and stretch it to fit the contents.

Hope it helps you. Please reply me if any questions.
Sincerely yours,

minorpan

jorma
2nd May 2006, 18:53
Thank you minorpan, your advice was excellent!

However, I have one more question:
with your advice resizing works automatically OK otherwise, but not in case the window is resized (the user drags with her mouse from the corner of the window and enlarges or shrinks it). When I try to cover also that by re-defining the event-handling for the appropriate event:

void MyTreeWidget::resizeEvent( QResizeEvent* event)
{
QTreeWidget::resizeEvent( event);

// in addition to plain old resizing update the column widths:
updateColumnWidth(); // minorpan's function
};


it works... almost. With my application I am always able to find such a tree expansion/window size combination, that after the window has been resized with the mouse, the scollbars flick enourmously and the PC CPU usage is close to 100%. How should I implement the resize-support properly?
- Jorma

jorma
3rd May 2006, 20:04
I'll answer myself now that I found out how to do it...

in order to get everything right, it is enough to say in MyTreeWidget's constructor also

setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOn);
setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOn);

connect(this->horizontalScrollBar(), SIGNAL(actionTriggered(int)),
this, SLOT(updateColumnWidth()));
connect(this->verticalScrollBar(), SIGNAL(actionTriggered(int)),
this, SLOT(updateColumnWidth()));

minorpan
5th May 2006, 06:15
Dear Jorma:

I have tried to reconstruct your problem by adding the following code to function main().

#include "MyTreeWidget.h"
int main(int argc, char* argv[])

QApplication app(argc, argv);
MyTreeWidget widget;
QTreeWidgetItem* pItem;
pItem = new QTreeWidgetItem(&widget, QStringList("aaaaaaaaaaaaaaaaaaaaaaa"));
pItem = new QTreeWidgetItem(pItem, QStringList("aaaaaaaaaaaaaaaaaaaaaaa"));
pItem = new QTreeWidgetItem(pItem, QStringList("aaaaaaaaaaaaaaaaaaaaaaa"));
pItem = new QTreeWidgetItem(pItem, QStringList("aaaaaaaaaaaaaaaaaaaaaaa"));
pItem = new QTreeWidgetItem(pItem, QStringList("aaaaaaaaaaaaaaaaaaaaaaa"));
pItem = new QTreeWidgetItem(pItem, QStringList("aaaaaaaaaaaaaaaaaaaaaaa"));
pItem = new QTreeWidgetItem(pItem, QStringList("aaaaaaaaaaaaaaaaaaaaaaa"));
pItem = new QTreeWidgetItem(&widget, QStringList("aaaaaaaaaaaaaaaaaaaaaaa"));
pItem = new QTreeWidgetItem(pItem, QStringList("aaaaaaaaaaaaaaaaaaaaaaa"));
pItem = new QTreeWidgetItem(pItem, QStringList("aaaaaaaaaaaaaaaaaaaaaaa"));
pItem = new QTreeWidgetItem(pItem, QStringList("aaaaaaaaaaaaaaaaaaaaaaa"));
pItem = new QTreeWidgetItem(pItem, QStringList("aaaaaaaaaaaaaaaaaaaaaaa"));
pItem = new QTreeWidgetItem(pItem, QStringList("aaaaaaaaaaaaaaaaaaaaaaa"));
pItem = new QTreeWidgetItem(pItem, QStringList("aaaaaaaaaaaaaaaaaaaaaaa"));
pItem = new QTreeWidgetItem(&widget, QStringList("aaaaaaaaaaaaaaaaaaaaaaa"));
pItem = new QTreeWidgetItem(pItem, QStringList("aaaaaaaaaaaaaaaaaaaaaaa"));
pItem = new QTreeWidgetItem(pItem, QStringList("aaaaaaaaaaaaaaaaaaaaaaa"));
pItem = new QTreeWidgetItem(pItem, QStringList("aaaaaaaaaaaaaaaaaaaaaaa"));
pItem = new QTreeWidgetItem(pItem, QStringList("aaaaaaaaaaaaaaaaaaaaaaa"));
pItem = new QTreeWidgetItem(pItem, QStringList("aaaaaaaaaaaaaaaaaaaaaaa"));
pItem = new QTreeWidgetItem(pItem, QStringList("aaaaaaaaaaaaaaaaaaaaaaa"));
widget.show();

}

With my original constructor of MyTreeWidget and your implementation of resizeEvent(), it works well, and the scroll bars do not flicker after the window is resized even if all items are expanded.
So could you please let me see the code of your application containing the problem? Thank you very much.


minorpan

jorma
5th May 2006, 17:36
OK minorpan! Here we go - the files mytreewidget.hpp and cpp are below.

Launch the application, and then
- click all tree nodes open
- resize the window from the right-bottom corner so that the first leaf node
(containing the text "aa" just above the long line) is on the right-bottom corner.
The horizontal scroll bar "underlines" this line (so to speak).
- then start resizing the window to the right. You know the long line of aaa's
is just below the horizontal scrollbar.

Do this a couple of times. Experiment with very small changes in the height of the
window. I am sure you will get the flicker-effect and your CPU load rises up, right?

- Jorma



// the file mytreewidget.hpp:
#include <QHeaderView>
#include <QTreeWidget>
#include <QApplication>

class MyTreeWidget: public QTreeWidget
{
Q_OBJECT

public:
MyTreeWidget(QWidget* parent = 0);
QIcon nodeIcon;
QIcon leafIcon;

virtual void resizeEvent( QResizeEvent* event);

protected slots:
void updateColumnWidth();

};


// the file mytreewidget.cpp:
#include "mytreewidget.hpp"

MyTreeWidget::MyTreeWidget(QWidget* parent): QTreeWidget(parent)
{
// setSelectionMode( QAbstractItemView::SingleSelection);
setDragEnabled(true); // inherited from QAbstractItemView
setAcceptDrops(true);
setDropIndicatorShown(true);


setObjectName(QString::fromUtf8("objectView"));
//setGeometry(QRect(10, 20, 120, 150));
setColumnCount(2);
header()->resizeSection(0, 0);
setItemHidden(headerItem(), true);

QObject::connect(this, SIGNAL(itemChanged(QTreeWidgetItem*, int)), this, SLOT(updateColumnWidth()));
QObject::connect(this, SIGNAL(itemExpanded(QTreeWidgetItem*)), this, SLOT(updateColumnWidth()));
QObject::connect(this, SIGNAL(itemCollapsed(QTreeWidgetItem*)), this, SLOT(updateColumnWidth()));
nodeIcon.addPixmap(style()->standardPixmap(QStyle::SP_DirClosedIcon),
QIcon::Normal, QIcon::Off);
nodeIcon.addPixmap(style()->standardPixmap(QStyle::SP_DirOpenIcon),
QIcon::Normal, QIcon::On);
leafIcon.addPixmap(style()->standardPixmap(QStyle::SP_FileIcon));
}


void MyTreeWidget::updateColumnWidth()
{

header()->resizeSection(0, 0);
resizeColumnToContents(0);

}

void MyTreeWidget::resizeEvent( QResizeEvent* event)
{
QTreeWidget::resizeEvent( event);

// in addition to plain old resizing update the column widths:
updateColumnWidth(); // minorpan's function
};



int main(int argc, char* argv[])
{
QApplication app(argc, argv);
MyTreeWidget widget;
QTreeWidgetItem* pItem;

pItem = new QTreeWidgetItem(&widget, QStringList("a"));
Qt::ItemFlags flags = pItem->flags() & (~ Qt::ItemIsEditable)| Qt::ItemIsSelectable
| Qt::ItemIsDropEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable;
pItem->setFlags(flags);
pItem->setIcon(0, widget.nodeIcon);
pItem = new QTreeWidgetItem(pItem, QStringList("aa"));
pItem->setFlags(flags);pItem->setIcon(0, widget.nodeIcon);

pItem = new QTreeWidgetItem(pItem, QStringList("aa"));
pItem->setFlags(flags);pItem->setIcon(0, widget.nodeIcon);

pItem = new QTreeWidgetItem(pItem, QStringList("aa"));
pItem->setFlags(flags);pItem->setIcon(0, widget.nodeIcon);

pItem = new QTreeWidgetItem(pItem, QStringList("aa"));
pItem->setFlags(flags);pItem->setIcon(0, widget.nodeIcon);

pItem = new QTreeWidgetItem(pItem, QStringList("aa"));
pItem->setFlags(flags);pItem->setIcon(0, widget.nodeIcon);

pItem = new QTreeWidgetItem(pItem, QStringList("aa"));
pItem->setFlags(flags);pItem->setIcon(0, widget.leafIcon);

pItem = new QTreeWidgetItem(&widget, QStringList("aaaaaaaaaaaaaaaaaaaaaaaaaaaaa"));
pItem->setFlags(flags);pItem->setIcon(0, widget.nodeIcon);

pItem = new QTreeWidgetItem(pItem, QStringList("aa"));
pItem->setFlags(flags);pItem->setIcon(0, widget.nodeIcon);

pItem = new QTreeWidgetItem(pItem, QStringList("aa"));
pItem->setFlags(flags);pItem->setIcon(0, widget.nodeIcon);


widget.show();
return app.exec();
}

minorpan
5th May 2006, 21:51
Thank you.
I have got the flicker-effect when running your demo application.
I think it's important to resize the viewport when the contents displaying are resized, such as font sizes, right? Therefore the minorpan's function :) may still be called within these event handlers. I will try to make it better, thanks for your advice which is really excellent ^_^

minorpan