PDA

View Full Version : Painting the inside of a shape in QGraphicsItem



xtraction
16th February 2012, 11:19
Hello,

I implemented a subclass of QGraphicsItem to draw with the mouse when the mouse button is pressed and moved on a QGraphicsView. Whatever shape is made with the mouse upon release of the button I draw a line between the first point and the last point to never have an unclosed shape.

What I want to do now is be able to move that shape created on the view. What I can't figure out is how can I know when the mouse is inside the bounds of the newly drawn shape?
And also how could I paint the inside of the shape, so for example you draw a circle, I want the only the inside of the circle painted when I release the mouse.

I really appreciate any help and tips on how to do this.

Thanks!

MarekR22
16th February 2012, 11:55
QPainterPath::contains

xtraction
16th February 2012, 12:53
I tried that but it always returns true. Even when no drawing of the item has started it already returns as if the cursor was inside a selection.

wysota
16th February 2012, 14:35
Even when no drawing of the item has started it already returns as if the cursor was inside a selection.
If you don't have an item yet, what are you calling this method on?

xtraction
16th February 2012, 15:08
At first I have a view a scene and an item. This item (called myItem) draws an image. I need to be able to draw on top of this image as background with the mouse cursor when pressing and moving until the mouse is released. For this I subclassed QGraphicsItem with my_Item as parent. So in the mousePressEvent I set the item subclass to visible and I implemented the paint event to draw according to the mouse trace. If this trace is not a closed shape on release a line gets drawn between the first point and last point so it will always be a closed shape.

So I am trying to find a way to first have the shape fill up with some color and know when my mouse cursor is inside the shape to be able to move the drawn shape freely after it has been drawn.

Is there perhaps a better way to do this??
Thanks

wysota
16th February 2012, 15:10
For this I subclassed QGraphicsItem with my_Item as parent. So in the mousePressEvent I set the item subclass to visible
You don't set classes to visible. At some point you must have created an instance of that class and this instance must have had boundingRect() (and hence shape()) defined. If you didn't redefine shape() then it by default equals to the boundingRect() hence everywhere inside that boundingRect (so in the bounding area of the item) is considered "inside" the item.

xtraction
16th February 2012, 15:21
Thanks for clearing that up.

If I can't set classes to Visible, what would be the right way to implement something like a rubberband to select an area of an image, except that I don't want a rubberband because I need to be able to define the shape of the selection with the mouse having a 'free hand' way of drawing. And If I don't like the selection I made, click, have it dissapear, and start again until I draw something I want.

I would really appreciate your advice.

wysota
16th February 2012, 15:25
I don't see how this functionality is related to "setting classes to visible". There is a myriad of ways you could implement lasso selection. The easiest one is to reimplement mouse events of the view, build an internal painter path as the user moves his mouse (possibly drawing that path on the view) and then apply that path to selecting items.

xtraction
16th February 2012, 15:45
So the lasso selection would just be the QPainterPath object, so there is no need to have a GraphicsItem to draw the path like in my case? I am doing something similar, I am creating a painterpath in the mouse events, but this is giving somewhat random behavior, sometimes I run the application and it draws fine, and sometimes it doesn't.

wysota
16th February 2012, 16:06
There is no need for any extra graphics items.


#include <QtGui>


class View : public QGraphicsView {
public:
View() : QGraphicsView(){}
protected:
void mousePressEvent(QMouseEvent *event) {
foreach(QGraphicsItem *i, scene()->items())
i->setSelected(false);
m_path.setFillRule(Qt::WindingFill);
m_path.moveTo(event->posF());
}
void mouseMoveEvent(QMouseEvent *event) {
m_path.lineTo(event->posF());
viewport()->update();
}
void mouseReleaseEvent(QMouseEvent *event) {
m_path.closeSubpath();

QList<QGraphicsItem*> it = scene()->items(mapToScene(m_path));
foreach(QGraphicsItem *i, it)
i->setSelected(true);
viewport()->update();
m_path = QPainterPath();

}

void paintEvent(QPaintEvent *event) {
QGraphicsView::paintEvent(event);
if(m_path.isEmpty())
return;
QPainter p(viewport());
QPen pen(QColor(Qt::red));
pen.setWidth(4);
p.setPen(pen);
p.setRenderHint(QPainter::Antialiasing);
p.setBrush(QColor(255,0,0,100));

p.drawPath(m_path);
}

private:
QPainterPath m_path;
};

int main(int argc, char **argv) {
QApplication app(argc, argv);
QGraphicsScene scene;
qsrand(QDateTime::currentDateTime().toTime_t());
for(int i=0;i<50;i++) {
QColor c(qrand() % 255, qrand() % 255, qrand() % 255);
scene.addEllipse(qrand() % 500, qrand() % 500, qrand() % 100, qrand() % 100, c, c)->setFlag(QGraphicsItem::ItemIsSelectable);
}
View view;
view.setRenderHint(QPainter::Antialiasing);
view.setScene(&scene);
view.show();
return app.exec();
}