PDA

View Full Version : Customize QListWidgetItem, how to?



martinn
2nd February 2010, 18:37
I'm using QListWidget to list things in my application. It's very easy to use but also very simple. What if I want a custom design of my QListWidgetItem? The standard is just one row of text but what if I want one large label and other smaller labels that shows text on my QListWidgetItem? Is there an easy way to cusomize this or should I use some other widget for this? Also is there possible to add Buttons on the QListWidgetItem?

A list like this is something I would like:
http://i47.tinypic.com/nwnekw.jpg

Thanks really much for your help!

ecanela
2nd February 2010, 18:49
i think iis more simple use a QListView whit a custom delegate.

martinn
2nd February 2010, 20:40
Hi and thanks!

Is there any examples on how to use a custom delegate for a QListView?

squidge
2nd February 2010, 21:12
Sure, in the 'examples' directory of the Qt distribution :)

been_1990
2nd February 2010, 21:18
Also check the ICS Network video tutorials at : http://www.ics.com/learning/icsnetwork/
Look for the model-view framework video.

aamer4yu
3rd February 2010, 05:13
Its not necessary to use QListView for delegates. You can use delgates with QListWidget.
Check the spin box and star delegate examples in Qt Demo.

martinn
3rd February 2010, 10:18
Thanks for your help!

I found out that I also could use QListWidget::setItemWidget(), which seems simplier than using a delegate?

This is what I tried, I can now build the ui of MyItem using the Design Editor:



//MyItem is a custom widget that takes two strings and sets two labels to those string.
MyItem *myItem = new MyItem("Text for label1","Text for label2");
QListWidgetItem *item = new QListWidgetItem();
item->setSizeHint(QSize(0,65));
ui.listWidget->addItem(item);
ui.listWidget->setItemWidget(item,myItem);


What is the best way if all I want is to show two different labels and an image, using a delegate or setItemWidget() like above? Is the way I use above a "heavy" solution?

If I use a delegate can I create my ListItem using Designer Editor then? And if so, where can I find examples of this?

Thanks again!

aamer4yu
3rd February 2010, 12:02
Is the way I use above a "heavy" solution?
Yes

If you use delegate, you can create your item in designer, but you cant see the effects of the delegate from the designer. You will need to run the code and check

martinn
3rd February 2010, 12:50
Thanks! I thought it seemed a little heavy.. :)

Is there any examples of using the designer when creating the item? (Sorry but I'm a real newbie to Qt)

Astronomy
3rd February 2010, 13:56
Hi,
Thanks to all for these General ideas, i can use them for my similar problem too. :)

greetz Astronomy

aamer4yu
3rd February 2010, 14:56
In the designer, double click on the QListWidget, you will get a dialog to add items.
Did you try it yet ?

martinn
3rd February 2010, 19:40
In the designer, double click on the QListWidget, you will get a dialog to add items.
Did you try it yet ?

Oh sorry! What I meant was if I could use the designer to build the item in the delegate. Right now I'm using the code below to create the delegate with QPainter as you can see. But I would like it if it was possible to create my ui in the designer instead and add my labels and so on.

Is that possible? And is there any examples of this?



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

if (option.state & QStyle::State_Selected) {
background = Qt::darkGray;
} else {
background = Qt::lightGray;
}
painter->fillRect(....
....
//More code here
....
painter->drawText(option.rect, Qt::AlignCenter, index.model()->data(index).toString());
}

aamer4yu
4th February 2010, 04:44
I dont think so. If it were, designer would not be a designer but a IDE then, isnt it ?

martinn
4th February 2010, 17:36
Thanks for your help! With your help I have now understand that I should use a delegate. This is how I'm testing it right now. It works just like I want as I can place my text with painter wherever I want. Thanks!

My problem is now that from this blog http://labs.trolltech.com/blogs/2007/11/01/qstyleditemdelegate-styling-item-views/ I have understood that my delegate should be able to use the QStyles that is set in the application. So what I do in my application is just to set the stylesheets for QListWidget::item and QListWidget::item:selected but nothing happens to my QListWidget::items that is created in the delegate. What am I doing wrong here? Should I do something else in my paint method to get Stylesheets working?

This is my code:


class MyDelegate : public QStyledItemDelegate {
public:
MyDelegate(QObject *parent=0) : QStyledItemDelegate (parent){}

void paint ( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const{
if(option.state & QStyle::State_Selected){
painter->fillRect(option.rect, option.palette.color(QPalette::Highlight));
}

QString title = index.data(Qt::DisplayRole).toString();
QString description = index.data(Qt::UserRole + 1).toString();

r = option.rect.adjusted(50, 0, 0, -50);
painter->drawText(r.left(), r.top(), r.width(), r.height(), Qt::AlignBottom|Qt::AlignLeft|Qt::TextWordWrap, title, &r);

r = option.rect.adjusted(50, 50, 0, 0);
painter->drawText(r.left(), r.top(), r.width(), r.height(), Qt::AlignLeft|Qt::TextWordWrap, description, &r);
}

QSize sizeHint ( const QStyleOptionViewItem & option, const QModelIndex & index ) const{
return QSize(200, 100);
}
};

int main(int argc, char **argv){
QApplication app(argc, argv);
QListWidget listWidget;

app.setStyleSheet("QListWidget { background: red; } QListWidget::item { background: yellow; } QListWidget::item:selected { background: blue; }");

for (int i = 0; i < 4; i++) {
QListWidgetItem *item = new QListWidgetItem();
item->setData(Qt::DisplayRole, "This is the title");
item->setData(Qt::UserRole + 1, "This is description");
listWidget.addItem(item);
}

listWidget.setItemDelegate(new MyDelegate(&listWidget));
listWidget.showMaximized();
return app.exec();
}

faldzip
4th February 2010, 22:02
Style is a different thing than Style Sheet. You always have some style in your app. If you are using windows xp then your style is WindowsXP (You can try different styles running your app with e.g. -style plastique or -style cleanlooks). And when settings style you either use style sheets or paint it your self. I can't understand why you are setting style sheet if then you are painting items in your own way?
And about style and widgets on item views: You can use QStyle class for drawing controls (and you can obtain your actual style with QApplication::style() static method) or use QStylePainter which is QPainter with QStyle's ability to draw controls.
With this you can draw for example a push button. But remember that it is only drawn button so it is let's say a picture of a button, so you have to implement event handling by yourself (like getting know when to draw a highlighted button and when sunken button etc).

martinn
4th February 2010, 23:05
Thanks for your answer! I thought that it was possible to use the stylesheets just like I use to even if I was using a delegate and painted everything. My misstake.. So if I want gradient (like the picture in my first post) I should just paint the gradient. And the stylesheets can't be used at all here?

faldzip
5th February 2010, 08:07
Read documentation about style sheet and check theirs functionality. If you decide that all you want to have in your view can be done with style sheet, then you can just use them without implementing your custom delegate at all. But if you decide that style sheet functionality is not enough for you then I suggest to do all your custom look in custom delegate as it gives you much more ways to customize your view.

martinn
5th February 2010, 13:15
Now I got my delegate up and running and I was able to paint it so it looks like I want. Thanks!

One thing is that I'm trying to add an image to each row as you can see in the code below. This is really slow.. Is it always slow when adding an image for each row or am I doing something wrong in my code? Is there a better way of adding the image?

This is the code where I load my listWidget:


for (int i = 0; i < 50; i++) {
QListWidgetItem *item = new QListWidgetItem();
item->setData(Qt::DisplayRole, "This is the title");
item->setData(Qt::UserRole + 1, "This is description");
item->setData(Qt::DecorationRole, QPixmap(":/images/myimage.png"));
listWidget.addItem(item);
}




In my delegate I paint the image like this:


QIcon ic = QIcon(qvariant_cast<QPixmap>(index.data(Qt::DecorationRole)));
r = option.rect;
ic.paint(painter, r, Qt::AlignVCenter|Qt::AlignLeft);

dubstar_04
21st February 2010, 21:36
hi martinn,

I am looking to implement a very similar type of list and I an wondering if it would be possible for you to share your code?

many thanks,

Dubstar_04

martinn
8th March 2010, 09:15
To set the delegate for a list:


myListWidget->setItemDelegate(new ListDelegate(myListWidget));
QListWidgetItem *item = new QListWidgetItem();
item->setData(Qt::DisplayRole, "Title");
item->setData(Qt::UserRole + 1, "Description");
myListWidget->addItem(item);


ListDelegate.h:


#include <QPainter>
#include <QAbstractItemDelegate>

class ListDelegate : public QAbstractItemDelegate
{
public:
ListDelegate(QObject *parent = 0);

void paint ( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const;
QSize sizeHint ( const QStyleOptionViewItem & option, const QModelIndex & index ) const;

virtual ~ListDelegate();

};

ListDelegate.cpp:


#include "ListDelegate.h"

ListDelegate::ListDelegate(QObject *parent)
{

}

void ListDelegate::paint ( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const{
QRect r = option.rect;

//Color: #C4C4C4
QPen linePen(QColor::fromRgb(211,211,211), 1, Qt::SolidLine);

//Color: #005A83
QPen lineMarkedPen(QColor::fromRgb(0,90,131), 1, Qt::SolidLine);

//Color: #333
QPen fontPen(QColor::fromRgb(51,51,51), 1, Qt::SolidLine);

//Color: #fff
QPen fontMarkedPen(Qt::white, 1, Qt::SolidLine);

if(option.state & QStyle::State_Selected){
QLinearGradient gradientSelected(r.left(),r.top(),r.left(),r.heigh t()+r.top());
gradientSelected.setColorAt(0.0, QColor::fromRgb(119,213,247));
gradientSelected.setColorAt(0.9, QColor::fromRgb(27,134,183));
gradientSelected.setColorAt(1.0, QColor::fromRgb(0,120,174));
painter->setBrush(gradientSelected);
painter->drawRect(r);

//BORDER
painter->setPen(lineMarkedPen);
painter->drawLine(r.topLeft(),r.topRight());
painter->drawLine(r.topRight(),r.bottomRight());
painter->drawLine(r.bottomLeft(),r.bottomRight());
painter->drawLine(r.topLeft(),r.bottomLeft());

painter->setPen(fontMarkedPen);

} else {
//BACKGROUND
//ALTERNATING COLORS
painter->setBrush( (index.row() % 2) ? Qt::white : QColor(252,252,252) );
painter->drawRect(r);

//BORDER
painter->setPen(linePen);
painter->drawLine(r.topLeft(),r.topRight());
painter->drawLine(r.topRight(),r.bottomRight());
painter->drawLine(r.bottomLeft(),r.bottomRight());
painter->drawLine(r.topLeft(),r.bottomLeft());

painter->setPen(fontPen);
}

//GET TITLE, DESCRIPTION AND ICON
QIcon ic = QIcon(qvariant_cast<QPixmap>(index.data(Qt::DecorationRole)));
QString title = index.data(Qt::DisplayRole).toString();
QString description = index.data(Qt::UserRole + 1).toString();

int imageSpace = 10;
if (!ic.isNull()) {
//ICON
r = option.rect.adjusted(5, 10, -10, -10);
ic.paint(painter, r, Qt::AlignVCenter|Qt::AlignLeft);
imageSpace = 55;
}

//TITLE
r = option.rect.adjusted(imageSpace, 0, -10, -30);
painter->setFont( QFont( "Lucida Grande", 6, QFont::Normal ) );
painter->drawText(r.left(), r.top(), r.width(), r.height(), Qt::AlignBottom|Qt::AlignLeft, title, &r);

//DESCRIPTION
r = option.rect.adjusted(imageSpace, 30, -10, 0);
painter->setFont( QFont( "Lucida Grande", 5, QFont::Normal ) );
painter->drawText(r.left(), r.top(), r.width(), r.height(), Qt::AlignLeft, description, &r);
}

QSize ListDelegate::sizeHint ( const QStyleOptionViewItem & option, const QModelIndex & index ) const{
return QSize(200, 60); // very dumb value
}

ListDelegate::~ListDelegate()
{

}

mero
8th May 2010, 01:11
can anybody add example how to insert image into ListDelegate.cpp ?

Sai Prasad
2nd December 2010, 05:23
Can u send this sorce code for me.

m.anis
29th July 2011, 10:22
thank you very much, very useful thread...

csuman
11th December 2016, 11:48
Excellent solution.
My only problem is when I have variable text length for each Description, I cannot set dynamic sizeHint, particularly the height will be different for each item Description. Please help.

QSize ListDelegate::sizeHint ( const QStyleOptionViewItem & option, const QModelIndex & index ) const
{
QSize(200, 60); // very dumb value ***************=> How to make this vary with each ITEM?
}

anda_skoa
12th December 2016, 10:47
You get the index to the cell's data.

Cheers,
_