patrickS patrickS - 3 years ago 167
C++ Question

Qt connect(*sender, *signal, *receiver, *method) doesn't call slots

I'm very new to Qt and also to c++. I tried to do a little Celsius/Fahrenheit converter. On the UI I use QDial and QLCDNumber to respectively change and show the temperature.
Unfortunately only the "standard connect" works:

connect(ui->celsiusDial, SIGNAL(valueChanged(int)), ui->celsiusLcd,SLOT(display(int)));


Spinning the dial leads to change on the LCD-Widget but anything else doesn't work (see the connect(...) calls in dialog.cpp.

The project have a QWidget with the name Dialog that calls the tempconverter.cpp class.
Dialog.cpp:

#include "dialog.h"
#include "ui_dialog.h"
#include "tempconverter.h"

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

TempConverter tempConverterObject(0, this);
TempConverter * tempConverter = &tempConverterObject;


connect(ui->celsiusDial, SIGNAL(valueChanged(int)), tempConverter, SLOT(setTempCelsius(int)));

connect(ui->celsiusDial, SIGNAL(valueChanged(int)), ui->celsiusLcd, SLOT(display(int)));
connect(tempConverter, SIGNAL(tempCelsiusChanged(int)), ui->celsiusDial, SLOT(setValue(int)));

connect(ui->fahrenheitDial, SIGNAL(valueChanged(int)), tempConverter, SLOT(setTempFahrenheit(int)));

connect(ui->fahrenheitDial, SIGNAL(valueChanged(int)), ui->fahrenheitLcd, SLOT(display(int)));
connect(tempConverter, SIGNAL(tempFahrenheitChanged(int)), ui->fahrenheitDial, SLOT(setValue(int)));

}

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


Here's my TempConverter-class:

Header: tempconverter.h

#ifndef TEMPCONVERTER_H
#define TEMPCONVERTER_H

#include <QObject>

class TempConverter : public QObject
{
Q_OBJECT
public:
TempConverter(int tempCelsius, QObject *parent = 0);

int tempCelsius() const; // const is signature for getters!(that's why they are blue!)
int tempFahrenheit() const;

public slots:
void setTempCelsius(int);
void setTempFahrenheit(int);

signals:
void tempCelsiusChanged(int); // Signals are only declared not "implemented", they are emitted when a event occurs
void tempFahrenheitChanged(int); // Signals are only declared not "implemented", they are emitted when a event occurs

private:
int m_tempCelsius; // internal representation of celsiusTemp <=> Java Attribute
};

#endif // TEMPCONVERTER_H


Class: tempconverter.cpp

#include "tempconverter.h"
#include <QDebug>

TempConverter::TempConverter(int tempCelsius, QObject *parent) : QObject(parent) // this is the constructor
{
qDebug("default constructor");
m_tempCelsius = tempCelsius;
}


void TempConverter::setTempCelsius(int tempCelsius)
{
//qDebug("setTempCelsius");
if(m_tempCelsius == tempCelsius)
return;
m_tempCelsius = tempCelsius;

emit tempCelsiusChanged(m_tempCelsius);
emit tempFahrenheitChanged(tempFahrenheit());


}

void TempConverter::setTempFahrenheit(int tempFahrenheit){
qDebug("setTempFahrenheit");
int tempCelsius = (5.0/9.0)*(tempFahrenheit-32);
setTempCelsius(tempCelsius);
qDebug("setTempFahrenheit");
}

int TempConverter::tempCelsius() const{
return m_tempCelsius;
}

int TempConverter::tempFahrenheit() const{
return (m_tempCelsius*2)+30;
}


And finally my UI looks like this: dialog.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Dialog</class>
<widget class="QDialog" name="Dialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<widget class="QWidget" name="">
<property name="geometry">
<rect>
<x>30</x>
<y>40</y>
<width>331</width>
<height>231</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Celsius</string>
</property>
<widget class="QDial" name="celsiusDial">
<property name="geometry">
<rect>
<x>0</x>
<y>30</y>
<width>161</width>
<height>141</height>
</rect>
</property>
</widget>
<widget class="QLCDNumber" name="celsiusLcd">
<property name="geometry">
<rect>
<x>3</x>
<y>172</y>
<width>161</width>
<height>41</height>
</rect>
</property>
</widget>
</widget>
</item>
<item row="0" column="1">
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Fahrenheit</string>
</property>
<widget class="QDial" name="fahrenheitDial">
<property name="geometry">
<rect>
<x>0</x>
<y>20</y>
<width>161</width>
<height>141</height>
</rect>
</property>
</widget>
<widget class="QLCDNumber" name="fahrenheitLcd">
<property name="geometry">
<rect>
<x>0</x>
<y>170</y>
<width>161</width>
<height>41</height>
</rect>
</property>
</widget>
</widget>
</item>
</layout>
</widget>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>
<connections/>
</ui>


Thanks in advance, I really have no clue where the error is coming from.

Answer Source

The problem is that the tempConverterObject variable only exists in the constructor since it has been created in that context, ie it is a local variable and it is removed from memory when that function is executed. The solution is to convert that variable to a member of the class:

*.h

private:
    Ui::Dialog *ui;
    TempConverter *tempConverter;

*.cpp

Dialog::Dialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog)
{
    ui->setupUi(this);    
    tempConverter = new TempConverter(0, this);
    connect(ui->celsiusDial, SIGNAL(valueChanged(int)), tempConverter, SLOT(setTempCelsius(int)));

    connect(ui->celsiusDial, SIGNAL(valueChanged(int)), ui->celsiusLcd, SLOT(display(int)));
    connect(tempConverter, SIGNAL(tempCelsiusChanged(int)), ui->celsiusDial, SLOT(setValue(int)));

    connect(ui->fahrenheitDial, SIGNAL(valueChanged(int)), tempConverter, SLOT(setTempFahrenheit(int)));

    connect(ui->fahrenheitDial, SIGNAL(valueChanged(int)), ui->fahrenheitLcd, SLOT(display(int)));
    connect(tempConverter, SIGNAL(tempFahrenheitChanged(int)), ui->fahrenheitDial, SLOT(setValue(int)));

}
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download