i'm trying to create an client server application in python. When the server closes i wish the gui of the client wich is on a separate thread to close, but the application crushes with Xlib error: bad implementation... I've searched and seems to be from accessing GUI interface from other thread. What should I do?python gui access from other thread
this might help you..
from PyQt4 import QtGui as gui
from PyQt4 import QtCore as core
import sys
import time
class ServerThread(core.QThread):
def __init__(self, parent=None):
core.QThread.__init__(self)
def start_server(self):
for i in range(1,6):
time.sleep(1)
self.emit(core.SIGNAL("dosomething(QString)"), str(i))
def run(self):
self.start_server()
class MainApp(gui.QWidget):
def __init__(self, parent=None):
super(MainApp,self).__init__(parent)
self.label = gui.QLabel("hello world!!")
layout = gui.QHBoxLayout(self)
layout.addWidget(self.label)
self.thread = ServerThread()
self.thread.start()
self.connect(self.thread, core.SIGNAL("dosomething(QString)"), self.doing)
def doing(self, i):
self.label.setText(i)
if i == "5":
self.destroy(self, destroyWindow =True, destroySubWindows = True)
sys.exit()
app = gui.QApplication(sys.argv)
form = MainApp()
form.show()
app.exec_()
Related
I am making mini chat application to improve my socket and GUI skills in Python. But my QThread is dumping every time when I'm launching application.
I need to run Thread with GUI
Here it is client.py
import socket
import sys
from colorama import Fore, Back, Style
from os import system, name
import sys
from chat import Ui_Form as Ui_Form
from login import Ui_Form as Ui_Form1
from PyQt5 import QtCore, QtGui, QtWidgets
from threading import Thread
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
app = QtWidgets.QApplication(sys.argv)
Form_login = QtWidgets.QWidget()
ui_login = Ui_Form1()
ui_login.setupUi(Form_login)
Form_login.show()
Form_chat = QtWidgets.QWidget()
ui_chat = Ui_Form()
ui_chat.setupUi(Form_chat)
history = ''
class listen_thread(QtCore.QObject):
running = False
listen_var = QtCore.pyqtSignal(str)
def run():
print('checkpoint')
while True:
listen_var.emit('message')
QtCore.QThread.msleep(1000)
def connect_pressed():
username = ui_login.lineEdit.text()
Form_login.hide()
Form_chat.show()
sock.connect(('127.0.0.1', 10000))
thread = QtCore.QThread()
listen1 = listen_thread()
listen1.moveToThread(thread)
listen1.listen_var.connect(update_chat_history)
thread.started.connect(listen1.run)
thread.start()
#QtCore.pyqtSlot(str)
def update_chat_history(message):
print(message)
ui_chat.textEdit_2.append(message)
def send_pressed():
message = ui_login.lineEdit.text() + ' > ' + ui_chat.lineEdit.text()
sock.send(bytes(str(message),'utf-8'))
# update_chat_history(message)
ui_chat.lineEdit.setText('')
def listen(some):
while True:
try:
data = sock.recv(1024)
except:
pass
else:
update_chat_history(str(data))
ui_login.pushButton.clicked.connect(connect_pressed)
ui_chat.pushButton.clicked.connect(send_pressed)
sys.exit(app.exec_())
When I'm launching it the output is:
QThread: Destroyed while thread is still running
Aborted (core dumped)
Can somebody help???
The explanation of your problem is simple: the thread created in connect_pressed has no reference outside that function, so it gets immediately garbage collected as soon as the function returns.
The "simple" solution would be to create the thread outside of that function and run the thread only there, or add the thread to a container (for instance, a list):
threads = []
def connect_pressed():
# ...
threads.append(thread)
But, the reality, is that your code has other serious issues, which would probably create other problems as soon as you try to expand your code even minimally, and that's also because Qt is easier to deal with when implementing the program using subclasses; even the pyqtSlot decorator (which is normally unnecessary) can only correctly work if it's set on a method of a QObject subclass.
Using only anonymous functions is usually discouraged, as they cannot have a direct reference to instances they must work with. Also, your run() function is wrong, as it doesn't have the self argument, which will result in a crash.
A better version of your code could be similar to this:
class LoginWindow(QtWidgets.QWidget, Ui_Form1):
def __init__(self, listenThread):
super().__init__()
self.setupUi(self)
self.pushButton.clicked.connect(listenThread.start)
class ChatWindow(QtWidgets.QWidget, Ui_Form):
def __init__(self, listenThread, loginWindow):
super().__init__()
self.listenThread = listenThread
self.loginWindow = loginWindow
self.setupUi(self)
self.listenThread.listen_var.connect(self.update_chat_history)
def update_chat_history(self, message):
print(message)
self.textEdit_2.append(message)
def send_pressed(self):
message = self.loginWindow.lineEdit.text() + ' > ' + self.lineEdit.text()
sock.send(bytes(str(message),'utf-8'))
self.lineEdit.setText('')
class ListenThread(QtCore.QThread):
listen_var = QtCore.pyqtSignal(str)
def run(self):
print('checkpoint')
while True:
listen_var.emit('message')
QtCore.QThread.msleep(1000)
listenThread = ListenThread()
loginWindow = LoginWindow(listenThread)
chatWindow = ChatWindow(listenThread, loginWindow)
sys.exit(app.exec_())
I have found stuff online suggesting that PyQt5 widgets are not thread safe.
And other Stackoverflow answers suggest creating a class that only fits their problem. I tried using _thread module in Python 3 which works for everything except PyQt.
app = QApplication([])
Ui_MainWindow, QtBaseClass = uic.loadUiType("UI/action_tab.ui") #specify the location of your .ui file
class MyApp(QMainWindow):
def __init__(self):
super(MyApp, self).__init__()
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.threadPool = QThreadPool()
self.ui.queryBox.returnPressed.connect(self.load_response)
def start_loader(self):
self.loading_animate = QMovie('IMAGES/GIFS/load_resp.gif')
self.loading_animate.setScaledSize(QSize(400, 300))
self.ui.loader.setMovie(self.loading_animate)
self.loading_animate.setSpeed(200)
self.ui.loader.show()
self.loading_animate.start()
def stop_loader(self):
self.ui.loader.hide()
self.loading_animate.stop()
def get_response(self):
plain_text, speech = get_Wresponse(self.ui.queryBox.displayText())
self.stop_loader()
self.ui.textDisplay.setText(plain_text)
if speech == '':
say("Here you GO!")
else:
say(speech)
def load_response(self):
self.start_loader()
_thread.start_new_thread(self.get_response, ())
#self.get_response()
if __name__ == '__main__':
window = MyApp()
window.setWindowFlags(Qt.FramelessWindowHint)
window.show()
sys.exit(app.exec())
Error in above code follows,
QObject: Cannot create children for a parent that is in a different thread.
(Parent is QTextDocument(0x19fe090b8c0), parent's thread is QThread(0x19fde197fb0), current thread is QThread(0x19fe3a0a5f0)
Do you think you can save me?
Please Do !
Thanks in Advance!!
You do not have to update the GUI from an external thread. There are several options like signals, QMetaObject::invokeMethod(...), QEvent and QTimer::singleShot(0, ...) with pyqtSlot.
Using the last method the solution is as follows:
from functools import partial
from PyQt5.QtCore import pyqtSlot
class MyApp(QMainWindow):
# ...
#pyqtSlot()
def stop_loader(self):
self.ui.loader.hide()
self.loading_animate.stop()
def get_response(self, text):
plain_text, speech = get_Wresponse(text)
QtCore.QTimer.singleShot(0, self.stop_loader)
wrapper = partial(self.ui.textDisplay.setText, plain_text)
QtCore.QTimer.singleShot(0, wrapper)
if speech == '':
say("Here you GO!")
else:
say(speech)
def load_response(self):
self.start_loader()
text = self.ui.queryBox.displayText()
_thread.start_new_thread(self.get_response, (text,))
I'm making an application in PyQt5 that runs a variety of long running tasks, such as scraping web pages. In order to avoid crashing the GUI, I've been using QThreads and QObjects
Currently I have a class that inherits QObject and contains a method for scraping the web pages. I move that object on to a QThread, connect a finished signal with a method that quits the thread and then start the thread.
import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
import threading
from concurrent.futures import ThreadPoolExecutor
import requests
class Main(QMainWindow):
def __init__(self, parent=None):
super(Main, self).__init__(parent)
self.init_ui()
self.test_obj = None
self.thread = QThread(self)
def init_ui(self):
widget = QWidget()
layout = QHBoxLayout()
widget.setLayout(layout)
thread_button = QPushButton("Start Thread")
check_button = QPushButton("Check Thread")
layout.addWidget(thread_button)
layout.addWidget(check_button)
thread_button.clicked.connect(self.work)
check_button.clicked.connect(self.check)
self.setCentralWidget(widget)
self.show()
def work(self):
self.test_obj = TestObject()
self.test_obj.moveToThread(self.thread)
self.test_obj.finished.connect(self.finished)
self.thread.started.connect(self.test_obj.test)
self.thread.start()
def check(self):
for t in threading.enumerate():
print(t.name)
#pyqtSlot()
def finished(self):
self.thread.quit()
self.thread.wait()
print("Finished")
class TestObject(QObject):
finished = pyqtSignal()
def __init__(self):
super(TestObject, self).__init__()
def test(self):
with ThreadPoolExecutor() as executor:
executor.submit(self.get_url)
self.finished.emit()
def get_url(self):
res = requests.get("http://www.google.com/")
print(res)
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Main()
sys.exit(app.exec_())
Everything works as expected, I get a:
"Response [200]"
"Finished"
Printed in the console. However when I check the running threads, it shows dummy-1 thread is still running. Every time I run, it creates an additional dummy thread. Eventually I am unable to create any more threads and my application crashes.
Is it possible to use a ThreadPoolExecutor on a QThread like this? If so, is there a correct way to ensure that I don't have these dummy threads still running once I've finished my task?
I watched a short tutorial on PyQt4 signals on youtube and am having trouble getting a small sample program running. How do I connect my signal being emitted from a thread to the main window?
import cpuUsageGui
import sys
import sysInfo
from PyQt5 import QtCore
"""Main window setup"""
app = cpuUsageGui.QtWidgets.QApplication(sys.argv)
Form = cpuUsageGui.QtWidgets.QWidget()
ui = cpuUsageGui.Ui_Form()
ui.setupUi(Form)
def updateProgBar(val):
ui.progressBar.setValue(val)
class ThreadClass(QtCore.QThread):
def run(self):
while True:
val = sysInfo.getCpu()
self.emit(QtCore.pyqtSignal('CPUVALUE'), val)
threadclass = ThreadClass()
# This section does not work
connect(threadclass, QtCore.pyqtSignal('CPUVALUE'), updateProgBar)
# This section does not work
if __name__ == "__main__":
threadclass.start()
Form.show()
sys.exit(app.exec_())
The signal must be created, inside your ThreadClass, or before but as you emit the signal inside the ThreadClass, it is better to create it inside your class.
After creation, you need to connect it to the progress bar function. Here is an example of the signal created and connected inside your class.
class ThreadClass(QtCore.QThread):
# Create the signal
sig = QtCore.pyqtSignal(int)
def __init__(self, parent=None):
super(ThreadClass, self).__init__(parent)
# Connect signal to the desired function
self.sig.connect(updateProgBar)
def run(self):
while True:
val = sysInfo.getCpu()
# Emit the signal
self.sig.emit(val)
Keep in mind that signals have changed style since PyQt5 : Description
if you watched a tutorial for PyQt4, it is not be the same.
I'm trying to create a client-server application, and when the server closes I wish that client GUI to close, which is running on another thread. I wish to access the GUI and close but I get X error:
Bad implementation(...).
How can I resolve this problem?
what you can do is emit a custom signal when the first thread goes down..
from PyQt4 import QtGui as gui
from PyQt4 import QtCore as core
import sys
import time
class ServerThread(core.QThread):
def __init__(self, parent=None):
core.QThread.__init__(self)
def start_server(self):
for i in range(1,6):
time.sleep(1)
self.emit(core.SIGNAL("dosomething(QString)"), str(i))
def run(self):
self.start_server()
class MainApp(gui.QWidget):
def __init__(self, parent=None):
super(MainApp,self).__init__(parent)
self.label = gui.QLabel("hello world!!")
layout = gui.QHBoxLayout(self)
layout.addWidget(self.label)
self.thread = ServerThread()
self.thread.start()
self.connect(self.thread, core.SIGNAL("dosomething(QString)"), self.doing)
def doing(self, i):
self.label.setText(i)
if i == "5":
self.destroy(self, destroyWindow =True, destroySubWindows = True)
sys.exit()
app = gui.QApplication(sys.argv)
form = MainApp()
form.show()
app.exec_()