Qobject: Cannot Create Children for a Parent That Is in a Different Thread

QObject: Cannot create children for a parent that is in a different thread

The run() member function is executed in a different thread, rather than the thread where QNetworkRequestManager object was created.

This kind of different-thread problems happen all the time with Qt when you use multiple threads. The canonical way to solve this problem is to use signals and slots.

Create a slot in the object where QNetworkRequestManager belongs to, create a signal in ResultThread and connect both of the somewhere, the constructor of ResultThread would be a good place.

The code which is currently in ResultThread::run() goes to the new slot, and is replaced by a emit(yourSignal()). If necessary send a pointer to your ResultThread as a parameter with your emit function to gain access to member functions/variables.

QObject Cannot create children for a parent that is in a different thread

First, what is wrong with your code:

You cannot use this in new QTcpSocket(this), because this->thread() is not the current thread (QThread::currentThread()).

You cannot call any function member of socket after socket->moveToThread(this->thread()), because socket->thead() is not the current thread anymore.

This is documented here:

Event driven objects may only be used in a single thread.
Specifically, this applies to the timer mechanism and the network
module
. For example, you cannot start a timer or connect a socket in a
thread that is not the object's thread.

Now, what you can do to fix your code if you just want to connect a TCP socket and do nothing more is to remove any reference to this and do something like that:

void MainWindow::checkCamStatus(){
while(1){
bool flag = false;
QScopedPointer<QTcpSocket> socket(new QTcpSocket());
socket->connectToHost("10.0.7.112", 80);
if(socket->waitForConnected(1000))//check for connection for i second
{
qDebug() << "Cam online";
}
else{
qDebug() << "..............................Cam offline";
}

QThread::sleep(1);
}
}

But, if you want to do something else with the TCP socket like sending or receiving data, you'd be better wrapping up your code in a class:

class CamWatcher : public QObject
{
Q_OBJECT
public:
CamWatcher(QObject *parent = 0) :
QObject(parent),
m_socket(new QTcpSocket(this))
{}
QTcpSocket *socket() { return m_socket; }

public slots:
void tryConnect() { socket->connectToHost("10.0.7.112", 80); }

private slots:
void onSocketConnected() { qDebug() << "Connected"; }
void onSocketDisconnected() { qDebug() << "Disconnected"; }
void onSocketError(QAbstractSocket::SocketError socketError)
{
qWarning() << m_socket->errorString();
}
private:
QTcpSocket *m_socket = nullptr;
}

This way you can have all the TCP stuff (monitoring, data transfer, etc.) ins a single object. You can have it in the same thread than your MainWindow, but you can also have it in another thread if needed.

Note that if you have the CamWatcher in another thread than MainWindow, but you want to call functions of CamWatcher you have to do something like this:

QTimer::singleshot(0, camwatcher, &CamWatcher::tryConnect);
QMetaObject::invokeMethod(camwatcher, "tryConnect", Qt::QueuedConnection); // No compile time check, works only with slots
QMetaObject::invokeMethod(camwatcher, &CamWatcher::tryConnect, Qt::QueuedConnection); // Requires Qt 5.10

QObject: Cannot create children for a parent that is in a different thread. PyQt5

You should not directly modify the GUI from another thread, one way to modify the GUI indirectly from another thread is to use the Qt signals:

import threading
from PyQt5 import QtCore, QtGui, QtWidgets
from mcstatus import MinecraftServer

class Ui_MainWindow(object):
def setupUi(self, MainWindow):
# ...

class Worker(QtCore.QObject):
logged = QtCore.pyqtSignal(str)
statusChanged = QtCore.pyqtSignal(bool)

def start(self):
threading.Timer(0.2, self._execute, daemon=True).start()

def _execute(self):
threading.Timer(0.2, self._execute, daemon=True).start()
ip = "..."
port = 25565 # Server 1
server = MinecraftServer(ip, port)

try:
filepath = "..."
with open(filepath, "r") as f:
contents = f.read()
self.logged.emit(contents)
except IOError as e:
self.statusChanged.emit(False)
else:
self.statusChanged.emit(True)

class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.setupUi(self)

self.worker = Worker()
self.worker.logged.connect(self.log_1.setText)
self.worker.statusChanged.connect(self.on_status_changed)
self.worker.start()

@QtCore.pyqtSlot(bool)
def on_status_changed(self, status):
text = '<html><head/><body><p><span style=" font-size:18pt;">Status: {}</span></p></body></html>'.format(
"On" if status else "Off"
)
self.StatusL_1.setText(text)

if __name__ == "__main__":
import sys

app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())

QObject: Cannot create children for a parent that is in a different thread: parent's thread:QThread(0x221f650), current thread:QThread(0x23a7950)

When you create worker, the object and all its members are created in the main thread. Then, you move worker to its own thread, which moves all its children QObjects. All slots in worker will now be executed on this new thread.

From fduprocess constructor, it looks like you don't give a parent to your socket (_ClientSocketInstance). That means the socket is not moved to the same thread as the worker but stays in the main thread, which gives this warning when you use it from a slot. If you pass this to _ClientSocketInstance constructor to make it a child of worker, it will automatically be moved to the same thread as worker and the warning should disappear.

QObject: Cannot create children for a parent that is in a different thread

I will just try to answer why you are seeing QThread: Destroyed while thread is still running error.

If you do this

void mtMethod () {

Citizen * c = new Citizen(this);
QThread thread;
c->moveToThread(&thread);

connect(&thread, SIGNAL(started()), c, SLOT(ProcessActions()));
thread.start();
}

The thread object will be destroyed when you exit the function but the thread that has been started is still running !. Qt is warning you that you should either stop the thread or create the thread object in a bigger scope. (i.e make it a member function of your class). Something like this :

class myClass
{
virtual ~myClass ();
QThread mythread;
};

myClass::~myClass
{
mythread.stop ();
}

void myClass::mtMethod () {

Citizen * c = new Citizen(this);
c->moveToThread(&mythread);

connect(&mythread, SIGNAL(started()), c, SLOT(ProcessActions()));
mythread.start();
}

Python PyQt5 threading QObject: Cannot create children for a parent that is in a different thread

The problem has nothing to do with the use of QThread or not. The problem is that the GUI elements (for example the QWidget, QTextDocument, etc) are not thread-safe so you should not modify them or create them in a different thread than the main one. To emphasize my initial comment in my solution I will not use QThread but I will continue using threading but I will send the information to the main thread through signals(what if they are thread-safe):

import sys, time
from threading import Thread

from PyQt5.QtCore import pyqtSignal, QObject
from PyQt5.QtWidgets import (
QApplication,
QMainWindow,
QWidget,
QPlainTextEdit,
QHBoxLayout,
)

class Worker(QObject):
messageChanged = pyqtSignal(str)

def start(self, fn):
Thread(target=self._execute, args=(fn,), daemon=True).start()

def _execute(self, fn):
fn(self)

def write(self, message):
self.messageChanged.emit(message)

def run1(worker):
for i in range(20):
worker.write(f"{i}\n")
time.sleep(0.0125)

def run2(worker):
for i in range(20):
worker.write(f"{i}\n")
time.sleep(0.0125)

def run3(worker):
for i in range(20):
worker.write(f"{i}\n")
time.sleep(0.0125)

app = QApplication([sys.argv])
win = QMainWindow()

text_1 = QPlainTextEdit()
text_2 = QPlainTextEdit()
text_3 = QPlainTextEdit()

my_widget = QWidget()
my_widget.layout = QHBoxLayout()
my_widget.layout.addWidget(text_1)
my_widget.layout.addWidget(text_2)
my_widget.layout.addWidget(text_3)
my_widget.setLayout(my_widget.layout)

win.setCentralWidget(my_widget)

worker1 = Worker()
worker1.messageChanged.connect(text_1.appendPlainText)

worker2 = Worker()
worker2.messageChanged.connect(text_2.appendPlainText)

worker3 = Worker()
worker3.messageChanged.connect(text_3.appendPlainText)

worker1.start(run1)
worker2.start(run2)
worker3.start(run3)

win.show()

sys.exit(app.exec_())

PyQt5 QObject: Cannot create children for a parent that is in a different thread

I will proceed to answer myself. Inspired by https://stackoverflow.com/a/33453124/1995261, I solved this by implementing the following:

1) I created a worker.py that executes the method _search_cast_ that was blocking the menu. When this method finishes searching, it emits two signals: a) one informing that he recovered the list, and b) that the method has finished.

#worker.py
from PyQt5.QtCore import QThread, QObject, pyqtSignal, pyqtSlot

class Worker(QObject):
finished = pyqtSignal()
intReady = pyqtSignal(list)
def __init__(self):
QObject.__init__(self)

@pyqtSlot()
def _search_cast_(self):
self.cc = casting()
self.cc.initialize_cast()
availablecc = self.cc.availablecc
self.intReady.emit(availablecc)
self.finished.emit()

2) In the main.py I dumped the following and I try to explain inside the code with comments:

#main.py
from PyQt5.QtCore import QThread, QObject, pyqtSignal, pyqtSlot
import worker # This is to import worker.py
class menubar(object):
def __init__(self):
signal.signal(signal.SIGINT, signal.SIG_DFL)
self.cc.cast = None
self.systray = True
self.stopped = False

self.obj = worker.Worker() # The worker is started with no parent!
self.thread = QThread() # We initialise the Qthread class with no parent!
self.obj.intReady.connect(self.onIntReady) # We receive the signal that the list is ready
self.obj.moveToThread(self.thread) # Moving the object to the thread
self.obj.finished.connect(self.thread.quit) # When the method is finished we receive the signal that it is finished
self.thread.started.connect(self.obj._search_cast_) # We need to connect the above with the desired method inside the work.py

self.app = QtWidgets.QApplication(sys.argv)

def search_menu(self):
self.SearchAction = self.menu.addAction("Search")
self.SearchAction.triggered.connect(self.search_cast)

def onIntReady(self, availablecc): # This method receives the list from the worker
print ('availablecc', availablecc) # This is for debugging reasons to verify that I receive the list with the correct content
self.availablecc = availablecc

def search_cast(self): #This method starts the thread when self.SearchAction is triggered
args.select_cc = True
self.thread.start()

In this way, when searching for the list the menu does not get blocked, no errors are shown on the screen and the number of threads when monitoring them in activity monitor stay correct.

I hope this helps people. For more precise information (I am still learning PyQt and my wording may not be very good), I suggest you to check the link that I posted above.



Related Topics



Leave a reply



Submit