I write a code with PyQt5 for send and receive data via serial port. when a button pressed, data sends without any problem. in receive, data packet length is different in every time and time between any send is random. I create a thread for read serial port buffer in while loop and if data was received, then put that in a global queue. in other thread , queue will be checked and if it is not empty, some process will be done on data.
but when I test program and send data to application , the bellow error display and application crash.
the error:
QObject: Cannot create children for a parent that is in a different thread.
(Parent is QTextDocument(0x1d1166f7620), parent's thread is QThread(0x1d116712ff0), current thread is
QThread(0x1d1166f7560)
here is the main part of code:
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import *
import errordialog as D1
import serial
import serial.tools.list_ports
import threading
import queue
class Ui_Form(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def setupUi(self, Form):
self.q = queue.Queue()
.
.
.
def open_port(self):
if self.comboBoxPORT.count()==0:
dialog.exec_()
else:
self.ser.port = self.comboBoxPORT.currentText()
b=int(self.lineEditBaudrate.text())
if b==0:
self.ser.baudrate = 9600
else:
self.ser.baudrate = int(self.lineEditBaudrate.text())
try:
self.ser.open()
self.pushButtonClose.setEnabled(True)
self.pushButtonOpen.setEnabled(False)
self.pushButtonOpen.setStyleSheet("background-color: lime")
self.pushButtonSend.setEnabled(True)
self.comboBoxPORT.setEnabled(False)
self.lineEditBaudrate.setEnabled(False)
self.textEditReceived.setReadOnly(False)
g=threading.Thread(target=ui.read_data)
e=threading.Thread(target=ui.printData)
g.start()
e.start()
except:
dialog.exec_()
def read_data(self):
while True:
t = self.ser.read().decode()
if t:
self.q.put(t)
def printData(self):
while True:
while not self.q.empty():
print(self.q.get())
self.textEditReceived.setText(self.q.get())
def close_port(self):
try:
self.ser.close()
self.pushButtonClose.setEnabled(False)
self.pushButtonOpen.setEnabled(True)
self.pushButtonOpen.setStyleSheet("background-color: azure")
self.pushButtonSend.setEnabled(False)
self.comboBoxPORT.setEnabled(True)
self.lineEditBaudrate.setEnabled(True)
except:
dialog.exec_()
def send(self):
self.ser.write(str.encode(self.textEditSent.toPlainText()))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
Form = QtWidgets.QWidget()
ui = Ui_Form()
ui.setupUi(Form)
Form.show()
##============= add error dialog
d1 = D1.Ui_DialogError()
dialog = QtWidgets.QDialog()
d1.setupUi(dialog)
##---======================----------
ui.pushButtonOpen.clicked.connect(lambda : ui.open_port())
d1.pushButtonCanceError.clicked.connect(lambda: dialog.close())
ui.pushButtonExit.clicked.connect(lambda: Form.close())
ui.pushButtonClose.clicked.connect(lambda: ui.close_port())
ui.pushButtonSend.clicked.connect(lambda: ui.send())
##=============-----------------
##----------====================
sys.exit(app.exec_())
Related
I've made an application with pyside2 (qml).
The purpose is to read and present the values comming from an arduino to a chart.
The data is send every second over the serial connection to the pc.
To achieve this I had to create an QThread for not freezing up the UI.
Used explenation here.
In the UI I've a button to start/pause the app.
The application is almost working as expected:
Only when I pause the app and say after a minute or so I resume the app (QThread) I got a lot of data gathered from the Arduino when this should not be happening.
I expect as long as the thread is "pausing" it won't read data that I don't need.
How do I fix it so it won't read the data when the thread in on "pause" ?
main.py
from PySide2.QtCore import Signal, Slot, QObject, QThread
from PySide2.QtQml import QQmlApplicationEngine
from PySide2.QtWidgets import QApplication
class Worker(QThread):
data = Signal(object)
def __init__(self, ctrl):
QThread.__init__(self)
self.ctrl = ctrl
def run(self):
while True:
while self.ctrl["running"]:
self.data.emit(arduino.read_arduino())
else:
time.sleep(0)
if self.ctrl["break"]:
break
class MainWindow(QObject):
def __init__(self):
QObject.__init__(self)
self.thread = QThread()
self.ctrl = {"break": False, "running": True}
self.worker = Worker(self.ctrl)
#Slot()
def start_measurement(self):
if not self.thread.isRunning():
self.worker.moveToThread(self.thread)
self.thread.started.connect(self.worker.run)
self.worker.data.connect(self.handle_arduino_raw_data)
self.thread.start()
else:
self.ctrl["running"] = True
if self.ctrl["running"] = True:
self.ctrl["running"] = False
#Slot(str)
def handle_arduino_raw_data(self, data):
# handle the data received from the arduino
arduino.py
def read_arduino(self):
raw_data = self.ser.readline().decode('utf-8').rstrip()
return raw_data
Read the data all the time, but only emit it when you're running, otherwise throw it away?
def run(self):
while not self.ctrl["break"]:
data = arduino.read_arduino()
if self.ctrl["running"]:
self.data.emit(data)
time.sleep(0.1)
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 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_()
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_()
I want to create a simple server/client app using python socket programming and PyQt.The client can send files to the server side.It worked.But I can't see my server side GUI!
After taking the Dikei's advice I changed my server side code by creating a new thread to handle socket part.
Here is my server side code:
#! /usr/bin/python
import sys
import socket
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from PyQt4.QtNetwork import *
HOST = '127.0.0.1'
PORT = 9996
SIZEOF_UINT32 = 4
class Form(QDialog):
def __init__(self, parent=None):
super(Form, self).__init__(parent)
self.worker = Worker()
self.connect(self.worker, SIGNAL("received"), self.updateUi)
self.connect(self.worker, SIGNAL("finished()"), self.updateUi)
self.connect(self.worker, SIGNAL("terminated()"), self.updateUi)
# Create widgets/layout
self.browser = QTextBrowser()
self.selectButton = QPushButton('Close server')
layout = QVBoxLayout()
layout.addWidget(self.browser)
layout.addWidget(self.selectButton)
self.setLayout(layout)
self.setWindowTitle("Server")
def updateUi(self, text):
self.browser.append(text)
class Worker(QThread):
def __init__(self,parent = None):
super(Worker, self).__init__(parent)
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
def receiveFile(self):
self.conn, self.addr = self.socket.accept()
totalData = ''
while 1:
data = self.conn.recv(1024)
if not data: break
totalData += data
print totalData
f = open('/home/jacos/downfrom','w')
f.write(totalData)
f.close()
self.emit(SIGNAL("received"),"received a file")
self.conn.close()
def run(self):
self.socket.bind((HOST, PORT))
self.socket.listen(5)
while 1:
self.receiveFile()
app = QApplication(sys.argv)
form = Form()
form.show()
app.exec_()
here is my client side code:
#! /usr/bin/python
# -*- coding: utf8 -*-
import sys
import socket
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from PyQt4.QtNetwork import *
HOST = '127.0.0.1'
PORT = 9996
SIZEOF_UINT32 = 4
class Form(QDialog):
def __init__(self, parent=None):
super(Form, self).__init__(parent)
# Create widgets/layout
self.browser = QTextBrowser()
self.selectButton = QPushButton('Send a File')
self.connectButton = QPushButton("Connect")
self.connectButton.setEnabled(True)
layout = QVBoxLayout()
layout.addWidget(self.browser)
layout.addWidget(self.selectButton)
layout.addWidget(self.connectButton)
self.setLayout(layout)
# Signals and slots for line edit and connect button
self.selectButton.clicked.connect(self.sendFile)
self.connectButton.clicked.connect(self.connectToServer)
self.setWindowTitle("Client")
# Update GUI
def updateUi(self, text):
self.browser.append(text)
def sendFile(self):
filename=QFileDialog.getOpenFileName(self, 'Open File', '.')
self.socket.sendall(open(filename,'rb').read())
self.updateUi("Sent a file:" + filename)
self.socket.close()
self.connectButton.setEnabled(True)
def connectToServer(self):
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.socket.connect((HOST, PORT))
self.connectButton.setEnabled(False)
self.updateUi("Connected")
app = QApplication(sys.argv)
form = Form()
form.show()
app.exec_()
The problems are:
My server side GUI doesn't appear at all!I don't understand
why. Should I use thread?
Also, the server only stores the file in a fixed place with a fixed
name. Is there any way I can specify the location in the server side
and get the original file name from client side?
Edit:Now #1 is solved but the signal emitted by the thread doesn't seem to be caught at all, the browser of the server isn't updated at all.
The #2 is still not solved.
Thanks for any help!
Your program is stuck in an infinite loop
while 1:
self.receiveFile()
The form.show() is never reached.
You should probably do everything in a different thread and send signal back to main thread which run the GUI.
For the second problem, you can send the filename first before sending the data. When the server receive the filename, the worker thread will emit a signal. This signal will trigger the main thread to pop up a QFileDialog for you to select a folder. After the folder is selected, the main thread will send a signal with the folder path to the worker thread and the worker thread can save the file.