Introduce a text in a lineEdit of PyQt from a thread - python

How can I introduce a text in a lineEdit from a thread that are getting the data whithout colapse the program? The important line is in the class "fil" where it shows Principal.self.aplicacio.actual_lineEdit.setText(self.temp)
# !/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import serial
import threading
from time import sleep
from PyQt4 import QtCore, QtGui
from temperaturaUI import Ui_Form
class Principal(QtGui.QWidget):
def __init__(self):
QtGui.QWidget.__init__(self)
self.aplicacio = Ui_Form()
self.aplicacio.setupUi(self)
self.aplicacio.sortir_Button.clicked.connect(exit)
self.aplicacio.connectar_Button.clicked.connect(self.connectar)
def connectar(self):
try:
arduino = serial.Serial('/dev/ttyACM0', 9600)
print "Connectat amb èxit"
temperatura = fil(0, arduino, self.aplicacio.actual_lineEdit)
temperatura.start()
except:
print "Impossible connectar a l'Arduino"
class fil(threading.Thread):
def __init__(self, temp, serie, line):
threading.Thread.__init__(self)
self.temp = temp
self.serie = serie
self.line = line
def run(self):
try:
while 1:
self.temp = self.serie.readline()
if self.temp != 0:
**Principal.self.aplicacio.actual_lineEdit.setText(self.temp)**
sleep(0.2)
except:
print "Error al llegir de l'Arduino"
def main():
app = QtGui.QApplication(sys.argv)
aplicacio = Principal()
aplicacio.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()

You can use signals. You would add a signal to the fil class that emits the new text:
class fil(threading.Thread):
update_line_edit = pyqtSignal(str)
def __init__(self, temp, serie, line):
...
def run(self):
try:
while True:
self.temp = self.serie.readline()
if not self.temp:
update_line_edit.emit(self.temp)
...
Then, simply connect that signal to a slot function in your Principal class:
class Principal(QtGui.QWidget):
def __init__(self):
...
def connectar(self):
try:
arduino = serial.Serial('/dev/ttyACM0', 9600)
print "Connectat amb èxit"
temperatura = fil(0, arduino, self.aplicacio.actual_lineEdit)
temperatura.change_line_edit.connect(self.update_line_edit)
...
def update_line_edit(self, text):
self.aplicacio.actual_lineEdit.setText(text)

There are a few ways to do this correctly.
The first is to use a QThread instead of a python thread. You can then use Qt signals to pass a message back from the fil thread to the Qt MainThread and append the message to the QLineEdit there. Another similar approach is to continue using a Python thread, but place your message in a Python Queue.Queue() object. This Queue is then read by a secondary QThread, whose sole purpose is to read messages out of the Queue and emit a signal back to the MainThread.
The common feature of these two methods is that you only access Qt GUI objects from the MainThread and use signals/slots to communicate between threads. Here are some other questions where I've answered similar questions (you should be able to adapt them to your program):
Redirecting stdout and stderr to a PyQt4 QTextEdit from a secondary thread
Syncing activity in PyQt QThreads
However, since answering those questions, my colleagues and I have created a project that helps simplify writing multi-threaded Qt applications. The project is called qtutils and is on PyPi so it can be installed with pip or easy_install (just run pip install qtutils or easy_install qtutils from a commandline/terminal window).
This library has (among others) some functions inmain and inmain_later which will run a specified method in the Qt MainThread (regardless of the thread the call is made from) synchronously or asynchronously. Documentation on how to use these methods is here. I've modified your example code to use my inmain method and put the code here: http://pastebin.com/QM1Y6zBx -- obviously you need to install qtutils for it to work!

Related

How do I receive a PyQt signal from another object when it is instantiated elsewhere?

I am building a system to connect Arduino-based sensors to a RPi via Bluetooth LE, and display the info (temperature and battery life) on a GUI. I have two main classes in my program, one that manages the GUI, and one that manages the BLE connection(class HubSensor). A HubSensor object takes the MAC address for each sensor and is supposed to emit a signal with an attached tuple that contains the temp sensed, battery life, and an index integer to let the main program know which sensor it is. HubSensor gets it's information once per second, and should be sending out the signal every time. (There is input validation already built but it's not relevant to my question.) Most of this is working fine so far.
My problem is I can't figure out how to create a slot to receive the signal so it can update the display (and later keep a log in a CSV file). I'm using the BluePy library to manage the BLE connection, which for me has it's own additional challenges.
So, this is how my program works (I think). Each thread (since I have multiple sensors) creates a HubSensor object. When the object makes the BLE connection, it then creates a MyDelegate object (subclassed from BluePy's DefaultDelegate. Inside the MyDelegate object, the Qt Signal is emitted. I need access to that signal outside of all of those classes and since I don't know the name of the MyDelegate object created, I don't know how to get to it.
I've tried having each of the above mentioned classes inherit each others' characteristics, but I'm not sure I did it right.
From trailerTempDisplay.py
import sys
from PyQt5.QtCore import *
from HubSensor import *
from PyQt5 import QtWidgets, uic
from bluepy.btle import *
from datetime import datetime
# mac addresses for the sensors. later, this will need a function to allow new devices to connect
bt_addrs = ['c1:49:02:59:ae:50', 'f3:ad:ed:46:ea:16']
app = QtWidgets.QApplication(sys.argv)
class Worker(QRunnable):
def __init__(self, macAddress, ind):
super(Worker, self).__init__()
self.macAddress = macAddress
self.ind = ind
#pyqtSlot()
#this is where each sensor exists. each object is created and runs here
def run(self):
self.sensor = HubSensor(self.macAddress, self.ind)
self.sensor.notified.connect(self.updateValues())
#close button
def buttonClicked():
app.closeAllWindows()
window = uic.loadUi("mainwindow.ui")
window.pushButton.clicked.connect(buttonClicked)
def updateValues(self):
print("value updated") # debugging
window.show()
window.threadpool = QThreadPool()
index = 0
for addr in bt_addrs:
worker = Worker(addr, index)
index += 1
window.threadpool.start(worker)
app.exec()
From HubSensor.py
from bluepy.btle import *
from PyQt5.QtCore import QObject, pyqtSignal
class MyDelegate(DefaultDelegate, QObject):
def __init__(self, index):
DefaultDelegate.__init__(self)
QObject.__init__(self)
self.index = index
# class variable for the notified signal
notified = pyqtSignal(tuple)
def handleNotification(self, cHandle, data):
# exception handling prevents bad data from being passed. cHandle is not used but might be useful later
try:
# defining the sensorData tuple. 1, 2, and 3 are dummy values
self.sensorData = (1, 2, 3)
self.notified.emit(self.sensorData) # this should emit a signal every time the function is called and send a tuple with temp, battery, and sensor index(id)
except (ValueError, IndexError):
pass
class HubSensor(MyDelegate):
# constructor. connects to device defined by mac address and position.
# uuid is static and should not change
def __init__(self, mac, index):
self.index = index # keeps track of sensor position
self.mac = mac
self.p = Peripheral(self.mac, 'random') # adafruit feathers must be 'random' for some reason
self.p.setDelegate(MyDelegate(self.index))
self.p.writeCharacteristic(35, b'\x01\x00') # writing these bits to handle '35' enables notifications
while True:
if self.p.waitForNotifications(1):
# when a bluetooth notification is received, handleNotification is called
continue
When I run the program, "value updated" is not displayed on the console. It should pop up about twice per second and just repeat. Later, I will add in the part that turns the values passed into the GUI display.
Let me apologize in advance because I am still very much a beginner. I think I've included all the relevant parts of my code, but I don't know for sure. Also, I'm pretty sure my terminology in some spots is incorrect, so I hope you all can decipher what I actually mean. Thank you in advance for any help you can give me!
Your code is confusing, for example that HubSensor is a delegate whose attribute is a Peripheral and that Peripheral has another delegate, among other problems.
So instead of relying on your code, I created the PeripheralManager class that will notify the information received by the assigned peripheral through a signal. In the case of the infinite loop, it will be handled in a thread using threading.Thread.
import threading
from PyQt5 import QtCore, QtWidgets, uic
from bluepy.btle import DefaultDelegate, Peripheral, BTLEDisconnectError
class PeripheralManager(QtCore.QObject, DefaultDelegate):
notified = QtCore.pyqtSignal(bytes)
def __init__(self, peripheral, parent=None):
super().__init__(parent)
self._peripheral = peripheral
self.peripheral.setDelegate(self)
self.peripheral.writeCharacteristic(35, b"\x01\x00")
threading.Thread(target=self._manage_notifications, daemon=True).start()
#property
def peripheral(self):
return self._peripheral
def handleNotification(self, cHandle, data):
self.notified.emit(self.data)
def _manage_notifications(self):
while self.peripheral.waitForNotifications(1):
continue
def buttonClicked():
QtWidgets.QApplication.closeAllWindows()
def updateValues(values):
print("value updated", values)
def main(args):
app = QtWidgets.QApplication(args)
bt_addrs = ["c1:49:02:59:ae:50", "f3:ad:ed:46:ea:16"]
managers = []
for addr in bt_addrs:
try:
p = Peripheral(addr, "random")
except BTLEDisconnectError as e:
print(e)
else:
manager = PeripheralManager(p)
manager.notified.connect(updateValues)
managers.append(manager)
window = uic.loadUi("mainwindow.ui")
window.pushButton.clicked.connect(buttonClicked)
window.show()
ret = app.exec_()
return ret
if __name__ == "__main__":
import sys
sys.exit(main(sys.argv))

Pyqt use QThread but GUI still not responding

I tried to download file from FTP to network shared folder(file size might 500mb or bigger) but every time when clicked "Start" the GUI will show "not responding" even using QThread
Did I do it wrong anything?
main.py
# -*- coding: utf-8 -*-
from PyQt4 import QtGui
import ftp100
class main_windows(QtGui.QWidget):
def __init__(self):
super(main_windows, self).__init__()
self._count = 0
self.Ftpallobject = []
def init(self):
#PASS SOME GUI CODE
button_go = QtGui.QPushButton('GO')
button_go.clicked.connect(self.Ftpstart)
self.fp = ftp100.ftpmethod()
self.fp.requestSignal_getinfo.connect(self.Ftpallobject)
def SendFtpInfo(self):
self.fp.update_getinfo.emit(self.allobject)
def Ftpstart(self):
self.fp.run()
ftp.py
# -*- coding: utf-8 -*-
from PyQt4 import QtCore
import ftputil
class ftpmethod(QtCore.QThread):
requestSignal_getinfo = QtCore.pyqtSignal()
update_getinfo = QtCore.pyqtSignal(list)
def __init__(self, parent=None):
super(ftpmethod, self).__init__(parent)
self._count = 0
self.ftpinfo = []
self.update_getinfo.connect(self.getinfo)
def run(self):
self.requestSignal_getinfo.emit()
while self._count<1:
for i in self.ftpinfo:
site = "".join(str(i[2].text()))
account = "".join(str(i[0].text()))
pwd = "".join(str(i[1].text()))
filepath = "".join(str(i[3].text()))
filename = "".join(str(i[4].text()))
downloadtolocal = "".join(str(i[7].text()))+"".join(str(i[4].text()))
print site,account,pwd,filepath,filename,downloadtolocal
try:
with ftputil.FTPHost(site,account,pwd) as host:
if filepath=='':
host.download(filename,downloadtolocal)
else:
host.chdir(filepath)
host.download(filename,downloadtolocal)
except:
print 'FTP ERROR'
self._count+=1
self._count=0
def getinfo(self,info):
self.ftpinfo = info
You are doing it wrong indeed.
What you are doing now is that you call the run-method directly, but instead of that you should be calling start(), so the correct implementation should be:
def Ftpstart(self):
self.fp.start()
When subclassing a QThread (or regular python thread for that matter), you implement the run-method, which represents the work the thread should be doing, and if you call it directly, you execute that code in the current thread (so in this case your main thread). This is why your GUI will become unresponsive.
But if you call start() instead, it will actually spawn a new thread first (if it does not already exist) and then call run. From PyQT Documentation:
QThread.start (self, Priority priority = QThread.InheritPriority)
Begins execution of the thread by calling run(). The operating system will schedule the thread according to the priority parameter. If the thread is already running, this function does nothing.
And for run()
QThread.run (self)
The starting point for the thread. After calling start(), the newly
created thread calls this function.

How to correctly lock Qthreads in pyqt5 using Python3

I am relatively new to python, but was able to get a reasonably useful program to run to crunch a lot of data. I am able to run it over multiple sets of data sequentially using another python script to call the program serially, but I wanted to create a GUI and use multithreading to allow others to use it without knowing all the ins and outs of programming. I created the GUI successfully, and can feed data bidirectionally using signals and slots. What I am having trouble with is creating multiple threads with the same function.
I have done some research and it appears that the function needs to be threadsafe, and unfortunately mine is not because I am using curve_fit() from scipy, which is not threadsafe. So, based on what I have read in this forum and others, I should be using mutex.lock(), but I get the "SystemError: null argument to internal routine" when calling curve_fit()
Here is some sample code to demonstrate what I have done:
import sip
sip.setapi('QString', 2)
import sys, time
from PyQt5 import QtCore, QtGui, uic, QtWidgets
from ZthCalculation import ZthObject
qtCreatorFile = "PyQtZthUI_01.ui" # Enter file here.
Ui_MainWindow, QtBaseClass = uic.loadUiType(qtCreatorFile)
#class MyApp(QtGui.QMainWindow, Ui_MainWindow):
class MyApp(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self):
super(self.__class__, self).__init__()
QtWidgets.QMainWindow.__init__(self)
Ui_MainWindow.__init__(self)
self.setupUi(self)
self.RunButton.clicked.connect(self.RunZthTest)
.
.
.
def RunZthTest(self):
#create as processes instead of threads???
# self.Process1 = QtCore.QProcess()
self.Thread1 = QtCore.QThread()
self.obj1 = ZthObject(self.InputWet1.text(), self.InputDry1.text(), self.Output1.text(), self.side1)
self.obj1.moveToThread(self.Thread1)
self.Thread1.started.connect(self.obj1.ZthCalculation)
self.obj1.textBox.connect(self.updateTextBox1)
self.signal1 = self.obj1.finished.connect(self.Thread1.quit)
self.Thread1.setObjectName("Thread1")
self.Thread1.start()
time.sleep(.1)
self.Thread2 = QtCore.QThread()
self.obj2 = ZthObject(self.InputWet2.text(), self.InputDry2.text(), self.Output2.text(), self.side2)
self.obj2.moveToThread(self.Thread2)
self.Thread2.started.connect(self.obj2.ZthCalculation)
self.obj2.textBox.connect(self.updateTextBox2)
self.signal2 = self.obj2.finished.connect(self.Thread2.quit)
self.Thread2.setObjectName("Thread2")
self.Thread2.start()
time.sleep(.1)
self.Thread3 = QtCore.QThread()
self.obj3 = ZthObject(self.InputWet3.text(), self.InputDry3.text(), self.Output3.text(), self.side3)
self.obj3.moveToThread(self.Thread3)
self.Thread3.started.connect(self.obj3.ZthCalculation)
self.obj3.textBox.connect(self.updateTextBox3)
self.signal3 = self.obj3.finished.connect(self.Thread3.quit)
self.Thread3.setObjectName("Thread3")
self.Thread3.start()
.
.
.
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
window = MyApp()
window.show()
# sys.exit(app.exec_())
app.exec_()
In another file, I have the main function that I am calling as a thread:
class ZthObject(QtCore.QObject):
killthread = False
finished = QtCore.pyqtSignal()
textBox = QtCore.pyqtSignal(str)
def __init__(self, wetFilePath, dryFilePath, outFilePath, side, parent=None):
super(self.__class__, self).__init__()
self.wetFilePath = wetFilePath
self.dryFilePath = dryFilePath
self.outFilePath = outFilePath
self.side = side
self.mutex = QtCore.QMutex()
def cleanup(self):
ZthObject.killthread = True
# def ZthCalculation(self, wetFilePath, dryFilePath, outFilePath, side):
def ZthCalculation(self):
#calculations here
.
.
.
print("waypoint2")
self.mutex.lock()
popt, pcov = curve_fit(Foster6, timeShort, ZthjcShort, p0 = [Rs, taus])
self.mutex.unlock()
.
.
.
self.finished.emit()
I can successfully run the code only calling one thread, but if I call multiple threads, then the output window prints out 'waypoint2' for each thread called, then crashes with the system error I mentioned above.
What am I doing wrong? Do I need to use separate processes instead of Qthreads? Am I misunderstanding how threads work? I want them to operate in independent variable spaces.
Using a mutex really only makes something thread safe if all of the other things sharing the internals of the function also respects the mutex. In this case, it won't because, while using a mutex prevents simultaneous calls to curve_fit, you don't know what it is that is thread unsafe about the function, and so you can't be sure that something else won't also use the thread unsafe bit of code at the same time in another thread (e.g. the main thread).
Coupled with the fact that the Python GIL prevents true threading (threading only provides a speed boost in Python if your task is IO bound rather than CPU bound), I would suggest moving to a multiprocess model.

Interrupting QThread sleep

I would like to know how to pause a QThread and then resume when I get a signal. I have read and know that I can do something like this:
def run(self):
...
self.ready=False
while not self.ready:
self.sleep(1)
...
...
#QtCore.Slot()
def set_ready(self):
self.ready = True
However, what I want to do is avoid the polling in the thread. I don't want to have to set the sleep to a short amount of time and keep checking. I want to go to sleep until I get a signal from my main thread to continue.
What I am doing in my thread is this:
(pseudo code)
with open file:
read a block of data
while data:
sendThread = send the block via UDP
read the next block of data
while not ready or sendThread.isRunning:
sleep(0.1)
In my main thread I have setup a QtNetwork.QUdpSocket to connect readyRead to a method to handle incoming datagrams and decode them. When it gets the response that I'm waiting for it sends a signal to the set_ready slot to tell the thread to send another datagram. I don't always know how long it will take for the other system to respond, though I will likely have some long timeout value of 30seconds or so.
Is there a way to interrupt the sleep of the thread? so I could do something like this:
sleep(30)
if not ready:
Timeout occurred stop processing
else:
Continue processing.
You can do this pretty easily using the worker pattern of using QThreads. There's an example in the QThread documentation. The exact code will be a little different depending on whether you're using PyQt or PySide (it looks like you're using PySide from your example).
One notable issue with PySide compared to PyQt is that they didn't wrap QtCore.Q_ARG, so in PyQt, where you could normally use QMetaObject.invokeMethod to call a slot (with arguments) on the Worker object from the main thread, you can't do that directly in PySide and have to create a dummy signal (ie. Main.send_signal) to connect to the slot on the worker so you can call it from the main thread.
import time
import sys
from PySide import QtCore, QtGui
class Worker(QtCore.QObject):
send_signal = QtCore.Signal(str) # using PySide
# QtCore.pyqtSignal(str) ## using PyQt
# #QtCore.pyqtSlot(str)
#QtCore.Slot(str)
def receive_slot(self, data):
# data could be a filepath
# open file
# ... do stuff
# close file
QtCore.QThread.sleep(1) # to simulate doing stuff
self.send_signal.emit(data + ' success')
class Main(QtGui.QWidget):
send_signal = QtCore.Signal(str)
def __init__(self):
super(Main, self).__init__()
self.worker = Worker()
self.thread = QtCore.QThread(self)
self.worker.moveToThread(self.thread)
self.worker.send_signal.connect(self.receive_slot)
self.send_signal.connect(self.worker.receive_slot)
self.thread.start()
self.send_signal.emit('Start')
#QtCore.Slot(str)
def receive_slot(self, data):
print 'Main: {}'.format(data)
self.send_signal.emit('Message {}'.format(time.time()))
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
window = Main()
window.show()
app.exec_()

cannot pass data between thread and Qt object in Python

I have created a GUI, on which i have to pass string data coming from serial COM port. One individual thread is handling the Serial data whereas Qt object needs to take that data and display it via 'setPlainText' method. It gives an error (on line i've marked in comments) is
"QObject: Cannot create children for a parent that is in a different thread.
(Parent is QTextDocument(0x3ebaa68), parent's thread is QThread(0x3dd5c58), current thread is QThread(0x3fbd6a8)"
Heres my code;
import sys
from PyQt4 import QtGui
from My_GUI_code import Ui_Dialog
import serial # import Serial Library
import threading
import time
test=""
arduinoData = serial.Serial('COM2', 9600) #
index=0
incoming_data=""
device_0_V=""
class Serial_read(threading.Thread):
"""
Thread to read data coming from Arduino
"""
def __init__(self):
threading.Thread.__init__(self)
def run(self):
global incoming_data
global device_0_V
global test
while 1:
while (arduinoData.inWaiting()==0): #Wait here until there is data
pass #do nothing
incoming_data = arduinoData.readline() #read the line of text from the serial port
if "V0" in incoming_data:
index = incoming_data.index("V0=")
device_0_V=incoming_data[index+3:index+6]
print device_0_V
#print incoming_data,
class Editor(QtGui.QMainWindow, threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
global device_0_V
super(Editor, self).__init__()
self.ui=Ui_Dialog()
#test=self.ui.Dev_1_V
self.ui.setupUi(self)
self.setWindowIcon(QtGui.QIcon('ICON.png'))
self.ui.Dev_1_V.setPlainText("anum")
self.show()
self.ui.Dev_1_ON.clicked.connect(self.handleButton)
def run(self):
global device_0_V
while 1:
self.ui.Dev_1_V.setPlainText(device_0_V) #<<here it gives ERROR
time.sleep(1)
def handleButton(self):
time = self.ui.time_dev_1.value()
self.ui.Dev_1_V.setPlainText(device_0_V)
print time
#print ('Hello World')
def main():
tx_socket_thread2 = Serial_read()
tx_socket_thread2.start()
app = QtGui.QApplication(sys.argv)
ex = Editor()
ex.start()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
I've seen some relevant questions asked in Stackoverflow, but I am not able to understand the concept still, as I am new in Classes, Qt and OOP things. I know i am doing some basic mistake here... Any help will be highly appreciated.
So after some readings on related asked questions in Stack overflow, I've managed to achieve what I want, Heres the code;
import sys
from PyQt4 import QtGui, QtCore
from My_GUI_code import Ui_Dialog
import serial # import Serial Library
import threading
import time
test=""
arduinoData = serial.Serial('COM2', 9600) #
index=0
incoming_data=""
device_0_V=""
class Serial_read(threading.Thread):
"""
Thread to read data coming from Arduino
"""
def __init__(self):
threading.Thread.__init__(self)
def run(self):
global incoming_data
global device_0_V
global test
while 1:
while (arduinoData.inWaiting()==0): #Wait here until there is data
pass #do nothing
incoming_data = arduinoData.readline() #read the line of text from the serial port
if "V0" in incoming_data:
index = incoming_data.index("V0=")
device_0_V=incoming_data[index+3:index+6]
print device_0_V
#print incoming_data,
class Editor(QtGui.QMainWindow):
def __init__(self):
#threading.Thread.__init__(self)
global device_0_V
super(Editor, self).__init__()
self.ui=Ui_Dialog()
#test=self.ui.Dev_1_V
self.ui.setupUi(self)
self.setWindowIcon(QtGui.QIcon('ICON.png'))
self.ui.Dev_1_V.setPlainText("anum")
self.show()
self.ui.Dev_1_ON.clicked.connect(self.handleButton)
self.worker = Worker(self) # an independent thread that will listen to a signal 'beep' and trigger a function self.update
self.connect(self.worker, QtCore.SIGNAL('beep'), self.update)
self.worker.start() # start the thread
def update(self, Serial_data):
# here, I am getting the Serial data via signaling
if "V0" in incoming_data:
index = incoming_data.index("V0=")
device_0_V=incoming_data[index+3:index+7]
self.ui.Dev_1_V.setPlainText(device_0_V)
def handleButton(self):
time = self.ui.time_dev_1.value()
self.ui.Dev_1_V.setPlainText(device_0_V)
print time
#print ('Hello World')
class Worker(QtCore.QThread):
def __init__(self, host_window):
super(Worker, self).__init__()
self.running = False
def run(self):
self.running = True
global incoming_data #kept the Serial data global
global device_0_V
while self.running:
#sending 'beep' signal to the main Qt object, with string data 'incoming_data'
self.emit(QtCore.SIGNAL('beep'), incoming_data)
time.sleep(0.1)
def stop(self):
self.running = False
def main():
tx_socket_thread2 = Serial_read()
tx_socket_thread2.start()
app = QtGui.QApplication(sys.argv)
ex = Editor()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
Inside the main Qt object, I've created a QThread "Worker" that sends signals to main Qt object with the Serial data. The update function is triggered every time a signal arrives from worker thread, and then further reads the data coming from worker thread.
Got help from this question
Thank you #Andy and #SiHa for your participation
Here's a page describing what Qt objects are and are not thread-safe -- http://doc.qt.io/qt-4.8/threads-reentrancy.html
For the most part, GUI objects are not thread safe and you should avoid modifying them from other threads.
One way of affecting the GUI from other threads is to use the signal and slot system, which is safe to use between threads so long as any objects passed are thread-safe. This usually means creating a thread-safe data structure in the secondary thread and passing it along with a signal to the main thread, which then reads the data structure and updates the GUI.
A more advanced version of that design pattern is to use a 2-way queue. One queue is populated by the main thread, which creates worker threads that process the items in the queue. When finished, the worker threads populate the other queue with thread-safe return values that the main thread then processes. Signals and events are still used to notify the main and worker threads when there are items in the queue to process.
Also, unless absolutely want to directly manage the threads, you can use QRunnable and QThreadPool to kick off threads without the need to directly manage them.

Categories