Passing data from a QThread to another QThread - python

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_())

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_())

how i can make thread for progress bar with pafy

i'm trying to fix problem in my program and this problem is when i start download video the program not responding and i can't see also progress bar move so i tried used threading module but i can't fix problem so how i can fix problem
From this code I can download the video and send the data to another function to retrieve information that I use to connect it to the progress bar
def video(self):
video_url = self.lineEdit_4.text()
video_save = self.lineEdit_3.text()
pafy_video = pafy.new(video_url)
type_video = pafy_video.videostreams
quality = self.comboBox.currentIndex()
start_download = type_video[quality].download(filepath=video_save,callback=self.video_progressbar)
This code is received information from video function to connect with progress bar
def video_progressbar(self,total, recvd, ratio, rate, eta):
self.progressBar_2.setValue(ratio * 100)
I use;python3.5 pyqt5 pafy
One way to move to another thread is to create a QObject that lives in another thread and execute that task in a slot. And that slot must be invoked through QMetaObject::invokeMethod or a signal.
with QThread and QMetaObject::invokeMethod:
import pafy
from PyQt5 import QtCore, QtWidgets
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
central_widget = QtWidgets.QWidget()
self.setCentralWidget(central_widget)
self.le_url = QtWidgets.QLineEdit("https://www.youtube.com/watch?v=bMt47wvK6u0")
path = QtCore.QStandardPaths.writableLocation(QtCore.QStandardPaths.DownloadLocation)
self.le_output = QtWidgets.QLineEdit(path)
self.btn_quality = QtWidgets.QPushButton("Get qualities")
self.combo_quality = QtWidgets.QComboBox()
self.btn_download = QtWidgets.QPushButton("Download")
self.progressbar = QtWidgets.QProgressBar(maximum=100)
self.downloader = DownLoader()
thread = QtCore.QThread(self)
thread.start()
self.downloader.moveToThread(thread)
self.btn_quality.clicked.connect(self.on_clicked_quality)
self.btn_download.clicked.connect(self.download)
self.btn_download.setDisabled(True)
self.downloader.progressChanged.connect(self.progressbar.setValue)
self.downloader.qualitiesChanged.connect(self.update_qualityes)
self.downloader.finished.connect(self.on_finished)
form_lay = QtWidgets.QFormLayout(central_widget)
form_lay.addRow("Url: ", self.le_url)
form_lay.addRow(self.btn_quality)
form_lay.addRow("qualities: ", self.combo_quality)
form_lay.addRow("Output: ", self.le_output)
form_lay.addRow(self.btn_download)
form_lay.addRow(self.progressbar)
#QtCore.pyqtSlot()
def on_finished(self):
self.update_disables(False)
#QtCore.pyqtSlot()
def on_clicked_quality(self):
video_url = self.le_url.text()
QtCore.QMetaObject.invokeMethod(self.downloader, "get_qualities",
QtCore.Qt.QueuedConnection,
QtCore.Q_ARG(str, video_url))
#QtCore.pyqtSlot(list)
def update_qualityes(self, types_of_video):
for t in types_of_video:
self.combo_quality.addItem(str(t), t)
self.btn_download.setDisabled(False)
#QtCore.pyqtSlot()
def download(self):
video_save = self.le_output.text()
d = self.combo_quality.currentData()
QtCore.QMetaObject.invokeMethod(self.downloader, "start_download",
QtCore.Qt.QueuedConnection,
QtCore.Q_ARG(object, d),
QtCore.Q_ARG(str, video_save))
self.update_disables(True)
def update_disables(self, state):
self.combo_quality.setDisabled(state)
self.btn_quality.setDisabled(state)
self.le_output.setDisabled(state)
self.le_url.setDisabled(state)
self.btn_download.setDisabled(not state)
class DownLoader(QtCore.QObject):
progressChanged = QtCore.pyqtSignal(int)
qualitiesChanged = QtCore.pyqtSignal(list)
finished = QtCore.pyqtSignal()
#QtCore.pyqtSlot(str)
def get_qualities(self, video_url):
pafy_video = pafy.new(video_url)
types_of_video = pafy_video.allstreams # videostreams
self.qualitiesChanged.emit(types_of_video)
#QtCore.pyqtSlot(object, str)
def start_download(self, d, filepath):
d.download(filepath=filepath, callback=self.callback)
def callback(self, total, recvd, ratio, rate, eta):
val = int(ratio * 100)
self.progressChanged.emit(val)
if val == 100:
self.finished.emit()
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.resize(320, 480)
w.show()
sys.exit(app.exec_())
with threading.Thread:
import pafy
import threading
from PyQt5 import QtCore, QtWidgets
class MainWindow(QtWidgets.QMainWindow):
qualitiesChanged = QtCore.pyqtSignal(list)
progressChanged = QtCore.pyqtSignal(int)
finished = QtCore.pyqtSignal()
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
central_widget = QtWidgets.QWidget()
self.setCentralWidget(central_widget)
self.le_url = QtWidgets.QLineEdit("https://www.youtube.com/watch?v=bMt47wvK6u0")
path = QtCore.QStandardPaths.writableLocation(QtCore.QStandardPaths.DownloadLocation)
self.le_output = QtWidgets.QLineEdit(path)
self.btn_quality = QtWidgets.QPushButton("Get qualities")
self.combo_quality = QtWidgets.QComboBox()
self.btn_download = QtWidgets.QPushButton("Download")
self.progressbar = QtWidgets.QProgressBar(maximum=100)
self.btn_quality.clicked.connect(self.on_clicked_quality)
self.btn_download.clicked.connect(self.download)
self.btn_download.setDisabled(True)
self.progressChanged.connect(self.progressbar.setValue)
self.qualitiesChanged.connect(self.update_qualityes)
self.finished.connect(self.on_finished)
form_lay = QtWidgets.QFormLayout(central_widget)
form_lay.addRow("Url: ", self.le_url)
form_lay.addRow(self.btn_quality)
form_lay.addRow("qualities: ", self.combo_quality)
form_lay.addRow("Output: ", self.le_output)
form_lay.addRow(self.btn_download)
form_lay.addRow(self.progressbar)
#QtCore.pyqtSlot()
def on_finished(self):
self.update_disables(False)
#QtCore.pyqtSlot()
def on_clicked_quality(self):
video_url = self.le_url.text()
threading.Thread(target=self.get_qualities, args=(video_url,)).start()
def get_qualities(self, video_url):
pafy_video = pafy.new(video_url)
types_of_video = pafy_video.allstreams # videostreams
self.qualitiesChanged.emit(types_of_video)
#QtCore.pyqtSlot(list)
def update_qualityes(self, types_of_video):
for t in types_of_video:
self.combo_quality.addItem(str(t), t)
self.btn_download.setDisabled(False)
#QtCore.pyqtSlot()
def download(self):
video_save = self.le_output.text()
d = self.combo_quality.currentData()
threading.Thread(target=d.download, kwargs={'filepath': video_save, 'callback': self.callback}, daemon=True).start()
def callback(self, total, recvd, ratio, rate, eta):
print(ratio)
val = int(ratio * 100)
self.progressChanged.emit(val)
if val == 100:
self.finished.emit()
def update_disables(self, state):
self.combo_quality.setDisabled(state)
self.btn_quality.setDisabled(state)
self.le_output.setDisabled(state)
self.le_url.setDisabled(state)
self.btn_download.setDisabled(not state)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.resize(320, 480)
w.show()
sys.exit(app.exec_())

Get GUI element value from QThread

How can a QThread get text from a QLineEdit?
i tried self.t.updateSignal.connect(self.inputedittext.text) to get the QLineEdit value, but I get an error:
TypeError: unsupported operand type(s) for +=:
PyQt4.QtCore.pyqtBoundSignal' and 'int'
or I get the message:
bound signal updateSignal of xxxxxx at 0x02624580
Code:
import sys
import time
from PyQt4 import QtGui, QtCore
class mc(QtGui.QWidget):
def __init__(self):
super(mc,self).__init__()
self.initUI()
def initUI(self):
self.setWindowTitle('QThread')
self.inputedittext = QtGui.QLineEdit()
self.startbutton = QtGui.QPushButton('start')
self.stopbutton = QtGui.QPushButton('stop')
self.textlable = QtGui.QLabel('0')
lv1 = QtGui.QVBoxLayout()
lb1 = QtGui.QHBoxLayout()
lb1.addWidget(self.inputedittext)
lb1.addWidget(self.startbutton)
lb1.addWidget(self.stopbutton)
lb2 = QtGui.QHBoxLayout()
lb2.addWidget(self.textlable)
lv1.addLayout(lb1)
lv1.addLayout(lb2)
self.setLayout(lv1)
self.t = test_QThread()
self.t.updateSignal.connect(self.inputedittext.text)
self.startbutton.clicked.connect(self.start_t)
self.connect(self.t,QtCore.SIGNAL('ri'),self.setlable)
def setlable(self,i):
self.textlable.setText(i)
def start_t(self):
self.t.start()
# print(self.inputedittext.text())
class test_QThread(QtCore.QThread):
updateSignal = QtCore.pyqtSignal(QtCore.QString)
def __init__(self):
QtCore.QThread.__init__(self)
def run(self):
i = self.updateSignal
# i=0
go = True
while go:
i+=1
time.sleep(1)
self.emit(QtCore.SIGNAL('ri'),str(i))
print('run...')
def main():
app = QtGui.QApplication(sys.argv)
mw = mc()
mw.show()
app.exec_()
if __name__ == '__main__':
main()
Use signals to communicate from thread to gui, and from gui to thread:
class mc(QtGui.QWidget):
...
def initUI(self):
...
self.t = test_QThread()
self.t.progressSignal.connect(self.setlable)
self.t.requestSignal.connect(self.sendText)
self.startbutton.clicked.connect(self.start_t)
self.stopbutton.clicked.connect(self.stop_t)
def sendText(self):
self.t.updateSignal.emit(self.inputedittext.text())
def setlable(self, i):
self.textlable.setText(str(i))
def start_t(self):
self.t.start()
def stop_t(self):
self.t.stop()
class test_QThread(QtCore.QThread):
requestSignal = QtCore.pyqtSignal()
updateSignal = QtCore.pyqtSignal(str)
progressSignal = QtCore.pyqtSignal(int)
def __init__(self, parent=None):
super(test_QThread, self).__init__(parent)
self.updateSignal.connect(self.updateSlot)
self._running = False
self._count = 0
def updateSlot(self, text):
print 'received: "%s", count: %d' % (text, self._count)
def stop(self):
self._running = False
def run(self):
self._count = 0
self._running = True
while self._running:
self._count += 1
time.sleep(1)
self.progressSignal.emit(self._count)
if self._count % 3 == 0:
self.requestSignal.emit()

Run 2 loop at the same time 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.

Categories