PDA

View Full Version : custom painting in QListWidget



Andrew
28th March 2007, 16:42
Hello,

I am using a QListWidget in ListMode and I want the items to be displayed a little offset'ed (10 pixels in the right and down)

How can I override the default items paint ?

Do I need to create my own model ? Can i override paint event and change the input rectangle ?

thank you.

Andrew
28th March 2007, 19:08
{ forked from: How customize items of ModelView? (http://www.qtcentre.org/forum/f-qt-programming-2/t-how-customize-items-of-modelview-6312.html) }

if instead of the QTableView would be a QListView what are the posibilities to change an item position ?

for example, when the mode in the list is Free you can move the items around in the widget so this tells me that items can be placed in a different position.

what i want to achieve to make all the items in a QListView \ QListWidget to be displayed at an offset from the default position ( i want to make them appear more to the right and down)

wysota
28th March 2007, 19:13
It doesn't matter which view you use, the model remains the same. If you want to modify the position of the text/icon of the item, it should be enough to reimplement the delegate and shift the painter before calling the base class drawing method.

Andrew
28th March 2007, 19:49
and shift the painter before calling the base class drawing method.

i implemented my own delegate and it works (it gets called)

void MyDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QItemDelegate::paint(painter, option, index);
}

but I don't know exactly how to achieve what i want (make the items to be displayed to the right with lets say 50 pixels)

i tried with painter->translate(QPoint(50, 0))
but obviously it will translate the coordinate system on each call to paint( ) which makes the items to be displayed in a diagonal :)

so what i need is to set the origin of the system.

i tried with setViewport and setWindow but its not working ( i guess the default implemenation of QItemDelegate::paint( ) set it )

what remains is to change the matrix

what do you think

Andrew
28th March 2007, 20:07
no, it does not work
modifying the coordinate system is not an option.

when I select an item the selection is displayed on the old position. it's a mess.

any other option for modifying a QListView\QListWidget item position ?

i tried to look at how to implement my own model but i dont see a way to modify item position.
i was not able to find any 'position' in QModelIndex \ QStyle

any ideas ?

wysota
28th March 2007, 20:08
i tried with painter->translate(QPoint(50, 0))
but obviously it will translate the coordinate system on each call to paint( ) which makes the items to be displayed in a diagonal :)
So translate it back after painting.

void MyDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const{
painter->translate(50, 0);
QItemDelegate::paint(painter, option, index);
painter->translate(-50,0);
}

Andrew
28th March 2007, 20:14
no, modifying the coords does not work.. see my previous post

btw, what i am trying to do is to use a QListWidget as a thumbnail viewer.
but i need to modify the position of the items (offset'ed to the right) so they appear more centered

jacek
28th March 2007, 20:39
Do I need to create my own model ?
You can't use a custom model with QListWidget. To do that you will have to switch to QListView.


Can i override paint event and change the input rectangle ?
A custom delegate should be enough. See QItemDelegate.

wysota
28th March 2007, 20:41
no, modifying the coords does not work.. see my previous post

Modify the QStyleOptionViewItem argument then. You can change the rectangle for instance...

Andrew
29th March 2007, 00:18
I did create my own delegate (a class derived from QItemDelegate and set using setItemDelegate )
and overriden
void paint ( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const

but i dont know how to modify the items position.
can you please be specific ?

Andrew
29th March 2007, 00:27
i dont see how you can modify QStyleOptionViewItem::rect
pls tell

jacek
29th March 2007, 00:30
i dont see how you can modify QStyleOptionViewItem::rect
You can modify its copy.

Andrew
29th March 2007, 00:40
You can modify its copy.

what's the purpose of modifying an object copy if you don;t modify the object itself ?

i begin to lose any confident to find a solution to my problem.
i see some people here reply just for the pleasure of doing that.

jacek
29th March 2007, 00:44
what's the purpose of modifying an object copy if you don;t modify the object itself ?
Too pass further the changed object:
void MyDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QStyleOptionViewItem newOption( option );
// change newOption
QItemDelegate::paint(painter, newOption, index);
}

Andrew
29th March 2007, 01:06
thanks.
i simply could not see that.
but now i seem to have another problem.


void MyDelegate::paint ( ..)
{
QStyleOptionViewItem newOption( option );
newOption.rect.translate(QPoint(40,40));

QItemDelegate::paint(painter, newOption, index);
}

when i select items the widget doesnt display the items correctly.
for example, if i select the 2nd item, the horizontal lower half of the first item is erased but the selected item is displayed ok.
but after i play around with selection the whole thing becomes a bigger mess.

what do you think ?
is delegate an option for modifying ListWidget items position ?
is this possible ?

thanks

jacek
29th March 2007, 01:14
when i select items the widget doesnt display the items correctly.
Actually it's almost the same solution as using QPainter::translate(). What you can try to do is to change the decorationSize --- this should move items to the right.

wysota
29th March 2007, 07:26
Maybe you could just center the item using regular methods (by setting the alignment role)? Depends how much you want your items shifted...

jacek
29th March 2007, 22:44
If you could post a screenshot, we would be able to fully understand why and where do you want to move those items.

Andrew
30th March 2007, 02:45
the default item painting in QListWidget is with icon painted very close to the widget left margin.
i want to have an offset.
in the same way, i want a vertical offset from the top.

i am using icon and text in items.

at this moment I see that the solution is to custom paint in a delegate the item (paint the icon and text and my desired locations).

what do you think ?

I have a question. how do I find out the QListWidget client rectangle minus the area occupied by the horizontal scrollbar widget ?
after i add items, I need to determine the width of this area.
i guess QListWidget::contentsRect( ) is the widget client rect but how do I find the scrollbar width ?
i tried with
ui.listWidget->verticalScrollBar()->rect()
after i inserted the items but it doesnt give the real size.
is there any way to find a 'metric' of a scrollbar (like how in win32 api is GetSystemMetrics if i remember right)

wysota
30th March 2007, 12:38
You don't have to do any custom painting. Just subclass QItemDelegate and reimplement its drawDisplay and drawDecoration methods calling the base class implementation with a reduced rectangle.

void MyItemDelegate::drawDecoration ( QPainter * painter, const QStyleOptionViewItem & option, const QRect & rect, const QPixmap & pixmap ) const {
QItemDelegate::drawDecoration(painter, option, rect.adjusted(2,2,0, -2), pixmap);
}

You can also reimplement sizeHint to make sure the item is bigger than is needed to fit the text and icon.

Andrew
30th March 2007, 14:13
I didnt look at QItemDelegate to see what can be overriden.
Thanks alot !

I still need to know the width of the vertical scrollbar.
I'll try to explain why.
I want QListWidget to display only 4 items at once (icons with text underneath)
(so the client rect is splitted in 4 equal parts).

For this i set IconMode view mode.
In order to display only 4 items I need to compute an item size and call QListWidgetItem::setHintSize( )
The item width cannot be just QListWidget::contentsRect().Width( ) / 2 because I need to take into account the left vertical scrollbar width also. Otherwise a horizontal scrollbar will appear.

that's why I need the width of the vertical scrollbar.

After I inserted items I tried to call
QRect rc = ui.listWidget->verticalScrollBar()->rect();
but it does not give consistent results.
I observed that the right size is computed after the first display.
is there a way to get scrollbar metrics \ force internal computation before actual painting ?

wysota
30th March 2007, 14:16
int width = style()->pixelMetric(QStyle::PM_ScrollBarExtent);