I have a Qt project made by Qt creator.
I let the creator itself generate a private slots function fx. on_pushbutton_clicked().
This function is declared in header, the function itself is in the cpp file created by the Qt creator.
When I move the function from cpp file generated by Qt creator to another cpp file (it is added in the project, it has the same includes as the generated cpp.
When I try to compile it, I get lnk2019 error.
Is there any way to have slots functions in different files?
I am using VC compiler.
Okay, here is extract from the code. (it is quite long)
gui.h
#ifndef GUI_H
#define GUI_H
#include <QMainWindow>
#include "buffer.h"
#include <string>
#include <map>
#include <math.h>
#include <sstream>
#include <stdlib.h>
#include "qcustomplot.h"
#include <limits>
#include <time.h>
#include <random>
namespace Ui {
class GUI;
}
class GUI : public QMainWindow
{
Q_OBJECT
public:
explicit GUI(QWidget *parent = 0);
~GUI();
private slots:
void on_setall_clicked();
void on_integrace_button_clicked();
void on_elipsy_button_clicked();
void on_grafy_button_clicked();
private:
Ui::GUI *ui;
};
#endif // GUI_H
gui.cpp
#include "gui.h"
#include "ui_gui.h"
double drand(double from, double to){
double f = (double)rand()/RAND_MAX;
return from + f * (to - from);
}
GUI::GUI(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::GUI)
{
ui->setupUi(this);
srand(time(0));
}
GUI::~GUI()
{
delete ui;
}
void GUI::on_setall_clicked(){...};
void GUI::on_grafy_button_clicked(){...};
void GUI::on_integrace_button_clicked(){...};
elipsy.cpp
#include "gui.h"
void GUI::on_elipsy_button_clicked(){...};
GUI.pro
#-------------------------------------------------
#
# Project created by QtCreator 2013-03-27T09:01:31
#
#-------------------------------------------------
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets printsupport
TARGET = GUI
TEMPLATE = app
SOURCES += main.cpp\
gui.cpp \
solve_rpn.cpp \
shunting_yard.cpp \
qcustomplot.cpp \
elipsy.cpp \
grafy.cpp \
integrace.cpp
HEADERS += gui.h \
buffer.h \
qcustomplot.h
FORMS += gui.ui
And the error code it gives me when i try to compile with the function elipsy_button_clicked() in file other than gui.cpp
moc_gui.obj:-1: Chyba:LNK2019: unresolved external symbol "private: void __cdecl GUI::on_elipsy_button_clicked(void)" (?on_elipsy_button_clicked#GUI##AEAAXXZ) referenced in function "private: static void __cdecl GUI::qt_static_metacall(class QObject *,enum QMetaObject::Call,int,void * *)" (?qt_static_metacall#GUI##CAXPEAVQObject##W4Call#QMetaObject##HPEAPEAX#Z)
debug\GUI.exe:-1: Chyba:LNK1120: 1 unresolved externals
Well, in case you need the entire sourcecode, I uploaded it
http://seed.gweana.eu/public/GUI.7z
FIXED: The file was ignored by the project, running qmake again solved the issue. Many thanks for the answers :)
One of the problems is that you exported the slot methods to elipsy.cpp where on line 14 you try to use: ui ... which is defined in ui_gui.h included only in gui.cpp, but forward declared in gui.h (which you include of course in elipsy.cpp) so this should give you a compilation error. Solution: include ui_gui.h in elipsy.cpp. If it doesn't give you a compilation error try to rebuild the application.
Secondly, your drand function is defined in gui.cpp but not in any header file (easily fixable, modify gui.h)...
After fixing these two issues the compilation was ok for me.
So, a few recommendations:
Leave the things as they are when comes to Qt ... you will just mess up your head when moving things around.
have a separate "module" for utilities, such as drand
(PS: Nice app :) )
Generally slots are declared in a header file like,in my Counter.h :
#include <QObject>
class Counter : public QObject
{
Q_OBJECT
public:
Counter() { m_value = 0; }
int value() const { return m_value; }
public slots:
void setValue(int value);
....
Now in Counter.cpp(and it has to include Counter.h), i will define this function like any other normal function.
So in this case everything will work correctly.Does that answers your question?
Related
I have linking problems by creating a Qt C++ plugin to extend the functionality of my application. The code compiles and everithing works, but only as long as I use the Qt library classes, like QString for example. The moment I give to the plugin's class a reference to an object from the classes defined in the host app, the project is not linked anymore. Creating the plugin I follow the procedure from the Qt documentation and take into consideration the given examples - echo and plug&paint. However, such case is not covered there.
update
Here is the error:
myPlugin.obj:-1: error: LNK2019: unresolved external symbol "public: class QString __cdecl myClass::answer(void)const " (?answer#myClass##QEBA?AVQString##XZ) referenced in function "public: virtual class QString __cdecl myPlugin::echo(class myClass *)" (?echo#myPlugin##UEAA?AVQString##PEAVmyClass###Z)
And here is the project that causes it:
plugtest.pro
TEMPLATE = subdirs
SUBDIRS += \
host \
plugin
host.pro
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = host
TEMPLATE = app
SOURCES += main.cpp\
MainWindow.cpp \
myClass.cpp
HEADERS += MainWindow.h \
myClass.h \
plugInterface.h
FORMS += MainWindow.ui
MainWindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QMessageBox>
#include <QPluginLoader>
#include <QDir>
#include "myClass.h"
#include "plugInterface.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void on_button_clicked();
private:
bool loadPlugin();
Ui::MainWindow *ui;
plugInterface *m_interface;
myClass *m_class;
};
#endif // MAINWINDOW_H
myClass.h
#ifndef MYCLASS_H
#define MYCLASS_H
#include <QObject>
class myClass : public QObject
{
Q_OBJECT
public:
explicit myClass(QObject *parent = 0);
QString answer() const;
void setAnswer(const QString &str);
private:
QString m_answer;
};
#endif // MYCLASS_H
plugInterface.h
#ifndef PLUGINTERFACE_H
#define PLUGINTERFACE_H
#include <QString>
#include "myClass.h"
class plugInterface
{
public:
virtual ~plugInterface() {}
virtual QString echo(myClass *value) = 0;
};
#define PlugInterface_iid "example.suite.app.PluginInterface"
Q_DECLARE_INTERFACE(plugInterface, PlugInterface_iid)
#endif // PLUGINTERFACE_H
MainWindow.cpp
#include "MainWindow.h"
#include "ui_MainWindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
if (!loadPlugin())
{
QMessageBox::information(this, "Error", "Could not load the plugin");
}
m_class = new myClass(this);
m_class->setAnswer("Good!");
}
MainWindow::~MainWindow()
{
delete ui;
}
bool MainWindow::loadPlugin()
{
QDir pluginsDir(qApp->applicationDirPath());
if (pluginsDir.dirName().toLower() == "debug" || pluginsDir.dirName().toLower() == "release")
pluginsDir.cd("plugins");
foreach (QString fileName, pluginsDir.entryList(QDir::Files))
{
QPluginLoader pluginLoader(pluginsDir.absoluteFilePath(fileName));
QObject *plugin = pluginLoader.instance();
if (plugin) {
m_interface = qobject_cast<plugInterface *>(plugin);
if (m_interface)
return true;
}
}
return false;
}
void MainWindow::on_button_clicked()
{
ui->lineResult->setText(m_interface->echo(m_class));
}
myClass.cpp
#include "myClass.h"
myClass::myClass(QObject *parent) : QObject(parent)
{
}
QString myClass::answer() const
{
return m_answer;
}
void myClass::setAnswer(const QString &str)
{
m_answer = str;
}
plugin.pro
TEMPLATE = lib
CONFIG += plugin
QT += widgets
INCLUDEPATH += ../host
HEADERS = myPlugin.h
SOURCES = myPlugin.cpp
TARGET = $$qtLibraryTarget(myPlugin)
DESTDIR = ../plugins
myPlugin.h
#ifndef MYPLUGIN_H
#define MYPLUGIN_H
#include <QObject>
#include "plugInterface.h"
class myPlugin : public QObject, plugInterface
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "example.suite.app.PluginInterface")
Q_INTERFACES(plugInterface)
public:
QString echo(myClass *value) Q_DECL_OVERRIDE;
};
#endif // MYPLUGIN_H
myPlugin.cpp
#include "myPlugin.h"
QString myPlugin::echo(myClass *value)
{
return value->answer();
}
The solution that worked for me is to make the myClass a part of a library and include it dynamically in both the plug-in and the host. However, I am curious if this could be done without creating a library.
I started working on the GUI for an application in C++ using the Qt-Creator and Designer. I always added the new files (cpp, h, ui) by using the dialog that Qt provides.
Here's what I get now:
moc_basewidget.obj:-1: Error: LNK2019: unresolved external signal ""public: void __cdecl BaseWidget::onNewProjects(void)" (?onNewProjects#BaseWidget##QEAAXXZ)" in function ""private: static void __cdecl BaseWidget::qt_static_metacall(class QObject *,enum QMetaObject::Call,int,void * *)" (?qt_static_metacall#BaseWidget##CAXPEAVQObject##W4Call#QMetaObject##HPEAPEAX#Z)".
Here's my BaseWidget.h:
#ifndef BASEWIDGET_H
#define BASEWIDGET_H
#include <QWidget>
#include "mainmenu.h"
#include "projectlist.h"
namespace Ui {
class BaseWidget;
}
class BaseWidget : public QWidget
{
Q_OBJECT
public:
explicit BaseWidget(QWidget *parent = 0);
~BaseWidget();
public slots:
//called in MainMenu
void onProjects();
private:
Ui::BaseWidget *ui;
MainMenu * mainMenu;
ProjectList * projectList;
};
#endif //BASEWIDGET_H
And my BaseWidget.cpp:
#include "basewidget.h"
#include "ui_basewidget.h"
BaseWidget::BaseWidget(QWidget *parent) : QWidget(parent), ui(new Ui::BaseWidget) {
ui->setupUi(this);
//add all the widgets
this->mainMenu = new MainMenu(this);
ui->stackedWidget->addWidget(mainMenu);
this->projectList = new ProjectList(this);
ui->stackedWidget->addWidget(projectList);
}
BaseWidget::~BaseWidget()
{
delete ui;
}
void BaseWidget::onProjects()
{
ui->stackedWidget->setCurrentWidget(this->projectList);
}
And finally, my .pro file:
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = GUI
TEMPLATE = app
SOURCES += main.cpp\
basewidget.cpp \
mainmenu.cpp \
projectlist.cpp
HEADERS += basewidget.h \
mainmenu.h \
projectlist.h
FORMS += basewidget.ui \
mainmenu.ui \
projectlist.ui
I've read about it for hours now. I tried cleaning the build-directory and rebuilding, but it always comes down to this.
I was trying to make QLCDNumber clickable, by inheriting a new class from it. All it does is define a mouseReleaseEvent(QMouseEvent *e) sending a clicked() signal.
I think my code is correct, but it can't find the signal (unresolved external symbol on clicked() inside mouseReleaseEvent()
//myLCDNumber.h
#ifndef MYLCDNUMBER_H
#define MYLCDNUMBER_H
#include <QLCDNumber>
#include <QMouseEvent>
class myLCDNumber : public QLCDNumber
{
public:
myLCDNumber(uint numDigits);
~myLCDNumber();
void mouseReleaseEvent(QMouseEvent *e);
signals:
void clicked(void);
};
#endif // MYLCDNUMBER_H
//myLCDNumber.cpp
#include "mylcdnumber.h"
myLCDNumber::myLCDNumber(uint numDigits):QLCDNumber(numDigits){}
myLCDNumber::~myLCDNumber(){}
void myLCDNumber::mouseReleaseEvent(QMouseEvent *e)
{
qDebug("Click check");
if (e->button() == Qt::LeftButton)
emit myLCDNumber::clicked();
}
EDIT : I checked the SOURCES list for all my files to be correctly referenced in my project file, and I rerun qmake. No change.
Your problem is that you use signals and/or slots without using Qt's Meta Object Compiler. Add the Q_OBJECT Macro to your class definition and it'll work:
//myLCDNumber.h
#ifndef MYLCDNUMBER_H
#define MYLCDNUMBER_H
#include <QLCDNumber>
#include <QMouseEvent>
class myLCDNumber : public QLCDNumber
{
Q_OBJECT
public:
myLCDNumber(uint numDigits);
~myLCDNumber();
void mouseReleaseEvent(QMouseEvent *e);
signals:
void clicked(void);
};
#endif // MYLCDNUMBER_H
Don't forget to add the header file to the HEADERS variable and rerun qmake before building again.
You need to add Q_OBJECT macro to your class declaration and run qmake...maybe to rebuild your project
I'm having a very serious issue with QT Creator. I can no longer use pointers to other classes and autocompletion doesn't work in my primary class. It feels like something has become corrupt, but all my code was working with a few pointers existing, then all at once none of them worked and errored out.
Line 21: InkPuppet *pointerToPuppet; errors: x:\development\inkpuppet\newdialog.h:21: error: C2143: syntax error : missing ';' before '*' and x:\development\inkpuppet\newdialog.h:21: error: C4430: missing type specifier - int assumed. Note: C++ does not support default-int
Here is my .pro file:
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = InkPuppet
TEMPLATE = app
SOURCES += main.cpp\
inkpuppet.cpp \
aboutdialog.cpp \
inkspot.cpp \
newdialog.cpp
HEADERS += inkpuppet.h \
aboutdialog.h \
inkspot.h \
newdialog.h
FORMS += inkpuppet.ui \
aboutdialog.ui \
newdialog.ui
OTHER_FILES += \
InkPuppet.pro.user
RESOURCES += \
resources.qrc
Here is my default header. inkpuppet.h
#ifndef INKPUPPET_H
#define INKPUPPET_H
#include "inkspot.h"
#include "ui_inkpuppet.h"
#include <QMainWindow>
#include <QWidget>
namespace Ui {
class InkPuppet;
}
class InkPuppet : public QMainWindow
{
Q_OBJECT
public:
explicit InkPuppet(QWidget *parent = 0);
~InkPuppet();
Ui::InkPuppet *ui;
private slots:
void setMinimum(int value);
void setMaximum(int value);
void actionNew();
void actionAbout();
void testButton();
};
#endif // INKPUPPET_H
newdialog.h
#ifndef NEWDIALOG_H
#define NEWDIALOG_H
#include "inkspot.h"
#include "inkpuppet.h"
#include "ui_inkpuppet.h"
#include <QDialog>
namespace Ui {
class NewDialog;
}
class NewDialog : public QDialog
{
Q_OBJECT
public:
explicit NewDialog(QWidget *parent = 0);
~NewDialog();
InkPuppet *pointerToPuppet;
private:
Ui::NewDialog *ui;
private slots:
void createNew();
};
#endif // NEWDIALOG_H
Replace "InkPuppet *pointerToPuppet;" with "Ui::InkPuppet *pointerToPuppet;" will fix your compilation issue.
Reinstalling yourSDK may solve auto-completion issue. Problem with Qt creator autocomplete code
I am trying to make a link between my 3 windows , so I put this in my mainwindow.h :
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "video.h"
#include "flightdata.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
public slots:
void openNewWindowVideo();
void openNewWindowData();
private:
Ui::MainWindow *ui;
video *myVideoWindow;
flightdata *myDataWindow;
};
#endif // MAINWINDOW_H
And this in my implementation:
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
connect(ui->actionVideo,SIGNAL(triggered()),this,SLOT(openNewWindowVideo()));
connect(ui->actionFlight_data,SIGNAL(triggered()),this,SLOT(openNewWindowData()));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::openNewWindowVideo()
{
myVideoWindow = new video();
myVideoWindow->show();
this->close();
}
void MainWindow::openNewWindowData()
{
myDataWindow = new flightdata();
myDataWindow->show();
this->close();
}
This works.
But when O follow the same steps for the 2 other windows ( file.h + file.cpp ),
iI get the error :
qt error: 'flightdata' does not name a type
qt error: 'video' does not name a type
But when I include just first window and not the 2 others , I don't get this problem.
Maybe it is being caused by recursion.
Don't include your other classes in header files. Include them in source files only.
If you for some reason need to use another class in a header of other class, use forward declaration instead of include.
Header:
// no include for 'video.h'
class video;
class MainWindow : public QMainWindow {
//...
video *myVideoWindow;
};
Source:
#include "video.h"
//...
As far as I can tell, there are potentially two things that may be wrong:
Pre-processor/MACRO
If you created the other windows with QtCreator/Designer, the #ifndef macros should be unique. Meaning, video.h should have something like:
#ifndef VIDEOWINDOW_H
#define VIDEOWINDOW_H
instead of the default
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
These #ifndef MACROS are intended to help include the contents of the header file once and only once.
Missing include paths
Also, if you're using QtCreator, the editor should display #include "video.h" and #include "flightdata.h" as a link (control + left click). If the syntax is underlined red, it means that the project can't find those files.
Then you'll need to check to make sure that the files are either in your project folder or add have the path to those files added in the qmake variable INCLUDEPATH of your pro file.
# e.g.
INCLUDEPATH += ../myflightdata ../myvideofiles