PyQt5 Datein im listWidget als Bilder anzeigen

Python und das Qt-Toolkit, erstellen von GUIs mittels des Qt-Designers.
Antworten
Benutzeravatar
Felix92
User
Beiträge: 133
Registriert: Mittwoch 7. November 2018, 17:57

Huhu und zwar wollte ich mal nachfragen, wie ich im folgenden Bild Dateien die eingelesen wurden entweder:

Variante1:
links soll ein "Vorschaubild" der Datei (.jpg, .mp4, .wav) zu sehen sein und rechts daneben der Dateiname

oder

Variante2:
die eingelesenen Dateien sollen in Form eines GridLayouts angeordnet werden es soll nur ein Vorschaubild zu sehen sein und wenn man mit der Maus über eines der Vorschaubilder fährt soll der Dateiname angezeigt werden.

darstellen kann.

Alle Dateien sollten drag&drop bar sein.

Bild

Code:

Code: Alles auswählen

import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QWidget, QPushButton, QListWidget
from PyQt5 import uic
from PyQt5.QtCore import QObject
from config import Resources
import os

class Filemanager(QWidget):

    def __init__(self, parent=None):
        super(Filemanager, self).__init__(parent)
        uic.loadUi(Resources.get_instance().files.filemanager, self)
        self.setupUi()
        # self.retranslateUi()

    def setupUi(self):
        self.setObjectName("file_manager")
        #Dialog.resize(673, 280)
        self.pushButton_3 = self.findChild(QObject,'pushButton_3')
        self.pushButton_2 = self.findChild(QObject,'pushButton_2')
        self.listWidget = self.findChild(QObject,'listWidget')
        # self.retranslateUi(self)
        self.pushButton_2.clicked.connect(self.filePick)
        self.pushButton_3.clicked.connect(self.clearListWidget)
        QtCore.QMetaObject.connectSlotsByName(self)

    def retranslateUi(self):
        _translate = QtCore.QCoreApplication.translate
        self.setWindowTitle(_translate("Dialog", "Dialog"))
        self.pushButton_3.setToolTip(_translate("Dialog", "<html><head/><body><p>Clear</p></body></html>"))
        self.pushButton_3.setText(_translate("Dialog", "Clear"))
        self.pushButton_2.setToolTip(_translate("Dialog", "<html><head/><body><p>Pick File</p></body></html>"))
        self.pushButton_2.setText(_translate("Dialog", "Pick Files"))
        self.pushButton.setToolTip(_translate("Dialog", "<html><head/><body><p>Exit</p></body></html>"))
        self.pushButton.setText(_translate("Dialog", "Exit"))

    def filePick(self):
        fileNames, _ = QtWidgets.QFileDialog.getOpenFileNames(None, "QFileDialog.getOpenFileName()", "",
                                                  "All Files (*);;Image Files (*.png);; Sound Files(*.mp3);; Movie Files (*.mp4)")

        self.fillListWidget(fileNames)

    def fillListWidget(self, filenames):
        self.listWidget.addItems(filenames)

    def clearListWidget(self):
        self.listWidget.clear()

    def exit(self):
        sys.exit(app.exec_())

if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    Dialog = QtWidgets.QDialog()
    ui = Filemanager()
    ui.setupUi(Dialog)
    Dialog.show()
    sys.exit(app.exec_())
Da ich in PyQt5 noch ziemlich unerfahren bin wäre ich für Ideen, Vorschläge sowie zum Thema passende Tutorials sehr dankbar.

MfG Felix
Benutzeravatar
__blackjack__
User
Beiträge: 13077
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Felix92: Anmerkungen zum Quelltext:

Die Importe sind recht durcheinander. Es ist üblich die in Blöcken zu organisieren: Standardbibliothek, externe Bibliotheken, eigene Module.

`os`, `QtGui`, `QListWidget`, und `QPushButton` werden importiert, aber nicht verwendet.

Bei `PyQt5` werden sowohl die Module `QtCore` als auch `QtWidgets` importiert aber auch Namen aus diesen Modulen, wobei nicht klar ist nach welchem Muster jetzt auf die eine oder andere Weise zugegriffen wird. Das finde ich verwirrend.

Da `QApplication` sowieso importiert wird braucht man `QCoreApplication` nicht um an die statische `translate()`-Methode zu kommen.

Im ``if __name__ …:``-Block steht Code der a) globale Namen definiert und b) nicht lauffähig ist. Da wird versucht die `setupUi()`-Methode vom `Filemanager`-Objekt mit einem Argument aufzurufen – diese Methode erwartet aber gar kein Argument. Es ist auch nicht wirklich klar was das da überhaupt bewirken soll mit dem `QDialog`-Objekt‽ Zudem wird dort `sys` noch einmal importiert.

Wenn man das Hauptprogramm von Modulebene in eine Funktion verschiebt, kann `Filemanager.exit()` nicht mehr auf den vorher globalen Namen `app` zugreifen. Die Methode ist aber sowieso komisch und überflüssig.

Bei Python 3 braucht man bei `super()` nicht mehr die Klasse und `self` als Argumente angeben, die Funktion kann diese Werte selbst ermitteln.

Die ersten vier Zeilen von `setupUi()` sind überflüssig – das wird bereits von `uic.loadUi()` erledigt.

Ich sehe auch keinen Grund das in eine eigene Methode auszulagern.

Wenn `retranslateUi()` sowieso nicht genutzt wird, kann man die Methode auch weglassen.

`pushButton_2`, `pushButton_3`, und `listWidget` sind keine guten Namen. Der Leser will nicht wissen das es sich um eine Schaltfläche und um die wie vielte die erstellt wurde, oder allgemein um ein `listWidget` handelt, sondern was diese Elemente bedeuten.

Beim Dateidialog würde ich das Fenster als Elternobjekt übergeben.

Da bleibt dann das hier übrig (ungetestet):

Code: Alles auswählen

#!/usr/bin/env python3
import sys

from PyQt5 import uic
from PyQt5.QtWidgets import QApplication, QFileDialog, QWidget

from config import Resources


class Filemanager(QWidget):

    def __init__(self, parent=None):
        super().__init__(parent)
        uic.loadUi(Resources.get_instance().files.filemanager, self)
        # 
        # FIXME Better names for ui elements!
        # 
        self.pushButton_2.clicked.connect(self.pickFileNames)
        self.pushButton_3.clicked.connect(self.clearFileNames)

    def pickFileNames(self):
        fileNames, _ = QFileDialog.getOpenFileNames(
            self,
            'QFileDialog.getOpenFileNames()',
            '',
            (
                'All Files (*);;'
                'Image Files (*.png);;'
                'Sound Files(*.mp3);;'
                'Movie Files (*.mp4)'
            )
        )
        self.addFileNames(fileNames)

    def addFileNames(self, fileNames):
        self.listWidget.addItems(fileNames)

    def clearFileNames(self):
        self.listWidget.clear()


def main():
    app = QApplication(sys.argv)
    window = Filemanager()
    window.show()
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()
Falls das Bild in Variante 1 auch links neben dem Dateinamen sein darf, könntest Du beim `QListWidget`/`QListView` bleiben und Icons für die Einträge setzen. Ansonsten wäre das wohl ein Fall für `QTreeWidget`/`QTreeView` mit einer zweiten Spalte für das Bild rechts neben dem Namen.

Für Variante 2 könnte man ein `QListWidget`/`QListView` im `IconMode` verwenden.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
Felix92
User
Beiträge: 133
Registriert: Mittwoch 7. November 2018, 17:57

@__blackjack__ erstmal vielen Dank für deine ausführliche Antwort ...der Code ist leider von einem Teamkollegen da muss ich erstmal klären ob ich den ändern darf :D

Könntest du das speziell für Variante2 vlt. noch etwas präziser erklären wie ich da am besten vorgehen sollte !? den iconmode habe ich im Creator für das listWidget bereits aktiviert :)

Und vlt. könntest du mir das mit den imports für pyqt5 noch erklären gibt es keine einfachere Variante als immer die Oberklasse suchen zu müssen ? :/

MfG Felix
Benutzeravatar
__blackjack__
User
Beiträge: 13077
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Felix92: Ich weiss nicht ob ich da ein `QListWidget` für nehmen würde oder nicht doch lieber ein `QListView`. Dafür könnte man dann eine entsprechende Model-Klasse von `QAbstractListModel` ableiten die bei `data()` je nach Rolle Icons für die Icons/Vorschaubildchen beziehungsweise den Tooltip mit dem Dateinamen liefert.

Die letzte Frage verstehe ich nicht.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
Felix92
User
Beiträge: 133
Registriert: Mittwoch 7. November 2018, 17:57

Naja ich verstehe nich warum man immer aus der Oberklasse die imports holen muss also zum Beispiel from pyqt5.QtWidgets import QWidget anstaat from pyqt5 import QWidget was meiner Meinung nach wesentlich einfacher und logischer wäre !? :/
__deets__
User
Beiträge: 14528
Registriert: Mittwoch 14. Oktober 2015, 14:29

PyQt5 ist die Version von PyQt. QtWidgets ist das Modul von Qt selbst. Und QWidget ist eine darin enthaltene Klasse. Das ist also durchaus alles sehr logisch. Und nicht nur das: waere wie von dir vorgeschlagen der gesamte Namensraum von Qt unterhalb von PyQt5 eingeblendet, wuerde das bedeuten, das auch ALLE Module geladen werden muessen. Selbst grosse, lange ladende, die du gar nicht benutzt. Das ist also auch keine so wahnsinnig grossartige Idee. Und last but not least: es ist halt so. Welchen Sinn genau hat es, sich darueber zu echauffieren?
Benutzeravatar
__blackjack__
User
Beiträge: 13077
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Felix92: Das ist keine Oberklasse sondern ein Modul und die entsprechen den Namensräumen in denen das in C++ von den Qt-Entwicklern organisiert wurde, also ``namespace … { … }`` in C++. Ich weiss auch nicht was daran unlogisch sein sollte das in `QtWidgets` alle (grundlegenden) Widget-Klassen stecken. Und in `QtCore` alle grundlegenden Klassen für die man keine grafische Oberfläche braucht, und so weiter. Das ist eben thematisch sortiert.

Und suchen, naja, das allermeiste was man normalerweise braucht ist in `QtCore` wenn es nicht zwingend eine GUI braucht und in `QtWidgets` wenn es eine GUI braucht. Zwei Module und ein relativ einfaches Unterscheidungsmerkmal.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
Felix92
User
Beiträge: 133
Registriert: Mittwoch 7. November 2018, 17:57

Ah danke das hilft mir wesentlich weiter ich habe bisher immer geschaut aus welchem Modul ich das entsprechende importieren muss aber wenn es eh nur die beiden gibt ist das voll ok da gebe ich dir Recht :)
__deets__
User
Beiträge: 14528
Registriert: Mittwoch 14. Oktober 2015, 14:29

Etwas ärgerlich ist das gelegentlich QtGui verwendet wird. Das Muster ist mir auch noch nicht klar. Letztlich aber folgt es eben einfach der Dokumentation von Qt.
Benutzeravatar
Felix92
User
Beiträge: 133
Registriert: Mittwoch 7. November 2018, 17:57

Da hätte ich gleich noch eine Frage ist es in VSCode möglich sich Möglichkeiten anzeigen zu lassen also welche Methoden z.B. man auf die Klasse anwenden kann inklusive eine Beschreibung : was macht die Methode , Parameter etc. ?
Benutzeravatar
Felix92
User
Beiträge: 133
Registriert: Mittwoch 7. November 2018, 17:57

closed
Antworten