PDA

View Full Version : Custom mouse dragging an entire scene?



swbluto
26th October 2009, 03:19
Hello, I'm trying to implement dragging in a scene such that all of the images on the scene move exactly the amount that I drag my mouse while the button is pressed. My code for one image worked excellently, but as soon as I went to create an array of images... only one moves, and the one before it periodically "jumps" and all the rest are bumps on a log. How do I get all of them to move?

Here's the code:



#include <QApplication>
#include <QGraphicsEllipseItem>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QtGui>

#include <qdatetime.h>
#include <qmainwindow.h>
#include <qstatusbar.h>
#include <qmessagebox.h>
#include <qmenubar.h>
#include <qapplication.h>
#include <qpainter.h>
#include <qprinter.h>
#include <qlabel.h>
#include <qimage.h>
#include <qpixmap.h>
#include <QMouseEvent>
#include <QStyleOptionGraphicsItem>
#include <qdebug.h>
#include <stdlib.h>
#include <qtimer.h>

QString myImgName = "myimg.png";
static QImage *myImg;
int xOffset;
int yOffset;
static const int imageRTTI = 984376;
void debug(QString s)
{
qDebug(s.toAscii());
}

class mapScene: public QGraphicsScene
{
public:
mapScene();

int mouseMoveX;
int mouseMoveY;
QPointF prevMousePoint;
QPointF currMousePoint;

bool mouseDown;
protected:
void mouseMoveEvent ( QGraphicsSceneMouseEvent * mouseEvent );
void mousePressEvent ( QGraphicsSceneMouseEvent * mouseEvent );
void mouseReleaseEvent ( QGraphicsSceneMouseEvent * mouseEvent );
};

mapScene::mapScene()
{
mouseDown = false;
mouseMoveX = 0;
mouseMoveY = 0;
xOffset =0;
yOffset =0;

}

void mapScene::mouseMoveEvent( QGraphicsSceneMouseEvent * event)
{
if(mouseDown)
{
xOffset = (int)(event->scenePos().x() - event->lastScenePos().x());
yOffset = (int)(event->scenePos().y() - event->lastScenePos().y());
advance();
}
else
{
xOffset = 0;
yOffset = 0;
}
}

void mapScene::mousePressEvent( QGraphicsSceneMouseEvent * event)
{
mouseDown = true;
}

void mapScene::mouseReleaseEvent( QGraphicsSceneMouseEvent * event)
{
mouseDown = false;
xOffset = 0;
yOffset = 0;
}

class ImageItem: public QGraphicsRectItem
{
public:
ImageItem( QImage img );
int rtti () const { return imageRTTI; }
void advance(int phase);
protected:
void paint( QPainter *, const QStyleOptionGraphicsItem *option, QWidget *widget );
private:
QImage image;
QPixmap pixmap;
int state;
};


void ImageItem::advance(int phase)
{
moveBy(xOffset,yOffset);
xOffset = 0; yOffset = 0;
}


ImageItem::ImageItem( QImage img )
: image(img)
{
state = 0;
setRect(0, 0, image.width(), image.height());
setFlag(ItemIsMovable);
#if !defined(Q_WS_QWS)
pixmap = pixmap.fromImage(image, Qt::OrderedAlphaDither);
#endif
}

void ImageItem::paint( QPainter *p, const QStyleOptionGraphicsItem *option, QWidget * )
{
// On Qt/Embedded, we can paint a QImage as fast as a QPixmap,
// but on other platforms, we need to use a QPixmap.
#if defined(Q_WS_QWS)
p->drawImage( option->exposedRect, image, option->exposedRect, Qt::OrderedAlphaDither );
#else
p->drawPixmap( option->exposedRect, pixmap, option->exposedRect );
#endif
}

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

mapScene scene;//mapScene scene;
scene.setSceneRect( -500.0, -500.0, 1000.0, 1000.0 );//( -100.0, -100.0, 200.0, 200.0 );

myImg = new QImage;
myImg->load(myImgName);

QAbstractGraphicsShapeItem* i[10];
for (int temp=0;temp<10;temp++)
{
i[temp] = new ImageItem(*myImg);
scene.addItem(i[temp]);
i[temp]->setPos(-200+50*temp,-50);
}

QGraphicsView view( &scene );
view.setRenderHints( QPainter::Antialiasing );
view.show();

return app.exec();
}


Here's a youtube video of the program working.

http://www.youtube.com/watch?v=aqEtnT-TxUo

Anyone know of a way to embed the video in this thread?

Oh shoot, I think the advance() function where I put xOffset = 0 and yOffset = 0 is what's causing the images after the first one to not move. I put that in the advance function because I had the issue that the image would keep moving after I stopped the mouse but didn't release the button and it didn't seem that I was able to process a "mouse pressed / held down" event, so by resetting it after the picture was moved, the picture wouldn't move unless the mouse was moved again.

But now I have multiple images... so, heh. I might need to reset the xOffset and yOffset (Corresponding to the amount the mouse's x and y changed while dragging) after the last image is drawn, but I don't know how to implement that. I could need to pass the x-offset to each image somehow so that all of them could maintain their own x and yoffset variables, and they can all reset their own x and yoffset variables.

I don't know how to do either of those. Well... let's think. I think I could trigger a variable that signals the first image is being advanced() - when that happens, I can find out how many items are in the scene(can I?), and then count-down for each image whose position has been changed. Once the last one is reached, the count-down reaches zero and then I reset the xOffset and yOffset, and also reset the firstImageBeingAdvanced flag to false (for the next time it gets redrawn).

Sweet, my idea worked. Now, I'm just getting to be afraid of all the global variables I'm using. Is there a better software practice for sharing values between different classes?


#include <QApplication>
#include <QtGui>

#include <stdlib.h>
#include <qtimer.h>

bool firstOneRedrawn = true;
int numGfxItems = 4;
int redrawnCountDown = 4;

QString myImgName = "myimg.png";
static QImage *myImg;

int xOffset;
int yOffset;

static const int imageRTTI = 984376;

void debug(QString s)
{
qDebug(s.toAscii());
}

class mapScene: public QGraphicsScene
{
public:
mapScene();

int mouseMoveX;
int mouseMoveY;
QPointF prevMousePoint;
QPointF currMousePoint;

bool mouseDown;
protected:
void mouseMoveEvent ( QGraphicsSceneMouseEvent * mouseEvent );
void mousePressEvent ( QGraphicsSceneMouseEvent * mouseEvent );
void mouseReleaseEvent ( QGraphicsSceneMouseEvent * mouseEvent );

};

mapScene::mapScene()
{
mouseDown = false;
mouseMoveX = 0;
mouseMoveY = 0;
xOffset =0;
yOffset =0;

}

void mapScene::mouseMoveEvent( QGraphicsSceneMouseEvent * event)
{
if(mouseDown)
{
QString dummy;
debug("mommy");
/*
debug(dummy.setNum(event->pos().x()));
debug(dummy.setNum(event->lastPos().x()));
debug(dummy.setNum(event->lastScenePos().x()));
debug(dummy.setNum(event->scenePos().x()));
*/
xOffset = (int)(event->scenePos().x() - event->lastScenePos().x());
yOffset = (int)(event->scenePos().y() - event->lastScenePos().y());
numGfxItems = items().count();//gets the amount of items in the scene
advance();
}
else
{
xOffset = 0;
yOffset = 0;
}
}

void mapScene::mousePressEvent( QGraphicsSceneMouseEvent * event)
{
mouseDown = true;
}

void mapScene::mouseReleaseEvent( QGraphicsSceneMouseEvent * event)
{
mouseDown = false;
xOffset = 0;
yOffset = 0;
}



class ImageItem: public QGraphicsRectItem
{
public:
ImageItem( QImage img );
int rtti () const { return imageRTTI; }
void advance(int phase);
protected:
void paint( QPainter *, const QStyleOptionGraphicsItem *option, QWidget *widget );
private:
QImage image;
QPixmap pixmap;
int state;
};


void ImageItem::advance(int phase)
{

if(firstOneRedrawn)
{
firstOneRedrawn = false;
redrawnCountDown = numGfxItems;
}
redrawnCountDown--;
moveBy(xOffset,yOffset);
if(redrawnCountDown < 1) //resetting the advance function, after all items have been redrawn
{
xOffset = 0; yOffset = 0;
firstOneRedrawn = true;
}
}


ImageItem::ImageItem( QImage img )
: image(img)
{
state = 0;
setRect(0, 0, image.width(), image.height());
setFlag(ItemIsMovable);
#if !defined(Q_WS_QWS)
pixmap = pixmap.fromImage(image, Qt::OrderedAlphaDither);
#endif
}

void ImageItem::paint( QPainter *p, const QStyleOptionGraphicsItem *option, QWidget * )
{
// On Qt/Embedded, we can paint a QImage as fast as a QPixmap,
// but on other platforms, we need to use a QPixmap.
#if defined(Q_WS_QWS)
p->drawImage( option->exposedRect, image, option->exposedRect, Qt::OrderedAlphaDither );
#else
p->drawPixmap( option->exposedRect, pixmap, option->exposedRect );
#endif
}

int main( int argc, char **argv )
{

QApplication app(argc, argv);

mapScene scene;//mapScene scene;
scene.setSceneRect( -500.0, -500.0, 1000.0, 1000.0 );//( -100.0, -100.0, 200.0, 200.0 );

myImg = new QImage;
myImg->load(myImgName);



QAbstractGraphicsShapeItem* i[10];
for (int temp=0;temp<10;temp++)
{
i[temp] = new ImageItem(*myImg);
scene.addItem(i[temp]);
i[temp]->setPos(-200+50*temp,-50);
}



QGraphicsView view( &scene );
view.setRenderHints( QPainter::Antialiasing );
view.show();

return app.exec();
}

swbluto
26th October 2009, 16:46
(The below was originally a separate post, if not currently)

Gotcha.

(asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfa sdfasdf need to make sure the post is long enough for the forum software to accept it)