1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
| #!/usr/bin/python3
# -*- coding: utf-8 -*-
"""
Permet de sélectionner plusieurs fichiers et dossiers en conservant l'ordre
des sélections
N'utilise pas la fenêtre de sélection de l'OS
"""
from PyQt5.QtCore import (pyqtSlot, QEvent)
from PyQt5.QtWidgets import (QFileDialog, QTreeView, QFileSystemModel,
QAbstractItemView, QPushButton, QDialog, QLineEdit, QLabel)
##############################################################################
class SelectionFichiersDossiers(QFileDialog):
"""Une fenêtre de dialogue pour sélection de fichiers et de répertoires
"""
#=========================================================================
def __init__(self, parent=None,
titre='Sélectionnez fichiers et répertoires',
dossier='.',
filtre="Tous les fichiers (*)"):
super().__init__(parent, titre, dossier, filtre)
# n'utilise pas la fenêtre de dialogue de l'OS
self.setOptions(self.Options() | QFileDialog.DontUseNativeDialog)
# sélection pour ouvrir et non enregistrer
self.setAcceptMode(QFileDialog.AcceptOpen)
# affiche en même temps les répertoires et les fichiers
self.setFileMode(QFileDialog.Directory)
# aucune modification acceptée sur le disque
self.setOptions(self.Options() | QFileDialog.ReadOnly)
# affiche le filtre de sélection des fichiers sans ses détails
self.setOptions(self.Options() | QFileDialog.HideNameFilterDetails)
# change le comportement des sélections dans l'arborescence
self.treeView = self.findChild(QTreeView)
if isinstance(self.treeView.model(), QFileSystemModel):
# affiche l'arborescence du disque
self.treeView.setRootIsDecorated(True)
self.treeView.setItemsExpandable(True)
# définit le type de sélection
self.treeView.setSelectionMode(QAbstractItemView.ExtendedSelection)
# méthode à lancer à chaque sélection (active/désactive le bouton)
self.treeView.selectionModel().selectionChanged.connect(self.miseajour)
# change le comportement du bouton de fin de sélection
for bouton in self.findChildren(QPushButton):
if bouton.text().strip().lower().replace("&", "") in ['choose', 'choisir']:
bouton.clicked.disconnect() # suppression ancien lien
bouton.clicked.connect(self.findeselection) # nouveau lien
bouton.installEventFilter(self) # met en place le eventFilter
bouton.setEnabled(False) # désactivé avant 1ère sélection
self.bouton = bouton
break # le bon bouton a été choisi
# trouver l'adresse de la ligne d'édition
edits = self.findChildren(QLineEdit)
for edit in edits:
if edit.objectName() == "fileNameEdit":
self.edit = edit
break
# changer le titre de la ligne d'édition des fichiers/dossiers
labels = self.findChildren(QLabel)
for label in labels:
if label.objectName() == "fileNameLabel":
if "directory" in label.text().lower(): # version anglaise
label.setText("Files/folders :")
elif "dossier" in label.text().lower(): # version française
label.setText("Fichiers/dossiers :")
break
#=========================================================================
@pyqtSlot("QObject", "QEvent")
def eventFilter(self, watched, event):
"""évènement concernant le bouton lors d'un changement de sélection
"""
if event.type() == QEvent.EnabledChange:
if not watched.isEnabled():
if isinstance(self.treeView.model(), QFileSystemModel):
if len(self.treeView.selectionModel().selectedIndexes()) > 0:
watched.setEnabled(True) # active le bouton
return super().eventFilter(watched, event)
#=========================================================================
@pyqtSlot("QItemSelection", "QItemSelection")
def miseajour(self, _sel, _desel):
"""lancé à chaque nouvelle sélection de fichier ou de répertoire
active/désactive le bouton selon la présence/absence d'une sélection
"""
if isinstance(self.treeView.model(), QFileSystemModel):
if len(self.treeView.selectionModel().selectedIndexes()) > 0:
# activetion du bouton quand il y a au moins une sélection
self.bouton.setEnabled(True)
else:
# désactivation du bouton quand il n'y a aucune sélection
self.bouton.setEnabled(False)
# effacement de la ligne d'édition
self.edit.clear()
#=========================================================================
@pyqtSlot(bool)
def findeselection(self, _check=False):
"""lancé par le bouton de fin de sélection
termine la boucle locale et ferme la fenêtre de dialogue
en retournant l'acceptation de la sélection
"""
self.done(QDialog.Accepted)
##############################################################################
def selectionfichiersdossiers(parent=None,
titre="Sélection fichers et dossiers ",
dossier=".",
filtre="tous les fichiers (*)"):
"""fonction qui lance la fenêtre de dialogue pour sélectionner à la fois
des fichiers et des dossiers, et en retourne la liste
- titre: le titre de la fenêtre de dialogue
- dossier: le répertoire racine de la recherche
- filtre: chaine de car. donnant les motifs "wildcard" à afficher
exemple: "Musique (*.mp3 *.flac *.wma);; Tous les fichiers (*)"
"""
dialogue = SelectionFichiersDossiers(parent, titre, dossier, filtre)
print()
if dialogue.exec_() == QDialog.Accepted:
return dialogue.selectedFiles() # liste des fichiers et dossiers
else:
return [] # sortie du dialogue sans sélection |
Partager