Créer un outil de changement de nom de fichier en masse avec Python et PyQt – Real Python

By | mai 19, 2021

Formation Python

Supposons que vous deviez renommer plusieurs fichiers dans votre dossier personnel en utilisant un modèle de dénomination spécifique. Faire cela manuellement peut être long et source d'erreurs. Vous envisagez donc d'automatiser le processus de changement de nom de fichier en créant votre propre outil de changement de nom de fichier en bloc en utilisant Python. Si tel est le cas, ce tutoriel est pour vous.

Dans ce didacticiel, vous apprendrez à:

  • Créez l'interface graphique pour un outil de changement de nom de fichier en bloc à l'aide de Concepteur Qt et PyQt
  • Utiliser Fils PyQt pour décharger le processus de changement de nom de fichier et empêcher le gel des interfaces graphiques
  • Utiliser pathlib pour gérer les chemins système et renommer les fichiers
  • Mettre à jour le État de l'interface graphique selon le processus de changement de nom

En terminant le projet de ce didacticiel, vous serez en mesure d'appliquer un riche ensemble de compétences liées à PyQt, Qt Designer, les threads PyQt et à travailler avec des chemins de système de fichiers à l'aide de Python. pathlib.

Vous pouvez télécharger le code source final de l'outil de changement de nom de fichier en bloc que vous allez créer dans ce didacticiel en cliquant sur le lien ci-dessous:

Démo: outil de changement de nom de fichier en masse avec Python et PyQt

Dans ce didacticiel, vous allez créer un outil de changement de nom de fichier en bloc pour automatiser le processus de changement de nom de plusieurs fichiers dans un répertoire donné de votre système de fichiers. Pour créer cette application, vous utiliserez Python pathlib pour gérer le processus de changement de nom de fichier et PyQt pour créer l'interface utilisateur graphique (GUI) de l'application.

Voici à quoi ressemblera votre outil de changement de nom de fichiers en bloc et fonctionnera une fois que vous aurez atteint la fin de ce didacticiel:

Une fois la création de l'application terminée, vous pourrez renommer plusieurs fichiers dans votre système de fichiers, une tâche courante lorsque vous organisez vos fichiers et dossiers personnels. Dans cet exemple, l'application se concentre sur les images et les fichiers Python, mais vous pouvez ajouter d'autres types de fichiers au fur et à mesure.

Aperçu du projet

Le projet que vous allez créer dans ce didacticiel consiste en une application d'interface graphique qui charge plusieurs fichiers à partir d'un répertoire donné et vous permet de renommer tous ces fichiers en une seule fois en utilisant un préfixe de nom de fichier prédéfini et des nombres consécutifs. Dans cette section, vous allez jeter un premier regard sur le problème et une solution possible. Vous découvrirez également comment mettre en page le projet.

Présentation du projet

Pour créer votre outil de changement de nom de fichier en bloc, vous allez créer quelques modules et packages et les organiser dans une présentation d'application Python cohérente. Le répertoire racine de votre projet ressemblera à ceci:

./rprename_project/
│
├── rprename /
│ │
│ ├── ui /
│ │ ├── __init__.py
│ │ ├── window.py
│ │ └── window.ui
│ │
│ ├── __init__.py
│ ├── app.py
│ ├── rename.py
│ └── views.py
│
├── LISEZMOI.md
├── requirements.txt
└── rprenamer.py

Ici, rprename_project / est le répertoire racine du projet, dans lequel vous allez créer les fichiers suivants:

  • LISEZMOI.md fournit une description générale du projet et des instructions sur l'installation et l'exécution de l'application. Avoir un LISEZMOI.md fichier pour votre projet est considéré comme une bonne pratique en matière de programmation, en particulier si vous prévoyez de le publier en tant que solution open source.
  • requirements.txt fournit la liste des dépendances externes pour le projet.
  • rprenamer.py fournit un script de point d'entrée pour exécuter l'application.

Ensuite, vous avez le rprename / répertoire qui contiendra un package Python avec les modules suivants:

  • __init__.py permet rprename / en tant que package Python.
  • app.py fournit l'application squelette PyQt.
  • rename.py fournit les fonctionnalités de changement de nom de fichier.
  • views.py fournit l'interface graphique de l'application et les fonctionnalités associées.

le ui / Le sous-répertoire fournira un package pour stocker le code lié à l'interface graphique. Il contiendra les fichiers et modules suivants:

  • __init__.py permet ui / en tant que package Python.
  • window.py contient le code Python de la fenêtre principale de l'application. Vous verrez comment générer ce fichier à l'aide de pyuic5.
  • window.ui contient un fichier Qt Designer contenant le code de la fenêtre principale de l'application dans XML format.

Allez-y et créez cette structure de répertoires avec tous les fichiers et modules sauf pour window.ui et window.py. Vous verrez comment créer ces deux fichiers avec Qt Designer et pyuic5 plus loin dans ce didacticiel.

Pour télécharger la structure de répertoires du projet, cliquez sur le lien ci-dessous:

Présentation de la solution

Votre outil de changement de nom de fichier en bloc sera une application d'interface graphique entièrement fonctionnelle. Il vous permettra de charger plusieurs fichiers à partir d’un répertoire existant et de les renommer à l’aide d’un préfixe de nom de fichier descriptif et de numéros consécutifs. Pour créer l'application, vous devez suivre les étapes suivantes:

  1. Créez l'interface graphique de l'application.
  2. Fournit la fonctionnalité pour charger et renommer plusieurs fichiers.
  3. Mettez à jour l'interface graphique de l'application en fonction de la progression du processus de changement de nom de fichier.

Pour créer l'interface graphique de l'application, vous utiliserez Qt Designer. Cet outil fournit une interface conviviale pour créer des interfaces graphiques en faisant glisser et déposer des composants graphiques (widgets) sur un formulaire vierge. Avec cet outil, votre processus de création d'interface graphique sera rapide et productif.

En ce qui concerne la gestion des fichiers et des répertoires en Python, vous avez plusieurs options dans la bibliothèque standard. Par exemple, vous avez os.path pour travailler avec les chemins du système de fichiers et os pour utiliser les fonctionnalités du système d'exploitation, comme renommer des fichiers avec os.rename (). Dans ce didacticiel, cependant, vous utiliserez pathlib pour les deux tâches.

En règle générale, vous utiliserez pathlib.Path pour gérer les chemins de fichiers et de répertoires dans vos applications. Une fois que vous avez un Chemin objet qui pointe vers un fichier ou un répertoire physique, vous pouvez appeler .Renommer() sur cet objet pour renommer le fichier ou le répertoire associé.

Ensuite, vous devez coder la fonctionnalité pour charger plusieurs fichiers dans votre application et les renommer en une seule fois. Selon le nombre de fichiers à renommer, l'opération peut prendre un temps considérable. Cela peut entraîner le blocage de l'interface graphique de votre application. Pour éviter les problèmes de blocage de l'interface graphique, vous allez décharger le processus de changement de nom vers un thread de travail à l'aide de QThread.

Le processus de changement de nom de fichier doit être connecté à l'interface graphique de l'application afin que l'utilisateur sache ce qui se passe à tout moment. Dans cet exemple, vous allez configurer une barre de progression pour refléter la progression de l'opération.

Vous allez également écrire du code pour vous assurer que l'interface graphique est mise à jour en fonction de la progression et de l'état du changement de nom du fichier. Il existe au moins deux stratégies générales pour gérer la mise à jour de l'interface graphique:

  1. Utilisation d'instructions conditionnelles pour vérifier l'état et prendre des mesures en conséquence
  2. Activation et désactivation des widgets en fonction de l'état de l'application.

Dans ce projet, vous utiliserez la deuxième approche, qui peut être plus intuitive et plus conviviale, offrant une meilleure expérience utilisateur.

Conditions préalables

Pour terminer ce didacticiel et en tirer le meilleur parti, vous devez être à l'aise avec les concepts suivants:

  • Création d'applications GUI avec Python et PyQt
  • Utilisation de Qt Designer pour créer des interfaces graphiques
  • Utilisation de PyQt QThread pour décharger les tâches de longue durée et empêcher le gel des interfaces graphiques
  • Utilisant pathlib pour gérer les chemins système et renommer les fichiers

Si vous n’avez pas toutes les connaissances requises, c’est pas grave! Vous pouvez démarrer le didacticiel et prendre le temps de passer en revue les ressources suivantes chaque fois que vous en avez besoin:

De plus, vous pouvez consulter les ressources suivantes:

En termes de dépendances logicielles externes, votre outil de changement de nom de fichier en bloc dépend de PyQt v5.15.12. Vous pouvez installer cette bibliothèque à partir de PyPI en utilisant pépin comme d'habitude:

$ python -m pip installer pyqt5

Enfin, vous devez créer un environnement virtuel pour isoler les dépendances de votre projet, comme le recommandent les meilleures pratiques Python. Après cela, il est temps de commencer à travailler sur votre propre outil de changement de nom de fichiers en masse!

Étape 1: créer l'interface graphique de l'outil de changement de nom de fichier en bloc

Dans cette section, vous allez utiliser Qt Designer pour créer rapidement l’interface graphique de l’outil de changement de nom de fichier en bloc. À la fin de cette étape, vous aurez un Qt Designer .ui fichier fournissant le code requis pour la fenêtre suivante:

Interface graphique de la fenêtre principale de l'outil de changement de nom de fichier en bloc

Vous apprendrez également à traduire automatiquement votre .ui fichier dans le code Python. Vous utiliserez ce code pour fournir l'interface graphique de la fenêtre principale de votre application.

Pour télécharger ces fichiers et tout le code que vous allez écrire dans cette section, cliquez sur le lien ci-dessous:

Création de l'interface graphique avec Qt Designer

Pour commencer à travailler sur l'interface graphique de votre outil de changement de nom de fichier en bloc, lancez Qt Designer. Puis créez un basé sur un widget formulaire et exécutez les étapes indiquées dans la vidéo suivante:

Voici les étapes de la vidéo ci-dessus:

  1. Créez un nouveau formulaire en utilisant le Widget modèle du Nouvelle forme dialogue et définissez son titre sur Renamer RP.
  2. Ajoutez une étiquette et définissez son texte sur Dernier répertoire source:.
  3. Ajoutez une modification de ligne pour contenir le chemin d'accès au répertoire sélectionné et définir son .lecture seulement propriété à Vrai.
  4. Ajoutez un bouton poussoir et définissez son texte sur & Charger des fichiers.
  5. Ajouter deux étiquettes avec le texte Fichiers à renommer et Fichiers renommés, respectivement, et définissez leur style de police sur Audacieux.
  6. Ajoutez deux widgets de liste pour afficher respectivement les fichiers à renommer et les fichiers renommés.
  7. Définissez une disposition verticale pour les étiquettes et leurs widgets de liste correspondants.
  8. Joignez les deux arrangements à l'aide d'un séparateur.
  9. Ajoutez une étiquette et définissez son texte sur Préfixe de nom de fichier:.
  10. Ajoutez une modification de ligne pour prendre le préfixe de nom de fichier de l'utilisateur et définir son texte d'espace réservé sur Renommez vos fichiers en….
  11. Ajoutez une étiquette et définissez son texte sur .jpg.
  12. Ajoutez un bouton poussoir et définissez son texte sur &Renommer.
  13. Ajoutez une barre de progression et définissez sa valeur sur 0.
  14. Ajustez le minimumSize et taille maximum propriétés des étiquettes, des modifications de ligne et des boutons-poussoirs pour fournir un comportement de redimensionnement cohérent lorsque l'utilisateur redimensionne la fenêtre.
  15. Définissez une disposition de grille comme disposition de niveau supérieur du formulaire.

Une fois que vous avez terminé, enregistrez le formulaire sous window.ui sous le rprename / ui / annuaire. Ne fermez pas Qt Designer. Allez-y et changez le .objectName propriété pour les objets suivants:

Objet Valeur
Forme La fenêtre
ligneModifier dirEdit
bouton loadFilesButton
listWdget srcFileList
listWidget_2 dstFileList
lineEdit_2 préfixeModifier
label_5 extensionLabel
pushButton_2 renameFilesButton

Pour ce faire, vous pouvez sélectionner l'objet dans l'inspecteur d'objets et modifier la valeur de la propriété dans l'éditeur de propriétés:

Créer un fichier en masse Renommer Modifier les noms des objets Qt Designer

Vous devez modifier les noms des objets, car vous les utiliserez dans votre code Python, ils devraient donc être plus descriptifs et lisibles. Maintenant allez-y et cliquez Sauvegarder dans la barre d'outils de Qt Designer pour rendre les nouveaux noms d'objets persistants dans votre window.ui déposer. Vous pouvez également enregistrer le fichier en appuyant sur Ctrl+S sur votre clavier.

Une fois que vous avez terminé la création de l'interface graphique de l'outil de changement de nom de fichier en bloc, vous pouvez fermer Qt Designer car vous n'en aurez plus besoin. Ensuite, vous devez traduire le contenu du .ui fichier que vous venez de créer dans le code Python. C’est ce que vous ferez dans la section suivante.

Conversion de la sortie de Qt Designer en code Python

Une fois que vous avez un .ui avec une interface graphique adaptée à votre application, vous devez convertir le contenu de ce fichier en code Python afin de pouvoir charger l'interface graphique dans l'application finale. PyQt fournit un outil de ligne de commande appelé pyuic5 qui vous permet d'effectuer cette conversion.

Si vous regardez le contenu de votre window.ui fichier, vous verrez qu'il contient XML code. Ce code définit tous les composants graphiques de l'interface graphique de votre application. Voici un fragment du contenu du fichier:


<ui version ="4.0">
 La fenêtre
 <widget classe ="QWidget" nom ="La fenêtre">
  <propriété nom ="géométrie">
   
    0
    0
    720
    480
   
  
  <propriété nom ="windowTitle">
   Renamer RP
  
  

Dans ce petit fragment, la définition de La fenêtre est la classe de premier niveau. Cette classe représente votre fenêtre principale. Puis le XML code définit d'autres classes et définit leurs propriétés. Puisque PyQt fournit pyuic5 pour traduire automatiquement ceci XML code en code Python, vous n'avez pas à vous soucier du contenu de votre .ui des dossiers. Vous avez juste besoin de savoir comment utiliser pyuic5.

Ouvrez maintenant un terminal sur votre rprename / ui / répertoire et exécutez la commande suivante:

$ pyuic5 -o window.py window.ui

Cette commande génère un module Python appelé window.py du window.ui fichier et le place dans votre rprename / ui / annuaire. Le module contient le code Python de l'interface graphique de votre outil de changement de nom de fichier en bloc. Voici un petit échantillon du code:

# - * - codage: utf-8 - * -

# Implémentation de formulaire générée à partir de la lecture du fichier d'interface utilisateur 'window.ui'
#
# Créé par: PyQt5 UI code generator 5.14.1
#
# ATTENTION! Toutes les modifications apportées dans ce fichier seront perdues!

de PyQt5 importer QtCore, QtGui, QtWidgets

classer Ui_Window(objet):
    def setupUi(soi, La fenêtre):
        La fenêtre.setObjectName("La fenêtre")
        La fenêtre.redimensionner(720, 480)
        # Snip ...

    def retranslateUi(soi, La fenêtre):
        _Traduire = QtCore.QCoreApplication.Traduire
        La fenêtre.setWindowTitle(_Traduire("La fenêtre", "RP Renamer"))
        # Snip ...

Ui_Window fournit tout le code pour générer l'interface graphique de votre outil de changement de nom de fichier en bloc. Dans ce cas, .setupUi () contient le code pour créer tous les widgets requis et aussi pour les disposer sur l'interface graphique, tandis que .retranslateUi () contient du code pour l'internationalisation et la localisation, ce qui dépasse le cadre de ce didacticiel.

Puisque vous utilisez pyuic5 pour générer automatiquement le code Python à partir d'un .ui fichier, vous n'avez pas à vous soucier du contenu de window.py. Comme le ATTENTION! commentaire en haut des états du fichier, toutes les modifications que vous apportez à ce fichier disparaîtront si vous mettez à jour l'interface graphique avec Qt Designer et régénérez le code Python.

Avoir un module avec un code spécifique à l'interface graphique encourage fortement la séparation de la logique graphique de la logique métier, qui est un principe fondamental dans le modèle Model-View-Controller.

À ce stade, la mise en page de votre projet est terminée. Vous disposez de tous les fichiers dont vous avez besoin pour créer votre outil de changement de nom de fichier en bloc. Il est maintenant temps de créer le squelette de l’application PyQt à l’aide de l’interface graphique que vous venez de créer.

Étape 2: créer l'application squelette PyQt

Jusqu'à présent, vous avez créé une interface graphique pour l'outil de changement de nom de fichier en bloc à l'aide de Qt Designer. Vous avez également utilisé pyuic5 pour traduire automatiquement le .ui le contenu du fichier dans le code Python afin que vous puissiez l'utiliser dans l'application. Enfin, vous avez enregistré le code dans window.py sous le rprename / ui / annuaire.

Dans cette section, vous allez créer une application squelette PyQt et définir sa fenêtre principale pour utiliser le code GUI que vous avez dans window.py. Pour télécharger les fichiers et tout le code que vous allez écrire dans cette section, cliquez sur le lien ci-dessous:

Configuration de la fenêtre de l’outil de changement de nom de fichier en bloc

Pour créer le squelette de l'application PyQt pour votre outil de changement de nom de fichier en bloc, vous devez d'abord créer la fenêtre principale de l'application. Tout d'abord, lancez votre éditeur de code ou IDE préféré et ouvrez le rprename / __ init__.py déposer. Ajoutez-y le contenu suivant:

# - * - codage: utf-8 - * -
# rprename / __ init__.py

"" "Ce module fournit le package rprename." ""

__version__ = «0,1,0»

Hormis certains commentaires et le module docstring, le fichier ci-dessus définit une constante de niveau supérieur appelée __version__ pour contenir le numéro de version de l'application.

Ensuite, ouvrez rprename / views.py et écrivez-y le contenu suivant:

# - * - codage: utf-8 - * -
# rprename / views.py

"" "Ce module fournit la fenêtre principale de RP Renamer." ""

de PyQt5.QtWidgets importer QWidget

de .ui.window importer Ui_Window

classer La fenêtre(QWidget, Ui_Window):
    def __init__(soi):
        super().__init__()
        soi._setupUI()

    def _setupUI(soi):
        soi.setupUi(soi)

Dans views.py, vous importez d'abord QWidget de PyQt5.QtWidgets. Ensuite, vous importez Ui_Window de ui.window. Comme vous l'avez vu précédemment, cette classe fournit l'interface graphique de votre outil de changement de nom de fichier en bloc.

Ensuite, vous créez une nouvelle classe appelée La fenêtre. Cette classe utilise l'héritage multiple. Il hérite de QWidget et aussi de votre classe GUI, Ui_Window. QWidget active la fonctionnalité GUI de base, et Ui_Window fournit la disposition d'interface graphique spécifique que vous souhaitez pour cette application.

L'initialiseur de La fenêtre appelle l'initialiseur de classe de base en utilisant super(). Il appelle également ._setupUI (), qui est une méthode non publique qui collectera tout le code requis pour générer et configurer l'interface graphique. Jusqu'à ce point, ._setupUI (soi-même) seulement les appels .setupUi (), qui est fournie par la deuxième classe parente, Ui_Window.

Avec la version initiale de La fenêtre prêt à l'emploi, vous pouvez continuer et créer une application squelette PyQt pour votre outil de changement de nom de fichier en bloc.

Création de l'application squelette PyQt

Maintenant que la fenêtre principale de l'application est prête à être utilisée, il est temps d'écrire le code standard requis pour créer une application PyQt. Revenez à votre éditeur de code et ouvrez le rprename / app.py déposer. Ajoutez ensuite le code suivant:

# - * - codage: utf-8 - * -
# rprename / app.py

"" "Ce module fournit l'application RP Renamer." ""

importer sys

de PyQt5.QtWidgets importer QApplication

de .views importer La fenêtre

def principale():
    # Créer l'application
    appli = QApplication(sys.argv)
    # Créer et afficher la fenêtre principale
    gagner = La fenêtre()
    gagner.spectacle()
    # Exécutez la boucle d'événements
    sys.sortir(appli.exec())

Dans ce module, vous importez sys accéder sortir(). Cette fonction vous permet de quitter proprement l'application lorsque l'utilisateur ferme la fenêtre principale. Ensuite, vous importez QApplication de PyQt5.QtWidgets et La fenêtre de vues. La dernière étape consiste à définir principale() comme fonction principale de votre application.

Dans principale(), vous instanciez QApplication et La fenêtre. Alors tu appelles .spectacle() au La fenêtre. Enfin, vous exécutez l’application boucle principale ou alors boucle d'événement utilisant .exec ().

Codage du script de point d’entrée de l’application

Avec l'application squelette PyQt en place, vous pouvez créer un script de point d'entrée approprié afin de pouvoir exécuter l'application rapidement. Ouvrez le rprenamer.py fichier à partir de votre répertoire racine et tapez le code suivant dans celui-ci:

#! / usr / bin / env python3
# - * - codage: utf-8 - * -
# rprenamer.py

"" "Ce module fournit le script de point d'entrée RP Renamer." ""

de rprename.app importer principale

si __Nom__ == "__principale__":
    principale()

Ce script est assez petit. Vous importez d'abord principale() de ton app.py module. Ensuite, vous utilisez l'instruction conditionnelle traditionnelle Python qui appelle principale() si l'utilisateur exécute le module en tant que script Python.

Vous pouvez maintenant ouvrir un terminal et exécuter le script pour lancer l'application. Vous verrez la fenêtre suivante sur votre écran:

Interface graphique de la fenêtre principale de l'outil de changement de nom de fichier en bloc

Frais! Votre outil de changement de nom de fichier en bloc a une interface graphique agréable qui fournit un bouton pour charger les fichiers que vous souhaitez renommer. L'édition de la ligne supérieure affichera le chemin vers le répertoire source. Le widget de liste de gauche affichera la liste des fichiers à renommer, et le widget de liste de droite affichera les fichiers renommés.

Pour lancer le processus de changement de nom de fichier, l'utilisateur doit fournir un préfixe de nom de fichier, puis cliquer sur Renommer. La barre de progression en bas affichera la progression du changement de nom du fichier.

Dans la section suivante, vous allez écrire le code requis pour fournir la fonctionnalité principale de l'application, en renommant plusieurs fichiers en une seule fois. Fermez donc la fenêtre de l'application pour continuer à ajouter des fonctionnalités.

Étape 3: Renommer les fichiers avec pathlib et les threads PyQt

Pour mettre en œuvre la fonctionnalité de changement de nom de fichier pour votre outil de changement de nom de fichier en bloc, vous utiliserez Python pathlib et PyQt QThread. Avec pathlib, vous allez gérer les chemins du système de fichiers et renommer les fichiers. Avec QThread, en revanche, vous renommerez les fichiers dans un thread d’exécution distinct. Pourquoi?

Eh bien, selon le nombre de fichiers que vous souhaitez renommer, le processus de changement de nom peut prendre un temps considérable. Le lancement d'une tâche de longue durée dans le thread principal de l'application peut geler l'interface graphique, ce qui peut à son tour entraîner une mauvaise expérience utilisateur.

Pour éviter les problèmes de gel de l'interface graphique, vous pouvez créer un worker QThread pour décharger le processus de changement de nom de fichier et rendre votre application réactive.

Encore une fois, vous pouvez télécharger tout le code que vous allez écrire dans cette section en cliquant sur le lien ci-dessous:

Chargement et affichage des fichiers cibles

Pour commencer à renommer des fichiers, vous avez d'abord besoin d'un moyen de charger ces fichiers dans l'application. PyQt fournit une classe appelée QFileDialog qui vous permet de sélectionner des fichiers ou des répertoires dans votre système de fichiers à l'aide d'une boîte de dialogue prédéfinie. Une fois que vous avez sélectionné les fichiers que vous souhaitez renommer, vous devez stocker leurs chemins dans une structure de données pratique.

Revenez à la rprename / views.py et mettez à jour le code comme ceci:

# - * - codage: utf-8 - * -
# rprename / views.py

"" "Ce module fournit la fenêtre principale de RP Renamer." ""

de collections importer deque
de pathlib importer Chemin

de PyQt5.QtWidgets importer QFileDialog, QWidget

de .ui.window_ui importer Ui_Window

FILTRES = ";;".rejoindre(
    (
        "Fichiers PNG (* .png)",
        "Fichiers JPEG (* .jpeg)",
        "Fichiers JPG (* .jpg)",
        "Fichiers GIF (* .gif)",
        "Fichiers texte (* .txt)",
        "Fichiers Python (* .py)",
    )
)

classer La fenêtre(QWidget, Ui_Window):
    # Snip ...

Ici, vous importez d'abord deque de collections. Les Deques sont une généralisation des piles et des files d'attente. Ils prennent en charge des opérations d'ajout et de pop efficaces de chaque côté de la deque. Dans ce cas, vous utiliserez un deque pour stocker les chemins des fichiers que vous devez renommer.

Vous importez également Chemin de pathlib. Cette classe peut représenter des chemins de fichiers ou de répertoires concrets dans votre système de fichiers. Vous utiliserez cette classe pour effectuer différentes opérations sur des fichiers et des répertoires. Dans ce didacticiel, vous utiliserez Path.rename () pour renommer les fichiers physiques de votre disque dur.

Ensuite, vous importez QFileDialog de PyQt5.QtWidgets. Cette classe fournit une boîte de dialogue appropriée pour sélectionner des fichiers dans un répertoire donné. le FILTRE constante spécifie différents filtres de fichiers sous forme de chaîne. Ces filtres vous permettent de sélectionner parmi différents types de fichiers lors du chargement de fichiers dans l'application.

Garder views.py ouvrir et mettre à jour La fenêtre comme ça:

    1# rprename / views.py
    2# Snip ...
    3
    4classer La fenêtre(QWidget, Ui_Window):
    5    def __init__(soi):
    6        super().__init__()
    7        soi._des dossiers = deque()
    8        soi._filesCount = len(soi._des dossiers)
    9        soi._setupUI()
dix        soi._connectSignalsSlots()
11
12    def _setupUI(soi):
13        soi.setupUi(soi)
14
15    def _connectSignalsSlots(soi):
16        soi.loadFilesButton.cliqué.relier(soi.loadFiles)
17
18    def loadFiles(soi):
19        soi.dstFileList.dégager()
20        si soi.dirEdit.texte():
21            initDir = soi.dirEdit.texte()
22        autre:
23            initDir = str(Chemin.domicile())
24        des dossiers, filtre = QFileDialog.getOpenFileNames(
25            soi, "Choisissez les fichiers à renommer", initDir, filtre=FILTRES
26        )
27        si len(des dossiers) > 0:
28            extension de fichier = filtre[[[[filtre.indice("*") : -1]
29            soi.extensionLabel.Définir le texte(extension de fichier)
30            srcDirName = str(Chemin(des dossiers[[[[0]).parent)
31            soi.dirEdit.Définir le texte(srcDirName)
32            pour déposer dans des dossiers:
33                soi._des dossiers.ajouter(Chemin(déposer))
34                soi.srcFileList.ajouter un item(déposer)
35            soi._filesCount = len(soi._des dossiers)

Voici ce que fait le code nouvellement ajouté:

  • Ligne 7 crée ._des dossiers comme un objet deque. Cet attribut stockera les chemins vers les fichiers que vous souhaitez renommer.

  • Ligne 8 définit ._filesCount pour stocker le nombre de fichiers à renommer.

  • Ligne 10 appels ._connectSignalsSlots ().

  • Ligne 15 définit ._connectSignalsSlots (). Cette méthode collectera plusieurs connexions de signal et de slot en un seul endroit. Jusqu'à ce point, la méthode connecte le Charger des fichiers boutons .cliqué () signal avec le .loadFiles () fente. Cela permet de déclencher .loadFiles () chaque fois que l'utilisateur clique sur le bouton.

Ensuite, vous définissez .loadFiles () pour charger les fichiers que vous souhaitez renommer. Voici ce qu'il fait:

  • Ligne 19 efface le .dstFileList widget de liste à chaque fois que l'utilisateur clique Charger des fichiers.

  • Lignes 20 à 23 définir une instruction conditionnelle qui vérifie si le Dernier répertoire source l'édition de ligne affiche actuellement n'importe quel chemin de répertoire. Si tel est le cas, le si bloc de code définit le répertoire initial, initDir, pour tenir ce chemin. Sinon, le répertoire initial est défini sur Chemin.accueil (), qui renvoie le chemin d'accès au dossier de départ de l'utilisateur actuel. Vous utiliserez initDir pour fournir un répertoire d'initialisation au QFileOpen objet.

  • Lignes 24 à 26 appel .getOpenFileNames () au QFileDialog. Cette méthode statique prend plusieurs arguments, crée une boîte de dialogue pour permettre à l'utilisateur de sélectionner un ou plusieurs fichiers et renvoie une liste de chemins basés sur des chaînes vers les fichiers sélectionnés. Il renvoie également le filtre de fichiers actuellement utilisé. Dans ce cas, vous utilisez les arguments suivants:

    • parent contient le widget qui possède la boîte de dialogue, qui est soi ou le courant La fenêtre objet dans ce cas.

    • légende contient le titre ou la légende de la boîte de dialogue. Vous utilisez la chaîne "Choisissez les fichiers à renommer" dans cet exemple.

    • dir contient le chemin du répertoire d'initialisation. En d'autres termes, le chemin d'accès au répertoire dans lequel la boîte de dialogue est ouverte. Dans cet exemple, vous utilisez initDir pour initialiser la boîte de dialogue.

    • filtre contient un filtre de type de fichier afin que seuls les fichiers correspondant au filtre soient affichés dans la boîte de dialogue. Par exemple, si vous définissez le filtre sur "* .jpg", la boîte de dialogue affiche les fichiers correspondant à ce format.

  • Ligne 27 définit une instruction conditionnelle qui exécute un ensemble d'instructions si l'utilisateur sélectionne au moins un fichier dans le QFileDialog.

  • Ligne 28 tranche la chaîne de filtre actuelle pour extraire l'extension de fichier.

  • Ligne 29 définit le texte du .extensionLabel objet à l'extension de fichier extraite à la ligne 28.

  • Ligne 30 récupère les chemins vers le répertoire contenant les fichiers sélectionnés. Pour ce faire, vous créez un Chemin objet en utilisant le chemin d'accès au premier fichier de la liste des fichiers sélectionnés. le .parent L'attribut contient le chemin vers le répertoire contenant.

  • Ligne 31 définit les textes de la .dirEdit modifiez en ligne le chemin du répertoire que vous avez obtenu à la ligne 30.

  • Lignes 32 à 34 définir un pour boucle qui itère sur la liste des fichiers sélectionnés, crée un Chemin objet pour chaque fichier, et l'ajoute à ._des dossiers. La ligne 34 ajoute chaque fichier au .srcFileList widget de liste afin que l'utilisateur puisse voir les fichiers actuellement sélectionnés sur l'interface graphique de l'application.

  • Ligne 35 mises à jour ._filesCount avec le nombre actuel de fichiers dans la liste.

Si vous exécutez l'application maintenant, vous obtiendrez le comportement suivant:

Vous pouvez maintenant charger plusieurs fichiers dans votre outil de changement de nom de fichier en bloc en cliquant sur Charger des fichiers. Notez que vous pouvez spécifier le type de fichier que vous souhaitez charger dans l'application en choisissant parmi plusieurs filtres de fichiers dans le Choisissez les fichiers à renommer dialogue.

Frais! Votre projet prend déjà en charge le chargement de fichiers de différents types. Allez-y et fermez l'application pour continuer le codage. Dans la section suivante, vous allez mettre en œuvre la fonctionnalité de changement de nom de fichier.

Renommer plusieurs fichiers dans un travailleur QThread

Pour effectuer le processus de changement de nom de fichier, vous utiliserez un QThread objet. La création et la configuration d'un thread de travail vous permettent de décharger le processus de changement de nom de fichier du thread principal de l'application. De cette façon, vous évitez d'éventuels problèmes de gel de l'interface graphique lorsque vous sélectionnez un grand nombre de fichiers à renommer.

Le thread de travail effectuera le changement de nom du fichier en utilisant pathlib.rename (). Il émettra également des signaux personnalisés pour communiquer avec le thread principal et mettre à jour l'interface graphique de l'application. Allez-y et ouvrez le rprename / rename.py fichier dans votre éditeur de code. Tapez le code suivant:

    1# - * - codage: utf-8 - * -
    2# rprename / rename.py
    3
    4"" "Ce module fournit la classe Renamer pour renommer plusieurs fichiers." ""
    5
    6importer temps
    7de pathlib importer Chemin
    8
    9de PyQt5.QtCore importer QObject, pyqtSignal
dix
11classer Renamer(QObject):
12    # Définir des signaux personnalisés
13    progressé = pyqtSignal(int)
14    renomméFichier = pyqtSignal(Chemin)
15    fini = pyqtSignal()
16
17    def __init__(soi, des dossiers, préfixe):
18        super().__init__()
19        soi._des dossiers = des dossiers
20        soi._préfixe = préfixe
21
22    def renameFiles(soi):
23        pour numéro de dossier, déposer dans énumérer(soi._des dossiers, 1):
24            nouveau fichier = déposer.parent.joinpath(
25                F"soi._préfixe str(numéro de dossier) déposer.suffixe"
26            )
27            déposer.Renommer(nouveau fichier)
28            temps.dormir(0,1)  # Commentez cette ligne pour renommer les fichiers plus rapidement.
29            soi.progressé.émettre(numéro de dossier)
30            soi.renomméFichier.émettre(nouveau fichier)
31        soi.progressé.émettre(0)  # Réinitialiser la progression
32        soi.fini.émettre()

Voici ce que fait ce code:

  • Ligne 9 importations QObject et pyqtSignal () de PyQt5.QtCore. QObject vous permet de créer des sous-classes avec des signaux et des fonctionnalités personnalisés. Avec pyqtSignal (), vous pouvez créer des signaux personnalisés afin de pouvoir les émettre lorsqu'un événement donné se produit.

  • Ligne 11 définit une sous-classe de QObject appelé Renamer.

  • Lignes 13 à 15 définir trois signaux personnalisés:

    1. .progressé () sera émis chaque fois que la classe renomme un nouveau fichier. Il renvoie un entier représentant le numéro du fichier actuellement renommé. Vous utiliserez ce numéro pour mettre à jour la barre de progression dans l'interface graphique de l'application.

    2. .renamedFile () sera émis chaque fois que la classe renomme un fichier. Dans ce cas, le signal renvoie le chemin vers le fichier renommé. Vous utiliserez ce chemin pour mettre à jour la liste des fichiers renommés dans l'interface graphique de l'application.

    3. .fini() sera émis lorsque le processus de changement de nom de fichier sera terminé.

L'initialiseur de classe à la ligne 17 prend deux arguments obligatoires:

  1. des dossiers contient la liste des fichiers sélectionnés. Chaque fichier est représenté par son correspondant Chemin.

  2. préfixe contient le préfixe de nom de fichier que vous utiliserez pour renommer les fichiers.

Ensuite, vous définissez la méthode qui effectue le processus de changement de nom de fichier, .renameFiles (). Voici un résumé de son fonctionnement:

  • Ligne 23 définit un pour boucle pour parcourir la liste des fichiers sélectionnés. La boucle utilise énumérer() pour générer un numéro de fichier au fur et à mesure de la boucle.

  • Ligne 24 crée de nouveaux noms de fichiers en utilisant le préfixe de nom de fichier numéro de dossier et l'extension de fichier .suffixe. Ensuite, il joint le nouveau nom de fichier avec le chemin du répertoire parent pour créer le chemin du fichier à portée de main, nouveau fichier.

  • Ligne 27 renomme le fichier courant en appelant .Renommer() sur le courant déposer avec nouveau fichier comme argument.

  • Ligne 28 est un appel facultatif à le sommeil de temps() cela ralentit le processus de changement de nom de fichier afin que vous puissiez voir comment cela se passe. N'hésitez pas à supprimer cette ligne pour exécuter l'application à sa vitesse naturelle.

  • Lignes 29 et 30 émettre le .progressé () et .renamedFile () signaux. You’ll use those signals to update the application’s GUI in the next section.

  • Line 31 emits the .progressed() using 0 as an argument. You’ll use this value to reset the progress bar after finishing the file renaming process.

  • Line 32 emits the .finished() signal when the file renaming process has finished.

Once you’ve coded Renamer, you’re ready to start renaming files. To do that, you need to create and set up a worker thread. But first, get back to rprename/views.py and update its import section like this:

# rprename/views.py
# Snip...

de PyQt5.QtCore importer QThread
de PyQt5.QtWidgets importer QFileDialog, QWidget

de .rename importer Renamer
de .ui.window importer Ui_Window
# Snip...

In the first highlighted line, you import QThread de PyQt5.QtCore. This class allows you to create and manage worker threads in PyQt applications. In the second highlighted line, you import Renamer from your rename module.

Now scroll down a little bit in your views.py file and update Window like this:

    1# rprename/views.py
    2# Snip...
    3
    4classer Window(QWidget, Ui_Window):
    5    # Snip...
    6    def _connectSignalsSlots(self):
    7        self.loadFilesButton.clicked.connect(self.loadFiles)
    8        self.renameFilesButton.clicked.connect(self.renameFiles)
    9
dix    def loadFiles(self):
11        # Snip..
12
13    def renameFiles(self):
14        self._runRenamerThread()
15
16    def _runRenamerThread(self):
17        prefix = self.prefixEdit.text()
18        self._thread = QThread()
19        self._renamer = Renamer(
20            files=tuple(self._files),
21            prefix=prefix,
22        )
23        self._renamer.moveToThread(self._thread)
24        # Rename
25        self._thread.started.connect(self._renamer.renameFiles)
26        # Update state
27        self._renamer.renamedFile.connect(self._updateStateWhenFileRenamed)
28        # Clean up
29        self._renamer.finished.connect(self._thread.quit)
30        self._renamer.finished.connect(self._renamer.deleteLater)
31        self._thread.finished.connect(self._thread.deleteLater)
32        # Run the thread
33        self._thread.start()
34
35    def _updateStateWhenFileRenamed(self, newFile):
36        self._files.popleft()
37        self.srcFileList.takeItem(0)
38        self.dstFileList.addItem(str(newFile))

Here, you first connect the Rename button’s .clicked() to .renameFiles(). This method calls ._runRenamerThread() to create, set up, and run the worker thread. Here’s how it works:

  • Line 17 retrieves the text in the Filename Prefix line edit. The user needs to provide this filename prefix.

  • Line 18 creates a new QThread object to offload the file renaming process.

  • Lines 19 to 22 instantiate Renamer, passing the list of files and the filename prefix as arguments to the class constructor. In this case, you turn ._files into a tuple to prevent the thread from modifying the underlying deque on the main thread.

  • Line 23 calls .moveToThread() sur le Renamer instance. As its name implies, this method moves a given object to a different thread of execution. In this case, it uses ._thread as the target thread.

  • Line 25 connects the thread’s .started() signal with .renameFiles() sur le Renamer instance. This makes it possible to start the file renaming process when the thread starts.

  • Line 27 connects the Renamer instance’s .renamedFile() signal with ._updateStateWhenFileRenamed(). You’ll see what this method does in a minute.

  • Lines 29 and 30 connect the Renamer instance’s .finished() signal with two slots:

    1. The thread’s .quit() slot, which quits the thread once the file renaming process is finished

    2. le Renamer instance’s .deleteLater() slot, which schedules objects for later deletion

  • Line 31 connects the thread’s .finished() signal with .deleteLater(). This makes it possible to delete the thread but only after it’s finished doing its job.

  • Line 33 starts the worker thread.

The final piece of code defines ._updateStateWhenFileRenamed(). When a file is renamed, the method removes the file from the list of files to be renamed. Then the method updates the list of Files to Rename and also the list of Renamed Files on the application’s GUI.

Here’s how the application works now:

That’s it! Your bulk file rename tool already does its job. It allows you to load several files, provide a new filename prefix, and rename all the selected files. Great job!

Now you can close the application to continue with the development process. In the next section, you’ll learn how to update the application’s GUI according to the file renaming progress.

Step 4: Update the GUI State According to the Renaming Progress

So far, your bulk file rename tool provides its main functionality. You can already use the tool to rename multiple files in your file system. However, what would happen if the user clicked Rename in the middle of the renaming process? Also, what if the user forgets to supply an appropriate filename prefix?

Another and even more visible issue is why the application’s progress bar doesn’t reflect the file renaming progress.

All these questions have to do with updating the GUI according to the application’s state at any given time. In this section, you’ll write the required code to fix or prevent the issues mentioned above. You’ll start with the progress bar.

You can download the code you’ll write in this section by clicking the link below:

Updating the Progress Bar

In GUI applications, you typically use progress bars to inform your users about the progress of long-running tasks. If the users don’t get feedback on what the application is currently doing, then they might think that the application is frozen, stuck, or is having some internal issues.

In this project, you use a progress bar to provide feedback on how the file renaming process is going at any given time. To do that, get back to the rprename/views.py in your code editor and update it like this:

    1# rprename/views.py
    2# Snip...
    3
    4classer Window(QWidget, Ui_Window):
    5    # Snip...
    6    def _runRenamerThread(self):
    7        # Update state
    8        self._renamer.renamedFile.connect(self._updateStateWhenFileRenamed)
    9        self._renamer.progressed.connect(self._updateProgressBar)
dix        # Snip...
11
12    def _updateStateWhenFileRenamed(self, newFile):
13        # Snip...
14
15    def _updateProgressBar(self, fileNumber):
16        progressPercent = int(fileNumber / self._filesCount * 100)
17        self.progressBar.setValue(progressPercent)

Here’s what the newly added code does:

  • Line 9 connects the Renamer instance’s .progressed() signal with ._updateProgressBar().
  • Line 15 defines ._updateProgressBar(). The method takes a fileNumber as an argument. Note that .progressed() provides this file number every time a file gets renamed.
  • Line 16 computes the file renaming progress as a percentage of the total number of files, which is available in ._filesCount.
  • Line 17 updates the .value property on the progress bar using .setValue() with progressPercent as an argument.

That’s it! Go ahead and run your application again. It’ll work like this:

After these additions to Window, the progress bar of your bulk file rename tool reflects the progress of the file renaming operation, which is nice and improves your users’ experience.

Enabling and Disabling GUI Components

When you build GUI applications, you realize that some actions on the GUI are only available in certain situations. In your bulk file rename tool, for example, it doesn’t make sense to allow the user to click Rename if there’s no file already loaded into the application or if the user hasn’t provided a filename prefix.

There are at least two ways to deal with this kind of situation:

  1. Leave all the widgets enabled all the time and make sure that they don’t trigger any actions that don’t make sense in context.
  2. Enable and disable widgets depending on the application’s state.

To implement the first approach, you can use conditional statements to make sure a given action makes sense at a given moment. To implement the second approach, on the other hand, you need to figure out all the possible states your application can run into and provide methods to update the GUI accordingly.

In this tutorial, you’ll use the second approach, which might be more intuitive and user-friendly. To do that, you need to figure out the possible states the application can run into. Here’s a first approach to this problem:

State Description Method
No files loaded The application is running, and the list of Files to Rename is empty. ._updateStateWhenNoFiles()
Files loaded The list of Files to Rename contains one or more files. ._updateStateWhenFilesLoaded()
Ready to rename files The list of Files to Rename contains one or several files, and the user has provided a filename prefix. ._updateStateWhenReady()
Renaming files The user has clicked Rename, and the file renaming process has started. ._updateStateWhileRenaming()
Renaming done The file renaming process has finished, and there are no left files to rename. ._updateStateWhenNoFiles()

Since the first and the last states in the above table are quite similar, you’ll use the same method to update the GUI. That means you only have to implement four methods.

To start coding these methods, get back to views.py and add the following code to Window:

    1# rprename/views.py
    2# Snip...
    3
    4classer Window(QWidget, Ui_Window):
    5    # Snip...
    6    def _setupUI(self):
    7        self.setupUi(self)
    8        self._updateStateWhenNoFiles()
    9
dix    def _updateStateWhenNoFiles(self):
11        self._filesCount = len(self._files)
12        self.loadFilesButton.setEnabled(Vrai)
13        self.loadFilesButton.setFocus(Vrai)
14        self.renameFilesButton.setEnabled(False)
15        self.prefixEdit.clear()
16        self.prefixEdit.setEnabled(False)
17
18   # Snip...
19   def _runRenamerThread(self):
20        # Snip...
21        self._renamer.progressed.connect(self._updateProgressBar)
22        self._renamer.finished.connect(self._updateStateWhenNoFiles)
23        # Snip...

Here’s how this update works:

  • Line 8 calls ._updateStateWhenNoFiles() from inside ._setupUI(). This updates the GUI when you launch the application.
  • Line 10 defines ._updateStateWhenNoFiles().
  • Line 11 updates the total number of files. Under this state, len(self._files) returns 0.
  • Line 12 enables the Load Files button so it accepts the user’s events.
  • Line 13 moves the focus to the Load Files bouton. This way, users can press Space on their keyboard to load files into the application.
  • Line 14 disables the Rename bouton. The button is grayed out and unresponsive.
  • Line 15 clears the Filename Prefix line edit. This removes any previously supplied filename prefix.
  • Line 16 disables the Filename Prefix line edit. This way, the user won’t be able to type in a filename prefix if there are no files in the application.
  • Line 22 connects the Renamer instance’s .finished() signal with ._updateStateWhenNoFiles(). This updates the GUI once the file renaming process finishes.

When you run the application, you can press Space on your keyboard to launch the dialog and select the files you want to rename. Also, the Filename Prefix line edit and the Rename button are disabled so you can’t perform actions on them.

Now you can code the method to update the GUI when you load files into the application. Add the following code to Window:

# rprename/views.py
# Snip...

classer Window(QWidget, Ui_Window):
    # Snip...
    def loadFiles(self):
        si len(files) > 0:
            # Snip...
            self._updateStateWhenFilesLoaded()

    def _updateStateWhenFilesLoaded(self):
        self.prefixEdit.setEnabled(Vrai)
        self.prefixEdit.setFocus(Vrai)

When you load one or more files into the application, .loadFiles() calls ._updateStateWhenFilesLoaded(). This method enables the Filename Prefix line edit so you can enter a prefix to use for renaming files. It also moves the focus to that widget so you can provide a filename prefix immediately.

Next, you can code the method to handle the GUI update when the application is ready to rename a bunch of files. Add the following code to Window:

# rprename/views.py
# Snip...

classer Window(QWidget, Ui_Window):
    # Snip...
    def _connectSignalsSlots(self):
        # Snip...
        self.prefixEdit.textChanged.connect(self._updateStateWhenReady)

    def _updateStateWhenReady(self):
        si self.prefixEdit.text():
            self.renameFilesButton.setEnabled(Vrai)
        autre:
            self.renameFilesButton.setEnabled(False)

Here, you first connect the Filename Prefix line edit’s .textChanged() signal with ._updateStateWhenReady(). This method enables or disables the Rename button according to the content of the Filename Prefix line edit. This way, when the line edit is empty, the button gets disabled, and otherwise it’s enabled.

Finally, you need to code the method to handle the GUI update when the application is renaming your files. Go ahead and add the following code to Window:

classer Window(QWidget, Ui_Window):
    # Snip...
    def renameFiles(self):
        self._runRenamerThread()
        self._updateStateWhileRenaming()

    def _updateStateWhileRenaming(self):
        self.loadFilesButton.setEnabled(False)
        self.renameFilesButton.setEnabled(False)

When your user clicks Rename, the application starts the file renaming process and calls ._updateStateWhileRenaming() to update the GUI accordingly. The method disables the Load Files et Rename buttons so the user can’t click them while the renaming process is running.

That’s it! If you run the application now, then you’ll get the following behavior:

Your bulk file rename tool’s GUI now reflects the application’s state at any given time. This allows you to offer your users an intuitive, frustration-free experience. Great job!

Conclusion

Automatically renaming multiple files is a common problem when you’re organizing your personal files and folders. In this tutorial, you built a real-world GUI application to perform this task quickly and efficiently. By building this tool, you applied a wide range of skills related to creating GUI applications with PyQt and Qt Designer. You also worked with files using Python’s pathlib.

In this tutorial, you learned how to:

  • Build the GUI of a bulk file rename tool using Qt Designer
  • Utiliser PyQt threads to offload the bulk file renaming process
  • Manage system paths and rename files with pathlib
  • Update the GUI state according to the file renaming process

You can download the final source code for the bulk file rename project by clicking the link below:

Next Steps

Up to this point, you’ve built a real-world application to automate the process of renaming multiples files. Even though the application provides a minimal set of features, it’s a good starting point for you to continue adding features and learning along the way. This will help you take your skills with Python and PyQt GUI applications to the next level.

Here are some ideas you can implement to continue improving the project:

  • Add support for additional file types: You can add support for new file types, such as .bmp, .docx, .xlsx, or any other file type you need to work with. To do that, you can extend the FILTERS constant.

  • Generate date-based or random filename suffixes: You can also change the way you generate the filename suffix. Instead of using consecutive integer numbers, you can provide date-based suffixes using datetime, or you can provide random suffixes.

  • Generate an executable for the application: You can use PyInstaller or any other tool to generate an executable for your bulk file rename tool. This way, you’ll be able to share the application with your friends and colleagues.

These are just a few ideas of how to continue adding features to your bulk file rename tool. Take the challenge and build something amazing!

[ad_2]