J'ai créé une application graphique avec Python + PyQt5

J'ai créé une application qui fonctionne avec une interface graphique avec python. Je vais résumer brièvement cette période.

Spécifications: créez une liste de fichiers avec une extension spécifique, traitez-les un par un et visualisez leur progression

Par exemple, il s'agit d'une image qui ouvre un fichier Python dans un dossier spécifique, le traite un par un et affiche que XX sur XX est en cours d'exécution.

Créer une classe qui collecte des fichiers avec une extension spécifique

Tout d'abord, créez une classe `` FileList '' qui collecte les fichiers avec une extension spécifique et crée une liste.

filelist.py


import os


class FileList():
    ''' store file list'''
    def __init__(self, root_dir, ext):
        self.root_dir = root_dir
        self.ext = ext
        self.files = []

    def retrieve(self):
        for rd, _, fl in os.walk(self.root_dir):
            for f in fl:
                _, fext = os.path.splitext(f)
                if fext == self.ext:
                    self.files.append(os.path.join(rd, f))

    def print(self):
        for f in self.files:
            print(f)

C'est une classe extrêmement facile.

Je vais essayer.

20170625001.png

Ouais, peut-être vrai.

Conception graphique

Concevez l'interface graphique. Les éléments requis sont les suivants.

  1. Pièces pour entrer dans le dossier cible
  2. Parties d'instructions d'exécution
  3. Pièces qui affichent la progression

Les parties pour entrer dans le dossier cible doivent avoir un bouton "Rechercher un dossier" et une zone de texte qui affiche le dossier spécifié.

La partie pour instruire l'exécution doit avoir un bouton «exécuter».

Pour la partie qui affiche la progression, le nom du fichier en cours de traitement est affiché dans la zone de texte et le taux de progression global est affiché dans la barre de progression.

20170625002.png

Je pense que ce placement de pièce peut être facilement fait en utilisant un outil de conception graphique approprié, mais pour le moment, je l'écrirai à la main.

En gros, commencez par Premiers programmes dans PyQt5.

guimain.py


import sys
import os
from PyQt5.QtWidgets import (QWidget, QApplication, 
							 QPushButton, QLineEdit,
                             QHBoxLayout, QVBoxLayout, 
                             QTextEdit, QProgressBar,
                             QFileDialog)
from PyQt5.QtCore import Qt


class MainWidget(QWidget):
    dirname = ''
    step = 0

    def __init__(self, parent=None):
        super(MainWidget, self).__init__(parent)
        self.initUI()

    def initUI(self):
        self.resize(480, 360)

        self.txtFolder = QLineEdit()
        self.btnFolder = QPushButton('référence...')

        hb1 = QHBoxLayout()
        hb1.addWidget(self.txtFolder)
        hb1.addWidget(self.btnFolder)

        self.btnExec = QPushButton('Courir')
        self.btnExec.setEnabled(False)
        
        hb2 = QHBoxLayout()
        hb2.addWidget(self.btnExec)

        self.txtLog = QTextEdit()

        self.pbar = QProgressBar()
        self.pbar.setTextVisible(False)

        layout = QVBoxLayout()
        layout.addLayout(hb1)
        layout.addLayout(hb2)
        layout.addWidget(self.txtLog)
        layout.addWidget(self.pbar)
        self.setLayout(layout)

        self.setWindowTitle('PyQt5 Sample')


def main(args):
    app = QApplication(args)
    dialog = MainWidget()
    dialog.show()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main(sys.argv)

20170626001.png

C'est presque comme prévu.

la mise en oeuvre

Fonction du bouton "Parcourir ..." (btnFolder)

Défini comme un événement cliqué dans btnFolder.

self.btnFolder.clicked.connect(self.show_folder_dialog)
def show_folder_dialog(self):
    ''' open dialog and set to foldername '''
    dirname = QFileDialog.getExistingDirectory(self,
                                               'open folder',
                                               os.path.expanduser('.'),
                                               QFileDialog.ShowDirsOnly)
    if dirname:
        self.dirname = dirname.replace('/', os.sep)
        self.txtFolder.setText(self.dirname)
        self.btnExec.setEnabled(True)
        self.step = 0

Ouvrez la boîte de dialogue de spécification du dossier et activez le bouton "Exécuter".

Fonction du bouton "Exécuter" (btnExec)

Collectez les fichiers ".py" dans le dossier spécifié et affichez le nom du fichier dans txtLog. De plus, la progression lors de l'exécution est représentée par une barre de progression.

Importer la classe FileList

guimain.py


from filelist import FileList

Exécutez la méthode retrieve () de la classe FileList

Modifiez légèrement la classe FileList par rapport à la version d'origine.

filelist.py


class FileList():
    ''' store file list'''
    def __init__(self):
        self.root_dir = ''
        self.ext = ''
        self.files = []

    def setup(self, root_dir, ext):
        self.root_dir = root_dir
        self.ext = ext
        self.retrieve()

    def retrieve(self):
        self.files = []
        for rd, _, fl in os.walk(self.root_dir):
            for f in fl:
                _, fext = os.path.splitext(f)
                if fext == self.ext:
                    self.files.append(os.path.join(rd, f))

    def print(self):
        for f in self.files:
            print(f)

init()alors,root_dirQuandextA été spécifié, mais il a été nouvellement définisetup()Passez à la méthode.

Pour l'héritage de QThread

Dans le programme GUI, puisque le tableau GUI s'exécute sur mutti-thread, la classe FileList est héritée de QThread de sorte que le tableau de fichiers fonctionne lui-même également sur multi-thread.

Il implémente également une fonction pour envoyer un signal afin que la barre de progression puisse être déplacée pour chaque processus.

À l'origine, dans process_file (), par exemple, s'il s'agit d'un fichier image, des retouches sont effectuées, mais dans cet exemple, ce n'est pas le point principal, donc je ne ferai rien pour le moment.

filelist.py


import os
import sys
from PyQt5.QtCore import pyqtSignal, QMutexLocker, QMutex, QThread


class FileList(QThread):
    ''' store file list'''

    sig_file = pyqtSignal(str)

    def __init__(self, parent=None):
        super(FileList, self).__init__(parent)
        self.stopped = False
        self.mutex = QMutex()

    def setup(self, root_dir, ext):
        self.root_dir = root_dir
        self.ext = ext
        self.retrieve()
        self.stopped = False

    def stop(self):
        with QMutexLocker(self.mutex):
            self.stopped = True

    def run(self):
        for f in self.files:
            fname = f
            self.process_file(fname)
            self.sig_file.emit(fname)	#transmission du signal
        self.stop()
        self.finished.emit()		#transmission du signal

    def retrieve(self):
    	''' root_Obtenez un fichier avec l'extension ext à partir de dir'''
        self.files = []
        for rd, _, fl in os.walk(self.root_dir):
            for f in fl:
                _, fext = os.path.splitext(f)
                if fext == self.ext:
                    self.files.append(os.path.join(rd, f))
        self.length = len(self.files)

    def process_file(self, path):
        '''Ne rien faire pour le moment'''
        cnt = 0
        if os.path.exists(path):
            cnt += 1
        else:
            cnt = 0

    def print(self):
        for f in self.files:
            print(f)


def main(args):
    root_dir = '.'
    ext = '.py'
    if len(args) == 3:
        root_dir = args[1]
        ext = args[2]
    fileList = FileList()
    fileList.setup(root_dir, ext)
    fileList.print()

if __name__ == '__main__':
    main(sys.argv)

Si vous vous référez à cette classe FileList et appuyez sur le bouton, guimain.py qui analyse le dossier spécifié et affiche le processus est le suivant.

guimain.py


import sys
import os
from PyQt5.QtWidgets import (QWidget, QApplication, QPushButton, QLineEdit,
                             QHBoxLayout, QVBoxLayout, QTextEdit, QProgressBar,
                             QFileDialog)
from PyQt5.QtCore import pyqtSlot, Qt
from filelist import FileList


class MainWidget(QWidget):
    dirname = ''
    step = 0

    def __init__(self, parent=None):
        super(MainWidget, self).__init__(parent)
        self.initUI()
        self.fileList = FileList()
        self.fileList.sig_file.connect(self.update_status)
        self.fileList.finished.connect(self.finish_process)

    def initUI(self):
        self.resize(480, 360)

        self.txtFolder = QLineEdit()
        self.txtFolder.setReadOnly(True)
        self.btnFolder = QPushButton('référence...')
        self.btnFolder.clicked.connect(self.show_folder_dialog)
        hb1 = QHBoxLayout()
        hb1.addWidget(self.txtFolder)
        hb1.addWidget(self.btnFolder)

        self.btnExec = QPushButton('Courir')
        self.btnExec.clicked.connect(self.exec_process)
        self.btnExec.setEnabled(False)
        self.btnExec.setVisible(True)

        self.btnExit = QPushButton('Fin')
        self.btnExit.setVisible(False)	#Annulation
        self.btnExit.setEnabled(False)	#Ne montre pas
        self.btnExit.clicked.connect(self.close)

        hb2 = QHBoxLayout()
        hb2.addWidget(self.btnExec)
        hb2.addWidget(self.btnExit) 	#Ajout d'un bouton invisible à l'état initial

        self.txtLog = QTextEdit()
        self.txtLog.setReadOnly(True)

        self.pbar = QProgressBar()
        self.pbar.setTextVisible(False)

        layout = QVBoxLayout()
        layout.addLayout(hb1)
        layout.addLayout(hb2)
        layout.addWidget(self.txtLog)
        layout.addWidget(self.pbar)
        self.setLayout(layout)

        self.setWindowTitle('PyQt5 Sample')

    def show_folder_dialog(self):
        ''' open dialog and set to foldername '''
        dirname = QFileDialog.getExistingDirectory(self,
                                                   'open folder',
                                                   os.path.expanduser('.'),
                                                   QFileDialog.ShowDirsOnly)
        if dirname:
            self.dirname = dirname.replace('/', os.sep) #Convertir le délimiteur de répertoire en fonction du système d'exploitation
            self.txtFolder.setText(self.dirname)
            self.btnExec.setEnabled(True)
            self.step = 0

    def print_log(self, logstr):
        self.txtLog.append(logstr)

    @pyqtSlot()
    def exec_process(self):
        if os.path.exists(self.dirname):
            try:
                QApplication.setOverrideCursor(Qt.WaitCursor)
                self.fileList.setup(self.dirname, '.py')
                maxCnt = self.fileList.length
                self.pbar.setValue(0)
                self.pbar.setMinimum(0)
                self.pbar.setMaximum(maxCnt)
                self.fileList.start()
            except Exception as e:
                self.print_log(str(e))
            finally:
                QApplication.restoreOverrideCursor()
        else:
            self.print_log('{0} is not exists'.format(self.dirname))

    @pyqtSlot(str)
    def update_status(self, filename):
        self.txtLog.append(filename)
        self.step += 1
        self.pbar.setValue(self.step)	#barre de progression

    @pyqtSlot()
    def finish_process(self):
        self.fileList.wait()
        #Masquer le bouton d'exécution
        self.btnExec.setEnabled(False)
        self.btnExec.setVisible(False)
        #Afficher le bouton de fin
        self.btnExit.setEnabled(True)
        self.btnExit.setVisible(True)

def main(args):
    app = QApplication(args)
    dialog = MainWidget()
    dialog.show()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main(sys.argv)

Beaucoup d'accélération rapide dans la seconde moitié

Cela devient ennuyeux, donc si vous l'écrivez comme ci-dessus, cela fonctionnera pour le moment.

Dans FileList.run (), un signal est envoyé par `` self.sig_file.emit (fname) '' un par un, et en le recevant avec guimain.update_status (), la barre de progression s'affiche. Vous pouvez procéder un par un.


Résumé

J'ai écrit une application GUI en Python. La clé est d'hériter de QThread.

Code du jour

Recommended Posts

J'ai créé une application graphique avec Python + PyQt5
J'ai fait une loterie avec Python.
J'ai créé un démon avec Python
J'ai fait un compteur de caractères avec Python
J'ai créé une application de livre simple avec python + Flask ~ Introduction ~
J'ai fait une carte hexadécimale avec Python
J'ai fait un jeu rogue-like avec Python
J'ai fait un simple blackjack avec Python
J'ai créé un fichier de configuration avec Python
J'ai fait une application WEB avec Django
J'ai fait un simulateur de neurones avec Python
J'ai fait une prévision météo de type bot avec Python.
J'ai essayé de créer un bloqueur de filles pourries sur Twitter avec Python ①
[Python] J'ai créé un téléchargeur Youtube avec Tkinter.
J'ai fait un jeu de cueillette avec Python
Made Mattermost Bot avec Python (+ Flask)
J'ai fait un blackjack avec du python!
J'ai fait un texte Python
J'ai fait un blackjack avec Python.
[GUI avec Python] PyQt5-Préparation-
J'ai créé wordcloud avec Python.
[GUI avec Python] PyQt5 -Paint-
J'ai fait un Twitter BOT avec GAE (python) (avec une référence)
J'ai fait un jeu d'éclairage de sapin de Noël avec Python
J'ai créé une application de notification de nouvelles en ligne avec Python
J'ai créé un environnement Python3 sur Ubuntu avec direnv.
J'ai essayé de faire LINE BOT avec Python et Heroku
[GUI avec Python] PyQt5 -Widget II-
Faisons une interface graphique avec python.
J'ai joué avec PyQt5 et Python3
[GUI avec Python] PyQt5-Widget personnalisé-
J'ai fait un jeu de frappe simple avec tkinter de Python
J'ai créé un package pour filtrer les séries chronologiques avec python
J'ai fait un jeu de puzzle (comme) avec Tkinter of Python
J'ai fait un programme de gestion de la paie en Python!
J'ai dessiné une carte thermique avec Seaborn [Python]
J'ai essayé un langage fonctionnel avec Python
[Python] Une application web rapide avec Bottle!
Ce que j'ai fait avec les tableaux Python
J'ai fait un jeu de vie avec Numpy
Exécutez une application Web Python avec Docker
J'ai fait un générateur Hanko avec GAN
Après avoir étudié Python3, j'ai créé un Slackbot
J'ai fait un circuit simple avec Python (AND, OR, NOR, etc.)
J'ai fait un package qui peut comparer des analyseurs morphologiques avec Python
J'ai créé un formulaire de tweet Nyanko avec Python, Flask et Heroku
J'ai créé beaucoup de fichiers pour la connexion RDP avec Python
[Python] J'ai créé une visionneuse d'images avec une fonction de tri simple.
J'ai fait un shuffle qui peut être réinitialisé (inversé) avec Python
J'ai essayé de créer une application de notification de publication à 2 canaux avec Python
J'ai essayé de créer une application todo en utilisant une bouteille avec python
J'ai créé un chat-holdem de serveur de jeu de poker en utilisant websocket avec python
J'ai fait un robot de remplacement de tampon avec une ligne
Exécuter des scripts Python à partir d'applications C # GUI
J'ai créé un fichier de dictionnaire python pour Neocomplete
〇✕ J'ai fait un jeu
J'ai créé un outil pour parcourir automatiquement plusieurs sites avec Selenium (Python)
J'ai créé une application Web en Python qui convertit Markdown en HTML