Qt C++ signals and slots did not fire
- by Xegara
I have programmed Qt a couple of times already and I really like the signals and slots feature. But now, I guess I'm having a problem when a signal is emitted from one thread, the corresponding slot from another thread is not fired. The connection was made in the main program.
This is also my first time to use Qt for ROS which uses CMake. The signal fired by the QThread triggered their corresponding slots but the emitted signal of my class UserInput did not trigger the slot in tflistener where it supposed to. I have tried everything I can. Any help? The code is provided below.
Main.cpp
#include <QCoreApplication>
#include <QThread>
#include "userinput.h"
#include "tfcompleter.h"
int main(int argc, char** argv)
{
QCoreApplication app(argc, argv);
QThread *thread1 = new QThread();
QThread *thread2 = new QThread();
UserInput *input1 = new UserInput();
TfCompleter *completer = new TfCompleter();
QObject::connect(input1, SIGNAL(togglePause2()), completer, SLOT(toggle()));
QObject::connect(thread1, SIGNAL(started()), completer, SLOT(startCounting()));
QObject::connect(thread2, SIGNAL(started()), input1, SLOT(start()));
completer->moveToThread(thread1);
input1->moveToThread(thread2);
thread1->start();
thread2->start();
app.exec();
return 0;
}
What I want to do is.. There are two seperate threads. One thread is for the user input. When the user enters [space], the thread emits a signal to toggle the boolean member field of the other thread. The other thread 's task is to just continue its process if the user wants it to run, otherwise, the user does not want it to run. I wanted to grant the user to toggle the processing anytime that he wants, that's why I decided to bring them into seperate threads.
The following codes are the tflistener and userinput.
tfcompleter.h
#ifndef TFCOMPLETER_H
#define TFCOMPLETER_H
#include <QObject>
#include <QtCore>
class TfCompleter : public QObject
{
Q_OBJECT
private:
bool isCount;
public Q_SLOTS:
void toggle();
void startCounting();
};
#endif
tflistener.cpp
#include "tfcompleter.h"
#include <iostream>
void TfCompleter::startCounting()
{
static uint i = 0;
while(true)
{
if(isCount)
std::cout << i++ << std::endl;
}
}
void TfCompleter::toggle()
{
// isCount = ~isCount;
std::cout << "isCount " << std::endl;
}
UserInput.h
#ifndef USERINPUT_H
#define USERINPUT_H
#include <QObject>
#include <QtCore>
class UserInput : public QObject
{
Q_OBJECT
public Q_SLOTS:
void start(); // Waits for the keypress from the user and emits the corresponding signal.
public:
Q_SIGNALS:
void togglePause2();
};
#endif
UserInput.cpp
#include "userinput.h"
#include <iostream>
#include <cstdio>
// Implementation of getch
#include <termios.h>
#include <unistd.h>
/* reads from keypress, doesn't echo */
int getch(void)
{
struct termios oldattr, newattr;
int ch;
tcgetattr( STDIN_FILENO, &oldattr );
newattr = oldattr;
newattr.c_lflag &= ~( ICANON | ECHO );
tcsetattr( STDIN_FILENO, TCSANOW, &newattr );
ch = getchar();
tcsetattr( STDIN_FILENO, TCSANOW, &oldattr );
return ch;
}
void UserInput::start()
{
char c = 0;
while (true)
{
c = getch();
if (c == ' ')
{
Q_EMIT togglePause2();
std::cout << "SPACE" << std::endl;
}
c = 0;
}
}
Here is the CMakeLists.txt. I just placed it here also since I don't know maybe the CMake has also a factor here.
CMakeLists.txt
##############################################################################
# CMake
##############################################################################
cmake_minimum_required(VERSION 2.4.6)
##############################################################################
# Ros Initialisation
##############################################################################
include($ENV{ROS_ROOT}/core/rosbuild/rosbuild.cmake)
rosbuild_init()
set(CMAKE_AUTOMOC ON)
#set the default path for built executables to the "bin" directory
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
#set the default path for built libraries to the "lib" directory
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
# Set the build type. Options are:
# Coverage : w/ debug symbols, w/o optimization, w/ code-coverage
# Debug : w/ debug symbols, w/o optimization
# Release : w/o debug symbols, w/ optimization
# RelWithDebInfo : w/ debug symbols, w/ optimization
# MinSizeRel : w/o debug symbols, w/ optimization, stripped binaries
#set(ROS_BUILD_TYPE Debug)
##############################################################################
# Qt Environment
##############################################################################
# Could use this, but qt-ros would need an updated deb, instead we'll move to catkin
# rosbuild_include(qt_build qt-ros)
rosbuild_find_ros_package(qt_build)
include(${qt_build_PACKAGE_PATH}/qt-ros.cmake)
rosbuild_prepare_qt4(QtCore) # Add the appropriate components to the component list here
ADD_DEFINITIONS(-DQT_NO_KEYWORDS)
##############################################################################
# Sections
##############################################################################
#file(GLOB QT_FORMS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ui/*.ui)
#file(GLOB QT_RESOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} resources/*.qrc)
file(GLOB_RECURSE QT_MOC RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} FOLLOW_SYMLINKS include/rgbdslam_client/*.hpp)
#QT4_ADD_RESOURCES(QT_RESOURCES_CPP ${QT_RESOURCES})
#QT4_WRAP_UI(QT_FORMS_HPP ${QT_FORMS})
QT4_WRAP_CPP(QT_MOC_HPP ${QT_MOC})
##############################################################################
# Sources
##############################################################################
file(GLOB_RECURSE QT_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} FOLLOW_SYMLINKS src/*.cpp)
##############################################################################
# Binaries
##############################################################################
rosbuild_add_executable(rgbdslam_client ${QT_SOURCES} ${QT_MOC_HPP})
#rosbuild_add_executable(rgbdslam_client ${QT_SOURCES} ${QT_RESOURCES_CPP} ${QT_FORMS_HPP} ${QT_MOC_HPP})
target_link_libraries(rgbdslam_client ${QT_LIBRARIES})