Run 2 loop at the same time python - python

foo():
while True:
#do smthng
boo():
while True:
#do smthng
I will use this two method whenever my button pushed as:
Thread(target=foo).start()
Thread(target=boo).start()
In my code foo is button and for filling progress bar. boo is button and for undo filling progress bar.
When I press foo trigger button there is no problem shows when I press boo trigger button if get empty then I press foo again I got segmentation error.
How can I stop foo thread when boo pressed and boo thread when foo pressed?
Edit:
My all code is:
import time
import sys
from PyQt4 import QtGui, QtCore
import threading
QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_X11InitThreads)
class CustomThread(threading.Thread):
def __init__(self, target=None):
super(CustomThread, self).__init__(target=target)
self._stop = threading.Event()
def stop(self):
self._stop.set()
class CustomProgressBar(QtGui.QProgressBar):
def __init__(self, x, y, lenght, height, require_list=[]):
QtGui.QProgressBar.__init__(self)
self.require_list = require_list
self.setGeometry(x, y, lenght, height)
self.speed = 0
def fill(self):
while self.speed > 0 and self.value() < 100:
self.setValue(self.value()+self.speed)
time.sleep(0.01)
while self.speed < 0 and self.value() > 0:
self.setValue(self.value()+self.speed)
time.sleep(0.01)
self.speed = 0
class Valve(QtGui.QCheckBox):
def __init__(self, x, y, lenght, height, inputs=[], outputs=[]):
super(Valve, self).__init__()
self.sources = inputs
self.outputs = outputs
self.setGeometry(x, y, lenght, height)
self.stateChanged.connect(self.filler)
self.fill_thread_list = []
def is_fillable(self):
for source in self.sources:
if source.value() == 100:
return 1
return 0
def filler(self):
for thread in self.fill_thread_list:
thread.stop()
for output in self.outputs:
if self.is_fillable():
fillThread = CustomThread(target=output.fill)
self.fill_thread_list.append(fillThread)
if self.isChecked():
output.speed = 1
else:
output.speed = -1
fillThread.start()
class MainWindow(QtGui.QWidget):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.initUI()
def initUI(self):
layout = QtGui.QHBoxLayout()
#pipes and buttons
self.pipe = CustomProgressBar(20, 50, 100, 2)
self.pipe.setValue(100)
self.pipe2 = CustomProgressBar(120, 50, 100, 2, require_list=[self.pipe])
self.pipe3 = CustomProgressBar(120, 50, 100, 2, require_list=[self.pipe])
self.button1 = Valve(100, 50, 10, 10, inputs=[self.pipe], outputs=[self.pipe2, self.pipe3])
#add buttons to layout
layout.addWidget(self.button1)
layout.addWidget(self.pipe)
layout.addWidget(self.pipe2)
layout.addWidget(self.pipe3)
self.setLayout(layout)
self.setGeometry(0, 0, 1366, 768)
self.show()
def main():
app = QtGui.QApplication(sys.argv)
ex = MainWindow()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
It just different from this question.

Related

How to update a AnimationGroup without creating a new AnimationGroup every time?

I want to run a AnimationGroup with different changing animations.
But the problem is that the function clear()
self.group = QtCore.QSequentialAnimationGroup(self)
def anim(self):
if X == True:
self.group.addAnimation(self.animation_1)
self.group.addAnimation(self.animation_2)
elif X == False:
self.group.addAnimation(self.animation_3)
self.group.addAnimation(self.animation_4)
self.group.start()
self.group.clear()
displays an error
RuntimeError: wrapped C/C++ object of type QVariantAnimation has been deleted
I can’t constantly create a new group.
def anim(self):
self.group = QtCore.QSequentialAnimationGroup(self)
if X == True:
self.group.addAnimation(self.animation_1)
self.group.addAnimation(self.animation_2)
elif X == False:
self.group.addAnimation(self.animation_3)
self.group.addAnimation(self.animation_4)
self.group.start()
self.group.clear()
I tried to use removeAnimation
import sys
from PyQt5 import QtWidgets, QtGui, QtCore
class Rad(QtWidgets.QWidget):
def __init__(self, group, pos, parent=None):
super(Rad, self).__init__(parent)
self.resize(50, 50)
lay = QtWidgets.QVBoxLayout(self)
self.radio = QtWidgets.QRadioButton()
self.label = QtWidgets.QLabel()
self.label.setText('but-{}'.format(pos))
self.group = group
self.pos = pos
lay.addWidget(self.radio)
lay.addWidget(self.label)
self.radio.toggled.connect(self.fun)
self.animation = QtCore.QVariantAnimation()
self.animation.setDuration(1000)
self.animation.valueChanged.connect(self.value)
self.animation.setStartValue(100)
self.animation.setEndValue(0)
self.can = False
def value(self, val):
self.move(self.pos, val)
def fun(self):
self.animation.setStartValue(
100
if not self.can
else 0
)
self.animation.setEndValue(
0
if not self.can
else 100
)
if self.group.animationAt(1) == None :
print("Bad")
else :
print("Good")
self.group.removeAnimation(self.group.animationAt(0))
self.group.addAnimation(self.animation)
self.group.start()
self.can = not self.can
class Test(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.group = QtCore.QSequentialAnimationGroup(self)
self.buts = QtWidgets.QButtonGroup(self, exclusive=True)
wid_1 = Rad(self.group, 200, self)
wid_2 = Rad(self.group, 100, self)
wid_3 = Rad(self.group, 0, self)
self.buts.addButton(wid_1.radio, 0)
self.buts.addButton(wid_2.radio,1)
self.buts.addButton(wid_3.radio, 2)
wid_1.setStyleSheet('background:brown;')
wid_2.setStyleSheet('background:yellow;')
wid_3.setStyleSheet('background:green;')
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
w = Test()
w.resize(500, 500)
w.show()
sys.exit(app.exec_())
And now the animation has become sharp
And in the console output
QAnimationGroup::animationAt: index is out of bounds
From what I can deduce is that you want the pressed item to move down and if any item was in the low position then it must return to its position. If so then my answer should work.
You should not use the clear method since that removes and deletes the animation, instead use takeAnimation(0) until there are no animations, and just add the new animations, but that logic should not be inside "Rad" but in the Test class:
import sys
from PyQt5 import QtWidgets, QtGui, QtCore
class Rad(QtWidgets.QWidget):
def __init__(self, text, parent=None):
super(Rad, self).__init__(parent)
self.resize(50, 50)
self.radio = QtWidgets.QRadioButton()
self.label = QtWidgets.QLabel()
self.label.setText(text)
lay = QtWidgets.QVBoxLayout(self)
lay.addWidget(self.radio)
lay.addWidget(self.label)
self.animation = QtCore.QVariantAnimation()
self.animation.setDuration(1000)
self.animation.valueChanged.connect(self.on_value_changed)
self.animation.setStartValue(100)
self.animation.setEndValue(0)
#QtCore.pyqtSlot("QVariant")
def on_value_changed(self, val):
pos = self.pos()
pos.setY(val)
self.move(pos)
def swap_values(self):
self.animation.blockSignals(True)
start_value = self.animation.startValue()
end_value = self.animation.endValue()
self.animation.setStartValue(end_value)
self.animation.setEndValue(start_value)
self.animation.blockSignals(False)
class Test(QtWidgets.QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.buts = QtWidgets.QButtonGroup(self, exclusive=True)
wid_1 = Rad("but-200", self)
wid_1.setStyleSheet("background:brown;")
wid_1.move(200, 0)
wid_2 = Rad("but-100", self)
wid_2.setStyleSheet("background:yellow;")
wid_2.move(100, 0)
wid_3 = Rad("but-0", self)
wid_3.setStyleSheet("background:green;")
wid_3.move(0, 0)
self.buts.addButton(wid_1.radio, 0)
self.buts.addButton(wid_2.radio, 1)
self.buts.addButton(wid_3.radio, 2)
self.buts.buttonToggled.connect(self.on_button_toggled)
self.group = QtCore.QSequentialAnimationGroup(self)
self.last_widget = None
#QtCore.pyqtSlot(QtWidgets.QAbstractButton, bool)
def on_button_toggled(self, button, state):
if state:
wid = button.parent()
if self.group.animationCount() > 0:
self.group.takeAnimation(0)
if isinstance(self.last_widget, Rad):
self.last_widget.swap_values()
self.group.addAnimation(self.last_widget.animation)
wid.swap_values()
self.group.addAnimation(wid.animation)
self.group.start()
self.last_widget = wid
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
w = Test()
w.resize(500, 500)
w.show()
sys.exit(app.exec_())

How many times the most I can change the background of the pushButton?

So , I am trying to blink the push button with the color that I pass and between white. And it only seems to blink it so many times after that code would crash.
I have tried it to implement the blinking with different blink rates and it
would it still break at some time.
in 'a' I have the string like "Background-color: rgb(255,0,0)".
in 'timings' i have a list like[208, 280]or it could be [48,32,48,32,100,280], this represents the on and off timings 'zeroth index' represents on and 'index 1' represents off time and follows the pattern so on.
while True:
i = 0
while i < len(timings):
if self.p[2] == 1:
self.b.setStyleSheet("{}".format(a))
self.b.update()
time.sleep(timings[i]/1000)
self.b.setStyleSheet("Background-color: rgb(255,255,255)")
self.b.update()
time.sleep(timings[i+1]/1000)
i = i + 2
self.head1, self.head2, self.head3 all have list with some thing like this ["Background-color:rgb(255,0,0)",list of on and off patterns, head number#]
right now, I am working with three heads.
def flash(self):
obj1 = threads(self.head1, self.head1_pb)
obj2 = threads(self.head2, self.head2_pb)
obj3 = threads(self.head3, self.head3_pb)
obj1.start()
time.sleep(.02)
obj2.start()
time.sleep(.02)
obj3.start()
class threads(Thread):
def __init__(self, a, pb):
Thread.__init__(self)
self.p = a
self.b = pb
def run(self):
a = self.p[0]
timings = self.p[1]
print(timings[0])
while True:
i = 0
while i < len(timings):
if self.p[2] == 1:
self.b.setStyleSheet("{}".format(a))
self.b.update()
time.sleep(timings[i]/1000)
self.b.setStyleSheet("Background-color: rgb(255,255,255)")
self.b.update()
time.sleep(timings[i+1]/1000)
i = i + 2
elif self.p[2] == 2:
self.b.setStyleSheet("{}".format(a))
self.b.update()
time.sleep(timings[i]/1000)
self.b.setStyleSheet("Background-color: rgb(255,255,255)")
self.b.update()
time.sleep(timings[i+1]/1000)
i = i + 2
else:
self.b.setStyleSheet("{}".format(a))
self.b.update()
time.sleep(timings[i]/1000)
self.b.setStyleSheet("Background-color: rgb(255,255,255)")
self.b.update()
time.sleep(timings[i+1]/1000)
i = i + 2
You can change the color as many times as you want, the problem is that you should not use a time consuming loop or use time.sleep() because they block the eventloop generating the GUI to freeze. Instead, use a QTimer to call the task that changes color every so often.
In the following example, create a custom button that implements what you want:
from PySide2 import QtCore, QtGui, QtWidgets
class PushButton(QtWidgets.QPushButton):
def __init__(self, *args, **kwargs):
super(PushButton, self).__init__(*args, **kwargs)
self._color = QtGui.QColor("white")
timer_on = QtCore.QTimer(singleShot=True, timeout=self.on_timeout)
timer_off = QtCore.QTimer(singleShot=True, timeout=self.on_timeout)
self._timers = (timer_on, timer_off)
for timer, function in zip(self._timers, (self.on, self.off)):
timer.timeout.connect(function)
def setTime(self, on_time, off_time):
for t, timer in zip((on_time, off_time), self._timers):
timer.setInterval(t)
#QtCore.Slot()
def on_timeout(self):
timer = self.sender()
if timer not in self._timers:
return
timer_on, timer_off = self._timers
another_timer = timer_off if timer is timer_on else timer_on
another_timer.start()
def start(self):
timer_on, _ = self._timers
timer_on.start()
def stop(self):
for timer in self._timers:
timer.stop()
self.off()
def color(self):
return self._color
def setColor(self, color):
if self.color() == color:
return
self._color = color
def on(self):
self.setStyleSheet(
"""PushButton{ background-color: %s}""" % (self.color().name(),)
)
def off(self):
self.setStyleSheet(
"""PushButton{ background-color: rgb(255,255,255)}"""
)
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Widget, self).__init__(parent)
button = PushButton()
button.setColor(QtGui.QColor("salmon"))
button.setTime(208, 280)
button.start()
# stop blink in 30 seconds
# QtCore.QTimer.singleShot(30 * 1000, button.stop)
lay = QtWidgets.QVBoxLayout(self)
lay.addWidget(button)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
app.setStyle("fusion")
w = Widget()
w.show()
sys.exit(app.exec_())
Plus:
As you note that you have a lot of data, it is best to create an iterator to save memory. Considering the above I have created a QPushButton that obtains the data from the iterator.
import random
from functools import partial
from PySide2 import QtCore, QtGui, QtWidgets
def generate_data():
i = 0
while i < 1000000:
color_on = random.randint(10, 500)
color_off = random.randint(10, 500)
color = QtGui.QColor(*random.sample(range(255), 3))
yield color_on, color_off, color
i += 1
class PushButton(QtWidgets.QPushButton):
def __init__(self, *args, **kwargs):
super(PushButton, self).__init__(*args, **kwargs)
self._color = QtGui.QColor("white")
self._generator = None
self.m_timer = QtCore.QTimer(
self, timeout=self.on_timeout, singleShot=True
)
def setGenerator(self, generator):
self._generator = generator
def start(self):
self.on_timeout()
#QtCore.Slot()
def on_timeout(self):
try:
time_on, time_off, color = next(self._generator)
self.setColor(color)
self.m_timer.start(time_on + time_off)
QtCore.QTimer.singleShot(
time_on, partial(self.setColor, QtGui.QColor("white"))
)
except StopIteration:
self.m_timer.stop()
def setColor(self, color):
self.setStyleSheet(
"""PushButton{ background-color: %s}""" % (color.name(),)
)
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Widget, self).__init__(parent)
lay = QtWidgets.QVBoxLayout(self)
for _ in range(6):
button = PushButton()
button.setGenerator(generate_data())
button.start()
lay.addWidget(button)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
app.setStyle("fusion")
w = Widget()
w.resize(320, 240)
w.show()
sys.exit(app.exec_())

Passing data from a QThread to another QThread

I have a situation where a Gui is active and a QThread.
The QThread is getting and saving data in the background all the time, it should not stop doing this.
Now I want to process the latest data from the QThread without interrupting the QThread or freezing the Gui.
So I think I need another thread to do this?!
How can I pass its data to another thread and do something with it?
import sys, random, time
from PyQt5 import QtWidgets
from PyQt5.QtCore import *
class Ui(QtWidgets.QMainWindow):
def __init__(self):
super(Ui, self).__init__()
self.setWindowTitle('Window')
#getData
self.myGetData = getData()
self.myGetData.start()
self.show()
class getData(QThread):
#This Thread should run all the time
def run(self):
while True:
myNumber = random.randint(0, 100)
#He 'processData Thread'!! Do Something with mynumber!!
time.sleep(1)
class processData(QThread):
def processNumber(self, myNumber):
#Extremly complex code will execute while 'getData' is doing its thing.
newNumber = myNumber * 10
return newNumber
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = Ui()
sys.exit(app.exec_())
Found a lot of examples on how to pass data from a QThread to the interface (signals).. But not the other way around.
The signals are confusing me a bit in this case..
I would like to propose do next:
import sys, random, time
from PyQt5 import QtWidgets
from PyQt5.QtCore import *
from PyQt5 import Qt #+
class getData(QThread):
#This Thread should run all the time
threadSignalGetData = pyqtSignal(int)
def __init__(self, myNumber):
super().__init__()
self.myNumber = myNumber
def run(self):
#myNumber = 0
while True:
#He 'processData Thread'!! Do Something with mynumber!!
Qt.QThread.msleep(1000)
self.myNumber += 1
self.threadSignalGetData.emit(self.myNumber)
class MsgBoxGetData(Qt.QDialog):
def __init__(self):
super().__init__()
layout = Qt.QVBoxLayout(self)
self.label = Qt.QLabel("")
layout.addWidget(self.label)
close_btn = Qt.QPushButton("Close window GetData")
layout.addWidget(close_btn)
close_btn.clicked.connect(self.close)
self.setGeometry(900, 65, 400, 80)
self.setWindowTitle('MsgBox GetData')
self.setStyleSheet("""QLabel{
font-family:'Consolas';
color: green;
font-size: 16px;}""")
class processData(QThread):
threadSignalProcessData = pyqtSignal(int, int)
def __init__(self, myNumber):
super().__init__()
self.newNumber = myNumber
def run(self):
flagProcessData = True
while flagProcessData:
#Extremly complex code will execute while 'getData' is doing its thing.
newNumber = self.newNumber * 10
self.threadSignalProcessData.emit(self.newNumber, newNumber)
flagProcessData = False
class MsgBoxProcessData(Qt.QDialog):
def __init__(self):
super().__init__()
layout = Qt.QVBoxLayout(self)
self.label = Qt.QLabel("")
layout.addWidget(self.label)
close_btn = Qt.QPushButton("Close window ProcessData")
layout.addWidget(close_btn)
close_btn.clicked.connect(self.close)
self.setGeometry(900, 200, 400, 80)
self.setWindowTitle('MsgBox ProcessData')
self.setStyleSheet("""QLabel{
font-family:'Consolas';
color: red;
font-size: 24px;}""")
class Ui(Qt.QWidget):
def __init__(self, parent=None):
super(Ui, self).__init__(parent)
layout = Qt.QVBoxLayout(self)
self.lbl = Qt.QLabel("process GUI")
layout.addWidget(self.lbl)
self.btnA = Qt.QPushButton("Start getData")
layout.addWidget(self.btnA)
self.btnB = Qt.QPushButton("Start processData")
layout.addWidget(self.btnB)
self.setGeometry(550, 65, 300, 300)
self.setWindowTitle('Window')
self.btnA.clicked.connect(self.usingGetData)
self.btnB.clicked.connect(self.usingProcessData)
self.myNumber = 0
self.newNumber = None
self.msgGetData = MsgBoxGetData()
self.threadGetData = None
self.msgProcessData = MsgBoxProcessData()
self.threadProcessData = None
self.counter = 0
self.timer = Qt.QTimer()
self.timer.setInterval(1000)
# -------- timeout -------> def recurring_timer(self):
self.timer.timeout.connect(self.recurring_timer)
self.timer.start()
self.setStyleSheet("""QLabel{
font-family:'Consolas';
color: blue;
font-size: 20px;}""")
self.show()
def recurring_timer(self):
self.counter += 1
self.lbl.setText("process GUI: %d" % self.counter)
# ---- getData(QThread) -----------------------------------------------------#
def usingGetData(self):
if self.threadGetData is None:
self.threadGetData = getData(self.myNumber)
self.threadGetData.threadSignalGetData.connect(self.on_threadSignalGetData)
self.threadGetData.finished.connect(self.finishedGetData)
self.threadGetData.start()
self.btnA.setText("Stop getData(QThread)")
else:
self.threadGetData.terminate()
self.threadGetData = None
self.btnA.setText("Start getData(QThread)")
def finishedGetData(self):
self.threadGetData = None
self.btnA.setText("Start getData(QThread)")
def on_threadSignalGetData(self, value):
self.myNumber = value
self.msgGetData.label.setText(str(self.myNumber))
if not self.msgGetData.isVisible():
self.msgGetData.show()
# --END-- getData(QThread) -------------------#
# ---- processData(QThread) -----------------------------------------------------#
def usingProcessData(self):
if self.threadProcessData is None:
self.threadProcessData = processData(self.myNumber)
self.threadProcessData.threadSignalProcessData.connect(self.on_threadSignalProcessData)
self.threadProcessData.finished.connect(self.finishedProcessData)
self.threadProcessData.start()
self.btnB.setText("Stop processData(QThread)")
else:
self.threadProcessData.terminate()
self.threadProcessData = None
self.btnB.setText("Start processData(QThread)")
def finishedProcessData(self):
self.threadProcessData = None
self.btnB.setText("Start processData(QThread)")
def on_threadSignalProcessData(self, value1, value2):
self.newNumber = value2
self.msgProcessData.label.setText(str(value1)+" * 10 = "+str(self.newNumber))
if not self.msgProcessData.isVisible():
self.msgProcessData.show()
# --END-- processData(QThread) -------------------#
# -------------------- closeEvent --------------------------------------- #
def closeEvent(self, event):
reply = Qt.QMessageBox.question\
(self, 'Question',
"QUIT ?",
Qt.QMessageBox.Yes,
Qt.QMessageBox.No)
if reply == Qt.QMessageBox.Yes:
# close getData(QThread)
if self.threadGetData:
self.threadGetData.terminate()
self.msgGetData.close()
# close processData(QThread)
if self.threadProcessData:
self.threadProcessData.terminate()
self.msgProcessData.close()
#event.accept()
super().closeEvent(event)
else:
event.ignore()
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = Ui()
sys.exit(app.exec_())

PyQt5: How to run QTimer in sub tread and return value to main Widget?

I must say it is a beginner's question. But I tried/searched a lot without success.
There is a QLabel, by running the code I want to have the values from a sub-thread shown onto it.
Also I want to have the QTimer in the sub-thread, because the time is controlled there(not in the main QThread).
This is the effect on the QLable I want to achieve...
0 (show for 1 second)
1 (show for 1 second)
2 (show for 1 second)
...
11 (show for 2 second)
12 (show for 2 second)
...
21 (show for 3 second)
22 (show for 3 second)
...
Here is my code:
# -*- coding: utf-8 -*-
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
class WorkerThread(QThread):
def __init__(self, parent=None):
super(WorkerThread, self).__init__(parent)
self._running = False
self.timer = QTimer() # Question: define the QTimer here?
self.timer.timeout.connect(self.doWork)
self.timer.start(1000)
def run(self):
self._running = True
while self._running:
self.doWork()
def doWork(self):
for i in range(40): # Question: How to return the i onto the QLable?
if i <= 10:
# show the value of i on the QLabel and wait for 1 second
pass
elif i <= 20:
# show the value of i on the QLable and wait for 2 second
pass
elif i <= 30:
# show the value of i on the QLable and wait for 3 second
pass
else:
# show the value of i on the QLable and wait for 4 second
pass
def stop(self, wait = False):
self._running = False
if wait:
self.wait()
class MyApp(QWidget):
def __init__(self, parent= None):
super(MyApp, self).__init__(parent)
self.thread = WorkerThread()
self.initUI()
def initUI(self):
self.text = "hello world"
self.setGeometry(100, 100, 500, 100)
self.setWindowTitle('test')
self.lbl_1 = QLabel("for every number between 0-10 wait 1 second, for 11-20 wait 2 sec, ...", self)
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
window = MyApp()
window.show()
sys.exit(app.exec_())
In summary there are two questions:
1. How to define the QTimer in the sub-thread?
2. How to return the value from the sub-thread to QLabel?
Thank you for the help!
It is not necessary to use a QTimer to perform the task you need, in a thread you can have blocking elements such as QThead::sleep() that generates a pause. To send the information we can use the parent() to pass the GUI and combining it with QMetaObject::invokeMethod() we can update the label respecting the rules of Qt:
class WorkerThread(QThread):
[...]
def doWork(self):
for i in range(40): # Question: How to return the i onto the QLable?
if i <= 10:
QThread.sleep(1)
elif i <= 20:
QThread.sleep(2)
elif i <= 30:
QThread.sleep(3)
else:
QThread.sleep(4)
gui = self.parent()
QMetaObject.invokeMethod(gui.lbl_1, "setText", Qt.QueuedConnection,
Q_ARG(str, str(i)))
[...]
class MyApp(QWidget):
def __init__(self, parent=None):
super(MyApp, self).__init__(parent)
self.thread = WorkerThread(self) # passing the window as a parent
self.thread.start()
self.initUI()
def initUI(self):
[...]
We can also use QTimer together with QEventLoop to generate the same effect as QThread::sleep():
def doWork(self):
for i in range(40): # Question: How to return the i onto the QLable?
if i <= 10:
interval = 1000
elif i <= 20:
interval = 2000
elif i <= 30:
interval = 3000
else:
interval = 4000
loop = QEventLoop()
QTimer.singleShot(interval, loop.quit)
loop.exec_()
gui = self.parent()
QMetaObject.invokeMethod(gui.lbl_1, "setText", Qt.QueuedConnection,
Q_ARG(str, str(i)))
Instead of using QMetaObject::invokeMethod we can use signals:
class WorkerThread(QThread):
numberChanged = pyqtSignal(str)
def __init__(self, parent=None):
[...]
def doWork(self):
for i in range(40): # Question: How to return the i onto the QLable?
if i <= 10:
interval = 1000
elif i <= 20:
interval = 2000
elif i <= 30:
interval = 3000
else:
interval = 4000
loop = QEventLoop()
QTimer.singleShot(interval, loop.quit)
loop.exec_()
self.numberChanged.emit(str(i))
[...]
class MyApp(QWidget):
def __init__(self, parent=None):
super(MyApp, self).__init__(parent)
self.thread = WorkerThread(self)
self.thread.start()
self.initUI()
def initUI(self):
self.text = "hello world"
self.setGeometry(100, 100, 500, 100)
self.setWindowTitle('test')
self.lbl_1 = QLabel("for every number between 0-10 wait 1 second, for 11-20 wait 2 sec, ...", self)
self.thread.numberChanged.connect(self.lbl_1.setText, Qt.QueuedConnection)
self.show()

PyQt, QThread communication, update QLineEdit filed

I have a piece of code that is running, communication between two threads and status. I have faced with problem how to update QLineEdit field based on emitted value. So far, it works fine with commented lines, but it's not what I am looking for... How to modify show_process function to do the job...some help will be more than welcome?
import sys, time
from PyQt4 import QtGui, QtCore
class Window(QtGui.QMainWindow):
def __init__(self):
super(Window, self).__init__()
self.setGeometry(50, 50, 500, 200)
self.setWindowTitle("TEST APP!")
self.home()
def Label(self, name, width, length, fontSize) :
label_name = QtGui.QLabel(name, self)
label_name.move(width,length)
label_font = label_name.font()
label_font.setPointSize(fontSize)
label_name.setFont(label_font)
def Field(self, TrueFalse, width, length, startText) :
field_name = QtGui.QLineEdit(self)
field_name.setDisabled(TrueFalse)
field_name.move(width, length)
field_name.setAlignment(QtCore.Qt.AlignCenter)
field_name.setText(startText)
def home(self):
self.Label('TEST1', 10, 60, 10)
self.Label('TEST2', 10, 120, 10)
self.Field(True, 130, 60, 'Ready') # first one
self.Field(True, 130, 120, 'Ready') # second one
self.start = QtGui.QPushButton("start", self)
self.start.clicked.connect(self.startPressed)
self.start.move(260, 20)
self.stop = QtGui.QPushButton("Stop", self)
self.stop.clicked.connect(self.stopPressed)
self.stop.move(380, 20)
self.show()
def startPressed(self):
self.get_thread_start = Start_Process('239.200.10.1', 50010)
self.stop.clicked.connect(self.get_thread_start.terminate)
self.start.setDisabled(True)
self.get_thread_start.updated.connect(self.show_process)
self.get_thread_start.start()
def stopPressed(self):
self.start.setDisabled(False)
self.get_thread_start.running = False
def show_process(self, data):
if str(data) == '1' :
#self.textbox1.setText(str(data))
pass
elif str(data) == '0' :
#self.textbox2.setText(str(data))
pass
class Start_Process(QtCore.QThread):
updated = QtCore.pyqtSignal(int)
running = True
def __init__(self, mcstaddr, mcstport):
QtCore.QThread.__init__(self)
self.counter = 0
self.array = [1,0,1,0,1,0,1,0,1]
def run(self):
while self.running:
for i in self.array :
self.updated.emit(i)
time.sleep(0.5)
def main():
app = QtGui.QApplication(sys.argv)
GUI = Window()
GUI.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
A simple way to access the widget is to create a container, in this case we choose a dictionary:
self.field_dict = {}
Then we add in the Field() method we add the QLineEdits to the dictionary.
def Field(self, TrueFalse, width, length, startText, key) :
field_name = QtGui.QLineEdit(self)
...
self.field_dict[key] = field_name
Then we can get the QLineEdit through the key.
def show_process(self, key, data):
self.field_dict[key].setText(data)
Complete Example:
import sys, time
from PyQt4 import QtGui, QtCore
class Window(QtGui.QMainWindow):
def __init__(self):
super(Window, self).__init__()
self.setGeometry(50, 50, 500, 200)
self.setWindowTitle("TEST APP!")
self.field_dict = {}
self.home()
def Label(self, name, width, length, fontSize) :
label_name = QtGui.QLabel(name, self)
label_name.move(width,length)
label_font = label_name.font()
label_font.setPointSize(fontSize)
label_name.setFont(label_font)
def Field(self, TrueFalse, width, length, startText, key) :
field_name = QtGui.QLineEdit(self)
field_name.setDisabled(TrueFalse)
field_name.move(width, length)
field_name.setAlignment(QtCore.Qt.AlignCenter)
field_name.setText(startText)
self.field_dict[key] = field_name
def home(self):
self.Label('TEST1', 10, 60, 10)
self.Label('TEST2', 10, 120, 10)
self.Field(True, 130, 60, 'Ready', 0) # first one
self.Field(True, 130, 120, 'Ready', 1) # second one
self.start = QtGui.QPushButton("start", self)
self.start.clicked.connect(self.startPressed)
self.start.move(260, 20)
self.stop = QtGui.QPushButton("Stop", self)
self.stop.clicked.connect(self.stopPressed)
self.stop.move(380, 20)
self.show()
def startPressed(self):
self.get_thread_start = Start_Process('239.200.10.1', 50010)
self.stop.clicked.connect(self.get_thread_start.terminate)
self.start.setDisabled(True)
self.get_thread_start.updated.connect(self.show_process)
self.get_thread_start.start()
def stopPressed(self):
self.start.setDisabled(False)
self.get_thread_start.running = False
def show_process(self, key, data):
self.field_dict[key].setText(data)
class Start_Process(QtCore.QThread):
updated = QtCore.pyqtSignal(int, str)
running = True
def __init__(self, mcstaddr, mcstport):
QtCore.QThread.__init__(self)
self.counter = 0
self.array = [1,0,1,0,1,0,1,0,1]
def run(self):
while self.running:
for i in self.array :
self.updated.emit(i, str(self.counter))
time.sleep(0.5)
self.counter += 1
def main():
app = QtGui.QApplication(sys.argv)
GUI = Window()
GUI.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()

Categories