PDA

View Full Version : QItemDelegate, QTreeView and scrollbars



SiLiZiUMM
30th April 2008, 22:47
Hello again!

I have a custom delegate that inherits from QItemDelegate. When displayed into a QTreeView, the delegate renders fine. Except for one thing: if I reduce the viewing area, there is no scrollbars anymore:

Before resizing:
http://pemessier.hexpresso.org/misc/treeview_delegate_before.png

After resizing with the mouse (no scrollbars):
http://pemessier.hexpresso.org/misc/treeview_delegate_after.png

For information, I reimplement the sizeHint method to override the delegate height (it works).

I am guessing that I must inform the View that the delegate is that pixels wide, and that the view should scroll to display it. Am I looking at the right spot?

Thanks again!

wysota
4th May 2008, 20:39
Delegate has no width. It is the view that tells the delegate the rectangle to paint on based on some conditions. One of them is the value returned by the sizeHint() method. So there are two things to remember:
1. return proper values in sizeHint()
2. don't draw outside the rectangle given to the delegate's paint() method by the view.

Another thing to check is that you didn't turn off scrollbars manually using the view's properties.

SiLiZiUMM
5th May 2008, 16:43
Ok I just found the problem why the scrollbars were not showing up. I have a stylesheet in my QTreeView widget that sets the background color. This seems to be a problem for the scrollbars:

With stylesheet:
http://pemessier.hexpresso.org/misc/Navigator-with-stylesheet.png

Without stylesheet:
http://pemessier.hexpresso.org/misc/Navigator-without-stylesheet.png

Well that partly solves the problem :p Now back on it, the simplified problem is that the scrollbars are not in sync with the delegate width:

See, the text is clipped:
http://pemessier.hexpresso.org/misc/Navigator-without-stylesheet2.png




Delegate has no width. It is the view that tells the delegate the rectangle to paint on based on some conditions.One of them is the value returned by the sizeHint() method. So there are two things to remember:
1. return proper values in sizeHint()
2. don't draw outside the rectangle given to the delegate's paint() method by the view.


Ok, so in the delegate's paint() method, I have to "clip" my painting to fit within the given option.rect rectangle?

How does the View knows when to display a scrollbar?

Is it normal that the given option.rect rectangle in sizeHint is set to x0,y0, and has a width of -1 and a height of 0?

wysota
5th May 2008, 19:53
Ok, so in the delegate's paint() method, I have to "clip" my painting to fit within the given option.rect rectangle?
Yes, that's the rectangle containing the index you are currently painting.


How does the View knows when to display a scrollbar?
It calculates the size of all items and compares them to the size of its viewport.


Is it normal that the given option.rect rectangle in sizeHint is set to x0,y0, and has a width of -1 and a height of 0?

Yes, it's an empty QRect.

SiLiZiUMM
5th May 2008, 20:34
Ok now my delegate does not paint outside the option.rect in the paint() method. Still, no luck for the horizontal scrollbars.

I tried to return a QSize(1000, 50); in sizeHint: the row height is really 50 pixels, but the width parameter does absolutely nothing.. I was thinking that sizeHint would be used to calculate the width of the item, and that the returned with would be used by the view.. guess I am wrong again?

Also, after investigating a bit, sizeHint() is called when the item is expanded or collapsed, but not when the viewport size change...

wysota
5th May 2008, 21:38
What is the horizontalScrollBarPolicy of the view?

SiLiZiUMM
6th May 2008, 00:58
What is the horizontalScrollBarPolicy of the view?

The default policy (Qt::ScrollBarAsNeeded). In fact, if I choose the Qt::ScrollBarAlwaysOn policy, the scrollbars are greyed out until I reach the same point than the default policy : my text is clipped (and the QSize width of the delegate's returned sizeHint still have no effect)...

http://pemessier.hexpresso.org/misc/navigator-scrollbaralwayson.png

wysota
6th May 2008, 06:38
Could you post the contents of your delegate?

SiLiZiUMM
6th May 2008, 13:12
Sure, here's a simple version of my class (I removed the unneeded stuff for this problem, the following code reproduces the problem):

sizeHint():


QSize MyDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index ) const
{
// Override the default height
QSize size(QItemDelegate::sizeHint(option, index));
QFontMetrics fm(option.fontMetrics);

if(fm.height() > 16)
{
size.setHeight(fm.height() + 4);
}
else
{
size.setHeight(20);
}

//return QSize(1000,50);
return size;
}



paint():


void MyDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
{
painter->save();

// Useless stuff skipped...


// Draw the content of the delegate

// Text rectangle
// The text will be vertically centered.
// If a context is available, the context will be displayed in bold, between brackets.
QString text(index.data(Qt::DisplayRole).value<QString>());
if(!index.parent().isValid()) // TODO: IF CONTEXT
{
text.append(" <b>(bold text)</b>"); // TODO: get the text from the model
}

QTextDocument textDoc;
textDoc.setHtml(text);

int textX = option.rect.x();
int textY = (option.rect.height() - textDoc.size().height())/2 + option.rect.y();

// Set the text rectangle width (the smaller of the two will be used): either as wide as the text width, or as
int textWidth = qMin<int>(textDoc.size().width(), option.rect.width());
QRect textRect(textX, textY, textWidth, option.rect.height());

// Translate the painter to the position of the text rectangle in order to paint the QTextDocument
// Then paint the text as HTML formatted text
painter->save();
painter->translate(textRect.topLeft());
textDoc.drawContents(painter, textRect.translated(-textRect.topLeft()));
painter->restore();


painter->restore();
}

SiLiZiUMM
6th May 2008, 13:59
Oh by the way, my class inherits from QItemDelegate

wysota
6th May 2008, 16:55
Your sizeHint() implementation seems to be incorrect. If you use QTextDocument for rendering the data, you should also use it for checking the size needed to make the item fit.

SiLiZiUMM
6th May 2008, 17:23
Your sizeHint() implementation seems to be incorrect. If you use QTextDocument for rendering the data, you should also use it for checking the size needed to make the item fit.

From my example, wouldn't return QSize(1000,50) in sizeHint force the view to display the item 1000pixels wide (which it does not if I return that size) and 50 pixels tall (which it does)?