Auslesen von QListWidget

Python und das Qt-Toolkit, erstellen von GUIs mittels des Qt-Designers.
Antworten
lackschuh
User
Beiträge: 281
Registriert: Dienstag 8. Mai 2012, 13:40

Hallo

Ich bräuchte mal einen kleinen Klaps auf den Hinterkopf bzw nen Denkanstoss.

Es gibt eine Funktion, welche für das Öffnen zuständig ist und die ausgewählten Dateien in ein QListWidget lädt:

Code: Alles auswählen

    def onOpen(self):
        dateien = QtGui.QFileDialog.getOpenFileNames(
                            self,
                            u"Dateien öffnen",
                            QtGui.QDesktopServices.storageLocation(QtGui.QDesktopServices.PicturesLocation),
                            u"Images (*.JPG *.jpg *.png")
        
        for datei in dateien:
            datei = unicode(datei)
            print datei
            self.ui.listWidget.addItem(datei)
So weit so gut. Im listWidget wird der Pfad der Dateien eingetragen. Eine andere Funktion soll dann das listWidget auslesen bzw. die einzelnen Pfade. Und genau das krieg ich nicht gebacken. Nach langem Suchen in der anfängerfeindlichen Doku bin ich auf currentItem() gestossen. Jedoch funktioniert die ausgabe erst, wenn ich alle Elemente markiert habe, sonst kommt:

Code: Alles auswählen

    def onSkalieren(self):
        print self.ui.listWidget.currentItem().text()
#        eingabe = self.ui.lineBreite.text()
#        basewidth = int(eingabe)
#        img = Image.open('test.jpg')
#        wpercent = (basewidth/float(img.size[0]))
#        hsize = int((float(img.size[1])*float(wpercent)))
#        img = img.resize((basewidth,hsize), PIL.Image.ANTIALIAS)
#        img.save('test_new.jpg')
#        print 'Bild wurde skaliert auf %s px' %(eingabe)
Fehlermeldung:

Code: Alles auswählen

Traceback (most recent call last):
  File "C:\Projekte\Eclipse\BildSkalierer\gui.py", line 41, in onSkalieren
    print self.ui.listWidget.currentItem().text()
AttributeError: 'NoneType' object has no attribute 'text'
Programm wurde geschlossen
Was bietet mir die QListWidget Class für Funktionen, um mein obgenanntes Problem in den Griff zu bekommen?

Zusatzinfo:
Das Programm soll einfach eine Anzahl von Bildern auf die in der GUI eingegebene Grösse skalieren.
BlackJack

@lackschuh: An die Elemente solltest Du mit der `item()`-Methode heran kommen können. Allerdings sollte man GUI-Elemente eigentlich nicht zum Speichern von Daten verwenden.
lackschuh
User
Beiträge: 281
Registriert: Dienstag 8. Mai 2012, 13:40

Hi,

ich frag mal anders:

Ich öffne Dateien und lasse mir den jeweiligen Pfad im listWidget anzeigen. zB sieht es dann so aus:

C:\Users\rechner.name\Pictures\bild1.jpg
C:\Users\rechner.name\Pictures\bild2.jpg
C:\Users\rechner.name\Pictures\bild3.jpg
...

Dies funktioniert auch wunderbar mit der Funktion def onOpen(self):

Nun aber möchte ich die Pfade der Dateien für die Funktion onSkalieren(self): auslesen und ggf. in eine Liste etc. speichern, damit ich dann die Ausgewählten Bilder skalieren kann.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

lackschuh hat geschrieben: ich frag mal anders:

...

Nun aber möchte ich die Pfade der Dateien für die Funktion onSkalieren(self): auslesen und ggf. in eine Liste etc. speichern, damit ich dann die Ausgewählten Bilder skalieren kann.
Ich antworte mal genauso wie BlackJack: Du willst eine zu Grunde liegende Datenstruktur benutzen, in der die Pfade gehalten werden. Diese können natürlich in der GUI visuell dargestellt werden, aber für Dinge wie das Iterieren über *alle* Elemente greifst Du eben auf die Dtruktur zurück und *nicht* die GUI und deren Kindobjekte. Diese brauchst Du ja nur, wenn Du *spezielle* Items auswählen willst...

Wie BlackJack schon sagte kannst Du das über die ``item(int row)``-Methode des ``QListWidgets`` erreichen - über ``.count()`` bekommst Du die Länge und damit den maximalen Index heraus.

Wie "öffnest" Du denn Dateien? Oder meinst Du, Du holst Dir irgend wie die Dateinamen? Unter ersterem kann ich mir im Zusammenhang mit der Anzeige der Dateinamen nichts vorstellen, zweiteres legt nahe, dass Du die Namen ja bereits in einer passenden - oder zumindest leicht nutzbaren - Datenstruktur bekommst, etwa durch ``os.listdir()`` o.ä.

Generell solltest Du Dir mal den MVC-Pattern angucken; Qt bietet dazu einen eigenen Artikel an. Dann greifst Du eher auf die (offenen) Model basierten Klassen a la ``QListView`` zurück.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

@lackschuh: PyQt ist eigentlich so gestaltet, dass man durchaus mit nativen Python-Objekten (hier: `list`) interagieren kann. Du musst ja auch nicht jedes Mal einen `QString` erstellen, um eine Zeichenkette an das Qt-Framework zu übergeben. Auch das Öffnen von Dateien würde man eher mithilfe von Pythons Builtin-Funktion `open()` machen und nicht mit `QFile`.

Bedenke, dass die Qt-Bibliothek für C++ geschrieben wurde, wo eben vieles nicht so leicht von der Hand geht wie in Python, da in der Stdlib von C++ gewisse abstrakte Datentypen nicht (oder zumindest nicht mit der von Python gewohnten Funktionalität) vorhanden sind und bestimmte Vorhaben nur mit gewissem Mehraufwand zu realisieren sind. Daher stellt Qt Hilfsklassen bereit, die einem das Leben in dieser Hinsicht leichter machen sollen. Vieles davon braucht man aber wie gesagt bei der Verwendung von PyQt nicht, da man auf die von Python selbst bereit gestellten APIs zurückgreifen kann.

Ich will nicht behaupten, dass es keine Ausnahmen gäbe, aber in aller Regel sollte man IMHO schon soviel "echtes" Python benutzen wie möglich.

EDIT: Hier mal ein Beispiel aus der Doku:
The QStringList class is implemented as a mapped type that is automatically converted to and from a Python list of strings.
Quelle

Wobei PyQt auch nochmal Unterschiede in seinem Verhalten macht, je nachdem ob man Python 2 oder Python 3 nutzt. Da muss man ein bißchen aufpassen.
lackschuh
User
Beiträge: 281
Registriert: Dienstag 8. Mai 2012, 13:40

Hi

Sry dass ich erst jetzt antworte - war über Ostern weg :wink:

Mit QListWidget.item(int) bekomme ich ja nur die Speicheradresse und nicht den Pfad zur Datei, oder?

Ich hab es nun so gelöst:

Code: Alles auswählen

    def onOpen(self):
        self.dateien = QtGui.QFileDialog.getOpenFileNames(
                            self.filename,
                            u"Dateien öffnen",
                            QtGui.QDesktopServices.storageLocation(QtGui.QDesktopServices.PicturesLocation),
                            u"Images (*.JPG *.jpg *.png")
        #Bildvorschau
        for url in self.dateien:
            if os.path.exists(url):
                print(url)
                icon = QtGui.QIcon(url)
                pixmap = icon.pixmap(72, 72)
                icon = QtGui.QIcon(pixmap)
                item = QtGui.QListWidgetItem(url, self.ui.listWidget)
                item.setIcon(icon)
                item.setStatusTip(url)
    
    def onSkalieren(self):

        for k, datei in enumerate(self.dateien):
            datei = unicode(datei)
            print datei

            breite = self.ui.lineBreite.text()
            basewidth = int(breite)
            print basewidth
            img = Image.open(datei)
            wpercent = (basewidth/float(img.size[0]))
            hsize = int((float(img.size[1])*float(wpercent)))
            img = img.resize((basewidth,hsize), PIL.Image.ANTIALIAS)
            img.save(datei[:-4] +'_%s.jpg' % k)
            print 'Bild wurde skaliert auf %s px' %(eingabe)
Ob dies eine saubere Lösung ist bezweifle ich, zumal ja PyQt4 selbst Methoden - ich glaube es zumindest - zum Verkleinern hat.
Zuletzt geändert von lackschuh am Mittwoch 3. April 2013, 10:12, insgesamt 1-mal geändert.
BlackJack

@lackschuh: Eine Speicheradresse bekommst Du von der `item()`-Methode ganz sicher nicht. *Was* Du bekommst, kannst Du mit `type()` heraus finden.
lackschuh
User
Beiträge: 281
Registriert: Dienstag 8. Mai 2012, 13:40

BlackJack hat geschrieben:@lackschuh: Eine Speicheradresse bekommst Du von der `item()`-Methode ganz sicher nicht. *Was* Du bekommst, kannst Du mit `type()` heraus finden.
Ok, jetzt hab ich's gerafft. Ich muss halt den Wert noch umwandeln :K

Code: Alles auswählen

path = self.ui.listWidget.item(0)
print type(path)
value = path.text()
print value
Dann wäre die ganze Prozedur wie folgt:

Code: Alles auswählen

        anzahl = self.ui.listWidget.count()
        print anzahl
        for i in range(anzahl):
            path = self.ui.listWidget.item(i)
            value = path.text()
            print value
Jetzt stellt sich die Frage, was der bessere Weg ist, der obige oder mein bisheriger:

Code: Alles auswählen

#         for k, datei in enumerate(self.dateien):
#             datei = unicode(datei)
#             print datei
BlackJack

@lackschuh: Der bisherige, denn man verwendet die GUI normalerweise nicht zum Speichern vom Daten, sondern zum Anzeigen und entgegen nehmen von Daten.
Antworten