PDA

View Full Version : I need help understanding QGraphicsView



aarelovich
19th July 2009, 00:03
Ok so here is some code I wrote to get started:


scene = QGraphicsScene(0,0,100,100);
ui->view->addScene(scene);
QGraphicsRectItem *rect = new QGraphicsRectItem(0,0,50,50);
scene->addItem(rect);


The other parts of the code are cosmetics. But can't, even though I've read the help, understand the relationship between the dimensions and where the things appear drawn in the QGraphicsView.

The rectagle appears not in the middle of the screen, it's like one of the corners is in the middle of the screen, which makes no sense to me with the definition of the scene up above. What's more the size of the rectangle should be of about half the widget in both height and width and it's much smaller than that.

Can any one explain this to me? or tell me where I can find a example simple enough that explains this? Most of the examples I find are complex enough that I can't find a simple piece of explained code that says "This Item is drawn here with this size with respect to the scene".

Thanks for any help.

wagmare
19th July 2009, 12:34
Ok so here is some code I wrote to get started:
The rectagle appears not in the middle of the screen, it's like one of the corners is in the middle of the screen, which makes no sense to me with the definition of the scene up above. What's more the size of the rectangle should be of about half the widget in both height and width and it's much smaller than that.


Thanks for any help.

first u understand coordinate systems in Qt
http://doc.trolltech.com/4.3/coordsys.html

u have to use setPos(x,y) of QGraphicsItem to position the rect in scene ..

ur whole scene rect is (0, 0, 100, 100);
item rect is (0,0,50, 50);
so
position it at (50, 50) in scene like

rect->setPos(50, 50)
otherwise construct

QGraphicsRectItem *rect = new QGraphicsRectItem(50,50,50,50);

playing with coordinats is very simple and interesting

aarelovich
19th July 2009, 19:39
Hi:

Yes this I understand however it does not answer my question. I was afraid I wasn't clear enough. What I don't understand is:

1) Why when the I add the rectangle it appears in the middle of the screen when by my understanding it should appear in a corner? I know I can change the position with setPos but It's not very useful when you can't predict where it's going to appear.

2) Why if the rectangle has a width of 50 it uses much less than half of the screen, which was set to 100? Again I know I can change the size, but it's useless If i can't understand what It does?


Thanks for the reply and for any future help.

Lykurg
19th July 2009, 20:03
1) Why when the I add the rectangle it appears in the middle of the screen when by my understanding it should appear in a corner? I know I can change the position with setPos but It's not very useful when you can't predict where it's going to appear.

See QGraphicsView::setAlignment(). the default is center and middle.


2) Why if the rectangle has a width of 50 it uses much less than half of the screen, which was set to 100? Again I know I can change the size, but it's useless If i can't understand what It does?.

I guess with "screen" you mean the view. And therefore: View != Scene. Can you post a screenshot?

aarelovich
19th July 2009, 20:12
Hi I figured out what's been bugging me.

See I used the the setSceneRect(0,0,100,100) to set the scene. What I didn't figure out what the it created the 100x100 scene in the middle of the QGraphicsViewport and everything (position and size was relative to that). Which now makes sense.

So how did I solved it? I just did setSceneRect(0,0,this->width(),this->height()); Then every position and size got refered to the scene which coincided with the viewport (in this case I'm referring to the QGraphicsView widget as the viewport).

Thanks for all the help.

aarelovich
20th July 2009, 23:21
HI:

So I'm still a little fuzzy about some details.
As I understand things now, if I draw say one rectangle in a specific position and with a specific size and I want that rectangle to always maintain a specifc size relationship with the GraphicsView widget, I have (there is no other way) to reimplement the resizeEvent in my main window (the one that contains the GraphicsView) and redraw said rectangle. Is this right?

If it isn't, could you provide some code of how it's supposed to be done

Thanks for any help in advanced.

wagmare
21st July 2009, 07:28
see this Pad Navigator Example .. try to resize the window .. it will stretch ....
inside panel.cpp see

void Panel::resizeEvent(QResizeEvent *event)
{
QGraphicsView::resizeEvent(event);
fitInView(scene->sceneRect(), Qt::KeepAspectRatio);
}

this one is responsible for the resize event ... this you can use it in any graphicsView .

aarelovich
21st July 2009, 14:26
Ok.

Thank you so very much. That was exactly the kind of code I was looking for. I'll try it out and get back to you.

aarelovich
22nd July 2009, 01:37
Ok, so my dimensioning and positioning problems were solved but now I'm trying to create my own customized QGraphicsItem and I've run into a bit of a problem.

Heres is my code for my peg.h


#ifndef PEG_H
#define PEG_H

#include <QtGui>
#include <QtCore>

class Peg : public QGraphicsItem
{
public:
Peg(QColor color);

void paint( QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget = 0 );
QRectF boundingRect() const;

private:
QColor color;
};

#endif // PEG_H


and its corresponding peg.cpp



#include "peg.h"

Peg::Peg(QColor col){
color = col;
setFlag(ItemIsMovable);
}

QRectF Peg::boundingRect() const {
return QRectF(-1,-1,12,12);
}

void Peg::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget){
painter->setPen(QPen(Qt::black));
QRadialGradient gradient(3,3,9);
gradient.setColorAt(0.0,Qt::white);
gradient.setColorAt(0.5,color.lighter(120));
gradient.setColorAt(1.0,color);
painter->setBrush(gradient);
painter->drawEllipse(0,0,10,10);
}


Then this is the code of the constructor of my mainwindow:



Mastermind::Mastermind(QWidget *parent)
: QMainWindow(parent), ui(new Ui::Mastermind)
{
ui->setupUi(this);
scene = new QGraphicsScene(-50,-50,100,100);
scene->setBackgroundBrush(QBrush(QColor(23,23,23)));
ui->gvDrawArea->setScene(scene);
ui->gvDrawArea->setRenderHints(QPainter::Antialiasing|QPainter::Te xtAntialiasing);
Peg peg(Qt::red);
scene->addItem(&peg);
}

The only problem is, I thought I was supposed to see a somewhat red circle somewhere on the screen yet nothing has appeared.

What did I do wrong?

Thanks for the help.

wagmare
22nd July 2009, 07:22
use peg.setPos(x, y) to set that item in a particular location on scene ...

increase the ellipse size a little ... its very tiny on a big scene ...hahaha ..

wagmare
22nd July 2009, 08:11
your code is completed ... see your item in the attachment ...

actually u need to inherit QObject with your custom QGraphicsItem ...
that is the problem ... now it solved ... also use setPos() in QGraphicsScene()..


class Peg : public QObject, public QGraphicsRectItem
{

Q_OBJECT //if u need any connect in future

have a good day

aarelovich
22nd July 2009, 14:07
Hi:

So thanks for the help. But even though I did what you told me it still did not appear. But I figured out the problem and it did not have anything to do with QGraphicsView Framework and everything to do with C++.

I chaged this code



Peg peg(Qt::red);
scene->addItem(&peg);


with this code


Peg *peg = new Peg(Qt::red);
scene->addItem(peg);


It seems that by creating the local variable peg instead of a pointer it gets destroy at the end of the constructor therefore, it never shows up in the screen.

Thanks for all the help, I'll probably be posting more of my problems.

aarelovich
22nd July 2009, 17:07
HI:

So another day another problem that I don't understand. I'm doing the whole drag the peg into a box thing. Looking at the examples I found that it was a nice idea to use the close and open hand during the dragging movement. Here is the code for the peg class:


#include "peg.h"

Peg::Peg(QColor col){
color = col;
ScaleFactor = 1;
}

QRectF Peg::boundingRect() const {
double Margin = 2;
return QRectF(-Margin,-Margin,10*ScaleFactor + 2*Margin,10*ScaleFactor + 2*Margin);
}

void Peg::setMoveable(bool move){
setFlag(ItemIsMovable,move);
}

void Peg::setScaleFactor(double rad){
ScaleFactor = rad;
}

void Peg::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget){
painter->setPen(QPen(Qt::black));
QRadialGradient gradient(3,3,9);
gradient.setColorAt(0.0,Qt::white);
gradient.setColorAt(0.7,color.lighter(120));
gradient.setColorAt(1.0,color);
painter->setBrush(gradient);
painter->scale(ScaleFactor,ScaleFactor);
painter->drawEllipse(0,0,10,10);
}

void Peg::mousePressEvent(QGraphicsSceneMouseEvent *event){
if (event->button() != Qt::LeftButton){
event->ignore();
return;
}
setCursor(Qt::ClosedHandCursor);
}


void Peg::mouseReleaseEvent(QGraphicsSceneMouseEvent *event){
setCursor(Qt::OpenHandCursor);
}


I added the thing and when I click it the hand effectively closes but a soon as I start to move the peg, the peg inmediately appears in coordinates (0,0) of the scene and it starts moving from there (mantaining the distance from where the item originally lied to the (0,0)), Other than that it actually moves and it stays where the item is when I let go of the mouse button (which is a ways off from where the close hand cursor is).

Again, I ask,anyone got any idea of what am I doing wrong?

Thanks for any help.

aarelovich
22nd July 2009, 21:02
It's me again with another problem solved and whole new one.

The last problem was solved by calling QGraphicsItem::mouseReleaseEvent(event); and
QGraphicsItem::mousePressEvent(event); in the respective redefined events.

However now I've got a new problem. This is one that has apparently confused many before. I want to drag and drop a my own created Peg GraphicItem into a square also created by me. Here is the code I've done so far:

peg.cpp


Peg::Peg(QColor col){
color = col;
ScaleFactor = 1;
}

QRectF Peg::boundingRect() const {
double Margin = 2;
return QRectF(-Margin,-Margin,10*ScaleFactor + 2*Margin,10*ScaleFactor + 2*Margin);
}

void Peg::setMoveable(bool move){
setFlag(ItemIsMovable,move);
}

void Peg::setScaleFactor(double rad){
ScaleFactor = rad;
}

void Peg::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget){
painter->setPen(QPen(Qt::black));
QRadialGradient gradient(3,3,9);
gradient.setColorAt(0.0,Qt::white);
gradient.setColorAt(0.7,color.lighter(120));
gradient.setColorAt(1.0,color);
painter->setBrush(gradient);
painter->scale(ScaleFactor,ScaleFactor);
painter->drawEllipse(0,0,10,10);
}


void Peg::mousePressEvent(QGraphicsSceneMouseEvent *event){
if (event->button() != Qt::LeftButton){
event->ignore();
return;
}
setCursor(Qt::ClosedHandCursor);
QDrag *drag = new QDrag(event->widget()); \\Problem Code
QMimeData *mime = new QMimeData(); \\Problem Code
mime->setColorData(color); \\Problem Code
drag->setMimeData(mime); \\Problem Code
drag->exec(); \\Problem Code
QGraphicsItem::mousePressEvent(event);
}

void Peg::mouseMoveEvent(QGraphicsSceneMouseEvent *event){
QGraphicsItem::mouseMoveEvent(event);
}

void Peg::mouseReleaseEvent(QGraphicsSceneMouseEvent *event){
setCursor(Qt::OpenHandCursor);
QGraphicsItem::mouseReleaseEvent(event);
}


then there is the square.cpp



Square::Square(int w, int h){
Width = w;
Height = h;
setZValue(-1);
setAcceptDrops(true);
}

QRectF Square::boundingRect() const{
return QRectF(0,0,50,50);
}

void Square::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget){
painter->setBrush(QBrush(Qt::darkBlue));
painter->drawRect(0,0,50,50);
}

void Square::dropEvent(QGraphicsSceneDragDropEvent *event){
qDebug() << "I've got something";
event->acceptProposedAction();
}


Now when I added code marked with "\\Problem Code" I finally got the box to accept the drop event (otherwise it wasn't triggered) but now I can't move the peg itself. Rather, a small box forms over the cursor (indicating the draggin action) and dissapears when I let go, however the peg stays in the exact same spot. Is there anyway for this to work properly or do I have to implement some sort of routine that draws the peg under the mouse?

Thanks for any help.