PDA

View Full Version : Problem with slot



stefek
28th February 2009, 13:37
Hi!
I'm trying to develop a simple calculator. I'm using Qt Creator. I've already designed a form, but now I have a problem with slot. It calls, when i push the button with digit and adds the digit to lcd. I think everything is ok, but i get compiler's errors. Here is the source code:


//calc.h

#ifndef CALC_H
#define CALC_H

#include <QtGui/QDialog>

namespace Ui
{
class Calc;
}

class Calc : public QDialog
{
Q_OBJECT

public:
Calc(QWidget *parent = 0);
~Calc();

slots:
void setVal(const int &val);

private:
Ui::Calc *ui;
};

#endif // CALC_H





//calc.cpp
#include "calc.h"
#include "ui_calc.h"

Calc::Calc(QWidget *parent)
: QDialog(parent), ui(new Ui::Calc)
{
ui->setupUi(this);
}

Calc::~Calc()
{
delete ui;
}

void Calc::setVal(const int &val){

lcdNumber-> intValue*=10;
lcdNumber -> intValue+=val;
}



And these are the errors:


calc.h:16: error: expected primary-expression before ‘void’
calc.h:16: error: ISO C++ forbids declaration of ‘type name’ with no type
calc.h:16: error: expected ‘;’ before ‘void’
calc.cpp:11: error: no ‘void Calc::setVal(const int&)’ member function declared in class ‘Calc’


Please help me
Regards
Stefek

wysota
28th February 2009, 13:50
It should say "public slots:" and not "slots:".

stefek
28th February 2009, 14:13
Thanks, this problem is solved, but now come other problems.


calc.h:18: error: ISO C++ forbids declaration of ‘QLCDNumber’ with no type
calc.h:18: error: expected ‘;’ before ‘*’ token

So I added the declaration of QLCDNumber class: class QLCDNumber;. and now are problems with the inside of the slot:


calc.cpp:17: error: invalid use of member (did you forget the ‘&’ ?)


How can I solve it?

I think i solve this problem. I add to class Calc new variable int value, which stores the actual result of calculations and use display function.

But... I have new problem...
Here is my source code:


//calc.h

#ifndef CALC_H
#define CALC_H

#include <QtGui/QDialog>

class QLCDNumber;
namespace Ui
{
class Calc;
}

class Calc : public QDialog
{
Q_OBJECT

private:
QLCDNumber *lcdNumber;
QPushButton *seventhButton;
QPushButton *eighthButton;
QPushButton *ninethButton;
QPushButton *divisionButton;
QPushButton *fourthButton;
QPushButton *fifthButton;
QPushButton *sixthButton;
QPushButton *additionButton;
QPushButton *firstButton;
QPushButton *secondButton;
QPushButton *thirdButton;
QPushButton *subtractionButton;
QPushButton *zeroButton;
QPushButton *sqrtButton;
QPushButton *multiplicationButton;
QPushButton *moduloButton;
int value;

public:
Calc(QWidget *parent = 0);
~Calc();

public slots:
void setVal(const int &val);



private:
Ui::Calc *ui;
};

#endif // CALC_H




#include "calc.h"
#include "ui_calc.h"

Calc::Calc(QWidget *parent)
: QDialog(parent), ui(new Ui::Calc)
{
ui->setupUi(this);
connect(zeroButton, SIGNAL(clicked()), this, SLOT(setVal(0)));
}

Calc::~Calc()
{
delete ui;
}

void Calc::setVal(const int &val){

value*=10;
value+=val;
lcdNumber ->display(value);
}



In the constructor I add the conection between zero button and LCDNumber. It should works, but in the console are errors:


Segmentation fault



I have no idea how to do this. Could anyone help me?
It's harder than I thought at the beginning of lessons.

I've read in documentation that the signal and slot parameters mustn't contain variable name, but only type, so how can I send the value, which is needed?

wysota
28th February 2009, 18:39
Your original problem simply required including <QLCDNumber>. Your current problem is that you didn't create an object behind the zeroButton variable.

talk2amulya
28th February 2009, 18:56
u dont have to send any value from the slot..remove 0 from setVal(0) and it should work..the signal will IMPLICITLY send the data as required by the slot...in the case of clicked(bool), if the button is clicked, 'true' is the value sent, otherwise 'false' is sent

stefek
28th February 2009, 18:57
I've added in main function,after the Calc constructor, new procedure "connection" that connects signals with slots. The effect is the same = segfault.

Yes, there was error,but now is:

connect(this->zeroButton, SIGNAL(clicked(bool)), this, SLOT(setVal(const int &)));

And still is segfault.

wysota
28th February 2009, 22:52
Did you initialize the zeroButton variable to anything?

By the way, please read about signal-slot connections in the reference. You can't connect a bool signal to an int slot, it wouldn't make sense.

stefek
1st March 2009, 10:47
I've read this, but I can't write anything that could work. Is it really hard or do I make it more difficult than it is? :/
I think that actually the whole calculator is too difficult for me. I'll try to make simple dialog with one QPushButton and QLCDNumber.
I've written a function, which sets value to qlcdnumber:


void changeValue(const int &val){

lcdNumber->display(val);
}
But no matter how I call this function I get segfaults. I don't know why.

wysota
1st March 2009, 10:53
I will repeat this question the last time - did you initialize your variables? Do you have any knowledge of C++ at all? Do you understand the difference between a pointer and an object? You are getting a segmentation fault because you try to dereference an uninitialized pointer. The control flow doesn't even reach the connect statement because it segfaults a while earlier.

stefek
1st March 2009, 11:45
Here is actual source code:

//dialog.cpp
#include "dialog.h"
#include "ui_dialog.h"

Dialog::Dialog(QWidget *parent)
: QDialog(parent), ui(new Ui::DialogClass)
{
ui->setupUi(this);

}

Dialog::~Dialog()
{
delete ui;
}

void Dialog::changeValue(const int &val){

lcdNumber->display(val);
}



//dialog.h
#ifndef DIALOG_H
#define DIALOG_H

#include <QtGui/QDialog>
class QLCDNumber;
namespace Ui
{
class DialogClass;
}

class Dialog : public QDialog
{
Q_OBJECT

public:
Dialog(QWidget *parent = 0);
~Dialog();

public slots:
void changeValue(const int &val);

signals:
void onClick(const int &val);


private:
QLCDNumber *lcdNumber;
Ui::DialogClass *ui;
};

#endif // DIALOG_H




//ui_dialog.h
#ifndef UI_DIALOG_H
#define UI_DIALOG_H

#include <QtCore/QVariant>
#include <QtGui/QAction>
#include <QtGui/QApplication>
#include <QtGui/QButtonGroup>
#include <QtGui/QDialog>
#include <QtGui/QLCDNumber>
#include <QtGui/QPushButton>

QT_BEGIN_NAMESPACE

class Ui_DialogClass
{
public:
QLCDNumber *lcdNumber;
QPushButton *pushButton;

void setupUi(QDialog *DialogClass)
{
if (DialogClass->objectName().isEmpty())
DialogClass->setObjectName(QString::fromUtf8("DialogClass"));
DialogClass->resize(209, 62);
lcdNumber = new QLCDNumber(DialogClass);
lcdNumber->setObjectName(QString::fromUtf8("lcdNumber"));
lcdNumber->setGeometry(QRect(130, 20, 64, 23));
pushButton = new QPushButton(DialogClass);
pushButton->setObjectName(QString::fromUtf8("pushButton"));
pushButton->setGeometry(QRect(10, 20, 105, 25));
pushButton->setProperty("value", QVariant(0));

retranslateUi(DialogClass);

QMetaObject::connectSlotsByName(DialogClass);
} // setupUi

void retranslateUi(QDialog *DialogClass)
{
DialogClass->setWindowTitle(QApplication::translate("DialogClass", "Dialog", 0, QApplication::UnicodeUTF8));
pushButton->setText(QApplication::translate("DialogClass", "0", 0, QApplication::UnicodeUTF8));
Q_UNUSED(DialogClass);
} // retranslateUi

};

namespace Ui {
class DialogClass: public Ui_DialogClass {};
} // namespace Ui

QT_END_NAMESPACE

#endif // UI_DIALOG_H


//main.cpp
#include <QtGui/QApplication>
#include "dialog.h"

int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Dialog w;
w.show();



return a.exec();
}


I'm newbie in Qt and probably not C++ pro, but I want to learn and improve my skills.No one are the best at the beginning. Could you explain me how can I initialize variables? I'm in the brain dead.

wysota
1st March 2009, 15:57
Your problem is strictly related to C++. You have two lcdNumber member variables from different levels of inheritance and you use the one that is uninitialized. Get rid of lcdNumber from your Dialog class and use the one in ui.

pastor
1st March 2009, 16:56
I agree with wysota!

stefek, rewrite your code as follows:


void Dialog::changeValue(const int &val)
{
ui->lcdNumber->display(val);
}

Also you should remove QLCDNumber *lcdNumber member from Dialog class declaration.

stefek
6th March 2009, 19:02
Hi there, the weekend comes so I found time to continue my "project". Slot is now working, but I have a problem with signal. I don't know how to write it and it is hard to find in the Internet practical information about it. Could you help me write signal which will be connected to changeValue slot? It emits when I push the button. Thanks

jpn
6th March 2009, 19:53
Please make yourself familiar with the Signals and Slots documentation. It explains signals and slots better than anyone of us could.

stefek
7th March 2009, 21:32
I think that I've understood it. If i want to use parameterless signals as a signals with parameters, I should use QSignalMapper class. I wrote it:


Dialog::Dialog(QWidget *parent)
: QDialog(parent), ui(new Ui::DialogClass)
{
ui->setupUi(this);
QSignalMapper *signalMapper = new QSignalMapper();
connect(ui->pushButton, SIGNAL(clicked()), signalMapper, SLOT(map()));
signalMapper->setMapping(ui->pushButton, "0");
connect(signalMapper, SIGNAL(mapped(const QString &)), ui->lcdNumber, SLOT(changeValue(const QString &)));
}

Dialog::~Dialog()
{
delete ui;
}

void Dialog::changeValue(const QString &val){

int al = val.toInt();
ui->lcdNumber->display(al);
}


It compiled, but I get errors:


Object::connect: No such slot QLCDNumber::changeValue(const QString &) in dialog.cpp:11
Object::connect: (receiver name: 'lcdNumber')

Could you help me to find a mistake, which I made?

I found that he slot changeValue should not be a Dialog's function but a member of QLCDNumber class. But i don't know how to declare this membership. Is there any posibility to do this except for creating new class, which will inherit from QLCDNumber?

wysota
8th March 2009, 11:40
There is no slot "changeValue" in QLCDNumber. The slot is in your class not in the lcd number object.

stefek
8th March 2009, 11:46
#ifndef UI_DIALOG_H
#define UI_DIALOG_H

#include <QtCore/QVariant>
#include <QtGui/QAction>
#include <QtGui/QApplication>
#include <QtGui/QButtonGroup>
#include <QtGui/QDialog>
#include <QtGui/QLCDNumber>
#include <QtGui/QPushButton>

QT_BEGIN_NAMESPACE

class LCDNumber : public QLCDNumber{

public:
LCDNumber(QWidget * parent = 0);
LCDNumber(uint numDigits, QWidget * parent = 0);

public slots:
void changeValue(const QString &val);

};

class Ui_DialogClass
{
public:
LCDNumber *lcdNumber;
QPushButton *pushButton;

void setupUi(QDialog *DialogClass)
{
if (DialogClass->objectName().isEmpty())
DialogClass->setObjectName(QString::fromUtf8("DialogClass"));
DialogClass->resize(209, 62);
lcdNumber = new LCDNumber(DialogClass);
lcdNumber->setObjectName(QString::fromUtf8("lcdNumber"));
lcdNumber->setGeometry(QRect(130, 20, 64, 23));
pushButton = new QPushButton(DialogClass);
pushButton->setObjectName(QString::fromUtf8("pushButton"));
pushButton->setGeometry(QRect(10, 20, 105, 25));
pushButton->setProperty("value", QVariant(0));

retranslateUi(DialogClass);

QMetaObject::connectSlotsByName(DialogClass);
} // setupUi

void retranslateUi(QDialog *DialogClass)
{
DialogClass->setWindowTitle(QApplication::translate("DialogClass", "Dialog", 0, QApplication::UnicodeUTF8));
pushButton->setText(QApplication::translate("DialogClass", "0", 0, QApplication::UnicodeUTF8));
Q_UNUSED(DialogClass);
} // retranslateUi

};

namespace Ui {
class DialogClass: public Ui_DialogClass {};
} // namespace Ui

LCDNumber::LCDNumber(QWidget *parent) :QLCDNumber(parent){



}
LCDNumber::LCDNumber(uint numDigits, QWidget *parent) :QLCDNumber(numDigits, parent){


}
void LCDNumber::changeValue(const QString &val){

Ui::DialogClass::lcdNumber->display(val.toInt());
}
QT_END_NAMESPACE

#endif

That what I wrote, but compilator says:


In file included from dialog.cpp:2:
ui_dialog.h: In member function ‘void LCDNumber::changeValue(const QString&)’:
ui_dialog.h:37: error: object missing in reference to ‘Ui_DialogClass::lcdNumber’
ui_dialog.h:82: error: from this location

I think if I solve this, my program will finally work.

wysota
8th March 2009, 12:07
Please read this topic: Using a Component in Your Application

You shouldn't add any code to the ui_*.h files, they are generated and all your code will be overwritten next time uic runs. Instead use one of the inheritance approaches described in the manual and add your code there.

stefek
8th March 2009, 18:19
#include "calc.h"
#include "ui_calc.h"

Calc::Calc(QWidget *parent)
: QDialog(parent), ui(new Ui::Calc)
{
value = 0;
ui->setupUi(this);
this->setWindowTitle("Calqta");

QSignalMapper *signalMapper = new QSignalMapper();

connect(ui->firstButton, SIGNAL(clicked()), signalMapper, SLOT(map()));
signalMapper->setMapping(ui->firstButton, "1");

connect(ui->secondButton, SIGNAL(clicked()), signalMapper, SLOT(map()));
signalMapper->setMapping(ui->secondButton, "2");

connect(ui->thirdButton, SIGNAL(clicked()), signalMapper, SLOT(map()));
signalMapper->setMapping(ui->thirdButton, "3");

connect(ui->fourthButton, SIGNAL(clicked()), signalMapper, SLOT(map()));
signalMapper->setMapping(ui->fourthButton, "4");

connect(ui->fifthButton, SIGNAL(clicked()), signalMapper, SLOT(map()));
signalMapper->setMapping(ui->fifthButton, "5");

connect(ui->sixthButton, SIGNAL(clicked()), signalMapper, SLOT(map()));
signalMapper->setMapping(ui->sixthButton, "6");

connect(ui->seventhButton, SIGNAL(clicked()), signalMapper, SLOT(map()));
signalMapper->setMapping(ui->seventhButton, "7");

connect(ui->eighthButton, SIGNAL(clicked()), signalMapper, SLOT(map()));
signalMapper->setMapping(ui->eighthButton, "8");

connect(ui->ninethButton, SIGNAL(clicked()), signalMapper, SLOT(map()));
signalMapper->setMapping(ui->ninethButton, "9");

connect(ui->zeroButton, SIGNAL(clicked()), signalMapper, SLOT(map()));
signalMapper->setMapping(ui->zeroButton, "0");


connect(signalMapper, SIGNAL(mapped(const QString &)), this, SLOT(changeValue(const QString &)));
connect(ui->sqrtButton, SIGNAL(clicked()), this, SLOT(square()));

connect(ui->clearButton, SIGNAL(clicked()), this, SLOT(clear()));




}

Calc::~Calc()
{
delete ui;
}
void Calc::add(const QString &val){

str+=val;

}
void Calc::changeValue(const QString &val){

Calc::add(val);
value=str.toInt();
display(value);


}

void Calc::display(const int &val){

ui->lcdNumber->display(val);
}
void Calc::square(){ //works


value = std::sqrt(value);
display(value);
str.remove(0, str.length());
Calc::changeValue(QString::number(value));


}
void Calc::clear(){ //works

value = 0;
str.remove(0, str.length());
display(value);
}


I managed that simple dialog, so I came back to my calculator. All numeric buttons work correctly - adding digit to number works. Square root also works correctly. Now I have a problem with 2 arguments operations, such as addition. I don't have an idea how can I store the second argument - first is in the variable "value". Could you give me handy tip?
Regards
Stefek

wysota
8th March 2009, 21:48
You are currently using a postfix notation - you first store an operand and then expect an operator. Now you have to switch to an infix notation where the operator comes inbetween operands and where the second operand may be empty. You should have storage space (variables) for at least two operands and one variable for the operator. Then it will be easy to perform calculations. Consider this mockup:


class SimpleCalculator {
public:
enum Operator { NoOp, AddOp, SubOp, MulOp, DivOp, SqrtOp, SqrOp };
SimpleCalculator(){ m_left = 0; m_right = 0; m_op = NoOp; }
void setLeftOperand(int v){ m_left = v; }
void setRightOperand(int v){ m_right = v; }
void setOperator(Operator o){ m_op = o; }
int calculate(){
int result = 0;
switch(m_op){
case AddOp: result = m_left + m_right; break;
case SubOp: result = m_left - m_right; break;
...
case SqrOp: result = m_left*m_left;
case NoOp: default: result = m_left;
}
m_op = NoOp;
m_left = result;
m_right = 0;
return result;
}
};

Your next problem will be how to execute a sequence of operations but until you reach that step, first learn this one.