I've got a Error like this:
QObject::startTimer: Timers can only be used with threads started with QThread
My Whole Code:
from PyQt5.QtWidgets import *
from newCode import mp3Download
from PyQt5.QtCore import QTimer,QThread
from threading import Thread
import sys
class ListDownload(QWidget):
def __init__(self,path):
super().__init__()
self.path = path
self.time = 100
self.initUI()
def initUI(self):
self.VerticalLayout = QVBoxLayout()
self.SeasonOfWitch = QLabel()
self.SeasonOfWitch.setText("Enter the URLs : ")
self.URLs = QTextEdit()
self.URLs.setText("""enter the addresses in the here .a row for each url.
Delete this message before entering the URLs.""")
self.horizontalControlLayout = QHBoxLayout()
self.download = QPushButton("Download")
self.download.clicked.connect(self.videoDownload)
self.Cancel = QPushButton("Cancel")
self.Cancel.clicked.connect(self.cancelFunc)
self.horizontalControlLayout.addWidget(self.download)
self.horizontalControlLayout.addWidget(self.Cancel)
self.VerticalLayout.addWidget(self.SeasonOfWitch)
self.VerticalLayout.addWidget(self.URLs)
self.VerticalLayout.addLayout(self.horizontalControlLayout)
self.setLayout(self.VerticalLayout)
def cancelFunc(self):
self.close()
def videoDownload(self):
self.urlList = self.URLs.toPlainText().split("\n")
row = 1
errorList = list()
for url in self.urlList:
if 'www.youtube.com' in url.split("/") and (url.startswith("https://") or url.startswith("http://")):
row+=1
else:
errorList.append(row)
row+=1
decrease = 0#Each element deleting index changes the lenght of the list.Cause of that.
for row in errorList:
self.urlList.pop(row-1-decrease)
decrease += 1
messageObj = Thread(target=self.messageAnimation,name="message")
downloadObj = Thread(target=self.downloadFunc,name="download")
messageObj.start()
downloadObj.start()
while not(downloadObj.is_alive()):
messageObj._stop()
def downloadFunc(self):
mp3Download(self.urlList,self.path)
def messageAnimation(self):
def timerFunc():
self.animatedMessageFunc("Downloading ....")
self.timer = QTimer()
self.timer.timeout.connect(timerFunc)
self.timer.start(1000)
def remove_widget(self,layout,widget_name):
layout.removeWidget(widget_name)
widget_name.deleteLater()
widget_name = None
def animatedMessageFunc(self,message):
animatedMessage = message
self.URLs.clear()
iterator = iter(range(len(animatedMessage)))
for i in range(len(animatedMessage)):
QTimer.singleShot(self.time,lambda :self.URLs.setText(self.URLs.toPlainText()+animatedMessage[next(iterator)]))
self.time += 50
self.time = 100
Problem is the Timers. In animatedMessageFunc()
. I want to start two function
in same time.I use Thread
class from threading
module. I want it because
when self.downloadFunc()
ends I need to stop the self.messageAnimation()
function. I try to use QThread instead Thread. But I can't figure it out how do I use this class.There is errors as mine.But that errors in java or some other language.I can't find my solution in that questions.
It is not necessary that the timer is in another thread, it is enough to start when the thread starts and stop it when the thread ends its task, for this we create 2 signals: started
and finished
that will be emitted before and after calling mp3Download()
function, respectively.
import sys
from itertools import cycle
from threading import Thread
from PyQt5 import QtCore, QtGui, QtWidgets
from newCode import mp3Download
class ListDownload(QtWidgets.QWidget):
started = QtCore.pyqtSignal()
finished = QtCore.pyqtSignal()
def __init__(self, path):
super().__init__()
self.path = path
self.initUI()
def initUI(self):
VerticalLayout = QtWidgets.QVBoxLayout(self)
SeasonOfWitch = QtWidgets.QLabel("Enter the URLs : ")
self.URLs = QtWidgets.QTextEdit()
self.URLs.setText("""enter the addresses in the here .a row for each url.
Delete this message before entering the URLs.""")
horizontalControlLayout = QtWidgets.QHBoxLayout()
download = QtWidgets.QPushButton("Download")
download.clicked.connect(self.videoDownload)
Cancel = QtWidgets.QPushButton("Cancel")
Cancel.clicked.connect(self.close)
horizontalControlLayout.addWidget(download)
horizontalControlLayout.addWidget(Cancel)
VerticalLayout.addWidget(SeasonOfWitch)
VerticalLayout.addWidget(self.URLs)
VerticalLayout.addLayout(horizontalControlLayout)
self.started.connect(self.messageAnimation)
def videoDownload(self):
lines = self.URLs.toPlainText().split("\n")
urls = []
for line in lines:
if 'www.youtube.com' in line.split("/") and (line.startswith("https://") or line.startswith("http://")):
urls.append(line)
if urls:
Thread(target=self.downloadFunc, args=(urls,), name="download", daemon=True).start()
def downloadFunc(self, urls):
self.started.emit()
mp3Download(urls, self.path)
self.finished.emit()
def messageAnimation(self):
self.URLs.clear()
text = "Downloading ...."
timer = QtCore.QTimer(self, interval=50)
it = cycle(text+"\n")
timer.timeout.connect(lambda: self.appendLetter(next(it)))
timer.start()
self.finished.connect(timer.stop)
self.finished.connect(self.URLs.clear)
def appendLetter(self, letter):
if letter == "\n":
self.URLs.clear()
else:
self.URLs.moveCursor(QtGui.QTextCursor.End)
self.URLs.insertPlainText(letter)
self.URLs.moveCursor(QtGui.QTextCursor.End)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
path = QtCore.QStandardPaths.writableLocation(QtCore.QStandardPaths.DownloadLocation)
w = ListDownload(path)
w.show()
sys.exit(app.exec_())