#python #sockets #pyqt5
#python #сокеты #pyqt5
Вопрос:
У меня есть простая программа чата сервер-клиент, в которой я использую потоки для получения данных с сервера в фоновом режиме. Проблема в том, что когда клиент получает сообщение, необходимо создать новую вкладку для чата. Но я получаю данные в потоке, поэтому я могу проверять данные и создавать их в потоке. За исключением того, что я не могу создать виджет и установить его родительское окно my, потому что мое окно находится в основном потоке. Итак, это выглядит так:
class MainWindow(QWidget):
...
def addChatTab(self, nick, target, parent):
tab = ChatTab(target)
tab.setParent(parent) #where I get the eror
self.chatTabWidget.addTab(tab, nick)
self.chatTabs[nick] = tab
class ServerManagement():
...
def clientLoop(self): #runs in a different thread
...
if sender == settingsManager.getUserNick():
targetTab = receiver
else:
targetTab = sender
if targetTab in mainWindow.chatTabs.keys(): #if tab is already there
mainWindow.getChatTab(targetTab).write(message)
else:
mainWindow.addChatTab(targetTab, sender, mainWindow) #create and add it to QTabWidget
mainWindow.getChatTab(targetTab).write(message)
Ошибка:
QObject::setParent: Cannot set parent, new parent is in a different thread
Я понимаю, как и почему это происходит, но у меня просто нет решения для этого. Кто-нибудь может мне помочь?
Заранее спасибо…
Комментарии:
1. @eyllanesc поскольку мой код действительно запутан и неорганизован, потребовалась бы половина кода, чтобы воспроизвести проблему. Все, что мне нужно, это способ создать виджет и установить его родительский QWidget в другом потоке.
2. Вы не должны создавать GUI в другом потоке, что вам следует сделать, это отправить информацию в поток GUI с помощью сигналов
Ответ №1:
Вам не следует изменять (понимать также как создавать) графический интерфейс из другого потока, идея состоит в том, чтобы отправлять информацию из вторичного потока через сигналы, для этого мы можем заставить ServerManagement наследовать от QObject, чтобы он мог создавать сигналы и в общей области видимости между объектом ServerManagement и MainWindow устанавливать соединение:
class MainWindow(QWidget):
# ...
def addChatTab(self, nick, target, parent):
tab = ChatTab(target)
tab.setParent(parent) #where I get the eror
self.chatTabWidget.addTab(tab, nick)
self.chatTabs[nick] = tab
def foo_function(self, another_args)
# ... foo function is the method where you create the Server Management object
self.management = ServerManagement()
self.management.targetChanged.connect(self.update_gui)
#
@pyqtSlot(str)
def update_gui(self, targetTab):
if targetTab in self.chatTabs.keys(): #if tab is already there
self.getChatTab(targetTab).write(message)
else:
self.addChatTab(targetTab, sender, self) #create and add it to QTabWidget
self.getChatTab(targetTab).write(message)
class ServerManagement(QObject):
targetChanged = pyqtSignal(str)
def __init__(self, others_arguments):
super(ServerManagement, self).__init__()
# ...
def clientLoop(self): #runs in a different thread
# ...
if sender == settingsManager.getUserNick():
targetTab = receiver
else:
targetTab = sender
self.targetChanged.emit(targetTab)
Комментарии:
1. Я получаю ошибку
AttributeError: 'PyQt5.QtCore.pyqtSignal' object has no attribute 'connect'
приself.management.targetChanged.connect(self.update_gui)
2. @mbilal25tr Вы сделали ServerManagement наследуемым от QObject?
3. ДА. Я проверил еще раз, и у меня есть
class ServerManagement(QtCore.QObject):
и в initsuper().__init__()
4. @mbilal25tr Я думаю, что есть что-то, что вы не реализовали, у вас не должно возникнуть этой проблемы, поэтому вы должны предоставить MCVE
5. Я погуглил ошибку, и перемещение
self.management.targetChanged.connect(self.update_gui)
за пределы инициализации сработало. Мне пришлось всего лишь исправить пару ошибок в моем собственном коде. Спасибо!