I'm having trouble moving from VC++ to Qt-style programming with slots/signals. I wanted to create a button with an image that, when clicked, changed to another image, and when released, changed back to its original. I created a class called ClickableQLabel that inherits from QLabel, but it's telling me that certain functions are re-defined. Specifically, the ones that are emitted.
MainProgram.cpp
#include "MainProgram.h"
#include <QApplication>
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
CodeVault w;
w.show();
return a.exec();
}
MainProgram.h
#ifndef MAINPROGRAM_H
#define MAINPROGRAM_H
#include <QMainWindow>
#include "clickableqlabel.h"
namespace Ui {
class MainProgram;
}
class MainProgram : public QMainWindow
{
Q_OBJECT
public:
explicit MainProgram(QWidget *parent = 0);
~MainProgram();
private:
Ui::MainProgram *ui;
};
#endif // MAINPROGRAM_H
clickableqlabel.h
#ifndef CLICKABLEQLABEL_H
#define CLICKABLEQLABEL_H
#include <QLabel>
#include <QMouseEvent>
using namespace Qt;
class ClickableQLabel : public QLabel {
Q_OBJECT
QPixmap pushed;
QPixmap unpushed;
public:
ClickableQLabel(QWidget *parent = 0);
void mousePressEvent(QMouseEvent *eve );
void mouseReleaseEvent(QMouseEvent *eve );
void setPushed(QPixmap &p);
void setUnpushed(QPixmap &p);
signals:
void leftButtonPressed(ClickableQLabel* sender);
void leftButtonReleased(ClickableQLabel* sender);
};
#endif // CLICKABLEQLABEL_H
clickableqlabel.cpp
#include "clickableqlabel.h"
ClickableQLabel::ClickableQLabel(QWidget *parent) : QLabel(parent){
// set up qlabel
}
void ClickableQLabel::setPushed(QPixmap &p){
pushed = p;
}
void ClickableQLabel::setUnpushed(QPixmap &p){
unpushed = p;
}
void ClickableQLabel::leftButtonPressed(ClickableQLabel* sender){
if(!pushed.isNull())
sender->setPixmap(pushed.scaledToWidth(sender->width()));
}
void ClickableQLabel::leftButtonReleased(ClickableQLabel* sender){
if(!unpushed.isNull())
sender->setPixmap(unpushed.scaledToWidth(sender->width()));
}
void ClickableQLabel::mousePressEvent(QMouseEvent *eve ){
if(eve->button() == Qt::LeftButton){
emit leftButtonPressed(this);
}
}
void ClickableQLabel::mouseReleaseEvent(QMouseEvent *eve ){
if(eve->button() == Qt::LeftButton){
emit leftButtonReleased(this);
}
}
What I receive is the following 3 errors:
moc_clickableqlabel.obj:-1: error: LNK2005: "public: void __cdecl ClickableQLabel::leftButtonPressed(class ClickableQLabel *)" (?leftButtonPressed#ClickableQLabel##QEAAXPEAV1##Z) already defined in clickableqlabel.obj
moc_clickableqlabel.obj:-1: error: LNK2005: "public: void __cdecl ClickableQLabel::leftButtonReleased(class ClickableQLabel *)" (?leftButtonReleased#ClickableQLabel##QEAAXPEAV1##Z) already defined in clickableqlabel.obj
debug\CodeVault.exe:-1: error: LNK1169: one or more multiply defined symbols found
The two functions that are causing the errors are the two signals in the clickableqlabel.h file. How am I supposed to set up the connect function and where?
You shouldn't provide an implementation for your signals. You just declare signals in the class header. the Qt moc provides an implementation that is responsible to call the slots connected to the signal when it is emitted, see this. Because you are providing an implementation and Qt moc is providing another one, you end up with two different implementations and the linker complains.
so, to make some piece of code execute when a signal is emitted, you can put it in some slot that is connected to that signal, or you can execute it manually before emitting the signal. . .
Another thing to note is that your signals have a parameter named sender. normally there is no need to do this, QObject::sender() provides similar functionality.
How am I supposed to set up the connect function and where?
When you instantiate your ClickableQLabel in your MainProgram window for example (You can do this by using ClickableQLabel in a .ui form file), you can connect its signals to slots of the MainProgram, like this.
mainprogram.h
#ifndef MAINPROGRAM_H
#define MAINPROGRAM_H
#include <QMainWindow>
#include "clickableqlabel.h"
namespace Ui {
class MainProgram;
}
class MainProgram : public QMainWindow
{
Q_OBJECT
public:
explicit MainProgram(QWidget *parent = 0);
~MainProgram();
public slots:
void labelPressed();
void labelReleased();
private:
Ui::MainProgram *ui;
};
#endif // MAINPROGRAM_H
then in the constructor connect the ClickableQLabel's signals to the MainProgram's slots , something like this:
connect(clickableLabel, SIGNAL(leftButtonPressed()), this, SLOT(labelPressed()));
where clickableLabel is your ClickableQLabel object.
You should not explicitly define signal "functions" - they are simply emitted (as you do in the mousePressEvent() and mouseReleaseEvent() functions).
If you want some action performed (such as setPixmap), you would either do that in the slot functions that are connected to those signals, or perhaps directly in the mousePressEvent and mouseReleaseEvent functions.
Unrelated, but you may also need to do something like qRegisterMetaType<ClickableQLabel>() to use that data type with the signal/slot mechanism.
You don't need to subclass QLabel to achieve this: put an onLabelButtonClicked slot (method) in your MainWindow class, which is connected to the QPushButton clicked() signal, and which calls setText / setIcon as required.
If you want to re-use this clickable element you can of course encapsulate it in a class, but subclassing and handling raw-events is only required in Qt when defining new kinds of widget; if you're simply composing standard functionality (being clicked, adjusting appearance) then slots on your main window / dialog class are usually sufficient.
Related
I currently try to write an little application for experiments and more. I write everything in its own file (Menu -> menu.cpp etc.). Now I want to create a menu action, this works but interacting with the action doesnt. Thats what I've done so far:
menu.cpp
#include "menu.h"
#include <QMenuBar>
#include <QMenu>
#include <QAction>
void Menu::setupMenu(QMainWindow *window) {
QMenuBar *mb = new QMenuBar();
QMenu *fileMenu = new QMenu("File");
QAction *newAct = new QAction("New...", window);
window->connect(newAct, SIGNAL(triggered()), this, SLOT(newFile()));
fileMenu->addAction(newAct);
mb->addMenu(fileMenu);
window->setMenuBar(mb);
}
void Menu::newFile() {
printf("hello world!");
}
menu.h
#ifndef MENU_H
#define MENU_H
#include <QObject>
#include <QMainWindow>
#include <QWidget>
#include <QMenuBar>
class Menu : public QObject
{
public:
void setupMenu(QMainWindow *window);
private slots:
void newFile();
};
#endif // MENU_H
But its not printing out 'hello world', the only message I get is:
QObject::connect: No such slot QObject::newFile() in ../from Scratch written UI app C++/src/ui/menu.cpp:11
What can I do to fix this?
~ Jan
class Menu : public QObject
Menu is a QObject but is also needs to use the Q_OBJECT macro.
See the Qt5 - QObject documentation:
The Q_OBJECT macro must appear in the private section of a class definition that declares its own signals and slots or that uses other services provided by Qt's meta-object system.
Next, there is some confusion in your connect call. Here is the signature of the static connect function.
Qt5 - static QObject::connect:
QObject::connect(const QObject * sender, const char * signal, const QObject * receiver, const char * method, Qt::ConnectionType type = Qt::AutoConnection)
You can see it takes 5 parameters (object pointer, signal, object pointer, signal/slot) and the 5th parameter is defaulted.
There is also a member function connect.
Qt5 - QObject::connect:
QObject::connect(const QObject * sender, const char * signal, const char * method, Qt::ConnectionType type = Qt::AutoConnection) const
This takes 4 parameters (object pointer, signal, signal/slot) and the 4th parameter is defaulted.
Your code:
window->connect(newAct, SIGNAL(triggered()), this, SLOT(newFile()));
You're calling the the connect member function of window but you're passing parameters for the static connect function.
What can I do to fix this?
Figure out what you're trying to do and make the appropriate call.
For example: connect the QAction signal to a slot in Menu then either call the static function as follows.
connect(newAct, SIGNAL(triggered()), this, SLOT(newFile()));
Or using the member function.
connect(newAct, SIGNAL(triggered()), SLOT(newFile()));
I'm writing a program that send an UDP frame every 10 mS. Here's how my program is supposed to work :
I've got a client class :
//Constructor
clientSupervision::clientSupervision()
{
}
void clientSupervision::sendDataUDP(){
//Create a frame and send it
...
}
void clientSupervision::sendDataUDPTimer(int timer){
QTimer *tempsEnvoieTrameSupervision = new QTimer();//Create a timer
tempsEnvoieTrameSupervision->setInterval(timer);//Set the interval
//Mise en place des connections
QObject::connect (tempsEnvoieTrameSupervision,SIGNAL (timeout()),this, SLOT (envoiTrameSupervision())); //Connect the timer to the function
tempsEnvoieTrameSupervision->start();// Start the timer
}
//Call sendDataUDP
void clientSupervision::envoiTrameSupervision(){
std::cout << "Envoi de la trame de supervision";
sendDataUDP();
}
My header file of clienSupervision.h :
#ifndef CLIENTSUPERVISION_H
#define CLIENTSUPERVISION_H
#include <winsock2.h> // pour les fonctions socket
#include <cstdio> // Pour les Sprintf
#include "StructureSupervision.h"
#include "utilitaireudp.h"
#include <QTimer>
#include <QObject>
#include <iostream>
class clientSupervision
{
Q_OBJECT
public:
clientSupervision();
void sendDataUDP();
void sendDataUDPTimer(int timer);
public slots:
void envoiTrameSupervision();
};
#endif // CLIENTSUPERVISION_H
Then I use this in my main :
int main(int argc, char *argv[])
{
clientSupervision c;
c.sendDataUDPTimer(10);
QCoreApplication a(argc, argv);
return a.exec();
}
I've got the error :
no matching function for call to 'QObject::connect(QTimer*&, const char*, clientSupervision* const, const char*)
I don't understand why the connect function can't find a matching function.
What should I change?
There can be several reasons for the issue in general:
You do not inherit QObject.
You do not have the Q_OBJECT macro in your class.
You do not define the method as slot in your header file where the class is declared.
Your issue is the first which can be seen here:
class clientSupervision
You should change your code to:
class clientSupervision : public QObject
// ^^^^^^^^^^^^^^^^
Of course, the constructor implementation and signature would need to change, too, as follows:
explicit clientSupervision(QObject *parent = Q_NULL_PTR) : QObject(parent) { ... }
In addition, you seem to leak your QTimer instance as it does not get the parent as a parameter to the constructor.
Furthermore, the QObject:: scope is needless in your code as your class ought to inherit QObject directly or indirectly either way.
Even more, I would highly encourage you to utilize the new signal-slot syntax.
Another possible cause of this error is trying to connect to a slot which is overloaded. For example, this well cause the same error
QObject::connect(this,
&MazeWidget::MyUpdate,
this,
&QWidget::update,
Qt::QueuedConnection);
But not if you explicitely cast:
QObject::connect(this,
&MazeWidget::MyUpdate,
this,
static_cast<void (QWidget::*)()>(&QWidget::update),
Qt::QueuedConnection);
Here's another one that snuck up on me: The class of the slot object had been forward declared in the header, but not defined in the implementation by including its header.
If none of the answers above worked, check if you have assigned correct object to the signals and the slots. You will get this error when the signals and slots are valid and refer to one object but the object assigned to that signal and slot is different.
I'm a very beginnner at C++ /Qt programming. I've made this simple dialog box that check the QLineEdit, if the text entered is "bob" should enable the OK button.
I can't get it to compile successfully, it gives me:
dialog.cpp|31|undefined reference to `Dialogmio::send()'
What am I doing wrong?
This is dialog.h:
//dialog.h
#ifndef DIALOG_H_INCLUDED
#define DIALOG_H_INCLUDED
#include <QDialog>
class QPushButton;
class QLineEdit;
class Dialogmio : public QWidget
{
public:
Dialogmio(QWidget *parent =0);
signals:
void send ();
public slots:
void recip(QString &text);
private:
QLineEdit *linedit;
QPushButton *buttonOK;
};
#endif
This is dialog.cpp:
//dialog.cpp
#include <QtGui>
#include "dialog.h"
Dialogmio::Dialogmio(QWidget *parent)
: QWidget(parent)
{
linedit = new QLineEdit();
buttonOK = new QPushButton("OK");
buttonOK->setEnabled(FALSE);
connect( linedit, SIGNAL( textChanged(const QString &) ), this, SLOT( recip(const QString &) ));
connect (this,SIGNAL( send()), this, SLOT( buttonOK->setEnabled(true)) );
QHBoxLayout *layout = new QHBoxLayout();
layout->addWidget(linedit);
layout->addWidget(buttonOK);
setLayout(layout);
}
void Dialogmio::recip(QString &text)
{
QString a = linedit->text();
if (a == "bob"){
emit send(); //here it gives me the error
}
}
This is main.cpp:
#include <QApplication>
#include "dialog.h"
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
Dialogmio *dialog = new Dialogmio;
dialog->show();
return app.exec();
}
I've inserted the Q_OBJECT macro as suggested, now I get one more errors on line 7:
dialog.cpp|7|undefined reference to `vtable for Dialogmio'|
You start by including the Qt file for QDialog, but then go on to inherit from QWidget. While inheriting from QWidget is not a problem, was your intention to actually inherit from QDialog(?), in which case you should define your class this way: -
class Dialogmio : public QDialog
{
Q_OBJECT
public:
Dialog(QWidget* parent);
private slots:
void aSlotFunction();
}
The signals and slots mechanism are C++ extensions that are unique to Qt and in order for a class to use it, the class must include the Q_OBJECT macro, which adds all the necessary functionality. During the build stages, Qt parses the header and creates the code required for the extensions, including run-time type information, the dynamic property system and of-course the signals and slots.
As you state you're using codeblocks as the IDE, if it doesn't automatically run qmake before building, you'll need to do that whenever you add any signals or slots to a class in order for the moc (meta-object-compiler) to see them.
Another thing is that the call to connect signals and slots is wrong: -
connect (this,SIGNAL( send()), this, SLOT( buttonOK->setEnabled(true)) );
The parameter in the SLOT macro takes a slot function, so you need to create a slot and connect it to the send signal: -
connect(this, SIGNAL(send()), this, SLOT(aSlotFunction());
Inside the aSlotFunction, you can then call the set enabled for the button: -
void Dialogmio::aSlotFunction()
{
buttonOK->setEnabled(true);
}
If you're using Qt 5, there's an easier syntax of handling the connection: -
connect(this, &Dialogmio::send, this, &Dialogmio::aSlotFunction);
As this syntax accepts pointers to the functions that will be called, they don't actually have to be declared as slots to work. In addition, you do not provide the arguments, so if they change, you won't have to update the connect calls too.
I am trying to subclass QEditLine so that I can define a new SIGNAL that sends an object identifier. At the moment, I connect a parent signal to a slot in the new class and from that slot I emits a proper new signal with the additional object identifier.
I cannot understand one thing. The problem is I don't know how to define a new signal function itself. I don't know what I should put there. I mean I know its arguments but I don't know what it shpould do as a function. I am doing this for the first time and it may looks very silly ;p but I really stuck there >.<.
Can anybody please provide some clues. It is probably a very easy problem.
Thanks
// myqeditline.h
#ifndef MYQEDITLINE_H
#define MYQEDITLINE_H
#include <QWidget>
#include <QLineEdit>
#include <QString>
class MyQEditLine : public QLineEdit
{
Q_OBJECT
public:
explicit MyQEditLine(const QString& n, QWidget *parent = 0);
protected:
QString name;
signals:
void textChanged(QString textCHanged, QString sender);
protected slots:
public slots:
void myTextChanged(QString textChanged);
};
#endif // MYQEDITLINE_H
// myqeditline.cpp
#include "myqeditline.h"
MyQEditLine::MyQEditLine(const QString &n, QWidget *parent)
: QLineEdit(parent),name(n) {
connect(this,SIGNAL(textChanged(QString)),this,SLOT(myTextChanged(QString)));
}
void MyQEditLine::myTextChanged(QString textChanged) {
emit textChanged(QString textChanged, QString name);
}
I just realised that the answer to my question is on this Qt Project website, in section regarding "Signals", in 4th paragraph. It says: "Signals are automatically generated by the moc and must not be implemented in the .cpp file. They can never have return types (i.e. use void)."
I'm trying to call my function as a function slot in Qt,But i don't know how to go about it.
it seems the following approach is wrong :
Update:
According to an answer i updated my source code,but still something is apparently wrong with it.Trying to compile this snippet of code causes these errors:
C2515:' no appropriate default constructor is available.'
And
C2665: QObject::connect':none of the 3 overloads could convert all the
arguments.'
respectively in Visual studio 2010.
#include <QtGui/QApplication>
#include <QPushButton>
#include <QObject>
#include <QMessageBox>
class myclass;
int main(int argc,char *argv[])
{
QApplication a(argc,argv);
QPushButton btnshowmessage("show");
myclass *my=new myclass();
QObject::connect(&btnshowmessage,SIGNAL(clicked()),my,SLOT(warningmessage()));
btnshowmessage.show();
return a.exec();
}
//////////////////////////////////////////////////////////////////////////
class myclass: public QObject
{
Q_OBJECT
public:myclass(){}
public slots:
void warningmessage()
{
QMessageBox::warning(0,"Warning","Test Message!",QMessageBox::Ok);
}
};
You use signals and slots to connect one Object's signal to another Object's slot. Every signal or slot should be inside a class which must be also derived from QObject class and contain the Q_OBJECT macro.
So to make your code work, put the slot into some class of yours:
class MySlotClass:public QObject
{
Q_OBJECT
public slots:
void MyFunction()
{
QMessageBox::warning(0,"WarningTest","This is a waring text message",QMessageBox::Ok);
}
}
and connect like this:
MySlotClass m = new MySlotClass();
Qobject::connect(&btnShowaMessageBox,SIGNAL(clicked()), &m ,SLOT(MyFunction()));
Currently Qt does not allow connection of signals to functions that are not declared as slots on some QObject derivative. I believe Qt5 may offer this possibility, but connect will have different syntax to allow this.
basically your slot function must be in a QObject derived class and declared in a
public slots:
section.
Read the documentation on signals/slots.