doppelte Elemente abfangen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Benutzeravatar
Felix92
User
Beiträge: 133
Registriert: Mittwoch 7. November 2018, 17:57

Huhu und zwar stehe ich gerade etwas auf dem Schlauch :roll:
Vlt. kann mir ja jmd einen Tipp geben was im folgenden Code die einfachste Variante wäre, dass jedes Element nur einmal vorhanden sein darf also quasi wenn Datei/String bereits in Liste dann ....
Desweiteren verstehe ich nicht so recht, weshalb ich mit .getOpenFileNames nur eine Datei auswählen kann anstaat mehrere laut Doku müsste das doch möglich sein :/
Bild

Code:

Code: Alles auswählen

import sys
import os
import numpy as np
import cv2

from PyQt5 import uic
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtGui import QIcon, QPixmap, QImage
from PyQt5.QtWidgets import QApplication, QFileDialog, QWidget, QListWidget, QLabel, QPushButton, QListWidgetItem
from PyQt5.QtCore import QObject, QSize
from PIL import Image, ImageQt
from pathlib import Path
from config import Resources


class Filemanager(QWidget):

    def __init__(self, parent=None):
        super().__init__(parent)
        uic.loadUi(Resources.get_instance().files.filemanager, self)
        self.pickButton = self.findChild(QObject,'pushButton_2')
        self.clearButton = self.findChild(QObject,'pushButton_3')
        self.listWidget = self.findChild(QObject,'listWidget')
        self.listWidget.setDragEnabled(True)
        self.listWidget.setAcceptDrops(False)
        self.listWidget.setMouseTracking(True)
        self.listWidget.setIconSize(QSize(100,100))

        self.pickButton.clicked.connect(self.pickFileNames)
        self.clearButton.clicked.connect(self.clearFileNames)

        self.current_frame = 0
        self.preview_list = []

    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):
        last_element = fileNames[-1]

        if last_element.endswith(('.jpg','.JPEG', '.jpeg', '.JPG','.png', '.PNG')):
            picture = Image.open(last_element)
            picture = picture.resize(((275,183)), Image.ANTIALIAS)
            icon = QIcon(QPixmap.fromImage(ImageQt.ImageQt(picture)))
            item = QListWidgetItem(os.path.basename(last_element)[:20], self.listWidget)
            item.setIcon(icon)
            item.setToolTip(last_element)
            item.setStatusTip(last_element)

        elif last_element.endswith(('.mp4', '.MP4')):
            path = Resources.get_instance().images.media_symbols
            video_input_path = last_element
            cap = cv2.VideoCapture(str(video_input_path))

            number = 0
            while (number < 1):
                ret, frame = cap.read()
                if not ret or number == 1:
                    break
                else:
                    cv2.imwrite(os.path.join(path, "video%d.jpg" % self.current_frame), frame)
                    filename = "video%d.jpg" % self.current_frame
                    self.current_frame += 1
                    preview_file = Path(path, filename)
                    self.preview_list.append(preview_file)
                    number += 1
            cap.release()
            cv2.destroyAllWindows()

            element = self.preview_list[-1]

            picture = Image.open(element)
            picture = picture.resize(((275,183)), Image.ANTIALIAS)
            icon = QIcon(QPixmap.fromImage(ImageQt.ImageQt(picture)))
            item = QListWidgetItem(os.path.basename(last_element)[:20], self.listWidget)
            item.setToolTip(last_element)
            item.setStatusTip(last_element)
            item.setIcon(icon)

        elif last_element.endswith(('.mp3', '.MP3')):
            path = Resources.get_instance().images.media_symbols
            filename = "mp3logo.jpg"
            path_to_file = Path(path, filename)
            picture = Image.open(path_to_file)
            picture = picture.resize(((275,183)), Image.ANTIALIAS)
            icon = QIcon(QPixmap.fromImage(ImageQt.ImageQt(picture)))
            item = QListWidgetItem(os.path.basename(last_element)[:20], self.listWidget)
            item.setIcon(icon)
            item.setToolTip(last_element)
            item.setStatusTip(last_element)

        else:
            print("The datatype is not supported")
            pass

    def clearFileNames(self):

        self.listWidget.clear()


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


if __name__ == '__main__':
    main()
Vielen Dank im Vorraus
MfG Felix
Benutzeravatar
sparrow
User
Beiträge: 4538
Registriert: Freitag 17. April 2009, 10:28

1. So wie ich das sehe, funktioniert das mit den mehrere Dateien auswählen durchaus. Aber du verwendest ja nur das letzte Element aus der Liste.

2. Dein Programm funktioniert nicht, wie gewünscht, wenn jemand ".jPG" oder ".jPg" als Dateienamenerweiterung verwendet. Statt alle möglichen Varianten der Groß- und Kleinschreibung aufzuführen, ist es sinnvoller, den Dateinamen einmal in eine Schreibweise zu überführen (zum Beispiel Großschreibung) und dann gegen die entsprechenden Optionen zu testen.

3. Viele Deiner Anweisungen in den verschiedenen Fällen sind identische. Es ist sinnvoll, macht das Programm einfacher zu lesen und ist weniger fehleranfällig, wenn du das zusammenfasst und nur dort unterscheidest, wo es auch wirklich sinnvoll ist.

4. Bisher fügst du immer an, egal ob das Element bereits auf dem "listWidget" ist. Wenn es keine doppelten Elemente geben darf, dann musst du das an irgend einer Stelle prüfen. Im besten Fall direkt vor dem Einfügen. Entweder muss du schauen, ob das Element bereits auf "listWidget" vorhanden ist, oder du nimmst zusätzlich eine Liste, auf der du alle Elemente einfügst, die du auf das listWidget tust. Dann kannst du bei einem neuen Element schauen, ob es hier bereits vorhanden ist. Natürlich musst du es auch wieder von der Liste entfernen, wenn du es von Widget nimmst.
Benutzeravatar
sparrow
User
Beiträge: 4538
Registriert: Freitag 17. April 2009, 10:28

Das was du tust, um an ein Vorschaubild von Videos zu gelangen, sieht kaputt aus.

1. Du führst eine while-Schleife aus, die aber entweder abbricht oder auf jeden Fall nur ein einziges Mal ausgeführt wird. Dann braucht man auch keine while-Schleife.

2. Warum legst du current_frame auf self an?

3. Warum legst du preview_list auf self an?

4. self.current frame ist bei der ersten hinzugefügten Videodatei 0, bei der zweiten 1, bei der dritten 2, etc. Sicher dass das so sein soll?

5. Ich bin mir ziemlich sicher, dass du das extrahierte Bild aus dem Video direkt verwenden kannst, ohne es vorher auf die Platte zu schreiben und von dort wieder zu lesen.
Benutzeravatar
Felix92
User
Beiträge: 133
Registriert: Mittwoch 7. November 2018, 17:57

Danke für eure Antworten es funktioniert jetzt alles so wie es soll ....ausser das wenn ich mehrere Videos (erste Bild ist dann meistens einfach schwarz) und .jpg Bilder (nur bei .jpg alle anderen Formate funktionieren/ es wird für alle Dateien das letzte Bild angezigt, was bei png nicht so ist dort wird alles korrekt angezigt) hinzufüge diese nicht korrekt angezeigt werden. Woran liegt das ? Kennt jmd. eine Lösung dafür ? Es gibt halt auch keine Fehlermeldung!

Hier der Stand der Dinge:
Bild

Code:

Code: Alles auswählen

import sys
import os
import numpy as np
import cv2

from PyQt5 import uic
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtGui import QIcon, QPixmap, QImage
from PyQt5.QtWidgets import QApplication, QFileDialog, QWidget, QListWidget, QLabel, QPushButton, QListWidgetItem
from PyQt5.QtCore import QObject, QSize
from PIL import Image, ImageQt
from pathlib import Path
from config import Resources


class Filemanager(QWidget):

    def __init__(self, parent=None):
        super().__init__(parent)
        uic.loadUi(Resources.get_instance().files.filemanager, self)
        self.pickButton = self.findChild(QObject,'pushButton_2')
        self.clearButton = self.findChild(QObject,'pushButton_3')
        self.listWidget = self.findChild(QObject,'listWidget')
        self.listWidget.setDragEnabled(True)
        self.listWidget.setAcceptDrops(False)
        self.listWidget.setMouseTracking(True)
        self.listWidget.setIconSize(QSize(100,100))

        self.pickButton.clicked.connect(self.pickFileNames)
        self.clearButton.clicked.connect(self.clearFileNames)

        self.current_frame = 0
        self.preview_list = []
        self.file_list = []

    def pickFileNames(self):
        fileNames, _ = QFileDialog.getOpenFileNames(
            self,
            'QFileDialog.getOpenFileNames()',
            '',
            (
                'Files ( *.png *.jpg *.mp3 *.wav *.mp4);;'
            )
        )

        self.addFileNames(fileNames)


    def addFileNames(self, fileNames):

        for file in fileNames:

            if file in self.file_list:
                print("The file exist")
                break

            if file.upper().endswith(('.JPEG', '.JPG', '.PNG')):
                picture = Image.open(file)
                picture = picture.resize(((275,183)), Image.ANTIALIAS)
                icon = QIcon(QPixmap.fromImage(ImageQt.ImageQt(picture)))
                item = QListWidgetItem(os.path.basename(file)[:20], self.listWidget)
                item.setIcon(icon)
                item.setToolTip(file)
                item.setStatusTip(file)
                self.file_list.append(file)

            elif file.upper().endswith(('.MP4')):
                path = Resources.get_instance().images.media_symbols
                video_input_path = file
                cap = cv2.VideoCapture(str(video_input_path))

                number = 0
                if (number < 1):
                    ret, frame = cap.read()
                    if not ret or number == 1:
                        break
                    else:
                        cv2.imwrite(os.path.join(path, "video%d.jpg" % self.current_frame), frame)
                        filename = "video%d.jpg" % self.current_frame
                        self.current_frame += 1
                        preview_file = Path(path, filename)
                        number += 1
                cap.release()
                cv2.destroyAllWindows()


                picture = Image.open(preview_file)
                picture = picture.resize(((275,183)), Image.ANTIALIAS)
                icon = QIcon(QPixmap.fromImage(ImageQt.ImageQt(picture)))
                item = QListWidgetItem(os.path.basename(file)[:20], self.listWidget)
                item.setToolTip(file)
                item.setStatusTip(file)
                item.setIcon(icon)
                self.file_list.append(file)

            elif file.upper().endswith(('.MP3', '.WAV')):
                path = Resources.get_instance().images.media_symbols
                filename = "mp3logo.jpg"
                path_to_file = Path(path, filename)
                picture = Image.open(path_to_file)
                picture = picture.resize(((275,183)), Image.ANTIALIAS)
                icon = QIcon(QPixmap.fromImage(ImageQt.ImageQt(picture)))
                item = QListWidgetItem(os.path.basename(file)[:20], self.listWidget)
                item.setIcon(icon)
                item.setToolTip(file)
                item.setStatusTip(file)
                self.file_list.append(file)

            else:
                print("The datatype is not supported")
                pass

    def clearFileNames(self):

        self.listWidget.clear()

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


if __name__ == '__main__':
    main()
MfG Felix und vielen Dank für eure Zeit und Hilfe :)
Benutzeravatar
Felix92
User
Beiträge: 133
Registriert: Mittwoch 7. November 2018, 17:57

@sparrow die globalen Variablen und das abspeichern der Dateien soll so sein (frag mich bitte nicht wieso :D) bzw. wird später noch benötigt soweit ich weiß ... beim Videoframe direkt ohne abspeichern würde mich trotzdem interessieren wie das funktionieren soll, da ich davon ausging das es ohne imwrite() nicht funktioniert bzw. ich keine Variable mit diesem Frame initialisieren kann !?
Benutzeravatar
Felix92
User
Beiträge: 133
Registriert: Mittwoch 7. November 2018, 17:57

Ich habe den Code noch angepasst gerade beim Video und es mit time.sleep() probiert allerdings ohne große Fortschritte ...Ich verstehe es absolut nicht weshalb es beim Png Format einwandfrei funktioniert und bei jpg nicht !?
Benutzeravatar
Felix92
User
Beiträge: 133
Registriert: Mittwoch 7. November 2018, 17:57

Hier mal noch der aktuelle Code:

Code: Alles auswählen

import sys
import os
import numpy as np
import cv2
import time

from PyQt5 import uic
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtGui import QIcon, QPixmap, QImage
from PyQt5.QtWidgets import QApplication, QFileDialog, QWidget, QListWidget, QLabel, QPushButton, QListWidgetItem
from PyQt5.QtCore import QObject, QSize
from PIL import Image, ImageQt
from pathlib import Path
from config import Resources


class Filemanager(QWidget):

    def __init__(self, parent=None):
        super().__init__(parent)
        uic.loadUi(Resources.get_instance().files.filemanager, self)
        self.deleteButton = self.findChild(QObject,'pushButton_1')
        self.pickButton = self.findChild(QObject,'pushButton_2')
        self.clearButton = self.findChild(QObject,'pushButton_3')
        self.listWidget = self.findChild(QObject,'listWidget')
        self.listWidget.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection)
        self.listWidget.setDragEnabled(True)
        self.listWidget.setAcceptDrops(False)
        self.listWidget.setMouseTracking(True)
        self.listWidget.setIconSize(QSize(100,100))

        self.pickButton.clicked.connect(self.pickFileNames)
        self.clearButton.clicked.connect(self.clearFileNames)
        self.deleteButton.clicked.connect(self.remove)
        self.listWidget.itemSelectionChanged.connect(self.selected)

        self.current_frame = 0
        self.file_list = []

    def pickFileNames(self):
        fileNames, _ = QFileDialog.getOpenFileNames(
            self,
            'QFileDialog.getOpenFileNames()',
            '',
            (
                'Files ( *.png *.jpg *.mp3 *.wav *.mp4);;'
            )
        )

        for file in fileNames:
            self.addFileNames(file, fileNames)


    def addFileNames(self, file, fileNames):

        if file in self.file_list:
            print("The file exist")
            return

        if file.upper().endswith(('.JPG', '.PNG')):
            picture = Image.open(file)
                
        elif file.upper().endswith(('.MP4')):
            path = Resources.get_instance().images.media_symbols
            video_input_path = file
            cap = cv2.VideoCapture(str(video_input_path))

            ret, frame = cap.read()
            if not ret:
                return
            else:
                cv2.imwrite(os.path.join(path, "video%d.jpg" % self.current_frame), frame)
                filename = "video%d.jpg" % self.current_frame
                self.current_frame += 1
                preview_file = Path(path, filename)
            cap.release()
            cv2.destroyAllWindows()

            picture = Image.open(preview_file)
                
        elif file.upper().endswith(('.MP3', '*.WAV')):
            path = Resources.get_instance().images.media_symbols
            filename = "mp3logo.jpg"
            path_to_file = Path(path, filename)
            picture = Image.open(path_to_file)
                
        else:
            print("The datatype is not supported")
            pass

        time.sleep(0.5)
        picture = picture.resize(((275,200)), Image.ANTIALIAS)
        icon = QIcon(QPixmap.fromImage(ImageQt.ImageQt(picture)))
        item = QListWidgetItem(os.path.basename(file)[:20], self.listWidget)
        item.setIcon(icon)
        item.setToolTip(file)
        item.setStatusTip(file)
        self.file_list.append(file)

    def clearFileNames(self, fileNames):
        self.listWidget.clear()
        self.file_list.clear()

    def remove(self):
        try:
            path = self.listWidget.currentItem().statusTip()
            self.file_list.remove(path)
            self.listWidget.takeItem(self.listWidget.currentRow())
        except:
            return

    def selected(self):
        try:
            path = self.listWidget.currentItem().statusTip()
            print(path) #String for drag&drop ??
        except:
            return

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


if __name__ == '__main__':
    main()
MfG Felix wäre schon wenn mir dort jemand weiterhelfen könnte ich hänge dort gerade echt fest und weiß ohne jegliche Fehlermeldung auch nicht so recht was ich noch alles probieren soll :roll:
Benutzeravatar
Felix92
User
Beiträge: 133
Registriert: Mittwoch 7. November 2018, 17:57

Gelöst mit QApplication.processEvents()
closed
Benutzeravatar
__blackjack__
User
Beiträge: 14044
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Felix92: Bei den Importen könnte man mal aufräumen. Da wird so einiges gar nicht verwendet und Standardbibliothek und Drittanbieter sind gemischt.

Ich glaube ich hatte das schon mal erwähnt: die ganzen `findChild()`-Aufrufe sind überflüssig. Die benannten Widgets aus der `ui`-Datei gibt es bereits als Attribute. Du müsstest da dann nur welche in der `ui`-Datei umbennenen, damit sie gleich den richtigen Namen haben und nicht am Ende zweimal auf dem Objekt mit unterschiedlichen Namen ansprechbar sind.

`setSelectionMode()` ist überflüssig, denn `SingleSelection` ist die Voreinstellung. Die kannst Du höchstens in der *.ui-Datei verstellt haben, aber dann sollte man das *dort* wieder ändern.

Grunddatentypen haben in Namen nichts zu suchen. Das `_list` in `file_list` gehört da nicht hin. Wenn man den Typ nämlich im Laufe der Entwicklung mal ändert, dann muss man entweder überall die betroffenen Namen anpassen, oder man hat falsche, irreführende Namen im Programm stehen. Und den Typ sollte man hier ändern, denn was Du da mit der Liste machst, ist eigentlich ein Fall für ein `set()`.

Die `addFileNames()`-Methode ist a) falsch benannt, denn die fügt nur *einen* Dateinamen hinzu, und b) ist das zweite Argument sinnlos, denn das wird nirgends verwendet.

Man sollte auch nicht den Namen `file` verwenden wenn man eigentlich `filename` meint. Das ist ein Unterschied. Von etwas das `file` heisst, erwartet der Leser das es eine Datei repräsentiert und Methoden wie `read()`/`write()`/`close()` besitzt.

Der Name `video_input_path` ist überflüssig – warum bindest Du den Dateinamen noch mal an diesen Namen der dann auch nur einmal, gleich in der nächsten Zeile verwendet wird?

Das freigeben vom `VideoCapture`-Objekt sollte man in einen ``finally``-Zweig packen, damit das auch wirklich immer geschiet, egal was zwischen dem erstellen und dem freigeben passiert.

Du erstellst den selben Pfad und den nummerierten Dateinamen für die temporäre Datei zweimal. Einmal mit `Path` und einmal mit `os.path.join()`. Das macht keinen Sinn.

Zumal man sich das speichern sowieso sparen kann. Man kann auch das Bild im Speicher in ein `PIL.Image` umwandeln.

Beim Test auf WAV-Dateiendungen ist ein '*' was verhindern dürfte das WAV-Dateien erkannt werden.

In der Methode gibt es ein überflüssiges ``pass``.

Was hat das `time.sleep()` da zu suchen?

Unbekannte Dateendungen oder Ausnahmen aus anderen Gründen bei `addFilename()` führen dazu, dass keine weiteren ausgewählten Dateinamen mehr hinzugefügt werden. Das sollte man abfangen. Einer der wenigen Fälle wo es okay ist alle Ausnahmen zu behandeln. Aber nicht einfach durch ignorieren, sondern durch Ausgabe der Ausnahme samt Traceback, so dass man bei der Fehlersuche auch eine Chance hat.

Bei `clearFileNames()` wird ein unbenutztes Argument erwartet‽

Die ``try``/``except``\s in `remove` und `selected` haben da nichts zu suchen. Jegliche Ausnahme einfach ignorieren ist keine sinnvolle Ausnahmebehandlung.

`takeItem()` gibt einen Wert zurück – den kann man auch verwenden.

Zwischenstand (ungetestet):

Code: Alles auswählen

#!/usr/bin/env python3
import os
import sys
from pathlib import Path
from traceback import print_exc

from PyQt5 import uic
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QApplication, QFileDialog, QListWidgetItem, QWidget
from PyQt5.QtCore import QSize
from PIL import Image, ImageQt
import cv2

from config import Resources


class Filemanager(QWidget):

    def __init__(self, parent=None):
        super().__init__(parent)
        uic.loadUi(Resources.get_instance().files.filemanager, self)
        self.listWidget.setDragEnabled(True)
        self.listWidget.setIconSize(QSize(100, 100))

        self.pickButton.clicked.connect(self.pickFileNames)
        self.clearButton.clicked.connect(self.clearFileNames)
        self.deleteButton.clicked.connect(self.remove)
        self.listWidget.itemSelectionChanged.connect(self.selected)

        self.filenames = set()

    def pickFileNames(self):
        filenames, _ = QFileDialog.getOpenFileNames(
            self,
            'QFileDialog.getOpenFileNames()',
            '',
            ('Files ( *.png *.jpg *.mp3 *.wav *.mp4);;')
        )
        for filename in filenames:
            try:
                self.addFileName(filename)
            except Exception:
                print_exc()

    def addFileName(self, filename):
        if filename in self.filenames:
            print('The file exist')
            return

        if filename.upper().endswith(('.JPG', '.PNG')):
            picture = Image.open(filename)
                
        elif filename.upper().endswith(('.MP4')):
            video_capture = cv2.VideoCapture(str(filename))
            try:
                success, frame = video_capture.read()
                if not success:
                    return
                else:
                    picture = Image.fromarray(
                        cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
                    )
            finally:
                video_capture.release()
                cv2.destroyAllWindows()
                
        elif filename.upper().endswith(('.MP3', '.WAV')):
            path = Path(Resources.get_instance().images.media_symbols)
            picture = Image.open(path / 'mp3logo')
                
        else:
            print('The datatype is not supported')

        picture = picture.resize(((275, 200)), Image.ANTIALIAS)
        item = QListWidgetItem(
            QIcon(ImageQt.toqpixmap(picture)),
            os.path.basename(filename)[:20],
            self.listWidget,
        )
        item.setToolTip(filename)
        item.setStatusTip(filename)
        self.filenames.add(filename)

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

    def remove(self):
        item = self.listWidget.takeItem(self.listWidget.currentRow())
        self.filenames.remove(item.statusTip())

    def selected(self):
        path = self.listWidget.currentItem().statusTip()
        print(path) #String for drag&drop ??


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


if __name__ == '__main__':
    main()
`QApplication.processEvents()` klingt gefährlich. Gerade bei Anfängern oft ein Zeichen das sie sich da ihre eigene GUI-Schleife basteln weil sie mit dem Konzept von ereignisbasierter Programmierung nicht klar kommen.
„A life is like a garden. Perfect moments can be had, but not preserved, except in memory. LLAP” — Leonard Nimoy's last tweet.
Antworten