在激活 QT MainWindow 之前运行 PYQT 对话框

如何解决在激活 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 举报,一经查实,本站将立刻删除。

相关推荐


使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-
参考1 参考2 解决方案 # 点击安装源 协议选择 http:// 路径填写 mirrors.aliyun.com/centos/8.3.2011/BaseOS/x86_64/os URL类型 软件库URL 其他路径 # 版本 7 mirrors.aliyun.com/centos/7/os/x86
报错1 [root@slave1 data_mocker]# kafka-console-consumer.sh --bootstrap-server slave1:9092 --topic topic_db [2023-12-19 18:31:12,770] WARN [Consumer clie
错误1 # 重写数据 hive (edu)&gt; insert overwrite table dwd_trade_cart_add_inc &gt; select data.id, &gt; data.user_id, &gt; data.course_id, &gt; date_format(
错误1 hive (edu)&gt; insert into huanhuan values(1,&#39;haoge&#39;); Query ID = root_20240110071417_fe1517ad-3607-41f4-bdcf-d00b98ac443e Total jobs = 1
报错1:执行到如下就不执行了,没有显示Successfully registered new MBean. [root@slave1 bin]# /usr/local/software/flume-1.9.0/bin/flume-ng agent -n a1 -c /usr/local/softwa
虚拟及没有启动任何服务器查看jps会显示jps,如果没有显示任何东西 [root@slave2 ~]# jps 9647 Jps 解决方案 # 进入/tmp查看 [root@slave1 dfs]# cd /tmp [root@slave1 tmp]# ll 总用量 48 drwxr-xr-x. 2
报错1 hive&gt; show databases; OK Failed with exception java.io.IOException:java.lang.RuntimeException: Error in configuring object Time taken: 0.474 se
报错1 [root@localhost ~]# vim -bash: vim: 未找到命令 安装vim yum -y install vim* # 查看是否安装成功 [root@hadoop01 hadoop]# rpm -qa |grep vim vim-X11-7.4.629-8.el7_9.x
修改hadoop配置 vi /usr/local/software/hadoop-2.9.2/etc/hadoop/yarn-site.xml # 添加如下 &lt;configuration&gt; &lt;property&gt; &lt;name&gt;yarn.nodemanager.res