How to move class in the same thread - c++

I'm trying the add threading in my app write in C++ and QT.
I have a class Framework and one name DeviceMngr.
The framework.h is defined as below:
class Framework : public QObject
{
Q_OBJECT
QThread FrameWorkThread;
public:
Framework();
The framework is initialized by the main. My Main is just doing :
QApplication app(argc, argv);
QThread FrameWorkThread;
Framework *DeviceFramework = new Framework;
DeviceFramework->moveToThread(&FrameWorkThread);
QObject::connect(&FrameWorkThread, SIGNAL(finished()), DeviceFramework, SLOT(deleteLater()));
After, the main in it the main Windows and give the DeviceFramework as argument.
MainUI MyWindows(*DeviceFramework);
MyWindows is discussing with DeviceFramework using Signal/slots.
Framework based is access to an android device using class DeviceMngr and methode.
How is it possible for me to add the DeviceMngr in the same Thread than the Framework.
Can I do something like this in the framework.cpp:
Framework::Framework()
{
Device = new DeviceMngr();
Device->moveToThread(&FrameWorkThread);
}
And the device manager declared as below :
class DeviceMngr : public QObject
{
QThread FrameWorkThread;
public:
DeviceMngr();
~DeviceMngr();
Is this method place the framework and device manager in the FrameWorkThread ?
Thanks
Sebastien

It is possible to have your DeviceMngr and Framework instances in the same thread. To do this, you'll need to keep the QThread instance you want to have in common between them in one place (or pass a pointer).
Do you have a reason for not making your DeviceMngr instance a child of Framework? The documentation for QObject says the following about the thread affinity of a child of a QObject instance:
The QObject::moveToThread() function changes the thread affinity for
an object and its children (the object cannot be moved if it has a
parent).
http://doc.qt.io/qt-5/threads-qobject.html
This would be the simplest way of getting both objects on the FrameWorkThread.
main.cpp
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QThread FrameWorkThread;
Framework *DeviceFramework = new Framework();
DeviceFramework->moveToThread(&FrameWorkThread);
QObject::connect(&FrameWorkThread, SIGNAL(finished()), DeviceFramework, SLOT(deleteLater()));
}
framework.hpp
class Framework : public QObject
{
Q_OBJECT
public:
Framework();
}
framework.cpp
Framework::Framework()
{
Device = new DeviceMngr(this);
}

Related

Connecting slots and signals between a class instance and a dialog within another class instance

I am writing a program in QT, which currently has a GameEngine (data handling) class and a MainWindow (GUI) class.
The single instances of both GameEngineand MainWindow classes are owned by the int main function.
The MainWindow instance has a User Action-button, which will open an instance of a QDialog class called Dialog_UserAction. The instance of this QDialog is owned by the MainWindow, which is also the parent of the QDialog (to disable the MainWindow GUI while the Dialog_UserAction instance is open).
My issue is that many events (signals) need to be connected between the QDialog and the GameEngine instance.
Is there any simple way that I can achieve this?
I have already tried by forwarding the signals from Dialog_UserAction to GameEngine via the MainBoard and vice versa. This works, but it is quite a messy solution for this task.
I have also tried letting the Dialog_UserAction be owned by Main, but I don't know how to react on the User Action Button clicked-event in main context.
Finally, I have also tried letting the Dialog_UserAction be owned by the GameEngine instance, which would the easy solution (except that the MainBoard GUI will not be disabled, while Dialog_UserAction is opened). But, I would really prefer that all GUI related instances were kept out of the GameEngine context.
GameEngine.h:
class GameEngine : public QObject
{
Q_OBJECT
signals:
void someSignalToDialog(void);
public slots:
void on_someSignalFromDialog();
}
Dialog_UserAction.h:
class Dialog_UserAction: public QObject
{
Q_OBJECT
signals:
void someSignalToGameEngine(void);
public slots:
void on_someSignalFromGameEngine();
}
Main.cpp:
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
QApplication::setWindowIcon(QIcon(":/images/MageKnightLogo.jpg"));
GameEngine gameEngine;
Window_MainBoard mainBoard;
mainBoard.showFullScreen();
return a.exec();
}
MainBoard.cpp:
#include "Dialog_UserAction.h"
...
void Window_MainBoard::on_pushButton_enterUserAction_clicked() {
Dialog_UserAction actionDialog(this);
// connect signals and slots here?
if (actionDialog.exec() == QDialog::Accepted)
{
// Send signal with data to GameEngine
}
}
...
So, what I'm really asking is:
Is there any simple way I can setup the signal-slot connections in this setup where I can connect Dialog_UserAction with GameEngine without forwarding the signals in the MainBoard context?
If not, do you have any suggestions on how I could approach this in a better way in general? Thanks in advance.
Since the GameEngine object is a singleton (only one instance exists), you can have the Dialog_UserAction object connect its signals directly to the GameEngine object. You can do that in the Dialog_UserAction constructor.
To get easy access to the GameEngine object, simply add a static member function to it that returns a static GameEngine* member.
GameEngine.h
class GameEngine
{
public:
GameEngine()
{
Q_ASSERT(instance_ == nullptr); // Only one instance allowed.
instance_ = this;
}
static GameEngine* instance() noexcept
{ return instance_; }
private:
static GameEngine* instance_;
};
GameEngine.cpp
GameEngine* GameEngine::instance_ = nullptr;
You can now connect the Dialog_UserAction signals to GameEngine::instance().
So, just for clarification, I ended using the Singleton design pattern as suggested by Nikos C.
But I implemented the class a little differently, and therefore wanted to share this as a standalone answer.
I found that I needed to trigger the constructor of the the object somehow, and figured that this could be done using the so-called (I believe) Lazy Initialization method. Also, the constructor of the class should be private, such that only the instance itself will be able to call this, and thus making sure that the constructor is only called once.
Furthermore, I made the GameEngine::Instance()method as a const static GameEngine*-type in order to let the access to the object be read-only.
GameEngine.h
class GameEngine
{
public:
const static GameEngine* instance() { // Singleton instance reference getter
if (instance_ == nullptr)
instance_ = new GameEngine(); // This triggers the constructor of the object
return instance_;
}
private:
GameEngine(); // The constructor is made private!
};
GameEngine.cpp
// Place this declaration in the top of the file to create the global class instance pointer
// The initial value of the pointer must be nullptr to let the constructor be correctly triggered at the first instance()-call
GameEngine* GameEngine::instance_ = nullptr;
Then in Main and Dialog_UserAction (the clients) the access to the Singleton GameEngine instance is used by creating a const class instance pointer in the each context.
Main.cpp
#include "GameEngine.h"
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
Window_MainBoard mainBoard;
const GameEngine* gameEngine = GameEngine::instance(); // Const pointer to the Singleton instance of the GameEngine class (global object)
QObject::connect(gameEngine, SIGNAL(someSignalToDialog), &mainBoard, SLOT(on_someSignalFromGameEngine));
}
Dialog_UserAction.cpp
#include "GameEngine.h"
// Constructor
Dialog_UserAction::Dialog_UserAction(QWidget *parent) : QDialog(parent), ui(new Ui::Dialog_UserAction) {
ui->setupUi(this);
// Const pointer to the Singleton instance of the GameEngine class (global object)
const GameEngine* gameEngine = GameEngine::instance();
connect(this, SIGNAL(someSignalToGameEngine), gameEngine, SLOT(on_someSignalFromDialog) );
}

Creating QNetworkAccessManager in another thread

I have a QNetworkAccessManager created in another thread.
The network is meant to be used only in MyMegaThread.
QNetworkAccessManager is created from the thread's run method:
mp_manager.reset(new QNetworkAccessManager{this});
On creation I get such a message in console:
QObject: Cannot create children for a parent that is in a different thread.
(Parent is MyMegaThread(0x237eabd0ee0), parent's thread is QThread(0x237e70742a0), current thread is MyMegaThread(0x237eabd0ee0)
This message is totally harmless, but I wonder which parent the manager is supposed to have.
I suspect it happens because the MyMegaThread instance is created in the main thread, but I need a parent created in MyMegaThread instead.
What is an idiomatic way of doing this?
Parent is MyMegaThread(0x237eabd0ee0), parent's thread is
QThread(0x237e70742a0), current thread is MyMegaThread(0x237eabd0ee0)
The issue does not relate to QNetworkAccessManager.
Here is the demo to reproduce the warning.
#include <QDebug>
#include <QThread>
class MyMegaThread : public QThread
{
Q_OBJECT
public:
using QThread::QThread;
protected:
void run() override {
qDebug()<<QThread::currentThread()<<this->thread();
new QObject(this);
}
};
// main
MyMegaThread m;
m.start();
Output:
MyMegaThread(0x60fe18) QThread(0x16a7c48)
It's rule of QObject:
All QObjects must live in the same thread as their parent.
Consequently:
setParent() will fail if the two QObjects involved live in different
threads. When a QObject is moved to another thread, all its children
will be automatically moved too. moveToThread() will fail if the
QObject has a parent. If QObjects are created within QThread::run(),
they cannot become children of the QThread object because the QThread
does not live in the thread that calls QThread::run().
http://doc.qt.io/qt-5/qobject.html#thread-affinity
Have to make sure this code new QObject running QThread be same as given parent QObject thread.
mp_manager.reset(new QNetworkAccessManager{this});
No, the message is not harmless at all. The object you have created has a null parent and no reference on the thread association and thus its thread() method may return a dangling pointer at any time. It cannot safely use timers nor receive cross-thread calls. It is basically as useless object, and you're asking for undefined behavior to strike. This shouldn't be a warning, but a failure. Qt did you a disservice here by allowing you to continue.
The idiomatic way of doing it is first of all not to derive from QThread. QThread is a thread handle. It wraps a system resource. Put all of your functionality into a regular QObject moved into a QThread. The idiomatic way to endlessly "do stuff" on any thread, including the main thread, is to use a zero-duration timer. Note that zero-duration timers have nothing to do with timing at all. They are essentially event loop handles, calling them a timer is a misnomer.
To wit:
// https://github.com/KubaO/stackoverflown/tree/master/questions/thread-simple-50632807
#include <QtNetwork>
class Thread final : public QThread {
Q_OBJECT
public:
void takeObject(QObject *obj) {
obj->moveToThread(this);
}
~Thread() override {
requestInterruption();
quit();
wait();
}
};
class Class : public QObject {
Q_OBJECT
QBasicTimer m_workTimer;
QNetworkAccessManager m_manager{this};
void doWorkChunk() {
qDebug() << "tick...";
QThread::sleep(1); // emulate a blocking operation
}
protected:
void timerEvent(QTimerEvent *ev) override {
if (ev->timerId() != m_workTimer.timerId())
return;
doWorkChunk();
}
public:
explicit Class(QObject *parent = {}) : QObject(parent) {
m_workTimer.start(0, this);
}
};
int main(int argc, char *argv[]) {
QCoreApplication app(argc, argv);
Class object;
Thread workThread;
workThread.start();
workThread.takeObject(&object);
QTimer::singleShot(3000, &QCoreApplication::quit);
return app.exec();
}
#include "main.moc"
The QBasicTimer::stop: Failed. Possibly trying to stop from a different thread warning is relatively benign and indicates an internal timer handle leak. For a workaround, see this answer.

QT ui not showing up when MainWindow initated from another class (not in the main function)

Is it possible to initiate the object of MainWindow in QT and call the show method from another class, for example inside a thread class constructor, and then create the thread object in the main function and start the thread? It does not work for me (the ui flashes and disappears immediately). Is there any way to fix it? If not, how can I control buttons and other stuff from the thread. How can I communicate between them (the thread and ui class) by exchanging data?
My program looks like this. Thread constructor:
#include "mainwindow.h"
void thread::thread(){
MainWindow m;
m.show();
}
and the main function:
int main(int argc,char *argv[]){
QApplication a(argc,argv);
thread t;
t.start();
return a.exec();
}
You can do this, but before that you have to connect your MainWindow to the thread object. You should never call from another thread than the GUI-thread functions that modify the GUI.
The solution would be to use slots/signals. All the communication from threads to the UI is always done with slots and signals.
Below an example:
Create a signal in your Thread class called mySignal();
class Thread {
...
signals:
void mySignal();
...
}
and create a slot in your MainWindow
class MainWindow {
...
public slots:
void ShowWindow();
..
}
Create a function in your MainWindow class called showWindow()
void MainWindow::ShowWindow() {
this->show();
}
Connect your thread to the MainWindow
connect(threadObject, &Thread::mySignal, this, &MainWindow::ShowWindow);
Call the slot from your thread with emit mySignal();
PS: Your application should be a widget application not console.

Complex use of QThread -

I have wrote an app in QT/C++. This app have multiple classes to manage window, treewidget.. and a custom class.
The goal of the app is to be android file transfer -like in QT/c++ on MacOSx.
Currently the entire app is working in one thread which include the UI management and the android device management. The android device access is managed by a class named DeviceManager. This class will mostly open the device, read it, add/delete files....
What I want to do is to create a thread which will handle all method defined in the DeviceManager. I want the UI on one thread and the devicemngr in a separate thread.
Here is my current code :
main.cpp
int main(int argc, char *argv[])
{
PULS_mtp_error_t error = ERROR_GENERAL;
QThread PulsDeviceThread;
QApplication app(argc, argv);
DeviceMngr *MyMtp = new DeviceMngr;
error = MyMtp->OpenDevice();
...
MainUI MyWindow(*MyMtp);
MyWindow.show();
return app.exec();
}
the MainUI class is defined as below
MainUI::MainUI(DeviceMngr& device) :
m_device(device)
{
m_closing = false;
setWindowTitle(QString::fromUtf8("PULS"));
resize(800,600);
setUnifiedTitleAndToolBarOnMac(true);
/* Creation of the Top bar section */
createBackForwardButton();
createLogoSection();
createAddFolder();
QWidget *TopBarWidget = new QWidget();
TopBarWidget->setFixedHeight(61);
QHBoxLayout *TopBarLayout = new QHBoxLayout(TopBarWidget);
TopBarLayout->addWidget(BackForwardSection);
TopBarLayout->addWidget(LogoSection);
TopBarLayout->addWidget(AddFolderSection);
/* Creation of Tree View Section */
createTreeView();
/* Creation of the bottom bar section */
createInfoSection();
/*about*/
aboutAction = new QAction(tr("&About"),this);
connect(aboutAction, SIGNAL(triggered()),this ,SLOT(aboutPuls()));
QMenu *helpMenu = new QMenu("Help", this);
helpMenu->addAction(aboutAction);
menuBar()->addMenu(helpMenu);
/*Overall Layout*/
QWidget *MainWindowWidget = new QWidget();
QVBoxLayout *MainWindowLayout = new QVBoxLayout(MainWindowWidget);
MainWindowLayout->setSpacing(0);
MainWindowLayout->addWidget(TopBarWidget);
MainWindowLayout->addWidget(TreeViewSection);
MainWindowLayout->addWidget(CreateInfoSection);
setCentralWidget(MainWindowWidget);
PulsUnplugged = false;
#if 1
activeTimer = new QTimer(this);
activeTimer->setSingleShot(false);
activeTimer->setInterval(200);
connect(activeTimer, SIGNAL(timeout()), this, SLOT(PulsDetection()));
activeTimer->start();
#endif
show();
}
Some of the method such as createTreeView will use the m_device to access also to the device.
void MainUI::createTreeView()
{
TreeViewSection = new QWidget();
QVBoxLayout *TreeViewLayout = new QVBoxLayout(TreeViewSection);
MyTreeWidget = new MyNewTreeWidget(m_device, *this);
TreeViewLayout->addWidget(MyTreeWidget);
}
MyNewTreeWidget will also need to access to the DeviceMngr class.
Most of class used for the UI management can access to the DeviceMngr class. I don't know how to use the QThread to make sure that all UI classes can access to the DeviceMngr class.
I was thinking to create a Qthread in the main.cpp but I do not see how to add slots/signals in the main.cpp and DeviceMngr will have signals/slots to discuss with all other thread. the main will need for example to open the device and receive the result.
Do I need to create all signal/slot connection in the main or I can just add what I need in the different classes and create the connections when needed.
Any idea ? I have tried a first implementation but it not really working fine.
Thanks
I would suggest creating the worker thread and moving your DeviceMngr to it. Its slots (and whole event loop) will run in the context of the thread and you must use Qt's signal/slot mechanism that will ensure thread safe access to DeviceMngr from other QObjects.
int main(...) {
// ...
QThread MtpThread;
DeviceMngr MyMtp;
MyMtp.moveToThread(&MtpThread);
// connect signals/slots of DeviceMngr
// ...
// launch the thread
MtpThread.start();
// should you need to call slots of DeviceMngr from main use metacalls
QMetaObject::invokeMethod(&MyMtp, "nameOfSlot");
// run application
// in the end join
MtpThread.quit(); // stop event queue
MtpThread.wait(); // join the thread
}
I hope you get the idea. Key is moveToThread() and metacalls.

Qt: How to put collection of GUI-Elements into independent SubClass (with seperate *.ui file)

I'm trying to collect an often used subset of GUI-Elements together into one Subclass, which can be "included" into the real GUIs later without rewriting the given functionality (don't ask why, I wanna learn it for later use). The Subclass should use it's own *.ui-File and should be put into an QWidget resding in the real GUI. After this, it would be nice to access some methods of the Subclass from the real GUI -- like the state of a button or so.
But how do I do this right?
In the moment, my Subclass works and is instantiated in main, but cannot be accessed from the real GUI because its only declared in main.
My Subclass Header-File:
class logger : public QWidget, private Ui::loggerWidget {
Q_OBJECT
public:
logger(QWidget *parent = 0);
virtual ~logger();
// some more stuff...
}
The corresponding constructor. I had to run setupUI with "parent" instead of "this", but I'm not sure that this is correct -- anyways, it works... otherwise, the subelements from the subclass are not shown in the main-window of the real GUI.
logger::logger(QWidget *parent) : QWidget(parent){
setupUi(parent);
//ctor
}
Inside the main.cpp the main-window is constructed, which uses it's own *.ui-File (containing one widget "widget_loggerArea") aswell. Doing so, I can not access methods of "logger" from within "loggerTest":
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
loggerTest window;
logger myLog(window.widget_loggerArea);
window.show();
return app.exec();
}
I can't put the constructor of "logger" into the constructor of the main-window "loggerTest", since it will be destroyed immidiately and never enters the event-loop.
I'm sure I'm missing some concept of object-oriented programming, or the way qt handles its stuff... I would be gratefull if someone could put my nose to this ;-)
I was so stupid... using a pointer with new and delete does the job... this is so silly, I can't believe it! I'm more used to VHDL recently, this weakens my C++-karma...
So, the answer is in the real GUI class. The Constructor:
testLogger::testLogger(QMainWindow *parent) : QMainWindow(parent){
setupUi(this);
myLog = new logger(widget_loggerArea);
}
In main.cpp:
QApplication app(argc, argv);
testLogger window;
window.show();
And in constructor of logger, setupUi works with "this":
dfkiLogger::dfkiLogger(QWidget *parent) : QWidget(parent){
setupUi(this);
}
Yes, thats it... Just for completebility, maybe someone needs a similar "push in the right direction"...
EDIT: In the header of the SubClass the scope of the ui-Elements has to be updated to "public", too:
class logger : public QWidget, public Ui::loggerWidget {
Q_OBJECT
public:
logger(QWidget *parent = 0);
virtual ~logger();
}