如何解决在激活 QT MainWindow 之前运行 PYQT 对话框
我正在使用 PyQT 编写 Python 程序,该程序将从 SD 卡中的文件夹中收集文件列表,并让我查看照片和视频文件,因此我选择是否要将任何文件保存到更永久的存储中。根据 SD 卡的速度、卡上的文件数量以及我想要每个视频的长度,读取文件目录的过程可能会很慢。我想在设置 MainWindow 之前显示一个进度对话框。在此对话框中将有几个标签和一个进度条,我将在收集文件进行处理时进行更新。
我正在使用 QT Designer 创建 MainWindow 和对话框的“UI”文件。
我试图从 MainWindow 的 init 函数和收集文件夹中文件的函数内部实例化对话框。在任何一种情况下,当我使用“.exec()”对话框时,在函数完成之前和 MainWindow 启动之前我都看不到它。当它出现时,对话框会显示我为标签设置的最后一个文本,并且没有更新进度条。
我还尝试“显示”对话框,只得到一个黑框,没有显示 3 个小部件。
我还尝试使用函数从对话框中的文件夹中收集文件名,结果相同。
下面粘贴的代码是工作程序的框架(没有任何进度对话框) - 我去掉了与此问题无关的其他功能。
是否有任何指示可以帮助我完成此操作?
非常感谢!
#!/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_())
解决方法
最好将逻辑与扫描和 GUI 分开,以便我们更好地处理流程。这个想法是在第二个线程中运行扫描并通过信号将信息发送到 GUI。所以我们可以创建一个 QDialog 来显示进度,当用户按下接受按钮时,将显示主窗口。下面的例子试图展示一般的过程(不要实现所有的计算,比如 SDCard_filesets、sets_found 因为我不明白他们的逻辑)
from datetime import datetime
import os.path
import sys
import threading
import time
from PyQt5.QtCore import pyqtSignal,pyqtSlot,QObject,Qt
from PyQt5.QtWidgets import (
QApplication,QDialog,QDialogButtonBox,QLabel,QMainWindow,QProgressBar,QVBoxLayout,)
class SDCardScanner(QObject):
started = pyqtSignal()
filesProcessed = pyqtSignal(int,int)
directoriesProcessed = pyqtSignal(int,int)
finished = pyqtSignal(str,float,int,int)
def start(self,dev,directory):
threading.Thread(
target=self._execute,args=(dev,directory),daemon=True
).start()
def _execute(self,directory):
self.started.emit()
jpg_file_count = 0
avi_file_count = 0
files_found = 0
directories = []
start_time = datetime.now()
st = os.statvfs(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
for item in os.scandir(directory):
if item.is_dir():
directories.append(item.name)
# SDCard_folders.sort()
total_directories = len(directories)
# Organize into sets across all folders
for i,item in enumerate(directories,start=1):
full_folder_name = os.path.join(directory,item)
files = os.listdir(full_folder_name)
files.sort()
total_files = len(files)
for j,file_name in enumerate(files,start=1):
time.sleep(0.1)
self.filesProcessed.emit(j,total_files)
full_file_name = os.path.join(full_folder_name,file_name)
if file_name.endswith(".jpg"):
jpg_file_count += 1
elif file_name.endswith(".avi"):
avi_file_count += 1
self.directoriesProcessed.emit(i,total_directories)
stop_time = datetime.now()
elapsed_time = stop_time - start_time
files_found = jpg_file_count + avi_file_count
self.finished.emit(
dev,pct_used,elapsed_time,i,jpg_file_count,avi_file_count,files_found
)
class ProgressBarDialog(QDialog):
def __init__(self,parent=None):
super().__init__(parent)
self.setWindowTitle("Loading Sets and Files")
self.directories_progressbar = QProgressBar(format="%v of %m")
self.files_progressbar = QProgressBar(format="%v of %m")
button_box = QDialogButtonBox()
button_box.setOrientation(Qt.Horizontal)
button_box.setStandardButtons(QDialogButtonBox.Cancel | QDialogButtonBox.Ok)
button_box.accepted.connect(self.accept)
button_box.rejected.connect(self.reject)
lay = QVBoxLayout(self)
lay.addWidget(QLabel("Directories processed:"))
lay.addWidget(self.directories_progressbar)
lay.addWidget(QLabel("Files processed:"))
lay.addWidget(self.files_progressbar)
lay.addWidget(button_box)
self.setMaximumHeight(self.sizeHint().height())
self.resize(400,self.height())
@pyqtSlot(int,int)
def update_directories_processed(self,progress,maximum):
self.directories_progressbar.setMaximum(maximum)
self.directories_progressbar.setValue(progress)
@pyqtSlot(int,int)
def update_files_processed(self,maximum):
self.files_progressbar.setMaximum(maximum)
self.files_progressbar.setValue(progress)
class MainWindow(QMainWindow):
def __init__(self,parent=None):
super().__init__(parent)
self.SDCardCounts_label = QLabel()
self.setCentralWidget(self.SDCardCounts_label)
self.resize(640,480)
@pyqtSlot(str,int)
def show_scanner_data(
self,folder_count,files_found,):
self.SDCardCounts_label.setText(
"{} ({:.0f}% Used) -- Folders: {:d} -- Files: {:,d} (JPGs: {:,d},AVIs: {:,d})".format(
dev,)
)
def main():
app = QApplication(sys.argv)
w = MainWindow()
progressdialog = ProgressBarDialog()
scanner = SDCardScanner()
scanner.directoriesProcessed.connect(progressdialog.update_directories_processed)
scanner.filesProcessed.connect(progressdialog.update_files_processed)
scanner.start("/home","/home/dave/TrailCamera_Test/DCIM")
scanner.finished.connect(w.show_scanner_data)
if progressdialog.exec_() == QDialog.Accepted:
w.show()
else:
sys.exit(0)
ret = app.exec_()
sys.exit(ret)
if __name__ == "__main__":
main()
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。