Situation:
I have a Dialog class in Qt on which I draw a raster of squares. The squares are implemented in the MySquare class (MySquare: QGraphicsItem).
Question:
I want to signal the Dialog slot setTarget() that a square was clicked (and obviously I want to give it some information about that square like for example it’s x and y coordinates with it later). However I get an ‘undefined reference to ‘MySquare::targetChanged()‘ error. I have looked for a solution but have not found any; anybody an idea?
edit: I have added a Q_OBJECT macro inside the MySquare however the error does not dissapear and I get an additional “‘undefined reference to ‘vtable for MySquare()‘ error
dialog.h
class Dialog : public QDialog
{
Q_OBJECT
public:
explicit Dialog(QWidget *parent = 0);
~Dialog();
public slots:
void setTarget();
private:
Ui::Dialog *ui;
QGraphicsScene *scene;
};
dialog.cpp
Dialog::Dialog(QWidget *parent) : QDialog(parent), ui(new Ui::Dialog)
{
ui->setupUi(this);
scene = new QGraphicsScene(this);
ui->graphicsView->setScene(scene);
MySquare *item;
item = new MySquare(30,30,30,30);
QObject::connect(item,SIGNAL(targetChanged()),this,SLOT(setTarget()));
}
void Dialog::setTarget(){
qDebug() << "signal recieved" << endl;
}
mysquare.h
#include <QGraphicsItem>
#include <QPainter>
#include <QDebug>
#include <QKeyEvent>
#include <QObject>
class MySquare : public QGraphicsItem, public QObject
{
Q_OBJECT
public:
MySquare(int x,int y,int h, int w);
QRectF boundingRect() const;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
int x,y,h,w;
signals:
void targetChanged();
protected:
void mousePressEvent(QGraphicsSceneMouseEvent *event);
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
};
mysquare.cpp
#include "mysquare.h"
#include <QGraphicsSceneDragDropEvent>
#include <QWidget>
MySquare::MySquare(int _x,int _y, int _w, int _h)
{
setAcceptDrops(true);
color=Qt::red;
color_pressed = Qt::green;
x = _x;
y = _y;
w = _w;
h = _h;
}
QRectF MySquare::boundingRect() const
{
return QRectF(x,y,w,h);
}
void MySquare::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
QRectF rec = boundingRect();
QBrush brush(color);
if (Pressed){
brush.setColor(color);
} else {
brush.setColor(color_pressed);
}
painter->fillRect(rec,brush);
painter->drawRect(rec);
}
void MySquare::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
Pressed=true;
update();
QGraphicsItem::mousePressEvent(event);
emit targetChanged();
}
void MySquare::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
Pressed=false;
update();
QGraphicsItem::mouseReleaseEvent(event);
qDebug() << "mouse Released";
}
void MySquare::mouseMoveEvent(QGraphicsSceneMouseEvent *event){
qDebug() << "mouse Moved";
QDrag *drag = new QDrag(event->widget());
QMimeData *mime = new QMimeData;
drag->setMimeData(mime);
drag->exec();
}
void MySquare::keyPressEvent(QKeyEvent *event){
//out of bounds check?
int x = pos().x();
int y = pos().y();
QGraphicsItem::keyPressEvent(event);
}
Edit: If you have an undefined reference to a vtable, then it’s probably because you did not implement certain virtual functions. Have you implemented the mouse event handlers of the
MySquareclass somewhere? Have you also implemented theboundingRect()andpaint()functions of theMySquareclass?Old answer:
You need to write the
Q_OBJECTmacro after the opening ‘{‘ in theMySquareclass. Also Qt will complain about multiple inheritance at some point. Therefore, instead of inheriting fromQGraphicsItemandQObject, inherit fromQGraphicsObjectinstead.The actual reason, the linker complains about a missing function definition is the following: When you put a
Q_OBJECTmacro into the right place, then the Qt Meta Object Compiler (MOC) will generate a new cpp file for the project which contains the definition of the signal functions of the respective class. So Qt implements a function for every signal for you. If you don’t insert theQ_OBJECTmacro, then MOC won’t do anything for you and the function definition for the signal will be missing to the linker.