我已经编写过几次 Qt 程序,我非常喜欢信号和槽功能。但是现在,我想我遇到了一个问题,当一个线程发出信号时,另一个线程的相应插槽没有被触发。连接是在主程序中建立的。
这也是我第一次使用 Qt for ROS,它使用 CMake。 QThread 发出的信号触发了它们相应的槽,但我的类 UserInput 发出的信号没有触发 tflistener 中它应该触发的槽。我已经尽力了。有什么帮助吗?下面提供了代码。
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;
}
我想做的是..有两个独立的线程。一个线程用于用户输入。当用户输入 [space] 时,该线程会发出一个信号来切换另一个线程的 bool 成员字段。另一个线程的任务是在用户希望它运行时继续其进程,否则,用户不希望它运行。我想允许用户在他想要的任何时候切换处理,这就是为什么我决定将它们带入单独的线程。
以下代码是 tflistener 和 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;
}
用户输入.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
用户输入.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;
}
}
这是 CMakeLists.txt。我也只是把它放在这里,因为我不知道 CMake 是否在这里也有一个因素。
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})
最佳答案
很难从您发布的代码中找到错误。我只想指出一个问题:
您首先建立连接,然后将对象移动到新线程。由于它们是在同一个线程中创建的,因此它们具有相同的 Thread Affinity .所以默认情况下,连接类型将是直接,这意味着,slot
将从发出signal
的同一个线程中执行。
但是在移动到新线程后,两个对象的线程亲和性都发生了变化。虽然你没有说你怎么会发现它不起作用,但我建议看看这个问题。如果您希望 slot
在不同的线程中执行,并以这种方式进行测试,那么您可能无法获得所需的输出并认为它无法正常工作。
当signal
和slot
要在不同的线程中执行时,最好在将相应的对象移动到新线程后将它们连接起来。 Qt::AutoConnection
将在对象处于不同线程时默认使用 Qt::QueuedConnection
。
关于c++ - Qt C++ 信号和槽没有触发,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23894339/