PDA

View Full Version : How do draw a frame in QListView?



someralex
19th December 2006, 13:56
qt-4.2

I try to draw this way:


myView::myView(QWidget *parent)
: QListView(parent)
{
}

void myView::paintEvent(QPaintEvent *event)
{

QStyleOptionViewItem option = viewOptions();

QPainter painter(viewport());
painter.save();

QPen pen(Qt::blue, 5, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
painter.setPen(pen);
QRectF rectangle(option.rect.x(), option.rect.y(), option.rect.width(),option.rect.height());
painter.drawRoundRect(rectangle,5,5);
painter.restore();
}

but all items are being overlaped, though the scroll works and you can see that there are items there (behind the rectangle) How to draw on background behind items?

wysota
19th December 2006, 14:32
The easiest way would be to reimplement the delegate or modify the palette (depending on what you want to do). Probably using stylesheets is an option as well, if QListView is stylable.

BTW. Don't you think you should at least call the base class implementation for the items to be drawn?

I think you're either trying to do something weird or trying to do something useful the weird way :) What exactly are you trying to achieve?

someralex
19th December 2006, 15:03
I need a frame of an arbitrary form, with background of a solid color or texture. I would like to draw everything with primitives. I've done it this way:


myView::myView(QWidget *parent)
: QListView(parent)
{
}

void myView::paintEvent(QPaintEvent *event)
{
QStyleOptionViewItem option = viewOptions();

QPainter painter(viewport());

QPen pen(Qt::blue, 20, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
painter.setPen(pen);
QRect rectangle(option.rect.x(), option.rect.y(), option.rect.width()-10,option.rect.height()-10);
painter.drawRoundRect(rectangle,10,10);

QListView::paintEvent(event);
}

Both items and my rectangular can be drawn. But instead of the rectangular of the QListView size, a little area of blue color appears in the upper right corner. This blue piece scrolls with my list, however, I need to replace the standard border of QListView with my frame. What's wrong?

jpn
19th December 2006, 15:20
QListView inherits QFrame which has several options for modifying the frame. Maybe you can find something sufficient from there?

In the above myView::paintEvent() you are drawing something by yourself first and then calling the QListView implementation which most likely overrides what you have drawn.

QAbstractItemView::viewOptions() returns a QStyleOptionViewItem which is intended to be filled correctly by the view and then being passed for a delegate. The QStyleOptionViewItem::rect variable is a null rectangle.

someralex
19th December 2006, 16:42
How to get QFrame::painter ?

jpn
19th December 2006, 17:40
How to get QFrame::painter ?
What is that?

I meant something like:


listView->setLineWidth(5);
listView->setFrameStyle(QFrame::Panel | QFrame::Sunken);

someralex
19th December 2006, 17:57
It I did already.
now I need to draw on a background QListView.
How?
if i do


myView::myView(QWidget *parent)
: QListView(parent)
{
}

void myView::paintEvent(QPaintEvent *event)
{

QPainter painter(viewport());

QPen pen(Qt::green, 10, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
painter.drawText(rect(),Qt::AlignLeft,"Test DRive this List");

QListView::paintEvent(event);
}

i get painter from QAbstractItemView and my text scroll with item.
it follows from this that it is needed to draw on painter from QFrame or QWidget

jpn
19th December 2006, 18:20
I'm not sure if this works with QWindowsXpStyle but works with QPlastiqueStyle, at least. Set QPalette::Base brush to Qt::transparent:


QPalette p = listView->palette();
p.setBrush(QPalette::Base, Qt::transparent);
listView->setPalette(p);


And in this case draw before passing the paint event to the base class implementation.

jpn
19th December 2006, 18:25
i get painter from QAbstractItemView and my text scroll with item.
it follows from this that it is needed to draw on painter from QFrame or QWidget
So you want the drawing to stay in corresponding place at background when scrolling?


QPainter painter(viewport());
painter.translate(-horizontalScrollBar()->value(), -verticalScrollBar()->value());
painter.drawSomething(...);

someralex
19th December 2006, 19:01
this code work


QPainter painter(viewport());
QPen pen(Qt::green, 10, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
painter.setPen(pen);
painter.drawRect(rect());
painter.translate(-horizontalScrollBar()->value(), -verticalScrollBar()->value());
QListView::paintEvent(event);

but :
1.at scrolling of list, top and bottom lines of rectangle erase.If using painter.translate identical effect
2.rectangle paint over item

jpn
19th December 2006, 19:22
Translate first, then draw. Translating the painter after painting has no effect. The default QItemDelegate painting implementation fills items' background with QPalette::Base. That's why I told you to use a transparent brush.

someralex
19th December 2006, 19:46
after using


QPalette p = listView->palette();
p.setBrush(QPalette::Base, Qt::transparent);
listView->setPalette(p);

all ok. Thanks
but rectangle paint over viewport of scrollView
How i need to replace the standard border?
QFrame::painter() ?

wysota
19th December 2006, 21:58
There is no such thing as "QFrame::Painter()".

someralex
20th December 2006, 07:58
where then to draw decoration of widget - border,shade ?

wysota
20th December 2006, 09:58
It's drawn in the paintEvent (probably using QStyle primitives). I don't think you really wish to change that, but of course it is possible by reimplementing the event and drawing your own frame. It might be simpler to use stylesheets to substitute the frame with your border image or changing the style to draw another frame.

someralex
20th December 2006, 18:28
Can I obtain painter for parent QFrame in paintEvent method in QListView and re-draw it the way I want? If I can, how can I get it? Or do I need to create my own QFrame based on standard and create my ListView based on QListView and QFrame (class myView(QWidget *parent = 0) : public QListView, public myFrame) ?

wysota
20th December 2006, 20:02
You don't "obtain" a painter, you create it:

void MyWidget::paintEvent(QPaintEvent *e){
QPainter painter(this);
painter.drawRect(...);
//...
}

someralex
20th December 2006, 20:38
If I use:


QPainter painter(this);

nothing can be drawn and I get an error :

QPainter::begin: Widget painting can only begin as a result of a paintEvent

when cursor of the mouse enters the area of the window where widget is placed.

wysota
20th December 2006, 20:46
Obiously you can only create a painter in a paint event, like in the snippet I gave you in the previous post.

someralex
20th December 2006, 21:10
yes, I do exactly just like shown in your previous post. it gives me an error and draws nothing :confused:

wysota
20th December 2006, 21:30
Can we see the code along with the class declaration?

someralex
21st December 2006, 08:11
class myView : public QListView
{
Q_OBJECT
public:
myView(QWidget *parent = 0);
protected:
void paintEvent(QPaintEvent *event);
private:

};

myView::myView(QWidget *parent)
: QListView(parent)
{
}

void myView::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
QPen pen(Qt::green, 10, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
painter.setPen(pen);
painter.drawRect(rect());
QListView::paintEvent(event);
}

wysota
21st December 2006, 09:40
The code looks correct. You don't call the paintEvent yourself, do you?

jpn
21st December 2006, 11:09
It should be:

QPainter painter(viewport());

Which is mentioned in the docs QAbstractScrollArea::paintEvent():


Note: If you open a painter, make sure to open it on the viewport().

wysota
21st December 2006, 11:56
Oh, it's a listview! I somehow thought we were talking about QFrame :) Silly me...