I am writing a part of a basic FFmpeg GUI application, and this is the installation code.
While setting install_progress_bar from the 'download_thread' the terminal is spammed with QObject::setParent: Cannot set parent, new parent is in a different thread. When in the 'install_thread', the terminal is spammed with QBackingStore::endPaint() called with active painter; did you forget to destroy it or call QPainter::end() on it? so I'm obviously doing something wrong. After some googling, I still cannot figure out what I'm doing wrong. Any help?
The functions in question: (any bad formatting is due to copy and pasting, sorry about that.)
def download_thread(self):
HEADERS = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"}
size = 0
with requests.get("https://www.gyan.dev/ffmpeg/builds/ffmpeg-release-essentials.zip", headers = HEADERS, stream = True) as r: // this is not on a seperate line in the actual code
r.raise_for_status()
total_size = int(r.headers.get("content-length", 0))
with open("ffmpeg.zip", "wb") as f:
for chunk in r.iter_content(chunk_size = 8192):
size = size + f.write(chunk)
self.install_progress_bar.setValue(int(size / total_size * 100))
if threading.main_thread().is_alive() == False:
os.remove("ffmpeg.zip")
break
return 0
and
def install_thread(self):
self.zipFile = zipfile.ZipFile("ffmpeg.zip")
os.mkdir("ffmpegt/")
for member in self.zipFile.infolist():
self.install_progress_bar.setValue(self.install_progress_bar.value() + 1)
self.zipFile.extract(member, "ffmpegt/")
if threading.main_thread().is_alive() == False:
os.remove("ffmpeg.zip")
os.remove("ffmpegt/")
break
self.install_progress_bar.setValue(100)
return 0
The rest of the code is as follows:
import sys
import os
import subprocess
import requests
from time import sleep
from threading import Thread
import threading
from PyQt6.QtCore import Qt
from PyQt6.QtWidgets import QApplication, QMainWindow, QWidget, QLabel, QGridLayout, QVBoxLayout, QHBoxLayout, QPushButton, QFileDialog, QMessageBox, QProgressBar, QDialog, QDialogButtonBox
from PyQt6.QtGui import QPalette, QColor
import zipfile
with open("stylesheet.qss", "r") as stylesheet:
dark_stylesheet = stylesheet.read()
with open("stylesheet_bright.qss", "r") as stylesheet:
light_stylesheet = stylesheet.read()
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.setWindowTitle("FFmpeg check")
self.setGeometry(100, 100, 500, 100)
self.label = QLabel("Checking if you have FFmpeg installed...", alignment=Qt.AlignmentFlag.AlignCenter)
self.install_progress_bar = QProgressBar()
self.install_yes_button = QPushButton("Yes")
self.install_no_button = QPushButton("No")
self.install_yes_button.clicked.connect(self.install_yes)
self.install_no_button.clicked.connect(self.install_no)
self.container = QWidget()
self.Vlayout = QVBoxLayout()
self.Vlayout.addWidget(self.label)
self.PlaceholderLayout = QHBoxLayout()
self.Vlayout.addLayout(self.PlaceholderLayout)
self.Hlayout = QHBoxLayout()
self.Vlayout.addLayout(self.Hlayout)
self.container.setLayout(self.Vlayout)
self.setCentralWidget(self.container)
try:
process = subprocess.Popen(["FFmeg", "-version"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
output, error = process.communicate()
output = output.decode("utf-8")
error = error.decode("utf-8")
except FileNotFoundError:
output = ""
error = ""
if "ffmpeg version" in output:
self.label.setText("FFmpeg is installed.")
else:
self.label.setText("FFmpeg is not installed. Do you want to install it?")
self.Hlayout.addWidget(self.install_yes_button)
self.Hlayout.addWidget(self.install_no_button)
def install_yes(self, event):
self.PlaceholderLayout.addWidget(self.install_progress_bar)
self.install_progress_bar.setValue(0)
self.install_progress_bar.setMaximum(100)
self.install_progress_bar.setTextVisible(True)
self.install_progress_bar.setFormat("Downloading... %p%")
self.install_progress_bar.setAlignment(Qt.AlignmentFlag.AlignCenter)
self.install_progress_bar.setContentsMargins(0, 0, 0, 0)
self.label.setText("FFmpeg is downloading...")
download = Thread(target=self.download_thread)
sleep(0.5)
download.start()
while download.is_alive():
app.processEvents()
self.install_progress_bar.setFormat("Installing... %p%")
self.install_progress_bar.setValue(0)
self.label.setText("FFmpeg is installing...")
install = Thread(target=self.install_thread)
sleep(0.5)
install.start()
while install.is_alive():
app.processEvents()
self.label.setText("FFmpeg is installed.")
self.dialog = CustomDialog("FFmpeg is installed.")
self.dialog.exec()
return 0
def install_no(self, event):
app.quit()
def download_thread(self):
HEADERS = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"}
size = 0
with requests.get("https://www.gyan.dev/ffmpeg/builds/ffmpeg-release-essentials.zip", headers = HEADERS, stream = True) as r:
r.raise_for_status()
total_size = int(r.headers.get("content-length", 0))
with open("ffmpeg.zip", "wb") as f:
for chunk in r.iter_content(chunk_size = 8192):
size = size + f.write(chunk)
self.install_progress_bar.setValue(int(size / total_size * 100))
if threading.main_thread().is_alive() == False:
os.remove("ffmpeg.zip")
break
return 0
def install_thread(self):
self.zipFile = zipfile.ZipFile("ffmpeg.zip")
os.mkdir("ffmpegt/")
for member in self.zipFile.infolist():
self.install_progress_bar.setValue(self.install_progress_bar.value() + 1)
self.zipFile.extract(member, "ffmpegt/")
if threading.main_thread().is_alive() == False:
os.remove("ffmpeg.zip")
os.remove("ffmpegt/")
break
self.install_progress_bar.setValue(100)
return 0
class CustomDialog(QDialog):
def __init__(self, text, windowTitle = "Dialog", cancelable = True):
super().__init__()
self.setWindowTitle(windowTitle)
if cancelable == True:
QBtn = QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel
else:
QBtn = QDialogButtonBox.StandardButton.Ok
self.buttonBox = QDialogButtonBox(QBtn)
self.buttonBox.accepted.connect(self.accept)
self.buttonBox.rejected.connect(self.reject)
self.layout = QVBoxLayout()
message = QLabel(text)
self.layout.addWidget(message)
self.layout.addWidget(self.buttonBox)
self.setLayout(self.layout)
app = QApplication(sys.argv)
app.setStyleSheet(dark_stylesheet)
window = MainWindow()
window.show()
app.exec()
Please note the the code works, the progressbar updates as the download and the install completes, it's just that at a random point during this process the application crashes.
mainis running.queueto send message from one thread to main thread and main thread may use timer to check if there is new message and updatePostgressBar