Qt: Signals and Slots in QGraphicsPixmapItem class - qt

I have inherited a class called GraphicsPixmapItem from QGraphicsPixmapItem in order to override/create some mouse events. The problem is that I want to emit a signal after some calculations are performed, but it looks like it's not possible unless some hacks are performed, since this class is not a QObject.
To do so, I have tried to inherit the aformentioned new class from QObject as well, but I keep getting compiler errors.
My attemp:
Header file (graphicspixmapitem.h):
#ifndef GRAPHICSPIXMAPITEM_H
#define GRAPHICSPIXMAPITEM_H
#include <QObject>
#include <QGraphicsPixmapItem>
#include <QGraphicsSceneMouseEvent>
class GraphicsPixmapItem : public QObject, public QGraphicsPixmapItem
{
Q_OBJECT
public:
explicit GraphicsPixmapItem(QGraphicsItem *parent = 0);
virtual void mousePressEvent(QGraphicsSceneMouseEvent * mouseEvent);
virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent * mouseEvent);
signals:
void translationVector(QPointF info);
};
#endif // GRAPHICSPIXMAPITEM_H
Source file (graphicspixmapitem.cpp):
#include "graphicspixmapitem.h"
GraphicsPixmapItem::GraphicsPixmapItem(QGraphicsItem *parent) :
QGraphicsPixmapItem(parent)
{
}
void GraphicsPixmapItem::mousePressEvent(QGraphicsSceneMouseEvent * mouseEvent)
{
//Code
}
void GraphicsPixmapItem::mouseReleaseEvent(QGraphicsSceneMouseEvent * mouseEvent)
{
QPointF info;
//Code
emit(translationVector(info));
}
And I get the following linker errors:
undefined reference to `vtable for GraphicsPixmapItem'
undefined reference to
`GraphicsPixmapItem::translationVector(QPointF)'
Any clue about how to proceed accordingly?
Side note:
I am aware that QGraphicsObject may be a good alternative, but as discussed here, performance looks severely affected by the amount of signals that are emitted when operating with them, where most of them will not be used in my case. This is the reason why I prefer to create my own class with base QGraphicsItem, instead of QGraphicsObject.
Many thanks in advance.

It looks like the meta object compiler (moc) wasn't run over the code, or that moc's result wasn't included when linking.
Have you added graphicspixmapitem.h to qmake's HEADERS variable?
Have you re-run qmake and tried a clean build in general?
Is moc run on graphicspixmapitem.h? Check your compile log.
Is graphicspixmapitem_moc.o included when linking? Check your compile log.

I have finally found out the problem involving the linkage error. In this sense, I must give my thanks to Thomas McGuire for pointing out the key idea to look for the source of the problem.
The reason is that few days ago I attempted to subclass QGraphicsPixmapItem (for other purposes) with the exact same name than this one, namely, GraphicsPixmapItem (with header file graphicspixmapitem.h and source file graphicspixmapitem.cpp).
When I did that, I finally figured out that I could do things in a different way and I no longer needed that inherited subclass, hence I removed these files from the project. But doing this is a major mistake if you do not make sure to clean the project before removing the files from the project, because the files generated by qmake and moc (*.o, moc_*.cpp, moc_*.o) will remain in the build/debug directory unless you remove them by hand, because they will not be deleted by cleaning the project.
Therefore, it looks like in that situation, qmake detects that the files already exist and it does not generate the correct ones from the updated class, causing the linking error expounded above.
In summary, if you are going to delete some files from your project, make sure to clean it previously, especially if you are going to remove a class with the Q_OBJECT macro.

Related

Qt: a missing vtable usually means the first non-inline virtual member function has no definition

There are numerous threads on this all over. None seems to fit my bill. I'm getting the following linker errors in my code:
Undefined symbols for architecture x86_64:
"vtable for MSFSPlugin::MSFSPluginImpl", referenced from:
MSFSPlugin::MSFSPluginImpl::MSFSPluginImpl(QObject*) in MSFSPlugin.o
MSFSPlugin::MSFSPluginImpl::~MSFSPluginImpl() in MSFSPlugin.o
NOTE: a missing vtable usually means the first non-inline virtual member function has no definition.
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
It should have been something obvious as - a missing vtable usually means the first non-inline virtual member function has no definition. However, I don't see what I'm missing:
I have this class declation in MSFSPlugin.h:
class MSFSPlugin
:
public QObject,
public IMediaSource
{
Q_OBJECT
Q_INTERFACES(IMediaSource)
...
protected:
class MSFSPluginImpl;
MSFSPluginImpl* mImpl;
}
Then in MSFSPlugin.cpp, I have the following:
class MSFSPlugin::MSFSPluginImpl : public QThread
{
Q_OBJECT
public:
MSFSPluginImpl(QObject *parent = 0);
virtual ~MSFSPluginImpl();
QString getSourceDirectory() const;
void setSourceDirectory(QString sourceDirectory);
signals:
void loadDirectoryFinished(bool success);
protected:
QString mSourceDirectory;
};
Followed by definitions:
MSFSPlugin::MSFSPluginImpl::MSFSPluginImpl(QObject *parent) : QThread(parent)
{
}
MSFSPlugin::MSFSPluginImpl::~MSFSPluginImpl()
{
}
QString MSFSPlugin::MSFSPluginImpl::getSourceDirectory() const
{
return mSourceDirectory;
}
void MSFSPlugin::MSFSPluginImpl::setSourceDirectory(QString sourceDirectory)
{
mSourceDirectory = sourceDirectory;
}
...
In short, I don't think I'm missing any non-inline virtual member function definition. I'm using:
Apple LLVM version 5.1 (clang-503.0.40) (based on LLVM 3.4svn)
Target: x86_64-apple-darwin13.1.0
Thread model: posix
Additional Info:
In my moc_MSFSPlugin.cpp I don't see the autogenerated Q_OBJECT related code for class MSFSPlugin::MSFSPluginImpl which indirectly (via QThread) derives from QObject. Specifically, I don't see code generated for the signal, declared in that class (loadDirectoryFinished). Could this be the problem?
EDIT 1:
The error goes away if I comment out Q_OBJECT from the declation of MSFSPlugin::MSFSPluginImpl, but then I lose the signal functionality.
EDIT 2:
I see moc operates on header files only. Could this be related to the fact that my QObject derived class is declared & defined in a .cpp file?
Assuming we're dealing with qmake.
The golden rules are:
Make sure the Q_OBJECT macro is present in the definition of all QObject-derived classes.
Make sure you declare your QObject-derived classes in your header files only.
Make sure all of your header files are listed in your .pro file in the HEADERS= list.
Run qmake every time you add Q_OBJECT to one of your classes or modify your .pro file.
Explanation
EDIT 1: The error goes away if I comment out Q_OBJECT from the declation of MSFSPlugin::MSFSPluginImpl, but then I lose the signal functionality.
Yup. Q_OBJECT is needed for declaring signals, slots, invokables, qobject_cast, translations, properties, enums and methods introspection, and so on.
The #1 golden rule comes from the fact that without Q_OBJECT you can't use stuff like qobject_cast on your class; if you use (even indirectly) introspection facilities, for instance to debug an object hierarchy or to dump all active connections to an object, then objects of your class will have the real class name shown (and not the one of the superclass); etc.
Q_OBJECT does two things:
it tells builsystems to add calls to moc, whose job is to generate some extra code for the class. This code will provide all the facilities listed above;
since it's a normal C++ macro, when compiled it expands to a few declarations, including a couple of virtuals: qt_metacall() and metaObject(). moc will generate the implementation for these virtuals.
The error you get is the typical symptom of having declared the virtuals (because the macro was expanded in your code) but moc wasn't run, you had some unimplemented virtuals which will make the linking fail.
With gcc and GNU ld, you get an even more cryptic error, about an undefined reference to vtable for ClassName. Of course, googling such errors will immediately tell you how to solve the issue.
EDIT 2: I see moc operates on header files only. Could this be related to the fact that my QObject derived class is declared & defined in a .cpp file?
So, the question is: why wasn't moc run on a file containing a definition of a class with the Q_OBJECT macro?
When we use qmake to generate your Makefiles, then qmake will scan all the header files listed in the HEADERS variable. When it finds that a header contains a class definition with the Q_OBJECT macro, it will also emit instructions (in the Makefile) to run moc over that header, compile moc's output and link the resulting object in the final target.
And we have rules #2, #3, #4 right here.
#2 tells us to put Q_OBJECT classes in headers; and that's because HEADERS lists headers, not sources.
#3 tells us to indeed put all headers into the HEADERS list. That obviously because if a header containing a Q_OBJECT is not in that list, then qmake won't find it and emit the rules. (While not strictly necessary for headers not containing QObject subclasses, it's good practice to put every header in there in order to forget none.)
#4 tells us to re-run qmake every time we add Q_OBJECT or modify the .pro file. The reason for the first part of the rule is that if qmake already scanned a header and found no Q_OBJECT, then it didn't emit any rules in the Makefile. But adding Q_OBJECT also needs those rules; hence we need qmake to re-scan the headers, and that's precisely what re-running qmake does.
The same reason applies when the .pro is modified (for instance, when adding more headers -- maybe with Q_OBJECT under HEADERS).
Note that if you're using a GNU-like make, then qmake will emit a special rule that tells make to re-run qmake and then restart the Makefile, if the .pro gets modified after the Makefile. That's why usually on UNIX you don't need to manually re-run qmake when you modify your .pro -- just running make will also run qmake again. But this doesn't work everywhere.
So, is it impossible to have classes definition containing Q_OBJECT in a .cpp file?
No, it's perfectly possible, but it requires using a somehow undocumented qmake feature. The trick is adding a line like:
#include "foobar.moc"
at the end of the foobar.cpp file, file that contains one of more class definitions with Q_OBJECT.
qmake will find this special inclusion and generate a rule for moc to create foobar.moc, which will then be included by the .cpp and thus compiled together with it. (Hence, there will be no extra rules for compiling foobar.moc nor to link the result.)
EDIT 1: The error goes away if I comment out Q_OBJECT from the declation of MSFSPlugin::MSFSPluginImpl, but then I lose the signal functionality.
Yes, the Q_OBJECT macro is necessary for signals, slots, properties and so on.
EDIT 2: I see moc operates on header files only. Could this be related to the fact that my QObject derived class is declared & defined in a .cpp file?
Yes and no. I will explain..
Usually, it is solved by separation as you write, but it is also possible to include the moc file after your class definition to get it work, but you need to remember not to put more than one in there to avoid strange consequences.
Therefore, in your case, you could establish a MSFSPlugin_p.h or MSFSPluginImpl.h file for the implementation header.
By the way, it is a bad idea to make pimpl protected. The pimpl idiom means private implementation, not protected.

QCameraImageCapture() no matching function

I get the error,
error: no matching function for call to 'QCameraImageCapture::QCameraImageCapture()'
Simply by having the code,
#include <QCamera>
#include <QCameraImageCapture>
class Webcam : public QObject
{
Q_OBJECT
public:
Webcam();mageCaptured();
private:
QCameraImageCapture _imageCamera;
};
I have written no other code. Any idea what's going on here? It worked for QCamera _camera;
EDIT:
Sorry, this is completely my fault. Too much time using Python made me forget all about pointers.
QCameraImageCapture doesn't have a default constructor, see the documentation here, so you must pass a QMediaObject pointer to the constructor of QCameraImageCapture (QCamera inherits from QMediaObject so it can be used there)
Quote from documentation:
The QCameraImageCapture class is a high level images recording class. It's not intended to be used alone but for accessing the media recording functions of other media objects, like QCamera.

Qt Determine if application is launched from Qt Creator?

How can I from within my code determine if my application is started from Qt Creator (either by "F5" or "Ctrl + R")?
The reason why I want to know this is because I want to create my own debug message handler ( using qInstallMessageHandler()) only when the application is launched from the executable directly. Since Qt allows only one message handler, I don't want to create my own when launching from Qt Creator, or else I can't see the debug messages in Qt Creators own debug console.
I don't think there is an easy way to detect that.
You could add a command line argument to the run settings in QtCreator though, and check for that at runtime.
I have two possible solutions:
check the names of parent process (or parent of parent)
there are multiple ways to do this: under Posix (mingw, linux etc..) you have getppid(). Under Windows you can check the namehave the Psapi or other process handling functions. I have done this for other purposes in the past and it works reliably as long as the process names do not change. Alternatively you could check for the window names. Unfortunately none of these solutions are "Qt-Native".
supply a commandline argument only when started from Qt creator
If you use a library to scan commanline arguments this is probably the simplest solution. I usually use Boost Program Options (Google there). You could create a commandline argument like "--console-log" which specifies to put the logging output to the console. To set that option from within Qt Creator is documented here. This is probably the most "Qt-Native" solution. If you use Qt functions to parse the commandline, it is 100% Qt.
You can try IsDebuggerPresent or use only QDebug and check debug messages with debugview outside QT Creator.
You should google qInstallMessageHandler for more information.
But here goes the definitions:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QtGui>
#include <QtWidgets>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
static void myMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
// If you're running lots of threads you'll need to do some research to
// determine if you need to make this synchronized (i.e. locked)
if(staticTextEdit) {
staticTextEdit->appendPlainText(msg + "\n");
}
}
private slots:
void on_pushButton_clicked();
private:
// There's lots of different ways to do this ... this was the quickest way for me.
static QPlainTextEdit* staticTextEdit;
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
Here are the declarations:
#include "mainwindow.h"
#include "ui_mainwindow.h"
QPlainTextEdit* MainWindow::staticTextEdit = NULL;
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
staticTextEdit = ui->plainTextEdit;
qInstallMessageHandler(MainWindow::myMessageHandler);
}
MainWindow::~MainWindow()
{
delete ui;
}
// I'm using QtCreator to help create my slots. =).
void MainWindow::on_pushButton_clicked()
{
qDebug() << "CLICKED";
}
Here is a manual solution.
Define a macro in your .pro file....
# To turn on remove the comment marker '#'
# isEmpty(LAUNCH_FROM_IDE):LAUNCH_FROM_IDE = 1
!isEmpty(LAUNCH_FROM_IDE) {
DEFINES += APP_LAUNCH_FROM_IDE
}
And use in your header/source as needed...
#ifdef APP_LAUNCH_FROM_IDE
...
#endif
That's all
Not sure if this applies to the PC, but under OSX, when Qt Creator launches the application, it does it from the development build path; you can get the current launch path with:
QString expath = QCoreApplication::applicationDirPath();
Get that, dump it via qDebug(), and see where you're running from when launched from Qt. As long as that's not the location you run the application from when you're not launching it from within Qt, this should work.
I get this from the qDebug() when building and running in release mode from within Qt Creator:
"/Users/fyngyrz/build-iToolBox-Desktop_Qt_5_8_0_clang_64bit-Release/iToolBox.app/Contents/MacOS/iToolBox"
So for me, when building my app iToolBox I do the detection like this:
if (expath.indexOf("build-iToolBox-Desktop") != -1) // if we're running from inside Qt
{
}
else // we're not running from inside qt
{
}
Note1:
The release and build paths for Qt builds are different by default; so if you need this to work in both release and debug circumstances, you might have to do two checks of the path instead of one, depending on just what you're searching for.
Note 2:
If you incorporate this approach into your application, and the code will remain intact in the release build, be sure not to including anything in your search string that would incorporate any information you don't want to share, such as your real name which could be part of the path under some operating systems, depending on how you set up your user account.

Qt GUI Dialog Initialization Confusion

I am learning GUI coding with Qt and hope to clear up some confusion on my part. When I create a dialog with Qt Creator it creates code for me like this...
#ifndef LISTDIALOG_H
#define LISTDIALOG_H
#include <QDialog>
#include "ui_listdialog.h" //Q1:Why was this auto paced in cpp file instead of h file?
//Q2: This is what I'm really confused about.
//Is Ui namespace wrapping ui_listdialog class or the ListDialog class?
namespace Ui {
class ListDialog;
}
class ListDialog : public QDialog
{
Q_OBJECT
public:
explicit ListDialog(QWidget *parent = 0); //Q3: Why is this constructor explicit?
~ListDialog();
//CUSTOM FUNCTIONALITY NOT ADDED BY CREATOR (IGNORE FOR MY POST)
private slots:
void addItem();
void editItem();
void deleteItem();
//END CUSTOM FUNCTIONALITY
private:
Ui::ListDialog *ui; //Placed on heap instead of stack.
};
#endif // LISTDIALOG_H
There are things in the above code that differ from my 3 Qt books (all 3 out of date and ignore Creator).
My main confusion comes from Q2. Is "Ui" wrapping "ui_listdialog.h" or the class I have posted here ( class ListDialog )? The syntax seems to imply to me that it is wrapping the latter but I feel it must be actually wrapping the ui_listdialog.h class instead. Very confused about this. Can someone explain this clearly?
I also don't understand why the constructor was made explicit by Creator. I have not seen that in any of the 3 books.
Q1. The #include is placed in the .cpp to avoid too many dependencies in the header file. This shortens compilation time, because if you change the dialog, the only thing you have to recompile is the .cpp and not everything that includes your header file. In general, if a forward declaration of a class is enough (i.e. you only have a pointer or a reference to it in your class), then it's better not to #include the class's definition.
Q2. Ui is a namespace that contains a different class called ListDialog. You can open the header file and see the definition of this other class. A bit confusing until you get used to it.
Q3. It's a good habit to use the explicit keyword with constructors that take a single parameter. Otherwise the constructor can also be used as an automatic conversion operator, and this can cause problems if you're not aware of it. For example, if you have a function that takes a ListDialog parameter, and you pass a QWidget * parameter, it may call the constructor when in fact you want the compiler to shout (invalid parameter).
The ui_listdialog.h contains implementation to generate your user interface based on Qt Designer. It isn't necessary when declaring the class -- that's why the file was #included in the .cpp (Q1). Without the ui_listdialog.h in the header, the class declaration is necessary (Q2).
As for Q3, it's probably there to make you use the constructor syntax. Else, you could write misleading statements like
ListDialog dialog = parentDialog ;

Qt - no such signal error

I'm trying to trigger a signal when a double click happens in one of the draggable widgets on the fridge magnets example. Here's the changes I made to the example source:
DragLabel:
class DragLabel : public QLabel
{
public:
DragLabel(const QString &text, QWidget *parent);
QString labelText() const;
public slots:
void testSlot(){qDebug()<<"testSlot";} //<-- implemented this slot
protected:
void mouseDoubleClickEvent(QMouseEvent *ev){emit testSignal();} //<-- overriden this method
private:
QString m_labelText;
signals:
void testSignal(); //<-- added this signal
};
The only thing I changed in the implementation file is adding connect(this,SIGNAL(testSignal()),this,SLOT(testSlot())); to DragLabel's constructor.
Trying to compile the project resulted in 'undefined reference to `DragLabel::testSignal()' and 'collect2: ld returned 1 exit status' errors.
When I comment out the call to the signal, it compiles and runs, but gives off 'Object::connect: No such signal QLabel::testSignal() in draglabel.cpp' warning in the application output. Apparently testSignal() isn't being recognized as a signal.
I've tried to add the Q_OBJECT macro to DragLabel but it results in 4 'undefined reference to `vtable for DragLabel'' warnings and a 'collect2: ld returned 1 exit status' error.
What am I missing?
Put the Q_OBJECT macro at the top, (must be first thing in the class and no ";" )
Make sure you do a full rebuild, the VS-add-in especially doesn't always notice that a file has become qt-aware without a rebuild.
More good advice 20 ways to debug Qt signals and slots
It WAS the macro in the end. I had to reboot my PC for it to work though, cleaning and rebuilding the project didn't work out. Before rebooting Qt Creator kept giving the 'ld returned 1 exit status' error and the vtable warnings. Really weird. – David McDavidson
It's not weird, it's stupid.
I got the same error, but I make it after rearrange the .h files. Say:
1 classA.h include calssB.h ;
2 classB.h declared two class, classB and classC, (classB.h declared signals & slot)
I do three things,
seperate classC to another .h file
eliminate all forward class declaration about classB
classB.h included by classA.cpp, other than by classA.h
after that, QT compiled it. I'll test if it is working.

Resources