how to make parallel events in c++ (specific Qt 4.6) - c++

I have a problem with the execution of multiple functions at once.
Specific , I have two classes (MyRect and space). The Idea is similar to space invaders but I stuck on the beginning. In class MyRect I have defined two rectangles :: body (ship body) and bullet (ship bullet).In the main class space is created ship as MyRect new object with body && bullet rectangles.Also there is definition for keyPress events.
Problem is that when I fire bullet , everythig stops excetp moving of bullet and until loop MyRect::fireBullet(int x, int y) is done , i cant move ship during this event.Obviously, I do some fundamental mistakes so if someone is willing to clarify this.
here is sample code ::
MyRect.h
#include <QWidget>
#include <QRect>
#include <QMainWindow>
#include <QPainter>
#include <QLabel>
#include <ctime>
#include <QtGui/QMainWindow>
class space;
class MyRect : public QObject {
Q_OBJECT
public:
MyRect(int in_x, int in_y, int in_w, int in_h, QWidget* parent)
{
itsx = in_x;
itsy = in_y;
itsw = in_w;
itsh = in_h;
body = new QRect(itsx, itsy, itsw, itsh);
bullet = new QRect(itsx+41, itsy-15, itsw/8, itsh/2);
itsParent = parent;
}
~MyRect() {}
void move(int x ,int y);
public slots:
void fireBullet(int x, int y);
private:
int itsx;
int itsy;
int itsw;
int itsh;
QWidget* itsParent;
QRect* body;
QRect* bullet;
friend class space;
};
MyRect.cpp
#include "MyRect.h"
void wait( float seconds )
{
clock_t endwait;
endwait = clock () + seconds * CLOCKS_PER_SEC ;
while (clock() < endwait) {}
}
void MyRect::move(int x, int y)
{
body->moveTo(x,y);
bullet->moveTo(x+35, y-15);
}
void MyRect::fireBullet(int x, int y)
{
y = y-15;
for(int i=0 ; i<200 ; i++)
{
bullet->moveTo(x+41, y--);
itsParent->repaint();
wait(0.001);
}
}
space.h
#include <QKeyEvent>
#include <QMouseEvent>
#include "MyRect.h"
class space : public QMainWindow
{
Q_OBJECT
public:
space(QWidget *parent = 0);
~space(){}
protected:
void paintEvent(QPaintEvent *event);
void keyPressEvent(QKeyEvent* event);
private:
private:
int x;
int y;
int w;
int h;
MyRect* ship;
signals:
void fireBullet(int x, int y);
};
space.cpp
#include "space.h"
#include <QApplication>
space::space(QWidget *parent)
: QMainWindow(parent)
{
x = 170;
y = 250;
w = 90;
h = 25;
ship = new MyRect(x,y,w,h, this);
connect(this, SIGNAL(fireBullet(int,int)), ship, SLOT(fireBullet(int,int)) );
}
void space::paintEvent(QPaintEvent *event)
{
QPen pen(Qt::black, 2, Qt::SolidLine);
QColor hourColor(0, 255, 0);
QPainter painter(this);
painter.setBrush(hourColor);
painter.setPen(pen);
painter.drawRect( *(ship->body) );
painter.drawRect( *(ship->bullet) );
}
void space::keyPressEvent(QKeyEvent* event)
{
switch(event->key()) {
case Qt::Key_D :
{
x = x+10;
ship->move(x,y);
this->update();
break;
}
case Qt::Key_A :
{
x = x-10;
ship->move(x,y);
this->update();
break;
}
case Qt::Key_M :
{
emit fireBullet(x,y);
break;
}
}
}
main.cpp
#include "space.h"
#include <QDesktopWidget>
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
space window;
window.setWindowTitle("Lines");
window.resize(500,500);
window.show();
return app.exec();
}
Thanks for the answers.

You have an architectural problem. What you are doing is moving the bullet in a loop in its fireBullet method. While that loop is running, the rest of the program isn't, since a single thread can only be doing one thing at a time.
The solution is to refactor your code so that everything on the screen gets updated by one frame-worth of animation every time you call some kind of update method. Basically, you just need to retain enough state, where you are, how fast you are moving, how far you can go before disappearing, so that you can move by the desired amount each frame.
Another thing that you would change is to have the keyPressEvent update the state of the spaceship to know which way it should be moving, so that it can move on its regular paintEvent. For that you can use a QTimer

Related

How can I write a (very) basic custom QAbstractTextDocumentLayout subclass?

I'm trying to create a simple notepad-style Qt application. Since I think I might want a lot of control over exactly how text is rendered, I'm trying to write a custom QAbstractTextDocumentLayout class. The code below compiles and runs, but the text area is blank, no matter how much I type. The debug statements in my draw() function correctly show the entered text, so I know my input is in some form making it all the way to the draw() function, but it's not being rendered.
I just want to tweak this in a minimal way so I can at least see some text being rendered, even if the implementation is incomplete. I also haven't been able to find any documentation whatsoever on writing custom QAbstractTextDocumentLayout, so if anyone had a reference I'd also appreciate that.
main.cpp
#include <QtWidgets/QApplication>
#include <QtWidgets/QMainWindow>
#include <QtWidgets/QTextEdit>
#include <QKeyEvent>
#include "./DocumentLayout.cpp"
class MainContent : public QWidget
{
Q_OBJECT
QTextEdit textEdit;
DocumentLayout layout;
public:
MainContent() : textEdit(this), layout(textEdit.document())
{
int innerPadding = 20;
textEdit.document()->setDocumentMargin(innerPadding);
int textColor = 0xD8DEE9;
int backgroundColor = 0x2E3440;
int selectionColor = 0x2E3440;
int selectionBackgroundColor = 0x81A1C1;
QPalette palette = textEdit.palette();
palette.setColor(QPalette::Base, QColor(backgroundColor));
palette.setColor(QPalette::Text, QColor(textColor));
palette.setColor(QPalette::Highlight, QColor(selectionBackgroundColor));
palette.setColor(QPalette::HighlightedText, QColor(selectionColor));
textEdit.setPalette(palette);
textEdit.setFrameStyle(QFrame::NoFrame);
textEdit.document()->setDocumentLayout(&layout);
};
void resizeEvent(QResizeEvent *event)
{
textEdit.setGeometry(0, 0, this->width(), this->height());
}
void keyPressEvent(QKeyEvent *event)
{
if (event->key() == Qt::Key_W && event->modifiers() == Qt::ControlModifier)
{
qApp->quit();
}
}
};
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QMainWindow window;
window.setWindowTitle("Hello, world!");
window.resize(400, 500);
MainContent content;
window.setCentralWidget(&content);
window.show();
return app.exec();
}
#include "main.moc"
DocumentLayout.cpp
#include <QAbstractTextDocumentLayout>
#include <QPainter>
#include <QTextBlock>
#include <QDebug>
class DocumentLayout : public QAbstractTextDocumentLayout
{
public:
DocumentLayout(QTextDocument *document) : QAbstractTextDocumentLayout(document)
{
}
void draw(QPainter *painter, const PaintContext &context)
{
QTextDocument *document = this->document();
QTextBlock block = document->begin();
QPointF position(20, 20);
painter->setPen(context.palette.color(QPalette::Text));
QTextLayout *layout = block.layout();
layout->draw(painter, position);
position.ry() += layout->boundingRect().height();
qDebug() << "drew" << block.text() << "at" << position;
}
int hitTest(const QPointF &point, Qt::HitTestAccuracy accuracy) const
{
return 0;
}
int pageCount() const
{
return 1;
}
QSizeF documentSize() const
{
return QSizeF(400, 800);
}
QRectF frameBoundingRect(QTextFrame *frame) const
{
return QRectF(0, 0, 400, 800);
}
QRectF blockBoundingRect(const QTextBlock &block) const
{
return QRectF(0, 0, 400, 800);
}
void documentChanged(int from, int charsRemoved, int charsAdded)
{
}
};

Qt Creator Platformer Game - Can't make it work (Beginner with QGraphics)

i'm making a little game just for pratice. I basically want to make my character (a red triangle) move left and right, jump, etc.
The program is still very small at this state, And I wanna know 'how' I should do such things.
I've created a Player Class(QObject, QGraphicsPolygonItem) and a Game Class(QGraphicsView). It worked at first when I gave the Player Class a method for KeyPressEvent, but I had a problem with the jump loop : I wanted to do a scene->update() inside my jump loop, But I couldn't because the scene is an attribute of my Game Class.
Then, I tried giving the Game Class the PressKeyEvent method, so it would move the Player * player attribute.
So basically, what I want is to be able to see the position of my rect update every iteration of my for loop. Can I do that ?
Hope this makes sense, and as always, thanks a lot guys !!
Player.h & Player.cpp
#pragma once
#include <QGraphicsPolygonItem>
#include <QBrush>
class Player :
public QObject, public QGraphicsPolygonItem
{
Q_OBJECT
public:
Player();
// Setters
void setIsJumping(bool);
// Getters
bool getIsJumping();
public slots:
private:
bool isJumping;
};
#include "Player.h"
Player::Player()
{
// ***************
// Draw the player
// ***************
QVector<QPointF> gemPoints;
gemPoints << QPointF(0, 2) << QPointF(1, 0) << QPointF(2, 2);
// Size
int SCALE_BY = 8;
for (size_t i = 0; i < gemPoints.size(); i++)
{
gemPoints[i] *= SCALE_BY;
}
// Create the polygon
QPolygonF gemModel(gemPoints);
setPolygon(gemModel);
setPos(400, 500);
// Color
QBrush brush;
brush.setStyle(Qt::SolidPattern);
brush.setColor(Qt::red);
setBrush(brush);
// Make player focusable
this->setFlag(QGraphicsItem::ItemIsFocusable);
this->setFocus();
}
void Player::setIsJumping(bool jump)
{
if (jump == true)
{
isJumping = true;
}
else
{
isJumping = false;
}
}
bool Player::getIsJumping()
{
return isJumping;
}
Game.h & Game.cpp
#pragma once
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QKeyEvent>
#include "Player.h"
class Game :
public QGraphicsView
{
Q_OBJECT
public:
// Constructors
Game(QWidget* parent = NULL);
// Methods
void start();
void jump();
void keyPressEvent(QKeyEvent *event);
// Attributes
QGraphicsScene* scene;
Player* player;
};
#include "Game.h"
Game::Game(QWidget* parent)
{
// Set up the screen
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setFixedSize(1024, 768);
// Set up the scene
scene = new QGraphicsScene();
scene->setSceneRect(0, 0, 1024, 768);
setScene(scene);
}
void Game::start()
{
scene->clear();
player = new Player();
scene->addItem(player);
}
void Game::keyPressEvent(QKeyEvent * event)
{
if (event->key() == Qt::Key_Left)
{
player->setPos(x() - 3, y());
}
else if (event->key() == Qt::Key_Right)
{
player->setPos(x() + 3, y());
}
else if (event->key() == Qt::Key_Space)
{
for (size_t i = 0; i < 10; i++)
{
player->setIsJumping(true);
this->jump();
}
}
}
void Game::jump()
{
if (player->getIsJumping() == true)
{
for (size_t i = 0; i < 100; i++)
{
this->player->setPos(x(), y() - 0.1);
this->update();
}
player->setIsJumping(false);
}
}
Main.cpp
#include "plateforme.h"
#include <QtWidgets/QApplication>
#include "Game.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Game game;
game.show();
game.start();
return a.exec();
}
The problem is that I can't move the player correctly now, It moves only once and in a weird way. Any help is appreciated.
The problem is that when you set the position for player, you should modify the coordinates of player and not of this. Therefore, whenever you want to move the player, use:
player->setPos(player->x() - 3, player->y());
^ ^
and the same for jumping in your loop:
player->setPos(player->x(), player->y() - 0.1);
^ ^
When you use setPos(x()-3, y()), it sets the player position to position of your QGraphicsView, that is why it disappears from the view. Good luck with your game!

Qt: Custom derived class not declared in scope

Qt Newbie here experiencing a problem where it claims that I did not declare a class which I'm pretty sure is declared.
I cannot for the life of me figure this out. Please help.
Commenting out the problematic lines in Connection.h and .cpp results in compilable output.
Here is a slimmed down version of my code where the problem still exists:
Btw, Map.ui only has a Graphics View dragged into it.
Error message:
In file included from ../Map/Map.h:17:0,
from ../Map/City.cpp:1:
../Map/Connection.h:14:11: error: 'City' was not declared in this scope
QPair<City*, City*> cities;
^
../Map/Connection.h:14:18: error: 'City' was not declared in this scope
QPair<City*, City*> cities;
^
../Map/Connection.h:14:23: error: template argument 1 is invalid
QPair<City*, City*> cities;
^
../Map/Connection.h:14:23: error: template argument 2 is invalid
../Map/Connection.h:19:22: error: 'City' was not declared in this scope
Connection(QPair<City*, City*> cities, int cost);
^
../Map/Connection.h:19:29: error: 'City' was not declared in this scope
Connection(QPair<City*, City*> cities, int cost);
^
../Map/Connection.h:19:34: error: template argument 1 is invalid
Connection(QPair<City*, City*> cities, int cost);
Map.pro:
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = Map
TEMPLATE = app
SOURCES +=\
City.cpp \
Connection.cpp \
Map.cpp \
Driver.cpp
HEADERS += \
City.h \
Connection.h \
Map.h
FORMS += \
Map.ui
Map.h:
#ifndef MAP_H
#define MAP_H
#include <QApplication>
#include <QGraphicsItem>
#include <QMainWindow>
#include <QtCore>
#include <QtGui>
#include <QGraphicsScene>
#include <QGraphicsEllipseItem>
#include <QDebug>
#include <QPainter>
#include <QString>
#include <QVector>
#include "ui_Map.h"
#include "Connection.h"
#include "City.h"
namespace Ui
{
class Map;
}
class Map : public QMainWindow
{
Q_OBJECT
public:
explicit Map(QWidget *parent = 0);
~Map();
private:
Ui::Map *ui;
QGraphicsScene *scene;
};
#endif // MAP_H
Map.cpp:
#include "Map.h"
#include "ui_Map.h"
Map::Map(QWidget *parent) : QMainWindow(parent), ui(new Ui::Map)
{
ui->setupUi(this);
scene = new QGraphicsScene(this);
ui->graphicsView->setScene(scene);
City *c1 = new City(30, 30, 30, "K");
City *c2 = new City(30, 90, 30, "O");
Connection *conn1 = new Connection(45, 45, 45, 105, 1);
c1->setZValue(4);
c2->setZValue(4);
conn1->setZValue(2);
scene->addItem(c1);
scene->addItem(c2);
scene->addItem(conn1);
}
Map::~Map()
{
delete ui;
}
City.h:
#ifndef CITY_H
#define CITY_H
#include "Map.h"
class City : public QGraphicsItem
{
private:
int x;
int y;
int r;
QString name;
QRectF bounds;
QVector<QPair<City*, int> > neighbors;
public:
City();
City(int x, int y, int r, QString name);
int getX() { return this->x; }
int getY() { return this->y; }
int getR() { return this->r; }
QString getName() { return this->name; }
QVector<QPair<City*, int> > getNeighbors() { return this->neighbors; }
void setNeighbors(QVector<QPair<City*, int> >) { this->neighbors = neighbors; }
QRectF boundingRect() const;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
};
#endif // CITY_H
City.cpp:
#include "Map.h"
City::City()
{
this->bounds = QRectF(0, 0, 0, 0);
}
City::City(int x, int y, int r, QString name)
{
this->x = x;
this->y = y;
this->r = r;
this->name = name;
this->bounds = QRectF(x, y, r, r);
}
QRectF City::boundingRect() const
{
return QRectF(x, y, r, r);
}
void City::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
QRectF rec;
if (this->bounds == QRectF(0, 0, 0, 0))
rec = boundingRect();
else
rec = this->bounds;
QBrush brush(Qt::blue);
QPen pen(Qt::blue);
painter->setBrush(brush);
painter->setPen(pen);
painter->drawEllipse(rec);
}
Connection.h:
#ifndef CONNECTION_H
#define CONNECTION_H
#include "Map.h"
class Connection : public QGraphicsItem
{
private:
int x1, x2;
int y1, y2;
int cost;
QRectF bounds;
QPair<City*, City*> cities; // PROBLEMATIC LINE -- CLAIMS CITY WAS NOT DECLARED
public:
Connection();
Connection(int x1, int y1, int x2, int y2, int cost);
Connection(QPair<City*, City*> cities, int cost); // PROBLEMATIC LINE -- CLAIMS CITY WAS NOT DECLARED
int getCost() { return this->cost; }
QRectF boundingRect() const;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
};
#endif // CONNECTION_H
Connection.cpp:
#include "Map.h"
Connection::Connection()
{
this->bounds = QRectF(0, 0, 0, 0);
}
Connection::Connection(int x1, int y1, int x2, int y2, int cost)
{
this->x1 = x1;
this->x2 = x2;
this->y1 = y1;
this->y2 = y2;
this->bounds = QRectF(x1, x2, y1, y2);
}
Connection::Connection(QPair<City*, City*> cities, int cost) // PROBLEMATIC BLOCK
{
int r = cities.first->getR();
this->x1 = cities.first->getX() + r/2;
this->x2 = cities.second->getX() + r/2;
this->y1 = cities.first->getY() + r/2;
this->y2 = cities.second->getY() + r/2;
this->cost = cost;
this->bounds = QRectF(x1, x2, y1, y2);
}
QRectF Connection::boundingRect() const
{
return QRectF(0, 0, 0, 0);
}
void Connection::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
QRectF rec;
if (this->bounds == QRectF(0, 0, 0, 0))
rec = boundingRect();
else
rec = this->bounds;
QBrush brush(Qt::red);
QPen pen(Qt::red);
painter->setPen(pen);
painter->drawLine(QLine(this->x1, this->y1, this->x2, this->y2));
}
Driver.cpp:
#include "Map.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Map w;
w.show();
return a.exec();
}
Thank you for taking the time to look at this. I appreciate any feedback whatsoever. The problematic lines were compilable for a while but it seems that adding certain things "broke" it.
The answer to this thread got me thinking it might be something silly, but my attempts to change the order of things have not fixed it.
Just looking at the error message one can see that the City class is indeed not defined at Connection.
In file included from ../Map/Map.h:17:0,
from ../Map/City.cpp:1:
City.cpp starts out with a #include "Map.h" which is odd because there are no references to the Map type in the cpp file. City.cpp should start out with an #include "City.h".
City.h starts out with an #include "Map.h" which is even stranger because the City class make no mention of Map.
So at this point City.cpp:1 -> Map.h :17 you are including "Connection.h". At this point, there are no defined types. Not City, not Map. The compiler approaches the class Connection with no types defined.
Fixing it:
It is hard to guess how your dependencies actually look like but one solution for this particular include might be.
Start by including City.h first in your City.cpp. You should #include "X.h" for all X.cpp files.
Remove the #include "Map.h" from the City.h file.
If the Map type is required in City.cpp, include it.
The Connection.h obviously requires at least a forward declared class class City because of the pointers. So either do a forward declaration or an `#include "City.h"
In conclusion: Only include files in the header that your class actually requires. In the corresponding cpp, first include the header. Any type the header requires will also be required by the implementation. After that you include the additional types your implementation requires.

How to calculate total distance covered by a sensor from its set of locations which are 3D points?

I am using Qt GUI to track the motion of a sensor. The mainwindow.cpp file is:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "ATC3DG.h"
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/core/core.hpp>
#include "QTimer"
#include "qtimer.h"
#include "math.h"
double square(double x)
{
return x*x;
}
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_start_clicked()
{
points.clear(); //points is a global std::vector<cv::Point3> declared in mainwindow.h
errorCode = InitializeBIRDSystem();
errorCode = GetBIRDSystemConfiguration(&ATC3DG.m_config);
id = 0;
errorCode = SetSystemParameter(SELECT_TRANSMITTER, &id, sizeof(id));
EM_time = new QTimer(this);
connect(EM_time, SIGNAL(timeout()), this, SLOT(showValues()));
EM_time->start();
}
void MainWindow::showValues()
{
EM_time->stop();
pRecord = &record;
{
sensorID = 0;
{
errorCode = GetAsynchronousRecord(sensorID, pRecord, sizeof(record));
unsigned int status = GetSensorStatus(sensorID);
if ( status == VALID_STATUS )
{
points.push_back(cv::Point3f(record.x, record.y, record.z));
QString str;
str.sprintf("%f, %f, %f",record.x, record.y, record.z );
this->ui->label->setText(str);
}
}
}
EM_time->start();
}
void MainWindow::on_stop_clicked()
{
EM_time->stop();
double sum = 0;
double dist;
QString str;
for (int i=0; i<points.size()-1; i++)
{
dist = sqrt(square(points[i].x - points[i+1].x) + square(points[i].y - points[i+1].y) + square(points[i].z - points[i+1].z));
sum = sum+dist;
}
str.sprintf("%d cm", sum*2.54);
this->ui->distance->setText(str);
}
ATC3DG.h is the header file of the sensor. record.x, record.y, record.z gives the 3D location of x, y and z location of the sensor in inches. Basically what I am doing is, when I click the start button, the sensor is switched on and the QTimer starts with its signal emitted during timeouts and the showvalues() function will start to execute. This function displays the position of the sensor in label of the Qt GUI. During this loop, points will be filled with all the position values of the sensor.
The stop button stops the timer and calculates the distance using all the points containing in the points vector. This is done using:
double sum=0;
double dist;
for (int i=0; i<points.size()-1; i++)
{
dist = sqrt(square(points[i].x - points[i+1].x) + square((int)points[i].y - (int)points[i+1].y) + square(points[i].z - points[i+1].z));
sum = sum+dist;
}
The sum is giving me totally weird values. For example, when the sensor has moved only about 5 or 6 inches, it is showing values in the range of 100s and like that.
My mainwindow.h file is:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "ATC3DG.h"
#include "QTimer"
#include <opencv2/core/core.hpp>
namespace Ui {
class MainWindow;
}
class CSystem
{
public:
SYSTEM_CONFIGURATION m_config;
};
class CSensor
{
public: SENSOR_CONFIGURATION m_config;
};
class CXmtr
{
public: TRANSMITTER_CONFIGURATION m_config;
};
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
public slots:
void on_start_clicked();
void showValues();
void on_stop_clicked();
private:
Ui::MainWindow *ui;
private:
DOUBLE_POSITION_ANGLES_RECORD record, *pRecord;
CSystem ATC3DG;
CSensor *pSensor;
CXmtr *pXmtr;
int errorCode;
int sensorID;
int i;
short id;
QTimer *EM_time;
std::vector<cv::Point3f> points;
};
#endif // MAINWINDOW_H
issues I can see in your code:
overuse of braces (they do nothing) - this looks strange and may led to errors
GetAsynchronousRecord suggest asynchronous action and you are using value immediately! I don't known this library but this looks suspicious.
start and stop timer in same method.
you are calculating sum of distances from probably very noisy data. This means that when you do not move sensor over a time you are calculating sum of noise and as a result you have large distance when sensor is not moved at all. You have to filter data before calculating such distance (the easiest is low pass filter).

Qt Display tooltip after mouse hover on QGraphicsPixmapItem

I'm using QGraphicView to show game map that consist QGraphicsPixmapItems. I need to show tooltip on mouse hover at QGraphicsPixmapItem.
For saving QGraphicsPixmapItem position I using MazeItem:
#ifndef MAZEITEM_H
#define MAZEITEM_H
#include <QPoint>
#include <QGraphicsItem>
class MazeItem
{
private:
QPoint myPosition;
QString myToolTip;
public:
MazeItem();
QPoint position() const;
QString toolTip() const;
void setToolTip(const QString &toolTip);
void setPosition(const QPoint &position);
QPoint getPosition();
QGraphicsPixmapItem * pixmap;
};
#endif // MAZEITEM_H
I have widget class to display game map:
#include <QWidget>
#include <QtGui>
#include <QGraphicsView>
#include <QToolTip>
#include "mazeitem.h"
class MazeGUI : public QWidget
{
Q_OBJECT
private:
QGraphicsView * graphicsView;
QGraphicsScene * graphicsScene;
QString sceneString;
int imageSize;
QList<MazeItem> mazeItems;
void addItem(int x, int y, QPixmap picture);
bool event(QEvent *event);
int itemAt(const QPoint &pos);
public:
explicit MazeGUI(QWidget *parent = 0);
void setScene(QString sceneString);
signals:
public slots:
void redraw();
};
#endif // MAZEGUI_H
In constructor I set mouse tracking.
MazeGUI::MazeGUI(QWidget *parent) :
QWidget(parent)
{
setMouseTracking(true);
...
}
This is how I add new maze item.
void MazeGUI::addItem(int x, int y, QPixmap picture)
{
MazeItem mazeItem;
mazeItem.setPosition(QPoint(x, y));
mazeItem.setToolTip("text");
mazeItem.pixmap = this->graphicsScene->addPixmap(picture);
mazeItem.pixmap->setPos(y, x);
mazeItems.append(mazeItem);
}
And this I have from Qt tutorials,
bool MazeGUI::event(QEvent *event)
{
if (event->type() == QEvent::ToolTip) {
// HERE - it never goes here!!
QHelpEvent *helpEvent = static_cast<QHelpEvent *>(event);
int index = itemAt(helpEvent->pos());
if (index != -1) {
QToolTip::showText(helpEvent->globalPos(), mazeItems[index].toolTip());
} else {
QToolTip::hideText();
event->ignore();
}
return true;
}
return QWidget::event(event);
}
int MazeGUI::itemAt(const QPoint &pos)
{
for (int i=0; i < mazeItems.size(); ++i)
{
if (mazeItems[i].getPosition() == pos)
return i;
}
return -1;
}
Was adding the tooltip on wrong object:
Instead of:
mazeItem.setToolTip("text");
It should be:
mazeItem.pixmap->setToolTip("text");