I am coding a Python program using PyQT that will collect a list of files from folders in an SD card and let me view the photo and video files so I choose if I want to save any to more permanent storage. The process to read the directory of files can be slow based on the speed of the SD card, the number of files on the card, and the fact I want the length of each video. I want to display a progress dialog before putting up the MainWindow. In this dialog will be a couple of labels and a progress bar I will update as the files are collected for processing.
I am using QT Designer to create 'UI' files of the MainWindow and the dialog.
I've attempted to instantiate the dialog from the init function of the MainWindow and from inside the function that collects the files in the folders. In either case, when I '.exec()' the dialog, I do not see it until the function has completed and just before the MainWindow starts. When it does appear, the dialog shows the last text I set for the labels and has not updated the progress bar.
I have also tried to 'show' the dialog and get only a black box with none of the 3 widgets showing.
I've also tried putting the function to collect the filenames from the folders in the dialog with the same results.
The code pasted below is a skeleton of the working program (without any progress dialog) - I stripped out the other functions that don't relate to this issue.
Any pointers to help me accomplish this?
Many thanks!
#!/usr/bin/python3
Program_Version = "DEMO"
# Imports
import getopt
import sys
import os
import time
import subprocess
from datetime import datetime
from dateutil import tz
from ffprobe import FFProbe
import shutil
# GUI imports
from PyQt5 import QtWidgets, uic
from PyQt5.QtCore import Qt, QSize, QUrl
from PyQt5.QtGui import QPixmap
from PyQt5.QtMultimedia import QMediaContent, QMediaPlayer
from PyQt5.QtMultimediaWidgets import QVideoWidget
from PyQt5.QtWidgets import (QLabel, QVBoxLayout, QHBoxLayout, QWidget, QDialog,
QCheckBox, QStatusBar, QMessageBox, QSlider,
QPushButton, QShortcut, QProgressBar, qApp)
from PyQt5.uic import loadUi
# Arguments: 0=Program name,
# 0=-t/T/test/Test <use testing folder>
# Globals
# Target folder name when copying files
target_folder_name = ""
# SD Card device & folder name @ system level
SDCard_Dev = ""
SDCard_Dir = ""
# File & set Counters
sets_found = 0
sets_deleted = 0
sets_active = 0
#NotDeleted_set_list = []
files_found = 0
files_saved = 0
files_deleted = 0
# Open Progress Dialog
Ui_ProgressDialog, QtBaseClass = uic.loadUiType("ProgressDialog.ui")
class ProgressDialog(QDialog, Ui_ProgressDialog):
def __init__(self, parent=None):
# QT Initialization of dialog
QDialog.__init__(self, parent=None)
Ui_ProgressDialog.__init__(self)
self.setupUi(self)
print("ProgressDialog: Inside it")
# Open front page window
Ui_MainWindow, QtBaseClass = uic.loadUiType("SDCardViewer_V2.ui")
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self):
# QT Initialization of main window
QtWidgets.QMainWindow.__init__(self)
Ui_MainWindow.__init__(self)
self.setupUi(self)
print("MainWindow: Inside it")
# Set title
self.Title_label.setText("Trail Camera SD Card Photo & Video Manager "+Program_Version)
# Run the progress loading dialog
Progress_Dialog = ProgressDialog()
#Progress_Dialog.exec() # Opens after the function completes
Progress_Dialog.show() # Opens dialog with no widgets (black screen)
Progress_Dialog.setModal(Qt.WindowModal)
Progress_Dialog.setWindowTitle("Loading Sets and Files")
Progress_Dialog.Progress_bar.setValue(0)
# Get files from SD Card
self.get_SDFiles()
Progress_Dialog.destroy()
def closeEvent(self, event):
event.accept()
self.close()
# Functions
# Find and organize files of JPG and AVIs into 'sets' - photos taken prior to a video
def get_SDFiles(self):
# A set is collection of files consisting of photos and a video
jpg_file_count = 0
avi_file_count = 0
SDCard_folder_count = 0
SDCard_folders = []
SDCard_filesets = [[]]
sets_found = 0
SDCard_Dev = "/home"
SDCard_Dir = "/home/dave/TrailCamera_Test/DCIM"
file_set_new = False
# Capture time we start to process files
start_time = datetime.now()
# Calculate used space on source (SD Card)
st = os.statvfs(SDCard_Dev)
total = (st.f_blocks * st.f_frsize)
used = (st.f_blocks - st.f_bfree) * st.f_frsize
try:
pct_used = (float(used) / total) * 100
except ZeroDivisionError:
pct_used = 0
# Collect folders on SD Card under DCIM folder
for item in os.scandir(SDCard_Dir):
if item.is_dir():
SDCard_folders.append(item.name)
SDCard_folders.sort()
# Organize into sets across all folders
for item in SDCard_folders:
full_folder_name = os.path.join(SDCard_Dir, item)
SDCard_files = os.listdir(full_folder_name)
SDCard_folder_count += 1
print("get_SDFiles: Open Folder '{}' with {} files".format(item, len(SDCard_files)))
SDCard_files.sort()
progress_file_counter = 0
for file_name in SDCard_files:
time.sleep(.1)
progress_file_counter += 1
if progress_file_counter % 25 == 0:
print("get_SDFiles: Processed {} files {}%"
.format(progress_file_counter,int(100*progress_file_counter/len(SDCard_files))))
full_file_name = os.path.join(full_folder_name, file_name)
if file_name.lower().endswith(".jpg"):
jpg_file_count += 1
if file_set_new:
SDCard_filesets.append([full_file_name])
file_set_new = False
else:
SDCard_filesets[sets_found].append(full_file_name)
elif file_name.lower().endswith(".avi"):
#filesize = (float(os.path.getsize(full_file_name)))/(1024*1024)
#AVI_length = self.getVideoTime(full_file_name)
avi_file_count += 1
if file_set_new:
SDCard_filesets.append([full_file_name])
else:
SDCard_filesets[sets_found].append(full_file_name)
sets_found += 1
file_set_new = True
files_found = jpg_file_count + avi_file_count
# Capture time we stopped processing files
stop_time = datetime.now()
elapsed_time = (stop_time - start_time)
print("get_SDFiles: Elapsed time to read files was {} (h:mm:ss)".format(elapsed_time))
if sets_found == 0:
self.show_messagebox("Information","No files found. Program closing")
self.close()
else:
print("get_SDFiles: Found a total of {} files".format(files_found))
self.SDCardCounts_label.setText("{} ({:.0f}% Used) -- Folders: {:d} -- Files: {:,d} (JPGs: {:,d}, AVIs: {:,d})"
.format(SDCard_Dev, pct_used, SDCard_folder_count, files_found,
jpg_file_count, avi_file_count))
max_set_pointer = len(SDCard_filesets)-1
# Get length of the video
def getVideoTime(self,clip_file):
return(int(float(FFProbe(clip_file).streams[0].duration)))
# Start the main window
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
print("__main__: Instantiate MainWindow")
window = MainWindow()
print("__main__: Show MainWindow")
window.show()
sys.exit(app.exec_())