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})
It is hard to find bug from your posted code. I just want to point out one issue:
You are first making the connection and then moving the objects to new threads. Since they were created in same thread they had same Thread Affinity. So by default the connection type will be direct, which means, the slot will be executed from the same thread from which signal is emitted.
But after moving to new threads, thread affinity for both objects gets changed. Although you did not say how you could find out it is not working, I recommend to look at this matter. If you expect the slot to be executed in different thread, and tested that way, then you may not get desired output and think it is not working.
When signal and slot are meant to be executed in different thread, it is better to connect them after moving the corresponding objects to new threads. Qt::AutoConnection will by default use Qt::QueuedConnection when objects are in different thread.
Related
I'm trying to containerize my application but I'm having trouble getting log4cplus working. Bottom line up front, logging works when running on the host, but not in the container when I'm logging from long running loops. Its seems like a buffer somewhere is not getting flushed. A minimal example follows.
Additionally, removing the long lived loop removes the issue, presumably log4cplus flushes one last time before tearing down. Lengthening the sleep duration did not seem to help.
main.cpp
#include <iostream>
#include <unistd.h>
#include <log4cplus/logger.h>
#include <log4cplus/loggingmacros.h>
#include <log4cplus/configurator.h>
#include <log4cplus/initializer.h>
int main(int argc, char **argv)
{
std::cout << "Sanity Check" << std::endl;
auto log4cplus = ::log4cplus::Initializer();
std::string logconfig("log4cplus_configure.ini");
::log4cplus::PropertyConfigurator::doConfigure(logconfig);
auto logger = ::log4cplus::Logger::getInstance(LOG4CPLUS_TEXT("main"));
while (true) {
LOG4CPLUS_ERROR(logger, "Sleeping...");
// std::cout << "cout sleep..." << std::endl; // uncomment to get log messages working
sleep(1);
}
return 0;
}
log4cplus_configure.ini
log4cplus.rootLogger=INFO, MyConsoleAppender
log4cplus.appender.MyConsoleAppender=log4cplus::ConsoleAppender
log4cplus.appender.MyConsoleAppender.layout=log4cplus::PatternLayout
log4cplus.appender.MyConsoleAppender.layout.ConversionPattern=[%-5p][%d] %m%n
Dockerfile
FROM rockylinux:latest
RUN dnf install -y boost-system
COPY ./build/sandbox /
COPY ./log4cplus_configure.ini /
CMD ["/sandbox"]
CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
set (CMAKE_CXX_STANDARD 17)
# Project executable and library
add_executable(sandbox main.cpp)
target_link_libraries(sandbox
PUBLIC liblog4cplus.a
PUBLIC pthread
PUBLIC boost_system
)
Not sure why, but adding log4cplus.appender.MyConsoleAppender.ImmediateFlush=true to log4cplus_configure.ini solved my issue.
I was investigating the topic of async programming with Qt and I reached the conclusion that it is safe to emit signals from whatever kind of threads (although QT docs only mention QThread), as more or less described here. Now I faced the problem testing my application. To simplify as much as possible: I have the async operation, which might notify MainWindow by emitting the SIGNAL. It works fine in the production, but it doesn't work in unit-test environment with QTest. Complete example (project structure flat, no subdirs):
CMakeLists.txt
cmake_minimum_required(VERSION 3.0.0)
project(QtFailure)
enable_testing()
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
if(CMAKE_VERSION VERSION_LESS "3.7.0")
set(CMAKE_INCLUDE_CURRENT_DIR ON)
endif()
find_package(Qt5 COMPONENTS Core Widgets Test REQUIRED)
add_library(QtFailure source.cpp header.hpp)
target_include_directories(QtFailure PUBLIC .)
target_link_libraries(QtFailure
pthread
Qt5::Core
Qt5::Widgets
)
add_executable(main main.cpp)
target_link_libraries(main QtFailure)
add_executable(QtFailureTest test.cpp)
target_link_libraries(QtFailureTest
QtFailure
Qt5::Test
)
header.hpp
#pragma once
#include <QMainWindow>
#include <QWidget>
#include <future>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget* parent = nullptr);
~MainWindow();
void start();
int counter_value();
signals:
void sendSignal();
private slots:
bool triggerSlot();
private:
bool stop_;
std::future<void> async_oper_;
};
source.cpp
#include "header.hpp"
#include <QMainWindow>
#include <QWidget>
#include <QObject>
#include <QDebug>
#include <future>
#include <chrono>
#include <thread>
static int counter = 0;
MainWindow::MainWindow(QWidget* parent):
QMainWindow(parent),
stop_(false),
async_oper_()
{
QObject::connect(this, SIGNAL(sendSignal()), this, SLOT(triggerSlot()));
}
MainWindow::~MainWindow()
{
stop_ = true;
}
int MainWindow::counter_value()
{
return counter;
}
void MainWindow::start()
{
if (async_oper_.valid()) return;
emit sendSignal(); // this one works
async_oper_ = std::async(std::launch::async, [this]()
{
while (!stop_)
{
std::this_thread::sleep_for(std::chrono::milliseconds(100));
emit sendSignal(); // this one doesn't work in tests
}
});
}
bool MainWindow::triggerSlot()
{
qDebug() << "triggerSlot: " << counter;
counter++;
}
test.cpp
#include "header.hpp"
#include <QSignalSpy>
#include <QDebug>
#include <QtTest/QtTest>
#include <memory>
#include <chrono>
#include <thread>
class MyFixture: public QObject
{
Q_OBJECT
private:
std::unique_ptr<MainWindow> sut_;
private slots:
void init()
{
qDebug("MyFixture init");
sut_.reset(new MainWindow);
}
void cleanup()
{
qDebug("MyFixture cleanup");
sut_.reset();
}
void example_test()
{
QSignalSpy spy(sut_.get(), SIGNAL(sendSignal()));
sut_->start();
std::this_thread::sleep_for(std::chrono::seconds(1));
qDebug() << "num signals: " << spy.count();
qDebug() << "counter value: " << sut_->counter_value();
}
};
QTEST_MAIN(MyFixture)
#include "test.moc"
main.cpp
#include <QApplication>
#include "header.hpp"
int main(int argc, char** argv)
{
QApplication a(argc, argv);
MainWindow w;
w.start();
w.show();
return a.exec();
}
The output from my test is
PASS : MyFixture::initTestCase()
QDEBUG : MyFixture::example_test() MyFixture init
QDEBUG : MyFixture::example_test() triggerSlot: 0
QDEBUG : MyFixture::example_test() num signals: 10
QDEBUG : MyFixture::example_test() counter value: 1
QDEBUG : MyFixture::example_test() MyFixture cleanup
PASS : MyFixture::example_test()
PASS : MyFixture::cleanupTestCase()
Totals: 3 passed, 0 failed, 0 skipped, 0 blacklisted, 1003ms
which means that the slot was triggered only once, by the signal emitted from the main thread.
The output from main is:
...
triggerSlot: 25
triggerSlot: 26
triggerSlot: 27
etc ...
which is the expected behavior. Why is there a difference between QTest environment and normal QApplication in main? What should I do to correct tests behavior?
I must use standard C++ threads, because my GUI is just a facade to real non-Qt related system, which has different kinds of async opers, callbacks etc.
Sorry for the amount of code, but with QT I cannot really squeeze it in a few lines.
=== EDIT ===
Specifying Qt::DirectConnection connection attribute will "fix" the issue in the QTest environment. But this is something I cannot do in most cases, because GUI actions must take place in the main thread (e.g. scync oper emits signal to trigger QPixmap refresh);
The signal emit code is correct. Queued Signal-Slot connection requires event loop to be running in the receiver thread for signal delivery:
Events to that object are dispatched by that (receiver) thread's event loop.
Event loop of the receiver thread aren't working because you block it in the line
// just suspends current thread without running any event loop
std::this_thread::sleep_for(std::chrono::seconds(1));
That is, event loop of the receiver thread are blocking throughout the whole example_test() method body. There is no one line which runs an event loop within itself. That is not Qt Test or QTEST_MAIN() issue.
Here is how you can fix that:
void example_test()
{
QSignalSpy spy(sut_.get(), SIGNAL(sendSignal()));
sut_->start();
QElapsedTimer timer;
timer.start();
while(timer.elapsed() < 1000)
{
spy.wait(10); // event loop runs here
}
qDebug() << "num signals: " << spy.count();
qDebug() << "counter value: " << sut_->counter_value();
}
QSignalSpy::wait():
Starts an event loop that runs until the given signal is received.
Optionally the event loop can return earlier on a timeout (in
milliseconds).
Returns true if the signal was emitted at least once in timeout milliseconds, otherwise returns false.
I'm working on a very basic C++ application using Qt5.6 with CMake. Git Repo Here.
My problem? My main.cpp can #include Qt classes like <QtCore/QObject>, but my defined classes cannot.
error: QtCore/QObject: No such file or directory
I have downloaded the latest version of Qt with Qt Creator here.
Could this be an improperly set up Qt environment? I don't understand how main.cpp can access Qt but my defined classes cannot.
CMakeLists.txt
cmake_minimum_required(VERSION 2.8.11)
project(testproject)
# Find includes in corresponding build directories
set(CMAKE_INCLUDE_CURRENT_DIR ON)
# Instruct CMake to run moc automatically when needed.
set(CMAKE_AUTOMOC ON)
############ OpenCV PACKAGE #########
set(BUILD_SHARED_LIBS ON)
set(OpenCV_FIND_QUIETLY FALSE)
find_package( OpenCV REQUIRED)
include_directories( ${OpenCV_INCLUDE_DIRS} )
# Find the QtWidgets library
find_package(Qt5Widgets)
qt5_wrap_cpp(tcp_hdr_moc ${PROJECT_SOURCE_DIR}/TcpServer.h)
# Tell CMake to create the helloworld executable
add_executable(helloworld WIN32 main.cpp
TcpServer.h TcpServer.cpp
)
# Use the Widgets module from Qt 5.
target_link_libraries(helloworld Qt5::Widgets
${OpenCV_LIBS}
${PROJECT_SOURCE_DIR}/TcpServer.cpp
${PROJECT_SOURCE_DIR}/TcpServer.h
)
main.cpp
#include <iostream>
#include <QtWidgets/QApplication>
#include <QtCore/QObject>
//#include "TcpServer.h"
using namespace std;
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QString test = "Hello";
QObject test2;
int i = 0;
// TcpServer server;
}
User defined class: TcpServer.cpp
#include "TcpServer.h"
#include <QtNetwork/QTcpSocket>
#include <QtCore/QByteArray>
#include <QtCore/QtDebug>
#include <QtCore/QString>
#include <opencv2/core.hpp>
#include <opencv2/opencv.hpp>
TcpServer::TcpServer(QObject *parent) :
QObject(parent)
{
server = new QTcpServer(this);
// whenever a user connects, it will emit signal
connect(server, SIGNAL(newConnection()),
this, SLOT(newConnection()));
if (!server->listen(QHostAddress::Any, 9999))
qDebug() << "Server could not start";
else
qDebug() << "Server started!";
vCapture = new VideoCapture(0);
}
void TcpServer::newConnection()
{
QTcpSocket *socket = server->nextPendingConnection();
QByteArray ContentType = ("HTTP/1.0 200 OK\r\n" \
"Cache-Control: no-cache\r\n" \
"Cache-Control: private\r\n" \
"Content-Type: multipart/x-mixed-replace;boundary=--boundary\r\n");
socket->write(ContentType);
std::vector<uchar> buff;
Mat img; //OpenCV Material
while (1) {
// Image to Byte Array via OPENCV Method
buff.clear();buff.empty();
vCapture->read(img); //Read from webcam
//TODO set the compression parameters.
imencode(".jpg", img, buff);
std::string content(buff.begin(), buff.end());
QByteArray CurrentImg(QByteArray::fromStdString(content));
QByteArray BoundaryString = ("--boundary\r\n" \
"Content-Type: image/jpeg\r\n" \
"Content-Length: ");
BoundaryString.append(QString::number(CurrentImg.length()));
BoundaryString.append("\r\n\r\n");
socket->write(BoundaryString);
socket->write(CurrentImg); // Write The Encoded Image
socket->flush();
}
}
User Defined Class Header which throws the error: TcpServer.h
#ifndef TCPSERVER_H
#define TCPSERVER_H
#include <QtCore/QObject>
#include <QtNetwork/QTcpServer>
#include "opencv2/videoio.hpp"
using namespace cv;
class TcpServer : public QObject
{
Q_OBJECT
public:
explicit TcpServer(QObject *parent = 0);
void newConnection();
private:
QTcpServer* server;
VideoCapture* vCapture;
};
#endif
For reference I am working on these two related stack overflow questions.
How to Create a HTTP MJPEG Streaming Server With QTcp-Server Sockets?
Error while using QTcpSocket.
Add find_package(Qt5Core) in addition to find_package(Qt5Widgets) and add the following lines:
include_directories(${Qt5Widgets_INCLUDE_DIRS})
include_directories(${Qt5Core_INCLUDE_DIRS})
And do not forget to add Qt5::Core to the target_link_libraries.
BTW, I see you are using QtNetwork; you will have to make the same steps for that module too. And for every other module you will use.
I Wrote before but the details was not explained.
I explain step by step what I do;
Witty installation Guide Ubuntu
I did in order what ever said in this page.
sudo apt-get install gcc g++ libboost-all-dev cmake make
sudo apt-get install libssl-dev libfcgi-dev
sudo apt-get install libpq-dev libmysqlclient-dev firebird-dev
sudo apt-get install libpng12-dev libgraphicsmagick1-dev libhpdf-dev libpng12-dev libpango1.0-dev mesa-common-dev
sudo apt-get install asciidoc libqt4-dev
sudo apt-get install doxygen graphviz
wget -c http://kent.dl.sourceforge.net/sourceforge/witty/wt-3.3.4.tar.gz
tar xvxf wt-3.3.4.tar.gz
cd wt-3.3.4
mkdir build
cd build
cmake ..
make
make -C examples
and Test helloqt.wt test
./helloqt.wt --http-port 10000 --http-addr 0.0.0.0 --docroot .
Every things work fine
and then I changed someline for Qt events loop working
// Needed when using WQApplication with Qt eventloop = true
#include <QApplication>
Dictionary::Dictionary(const WEnvironment& env)
: WQApplication(env , true )
{
/*
* Note: do not create any Qt objects from here. Initialize your
* application from within the virtual create() method.
*/
}
.
.
.
int main(int argc, char **argv)
{
// Needed for Qt's eventloop threads to work
QApplication app(argc, argv);
return WRun(argc, argv, &createApplication);
}
still result is fine everything OK. eventloops( signal/slot working )
and I clean everything with
make clean
add line to cmakefiles.txt QtNetwork
.
.
.
IF(ENABLE_QT4)
FIND_PACKAGE(Qt4 REQUIRED QtCore QtGui QtNetwork)
IF(QT_FOUND)
INCLUDE(${QT_USE_FILE})
ENDIF(QT_FOUND)
ENDIF(ENABLE_QT4)
.
.
.
and also add to wtwithqt examples cmakelist.txt ${QT_QTNETWORK_LIBRARY}
FIND_PACKAGE(Qt4 COMPONENTS QtCore QtGui QtNetwork )
SET(QT_USE_QTNETWORK true)
INCLUDE(${QT_USE_FILE})
to below
IF(COMMAND cmake_policy)
CMAKE_POLICY(SET CMP0003 NEW)
ENDIF(COMMAND cmake_policy)
SET(BUILD_WTWITHQT true)
IF (NOT MULTI_THREADED_BUILD)
SET(BUILD_WTWITHQT false)
ENDIF (NOT MULTI_THREADED_BUILD)
IF (NOT QT_FOUND)
SET(BUILD_WTWITHQT false)
ENDIF (NOT QT_FOUND)
IF (NOT BUILD_WTWITHQT)
MESSAGE(STATUS "** Not building wtwithqt example.")
MESSAGE(STATUS " wtwithqt example requires a Qt4 installation.")
ELSE (NOT BUILD_WTWITHQT)
MESSAGE("\n\n " + ${QT_QTCORE_LIBRARY} + " \n" + ${QT_QTGUI_LIBRARY} + "\n" + ${QT_QTNETWORK_LIBRARY} + "\n" + ${QT_LIBRARIES} + "\n\n" )
FIND_PACKAGE(Qt4 COMPONENTS QtCore QtGui QtNetwork )
SET(QT_USE_QTNETWORK true)
INCLUDE(${QT_USE_FILE})
SUBDIRS(lib)
ADD_DEFINITIONS(-DWT_NO_SLOT_MACROS)
QT4_GENERATE_MOC(${CMAKE_CURRENT_SOURCE_DIR}/QtObject.h
${CMAKE_CURRENT_BINARY_DIR}/moccedQtObject.C)
WT_ADD_EXAMPLE(helloqt.wt
hello.C
QtObject.C
${CMAKE_CURRENT_BINARY_DIR}/moccedQtObject.C
)
TARGET_LINK_LIBRARIES(helloqt.wt
wtwithqt
${QT_QTCORE_LIBRARY}
${QT_QTGUI_LIBRARY}
${QT_QTNETWORK_LIBRARY}
${QT_LIBRARIES}
)
#
# If you have Wt installed somehwere, you should use the
# installed Wt header files for your own Wt projects.
# e.g. INCLUDE_DIRECTORIES(/usr/local/wt/include)
# instead of the following:
#
INCLUDE_DIRECTORIES(
${WT_SOURCE_DIR}/src
${CMAKE_CURRENT_SOURCE_DIR}/lib
${QT_QTCORE_INCLUDE_DIR}
${QT_QTNETWORK_INCLUDE_DIR}
${QT_INCLUDE_DIR}
)
ENDIF (NOT BUILD_WTWITHQT)
and add to QTcpSocket to function below
QtObject.h
// This may look like C code, but it's really -- C++ --
#ifndef QTOBJECT_H_
#define QTOBJECT_H_
#include <QThread>
#include <QTcpSocket>
class Dictionary;
/*! \class QtObject
* \brief A simple Qt object with sample signal and slot.
*
* This simple object class demonstrates that the Qt signal/slot
* mechanism may be used alonglisde Wt's signal/slot mechanism.
*/
class QtObject : public QObject
{
Q_OBJECT;
public:
QtObject(Dictionary *wt_, QObject *parent = 0);
void passGreet(const QString&);
QTcpSocket* socket;
signals:
void greet(const QString&);
public slots:
void doGreet(const QString&);
void Connected();
private:
Dictionary *wt_;
};
#endif // QTOBJECT_H_
QtObject.C file
#include "HelloApplication.h"
#include "QtObject.h"
#include <QHostAddress>
QtObject::QtObject(Dictionary *wt, QObject *parent)
: QObject(parent),
wt_(wt)
{
socket = new QTcpSocket();
QHostAddress adr;
adr.setAddress("192.168.0.2");
socket->connectToHost(adr,17776);
QObject::connect(socket,SIGNAL(connected()),this,SLOT(Connected()));
}
void QtObject::passGreet(const QString& name)
{
emit greet(name);
}
void QtObject::doGreet(const QString& name)
{
wt_->doGreet(name);
}
void QtObject::Connected(){
std::cout << "\n\nCONNNECTED\n\n";
emit greet(QString("QString"));
}
From this time
cml#cml-All-Series:~/wt-3.3.4/build$ make clean
cml#cml-All-Series:~/wt-3.3.4/build$ cmake ..
cml#cml-All-Series:~/wt-3.3.4/build$ make -j8
cml#cml-All-Series:~/wt-3.3.4/build$ make -C examples/wtwithqt
cml#cml-All-Series:~/wt-3.3.4/build/examples/wtwithqt$ ./helloqt.wt charts.wt --http-port 10000 --http-addr 0.0.0.0 --docroot .
[2015-Aug-22 10:34:04.692004] 3116 - [info] "WServer/wthttp: initializing built-in wthttpd"
[2015-Aug-22 10:34:04.693292] 3116 - [info] "wthttp: started server: http://0.0.0.0:10000"
when click on browser 0.0.0.0:10000
page is incoming and
socket emitting Connected() signals and Connected() SLOT Work
print screen to std::cout << "\n\nCONNNECTED\n\n";
and application
crashed. Segmentation fault and Core Dumped
I can not find what is wrong?
I Debug Qt Creator
WWebWidget.C file stopped there
bool WWebWidget::canOptimizeUpdates()
{
-> return WApplication::instance()->session()->renderer().preLearning();
}
Qt Creator Debugger says ->
The inferior stopped because it received a signal from the Operating System.
Signal name :
SIGSEGV
Signal meaning :
Segmentation fault
There talking about the solution
in my code I delete WText object after there is no fail seg fault...
this is not solution for me but I can use it
Wt::WApplication* app = Wt::WApplication::instance();
app->enableUpdates(true);
Wt::WApplication::UpdateLock uilock(app);
if( uilock ){
button->setText("Test"); //Here is Editable Widget
app->trigerUpdate();
app->enableUpdates(false);
}
For a big work you lock application and
control if locked change any thing
ServerPUSH.c
I have an application with notification area icon, so the main window may ignore close event. I am trying to save preferences and history on application quit. I also want to handle logout when the application is running. While the application is cross-platform, it is most convenient/useful in GNU/Linux, so Windows logout behavior is of much less concern.
This is a minimal compilable example that was used for testing behavior of different desktop environments/window managers:
// main.cpp
# include <QApplication>
# include <QMainWindow>
# include <QCloseEvent>
# include <QTimer>
# include <iostream>
class M : public QMainWindow
{
Q_OBJECT
public:
~M();
public slots:
void onAboutToQuit();
private:
void closeEvent(QCloseEvent *);
};
M::~M()
{
std::cout << "M::~M()" << std::endl;
}
void M::onAboutToQuit()
{
std::cout << "onAboutToQuit()" << std::endl;
}
void M::closeEvent(QCloseEvent * e)
{
std::cout << "closeEvent()" << std::endl;
hide();
QTimer::singleShot(5000, this, SLOT(show()));
e->ignore();
}
int main(int argc, char * argv[])
{
QApplication app(argc, argv);
M m;
m.setWindowModality(Qt::NonModal);
m.connect(& app, SIGNAL(aboutToQuit()),
SLOT(onAboutToQuit()));
m.show();
return app.exec();
}
# include "main.moc"
// CMakeLists.txt
cmake_minimum_required(VERSION 2.6)
project(closeeventbug)
option(QT5 "Use Qt5" OFF)
if(QT5)
find_package(Qt5Core REQUIRED)
find_package(Qt5Widgets REQUIRED)
else()
find_package(Qt4 REQUIRED)
include_directories(${QT_INCLUDES})
endif()
include_directories(${CMAKE_CURRENT_BINARY_DIR})
set(CMAKE_AUTOMOC ON)
add_executable(closeeventbug main.cpp)
if(QT5)
qt5_use_modules(closeeventbug Core Widgets)
else()
target_link_libraries(closeeventbug ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY})
endif()
Most full-blown desktop environments on logout attempt to close visible window. But since the test app does not exit when closed, logging out is interrupted/cancelled. If logging out is performed while the window is invisible, it quits gracefully (just like I want it to). Less feature-full desktop environments/window managers ignore the still-running application and exit. Most of them don't even warn the application about logging out, so there is neither "closeEvent()", nor "onAboutToQuit()", nor "M::~M()" in the file, to which the program output is redirected.
The detailed results (all non-Windows results are from Manjaro GNU/Linux):
Full-blown desktop environments that cancel logging out if the visible window refuses to exit, finish invisible application gracefully:
closeEvent()
onAboutToQuit()
M::~M()
{ KDE, XFCE, Mate, GNOME, Cinnamon }
All others don't cancel quit, but some of them try to warn the application.
I have no idea why onAboutToQuit() is present in the log, but M::~M() is not in this case...
closeEvent()
onAboutToQuit()
{ Windows7 }
3.
closeEvent()
{ icewm, E17 }
4.
<nothing in the log>
{ RazorQt, LxDE, LxQt, i3, budgie, fluxbox, awesome, openbox,
wmii, E16, pekWM, uwm, fvwm, xmonad, spectrwm, windowmaker,
herbstluftwm, WindowsXP }
The behaviour is exactly the same for any combination of (GCC 4.9.1 OR Clang 3.4.2) AND (Qt 4.8.6 OR Qt 5.3.1). However when I tried Qt 4.8 and Qt 5.2 on Xubuntu, the results were somewhat different: there was no blocking with Qt 5.2 in XFCE - the application finished gracefully regardless of main window visibility. But blocking was present with Qt 4.8 (just the same as in Manjaro).
I know that it is possible to handle logout properly (without blocking) because there are several applications that do that just fine. All of them have notification area icon, are closed to notification area, but don't block logging out.
Qt-based: GoldenDict, Transmission-Qt, Kopete;
GTK-based: Audacious, Pidgin.
I have examined the source code of Qt-based ones and found nothing special in handling closeEvent:
https://github.com/goldendict/goldendict/blob/master/mainwindow.cc
void MainWindow::closeEvent( QCloseEvent * ev )
{
if ( cfg.preferences.enableTrayIcon && cfg.preferences.closeToTray )
{
ev->ignore();
hide();
}
else
{
ev->accept();
qApp->quit();
}
}
https://github.com/bfleischer/transmission/blob/master/qt/mainwin.cc
void
TrMainWindow :: closeEvent( QCloseEvent * event )
{
// if they're using a tray icon, close to the tray
// instead of exiting
if( !myPrefs.getBool( Prefs :: SHOW_TRAY_ICON ) )
event->accept( );
else {
toggleWindows( false );
event->ignore( );
}
}
void
TrMainWindow :: toggleWindows( bool doShow )
{
if( !doShow )
{
hide( );
}
else
{
if ( !isVisible( ) ) show( );
if ( isMinimized( ) ) showNormal( );
//activateWindow( );
raise( );
QApplication::setActiveWindow( this );
}
}
git clone git://anongit.kde.org/kopete
void KopeteWindow::closeEvent ( QCloseEvent *e )
{
// if we are not ok to exit on close and we are not shutting down then just do what needs to be done if a
// window is closed.
KopeteApplication *app = static_cast<KopeteApplication *> ( kapp );
if ( !shouldExitOnClose() && !app->isShuttingDown() && !app->sessionSaving() ) {
// BEGIN of code borrowed from KMainWindow::closeEvent
// Save settings if auto-save is enabled, and settings have changed
if ( settingsDirty() && autoSaveSettings() )
saveAutoSaveSettings();
if ( queryClose() ) {
e->accept();
}
// END of code borrowed from KMainWindow::closeEvent
kDebug ( 14000 ) << "just closing because we have a system tray icon";
}
else
{
kDebug ( 14000 ) << "delegating to KXmlGuiWindow::closeEvent()";
KXmlGuiWindow::closeEvent ( e );
}
}
So the questions:
How to ensure that my application does not block logging out even if the main window is visible?
How to ensure that onAboutToQuit() and ~M() are called on logout in as many desktop environments/window managers as possible?
I suspect that some system signals should be listened to, but I have no idea which exactly...
QApplication has signal related to OS session actions - you can easily handle it. For more details take a look at Qt docs Session Management page