PDA

View Full Version : the simplest custom slot



tommy
6th November 2007, 00:00
Hi all,

I'm trying to figure out if I don't know how to make a custom slot or my compiler (Dev-C++) is not configured correctly to compile a program with a custom slot (everything compiles fine when I use a predefined slot). I'd be extremely thankful to you if you could either:
1) send me the simplest fully functioning code (using just one *.cpp file) that uses a custom slot,
or
2) take a look at my code and suggest why this is not compiling and I get this error:
[Linker error] undefined reference to `vtable for MyExit'

Here's my code:


#include <QApplication>
#include <QPushButton>
#include <QHBoxLayout>

using namespace std;

class MyExit : public QObject
{
Q_OBJECT
public:
MyExit (QObject *parent = 0);
public slots:
void myExitSlot();
};

MyExit::MyExit(QObject *parent):QObject(parent)
{
}

void MyExit::myExitSlot()
{
qApp->quit();
}

int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget window;
QHBoxLayout* mainLayout = new QHBoxLayout(&window);
QPushButton *b1 = new QPushButton("Exit");
mainLayout->addWidget(b1);

QObject::connect(b1, SIGNAL(clicked()), qApp, SLOT(myExitSlot()));
window.show();
return a.exec();
}

Thanks a lot in advance. Tommy

jacek
6th November 2007, 00:11
If you put Q_OBJECT macro inside a .cpp file, you have to add #include "filename.moc" at the end to let qmake know that it has to invoke moc on that file (normally qmake looks for Q_OBJECT only in header files).

jml
6th November 2007, 00:26
I'm not sure you can call connect from the main() routine; I believe it should be invoked from an object derived from QObject. Try moving your class declaration to a .h flie, and do the connect from the MyExit constructor.

wysota
6th November 2007, 00:31
I'm not sure you can call connect from the main() routine; I believe it should be invoked from an object derived from QObject.

No, you can call connect() from everywhere you want. It's a static method of QObject, so you just need to prefix it with QObject:: if you use it outside any QObject, just like the thread author did.

spud
6th November 2007, 06:27
The slot seems find, You need to connect to it, though.


MyExit myExit;
QObject::connect(b1, SIGNAL(clicked()), &myExit, SLOT(myExitSlot()));


Right now your connecting to a QApplication object, which doesn't have the slot myExitSlot();)

tommy
6th November 2007, 15:05
Thanks to all who responded to me. You have given me lots of ideas and helped me a lot.
For example I did not know that custom slot classes should be in the *.h file with mingw compiler. I had absolutely no idea that you could include "filename.moc" file if your custom class is in the *.cpp file. I did not get this to work yet but it it good to know that such an option exists. Thanks for pointing out that I had the slot connected all wrong, too.
So I guess I have to start using *.h files for classes and I will. But at the same time I'm very curious if my compiler has some kind of a problem. I'd appreciate it a lot if somone was able to run the below code through their compiler and let me know what kind of error messages other compilers gave. Or perhaps it'll work with other compilers no problem.
Thanks a lot.
Here's the code:


#include <QApplication>
#include <QPushButton>
#include <QHBoxLayout>

using namespace std;

class MyExit : public QObject
{
Q_OBJECT

public:
MyExit (QObject *parent = 0);
public slots:
void myExitSlot();
};



void MyExit::myExitSlot()
{
qApp->quit();
}

MyExit::MyExit(QObject *parent):QObject(parent)
{
}


int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget window;
QHBoxLayout* mainLayout = new QHBoxLayout(&window);
QPushButton *b1 = new QPushButton("Exit");

mainLayout->addWidget(b1);

QObject::connect(b1, SIGNAL(clicked()), &MyExit, SLOT(myExitSlot()));

window.show();
return a.exec();
}

jpn
6th November 2007, 15:09
Looks like no instance of MyExit is being created. Take a look at spud's post.

tommy
6th November 2007, 15:43
Thanks jpn.

Unfortunately I don't exactly understand how to do what I'm supposed to do: create that instance or make the connection (I just started with Qt a few days ago). Do you mind showing me the lines.
Thanks a lot.

Tommy

jacek
6th November 2007, 16:00
Unfortunately I don't exactly understand how to do what I'm supposed to do: create that instance or make the connection
You can create connections only between objects, but MyExit is a class. You have to create an object of this class (just like you did with QWidget or QPushButton).

tommy
6th November 2007, 16:27
Great. I created the instance required but the code still won't compile. And it won't compile when I put the new class in a *.h file either.
Does anyone have any more ideas?
Thankfully - Tommy.

Code:


#include <QApplication>
#include <QPushButton>
#include <QHBoxLayout>

using namespace std;

class MyExit : public QObject
{
Q_OBJECT

public:
MyExit (QObject *parent = 0);
public slots:
void myExitSlot();
};



void MyExit::myExitSlot()
{
qApp->quit();
}

MyExit::MyExit(QObject *parent):QObject(parent)
{
}


int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MyExit Exit;
QWidget window;
QHBoxLayout* mainLayout = new QHBoxLayout(&window);
QPushButton *b1 = new QPushButton("Exit");

mainLayout->addWidget(b1);

QObject::connect(b1, SIGNAL(clicked()), &Exit, SLOT(myExitSlot()));

window.show();
return a.exec();
}

jacek
6th November 2007, 16:30
The code is OK. Do you use qmake to compile it?

tommy
6th November 2007, 16:53
hi Jacek

Thanks for confirming my code. No, I do not use qmake. I'm going to need
another piece of help here if you don't mind because I do not know how to use qmake.
My compiler is Dev-C++ (mingw). I guess I have to put "qmake" somewhere in the
project options sections? Or is qmake a standalone program you run before or when you compile? (instead of your compiler?).
Thanks to you and the other helpful people my problem is now narrowed down to
compiler/linker problem and most likely qmake.

Tommy

rvb13
6th November 2007, 18:00
The code is OK. Do you use qmake to compile it?
Hi Jacek,

I was having a look at Tommy's code and I am a bit confused. In this MyExitSlot() implementation, I see he is calling qapp.quit(); and I dont see a QApplication object named as qapp. Shouldnt he be declaring one in the private section of MyExit ? I think thats the reason why the compiler is complaining because there is no reference to the method in the vtable, since there is no object defined. Right ? Please correct me if I am wrong.

Thanks
- Rahul

jpn
6th November 2007, 18:02
See qApp in QApplication docs:


A global pointer referring to the unique application object. It is equivalent to the pointer returned by the QCoreApplication::instance() function except that, in GUI applications, it is a pointer to a QApplication instance.

jacek
7th November 2007, 21:10
My compiler is Dev-C++ (mingw). I guess I have to put "qmake" somewhere in the
project options sections? Or is qmake a standalone program you run before or when you compile? (instead of your compiler?).
qmake is a tool that generates makefiles from .pro files, which are much simplier. To generate an initial .pro file you have to run "qmake -project" in the directory where your project is. Then you run "qmake" or "qmake filename.pro" to generate makefile. I don't use Dev-C++, but AFAIR you can make it use a custom makefile, so you just have to point it to the makefile generated by qmake.

tommy
8th November 2007, 00:12
Thanks Jacek,

You made a lot of things much more clear for me, I'm beginning to understand the basics now.
I was able to use qmake just as you suggested but did not get it to work with Dev-C++. I'm thinking of abandoning Dev-C++ and trying command line (just get plain mingw). How do you include the makefile when you compile from command line? What's the syntax?

Thankfully,
Tommy

jacek
8th November 2007, 00:44
I'm thinking of abandoning Dev-C++ and trying command line (just get plain mingw).
I'm sure you can find some tutorials about using Dev-C++ for Qt applications on google.

mchara
8th November 2007, 06:54
Hi,
I'm using qt on dev-cpp, so i had similar problem
I'm not using qmake(it says it can't find FORCE target), but i didn't searched the reason of this error, because i'm using multiple makefiles to have effect of several projects in one solution (dev-cpp works on projects only).
You need to set use custom makefile in projects options, add a tatget *.moc, with 2 commands:
1 moc your *.h to *.moc(or moc_*.cpp)
2 compile generated file

or the simpler way makefile that calls only qmake & make on file generated by, unfortunately i can't test this because of mentioned qmake error.

jacek
8th November 2007, 15:48
I'm not using qmake(it says it can't find FORCE target), but i didn't searched the reason of this error
What is the value of the TARGET variable in your .pro file? If it isn't set, what is the name of the .pro file?


You need to set use custom makefile in projects options, add a tatget *.moc, with 2 commands:
1 moc your *.h to *.moc(or moc_*.cpp)
2 compile generated file
What about all of those magic macros Qt needs?

mchara
9th November 2007, 07:04
What is the value of the TARGET variable in your .pro file? If it isn't set, what is the name of the .pro file?

Doesn't matter, i have the same error for every makefile generated by qmake, i found that
FORCE: is an empty target used to force something to be build even if there's no dependencies so it shall be empty definition.
It is in deed in generated makefiles' but i suppose that problem might be in missing tab & newline after FORCE: - some make's are sensitive for tabs instead of spaces etc., i think make is one of them.


What about all of those magic macros Qt needs?
What macros?
DO you mean those defines at the beginning

-DUNICODE -DQT_LARGEFILE_SUPPORT -DQT_DLL -DQT_NO_DEBUG -DQT_CORE_LIB -DQT_GUI_LIB -DQT_THREAD_SUPPORT -DQT_NEEDS_QMAIN
, i've copied them from first makefile found in qt's exapmles & worked fine.

Those are always the same view defines(& view more depending on used modules -DQT_*_LIB) so it's not much work.

I thought that maybe custom makefie that would have defined only qmake -project; qmake &make on newly generated makefile would solve the problem if we would find what's wrong with FORCE error... can anyone check is this common problem on mingw or just mine?

Oh, one more thing : make sure to not use --short-double or --expensive-optimizations because using one of them causes QPainter::drawPixmap()/drawImage() stops working... it's really strange but i've checked it several times & it really happens.

wysota
9th November 2007, 10:12
What macros?
DO you mean those defines at the beginning

-DUNICODE -DQT_LARGEFILE_SUPPORT -DQT_DLL -DQT_NO_DEBUG -DQT_CORE_LIB -DQT_GUI_LIB -DQT_THREAD_SUPPORT -DQT_NEEDS_QMAIN
, i've copied them from first makefile found in qt's exapmles & worked fine.
This is not a good thing to do. The macros change depending on how you configure your project - in this situation you only enable core and gui libraries. What if you want to use other Qt modules like network, xml or any of the others? Your static compilation rule will fail. If you install newer Qt release that has more switches, your compilation will fail. If you want to switch between debug and release, it won't be possible, etc.

mchara
9th November 2007, 10:26
I know it's not good solution, but the only one working i have for now...
I promise to let you know, when i'll find what's wrong with that "FORCE" qmake's error & figure out how to use dev-cpp's makefile to generate & build second one from qmake.
P.S.
If i'm adding some module i have to add include, lib & define by hand, i have to add each file i'm adding to project to makefile also, so it's lots of unnecessary work...
Only positive side of this solution is the fact that application compiles itself from dev-cpp environtment.

wysota
9th November 2007, 11:13
Isn't it possible to do the compilation just by making qmake && make your build sequence in the IDE?

mchara
9th November 2007, 11:29
It should be possible, i've used only use custom makefile option. As i said i got an error on makefiles generated by qmake & i don't know the reason jet so i was using own makefiles.
it would be nice to have qmake & make integrated with IDE but first qmake must work. When i'll force qmake to work properly, i'll start searching how to integrate it with dev-cpp in best way.

wysota
9th November 2007, 11:39
What kind of make do you have? What does make -v return?

mchara
9th November 2007, 11:54
GNU Make 3.80
Copyright (C) 2002 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.

i think it can be caused by missing tab after FORCE:
but i can't test it now - i'm using vs2005 with integration in work while dev-cpp with open-source edition of qt at home, i'm working now and unluckily have no network at home so i'll come up at monday with more details about qmake on mingw.

on the margin: those qmake supports doxygen or some other source documentation tools?

wysota
11th November 2007, 15:13
I don't have anything missing in my qmake+gmake makefiles... What is the exact error message you get? And what are the exact conditions of getting it?

mchara
12th November 2007, 07:04
Sorry, my error was caused by delphi installed on my system. I've forgot about it(long time not used:D) & didn't checked paths order in environtment and qmake tried to use borland's make...
stupid mistake...

anyhow, dev-cpp allows to use custom makefile or *.mak make addons.
I don't know what are those addons, but setting custom makefile to one generated by qmake shall be enough to work with single projects(makefile generated from qmake has a rule to regenerate itself from *.pro file, so it should guarantee makefile to be up to date).

personally i prefer to keep using makefiles written by hand - it's not so hard & allows me to have multiple projects in one environment(a bit like solution in vs)by using separate makefiles for projects & dev-cpp set to makefile that builds application and calls makes to build a number of dlls recursively. There will be source documentation generated from those makefiles in future and help file compilation.To do this with qmake i would have to provide pro files, makefiles for them and additional makefile that calls them, it's more things to maintain without bigger benefits for me, but as i said - for single projects qmake's makefile should do the work.

wysota
12th November 2007, 10:10
makefile generated from qmake has a rule to regenerate itself from *.pro file, so it should guarantee makefile to be up to date
Only if the .pro file changes. But if you only change one of the files that require the makefile to be recreated (like when adding a Q_OBJECT macro to an existing class), you need to rerun qmake manually. Furthermore, if you add a new file to the project, you'll have to modify the .pro file manually as well.


personally i prefer to keep using makefiles written by hand - it's not so hard & allows me to have multiple projects in one environment(a bit like solution in vs)by using separate makefiles for projects & dev-cpp set to makefile that builds application and calls makes to build a number of dlls recursively.
qmake supports that as well. Just take a look at the SUBDIRS template for qmake. You can also make qmake generate make rules for things you mention - like building help and documentation. Some features that are poorly documented (or even not documented at all) might be explained better in our wiki (http://wiki.qtcentre.org).

mchara
12th November 2007, 11:05
It's really good article, it seems that qmake can do all that stuff that make can!
hmm... i don't know, there's no features that would be MUCH easier with qmake than with make. I'm familiar with make enough to feel comfortable with maintaining makefiles as well as qmake projects. In addition dev-cpp's dump debugger fails to trace errors in files that are build in sub makefile, it traces only files mentioned in main makefile so i'm compiling only release version without additional subdirs for output(everything builds into target structure of directories). qmake makes some mess for me with generating lots of unwanted files.

I really don't know, it's hard choice... i think qmake is powerful tool that can do some work for me, but it also does some unwanted tasks...

maybe i just like to have full control over my source and qmake (as every automation tool) takes over some control to make things easier... makefile have just view lines more than *.pro and keep lower number of files to maintain.

wysota
12th November 2007, 11:18
It's really good article, it seems that qmake can do all that stuff that make can!
qmake doesn't substitute make! It uses it to obtain its goal instead. You can't use qmake without make, be aware of that. qmake is just a tool for maintaining the project - something make can't do on its own. If you like writing makefiiles, you might not use qmake at all or try to mimic its behaviour using pure make rules. Just remember that qmake guarantees that Qt applications will build properly. Without it you have to guarantee that yourself by adding or removing appropriate defines or other statements to the makefile.