PDA

View Full Version : Model View - Delegate - setIndexWidget



starcontrol
28th March 2008, 09:13
Hi,
I tried to use the setIndexWidget() function in my MV GUI Qt Code.
I just want to have a simple composed widget in my subclass instance of QTableView, an widget inside an table cell.
Do you have any ideas or better code examples, how to use this function in the right way ? Trolltechs API docu does not explain, how to use this function in Qt's Model-View architecture. As is read before, the best way would be to use this in the delagate (with some dirty tricks), here you find some threads too, which describe my problem best:

http://lists.trolltech.com/qt-interest/2...ead00097-0.html

http://lists.trolltech.com/qt-interest/2...ead00550-0.html

Kind regards,
Alex

jpn
29th March 2008, 22:25
Index widgets are not actually part of the MVC concept but they are additional widgets laid on top of items in the view. They are expensive to maintain and one should avoid them. What kind of widgets would you like to put there?

starcontrol
31st March 2008, 08:19
I want to provide widgets in table cells, which consist of some text labels, some icons and an text edit field(date field), perhaps similar to the graphical interface of outlook calender...
Can you help me how to proceed ?

wysota
31st March 2008, 08:22
As for icons and text the default delegate should handle it fine. As for text edit fields - you'll be only editing one field at a time, so a slightly modified delegate returning a QTextEdit instance as the editor should be enough.

starcontrol
31st March 2008, 08:48
Do you mean, I have to use the different roles in my custom model to let the default delegate render the cells content ?
I tried to do so, but what made me first think of to try an different way, was, that with the decoration role I only could render one icon.
I am also not sure, would it be possible to have drag and drop support, if I implement the cells content in this way ?

wysota
31st March 2008, 09:25
Do you mean, I have to use the different roles in my custom model to let the default delegate render the cells content ?
Yes, that's correct.


I tried to do so, but what made me first think of to try an different way, was, that with the decoration role I only could render one icon.
If you want something non-standard, use a custom delegate. You'll be able to render whatever you want depending on the data contained in an item.


I am also not sure, would it be possible to have drag and drop support, if I implement the cells content in this way ?
Yes, itemviews support d&d.

starcontrol
31st March 2008, 10:44
So I have to implement the delegates paint() function to render my widget ?
Do I have to paint my icons, text labels, editor fields ? There must be an way, instead "manually painting" the widgets, or ?

A second wish:
I have to create spans inside my table view, these spans will have to contain what I described before. The QTableView has an method setSpan(), but how can I check in my custom view from my custom model, where it has to paint the spans?

wysota
31st March 2008, 11:12
So I have to implement the delegates paint() function to render my widget ?
Not widget, but item - yes.


Do I have to paint my icons, text labels, editor fields ?
You only paint the inactive state. In the editing state the delegate returns a real widget.


There must be an way, instead "manually painting" the widgets, or ?
I think you have to define what you mean by "widget". Icon is not a widget. Text is not a widget. So, what is a widget according to your definition?


I have to create spans inside my table view, these spans will have to contain what I described before. The QTableView has an method setSpan(), but how can I check in my custom view from my custom model, where it has to paint the spans?
Why should the model care about the span? It's just a set of data.

starcontrol
31st March 2008, 14:01
I think "manually painting" the items may not be the succeeding way. If I'll use the delegates paint method, I have a simple bitmap, which is rendered inside the table view cell (in my case, inside the span). If the span will be very long, because of an longer event (calender event) the bitmap will be strechted and the text will be rendered not clean, you understand what I mean ?
The second problem is, the item will also have to contain an "active text edit field (date edit field for editing the event)" in the inactive state, how will this be possible with an rendered bitmap ?

Kind regards,
Alex

wysota
31st March 2008, 14:44
If the span will be very long, because of an longer event (calender event) the bitmap will be strechted and the text will be rendered not clean, you understand what I mean ?
The model doesn't care. It doesn't have a concept of width or height. The delegate handles all that and it is given the rectangle that needs to be painted.


The second problem is, the item will also have to contain an "active text edit field (date edit field for editing the event)" in the inactive state, how will this be possible with an rendered bitmap ?

Render the date as text and react on clicking the cell - activate the editor and let the user edit the date. You don't need the spinbox to be active all the time. You can even render the looks of the box if you really need to.

starcontrol
2nd April 2008, 08:48
Ok, I tried your suggestion..., but nothing is displayed in my table cells, do you know, what I am doing wrong ? How do I have to implement the sizeHint() function ?


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

if (option.state & QStyle::State_Active)
painter->fillRect(option.rect, option.palette.highlight());

// gets the cells size and draws the text inside
QRect myRect = QRect(option.rect.topLeft(), option.rect.bottomRight()) ;
painter->drawText(myRect, Qt::AlignCenter, "test");

painter->restore();
}

/*
QSize sizeHint(const QStyleOptionViewItem &option,
const QModelIndex &index ) const
{
// ????????????
}

jpn
2nd April 2008, 08:52
The signature doesn't match. QAbstractItemDelegate::paint() is a const method. So in fact you're not reimplementing but shadowing the function.

starcontrol
2nd April 2008, 10:33
ok, thanks a lot ! ;-)
Now it paints right... My second approach is, to paint an widget inside the table cell by grabbing the widget to an pixmap. This experiment seems to function, but the widget is VERY small inside the cell and you can only see the picture, if you resize the cell to a very, very large cell. I don't know why. The delegates painter got the right size of the cell.
painter->drawPixmap(option.rect, courseItem);
Do you know what I have to do ?



void SchulungsplanDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex &index) const
{
if (index.column() == 3 && index.row() == 2)
{
painter->save();

if (option.state & QStyle::State_Active)
painter->fillRect(option.rect, QBrush(QColor(Qt::darkGreen), Qt::SolidPattern));
painter->setPen(QColor(Qt::white));
painter->drawText(option.rect, Qt::AlignCenter, " 060505K1 8 von 01.01.2008 bis 10.01.2008 ");

// painter->drawPixmap(option.rect, QPixmap("arrowOpen.png"));
painter->restore();
}

if (index.column() == 1 && index.row() == 1)
{
painter->save();

QLabel* courseLabel = new QLabel("Hallo Welt");
QPixmap courseItem = QPixmap::grabWidget(courseLabel);
painter->drawPixmap(option.rect, courseItem);

painter->restore();
}
}

jpn
2nd April 2008, 12:36
You might not want to allocate a QLabel like that during every call to paint(). First of all, currently it's leaking memory quite a bit because those labels allocated during every paint event are never deleted. Secondly, the geometry of a widget is calculated upon first time shown so you should call something like QWidget::adjustSize() or QWidget::ensurePolished() first. But anyway, what's the point of doing so expensive operations such as constructing a label with text and taking a screenshot of it when you could just paint the text with QPainter?

starcontrol
2nd April 2008, 12:59
ups, that's right, obviously it is much more performant to render the items manually, but I thought, it'll be easier for me to implement, because so I only need to create a simple widget and let this paint. I need to fill the table cells with some text and some icons, so I don't know how to get the icons on the right side of the cell, beside the text information.
The item (cell) has to be like this "abstract graphic":

Course 4711 From: 01.01.2008 To: 10.01.2008 ICON1 ICON2

Sometimes there has to be one icon, sometimes two. So I think I have to calculate some space to render between the text and the icon. Do you have any idea how to solve this ?

I think, it will go in this direction, or ?:
/*
QPoint iconStart = ... end of text
QPoint iconEnd = ... end of cell ???
QRect iconsRect = ...
painter->drawPixmap(iconsRect, QPixmap("test.png"));
*/

starcontrol
2nd April 2008, 14:17
I think, i will have to devide the cell into two or more rectangles and paint into the devided new rectangles, perhaps like this:



void SchulungsplanDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex &index) const
{
if (index.column() == 3 && index.row() == 2)
{
painter->save();

if (option.state & QStyle::State_Active)
painter->fillRect(option.rect, QBrush(QColor(Qt::darkGreen), Qt::SolidPattern));
if (option.state & QStyle::State_Selected)
painter->fillRect(option.rect, QBrush(QColor(Qt::red), Qt::SolidPattern));

QRect rect1 = QRect(option.rect->topLeft(),
QPoint(option.rect->center()->x(), option.rect->bottomLeft()->y()));

QRect rect2 = QRect(QPoint(option.rect->center()->x(), option.rect->topRight->y()),
option.rect->bottomRight());

painter->setPen(QColor(Qt::white));
painter->drawText(rect1, Qt::AlignCenter, " RECT1 ");
painter->setPen(QColor(Qt::yellow));
painter->drawText(rect2, Qt::AlignCenter, " RECT2 ");

/*
QPoint iconStart = ... end of text
QPoint iconEnd = ... end of cell ???
QRect iconsRect = ...
painter->drawPixmap(iconsRect, QPixmap("test.png"));
*/

painter->restore();
}

jpn
2nd April 2008, 14:30
Yes, that's basically how QItemDelegate does it too. It divides to whole area to sub-areas for possible icon, checkbox, text etc. QRect should have enough helpful methods for the calculation and QStyle::alignedRect() might also become handy especially if you have to take both layout directions into consideration.