3

I made a prototype of a project with PyQt and made it work there, now I'm trying to convert it to C++ and am having some problems.

If I don't put the Q_OBJECT macro in, it compiles and works, but if I comment it out, I get the following errors:

Undefined symbols:
  "vtable for MapView", referenced from:
      MapView::~MapView()in mapview.o
      MapView::~MapView()in mapview.o
      MapView::MapView(QObject*)in mapview.o
      MapView::MapView()in mapview.o
  "MapView::staticMetaObject", referenced from:
      MapView::MapView(QObject*)in mapview.o
      MapView::MapView()in mapview.o

Here's the header:

#ifndef MAPVIEW_H
#define MAPVIEW_H

#include <QtGui>
#include <QObject>

class MapView : public QGraphicsScene
{
    //Q_OBJECT

public:
    MapView();
    explicit MapView(QObject *parent = 0);
    QGraphicsPixmapItem *mappixmap;
    ~MapView();

private:
    bool dragging;
    float offsetX, offsetY, downoffsetX, downoffsetY;

protected:
    void mousePressEvent(QGraphicsSceneMouseEvent *event);
    void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
    void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);

};

#endif // MAPVIEW_H

Secondary question is will Bad Things happen if I just omit the Q_OBJECT macro here?

And yes, I'm aware of that it's stupid to call a QGraphicsScene a "view".

Gareth Stockwell
  • 3,112
  • 18
  • 23
teukkam
  • 4,267
  • 1
  • 26
  • 35
  • I will post function implementations per request, I just don't want to post everything here at once... – teukkam Aug 31 '10 at 08:24

2 Answers2

7

This kind of errors usually happen when you add the Q_OBJECT macro and forget to rerun moc. If you use qmake, just run make qmake after you added the macro.

As for your second question: you won't be able to use signals/slots (among other things) without the Q_OBJECT macro. See the docs for more information about this.

mtvec
  • 17,846
  • 5
  • 52
  • 83
  • Thanks, rerunning qmake indeed this fix this! I don't really need to use signal and slots here, just receive calls to the event handlers I've defined. But I still want to do things the proper way. – teukkam Aug 31 '10 at 08:56
  • @teukkam, If your classes are inherited from `QObject`, you will need `Q_OBJECT` macro... – liaK Aug 31 '10 at 09:05
  • 1
    @liaK: No, you only need it for signals/slots and some other things. See the link in my answer. – mtvec Aug 31 '10 at 09:23
  • Obviously I don't need that macro, because the program works as expected even if I omit it. I just like to have it there so the code looks like how one would expect it to look in the typical case. – teukkam Aug 31 '10 at 09:34
  • 1
    @ Job, http://doc.trolltech.com/4.6/metaobjects.html Check out this link.. From the docs, **we strongly recommend that all subclasses of QObject use the Q_OBJECT macro regardless of whether or not they actually use signals, slots, and properties.** – liaK Aug 31 '10 at 09:42
  • @liaK: I agree it's best practice to use the macro. I just meant it is not strictly necessary. – mtvec Aug 31 '10 at 10:12
  • Thanks for the recommendation of running QMake again! This issue has been tripping me up too, albeit with a different codebase involved (obviously). :) – Tyson Feb 06 '11 at 19:16
1

Recently I tried to compile QDeviceWatcher on Linux and I get the same error WRT QDeviceWatcherPrivate class, which declaration can be found in qdevicewatcher_p.h and definition in qdevicewatcher_linux.cpp (on Linux).

I use cmake as build system and my CMakeLists.txt looks like:

cmake_minimum_required(VERSION 3.8)

project("QDeviceWatcher" LANGUAGES CXX)

set(CMAKE_INCLUDE_CURRENT_DIR ON)

set(CMAKE_AUTOMOC ON)

find_package(Qt5 REQUIRED COMPONENTS Core Network)

set(SOURCES)
list(APPEND SOURCES "qdevicewatcher.cpp")
if(WINCE)
    list(APPEND SOURCES "qdevicewatcher_wince.cpp")
elseif(WIN32)
    list(APPEND SOURCES "qdevicewatcher_win32.cpp")
elseif(APPLE)
    list(APPEND SOURCES "qdevicewatcher_mac.cpp")
elseif(UNIX)
    list(APPEND SOURCES "qdevicewatcher_linux.cpp")
else()
    message(FATAL_ERROR "no supported platform detected")
endif()

add_library(${PROJECT_NAME} STATIC ${SOURCES})
target_include_directories(${PROJECT_NAME} PUBLIC ".")

target_link_libraries(${PROJECT_NAME} PUBLIC Qt5::Core Qt5::Network)

set_target_properties(${PROJECT_NAME} PROPERTIES
    CXX_STANDARD 17
    CXX_STANDARD_REQUIRED YES
    CXX_EXTENSIONS YES
    )

As you can see in add_library I only provide *.cpp files. I suspect, that cmake runs Meta object compiler and looks through all the sources, maybe except #include dependencies, which filenames (w/o extension) not match *.cpp's filenames (just assumption), for the QObject/QWidget/... bases and Q_OBJECT macro. And I think cmake missed qdevicewatcher_p.h to look through and run MOC against it.

After I added the "qdevicewatcher_p.h" to the list of sources the error is ceased to exist.

Tomilov Anatoliy
  • 15,657
  • 10
  • 64
  • 169