Ein taubstummer Fehler

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
Sophus
User
Beiträge: 1109
Registriert: Freitag 25. April 2014, 12:46
Wohnort: Osnabrück

Hallo Leute,

den Betreff habe ich mit Absicht gewählt. Es funktioniert etwas nicht, aber Python spuckt keine Fehlermeldung aus. Nun, was habe ich vor? Ich möchte ein Bild mittels der QFileDialog in QLabel() laden. Hier der Quelltext des ausführbaren Programms:

Code: Alles auswählen

#!/usr/bin/env python

from PyQt4 import QtCore, QtGui
import os

class Window(QtGui.QWidget):
    def __init__(self):
        super(Window, self).__init__()

        self.load_pushButton = QtGui.QPushButton()
        self.load_pushButton.setText("Load picture")
        self.load_pushButton.clicked.connect(self.open_file_dialog)
        self.image_label = QtGui.QLabel ()

        h_layout = QtGui.QHBoxLayout()
        h_layout.addWidget(self.load_pushButton)
        h_layout.addWidget(self.image_label)
        self.setLayout(h_layout)

    def load_pic(self, img_path):
        self.image_label.setPixmap(QtGui.QPixmap(""))
        self.image_label.setPixmap(QtGui.QPixmap(img_path))
    
    def open_file_dialog(self):
        qfile_dialog_title = self.tr("Select picture")

        file_path_pic = unicode(QtGui.QFileDialog.getOpenFileName(self, qfile_dialog_title,
                                                                                 os.path.expanduser(""),
                                                                                  "*.png *.jpg *.bmp"))

        self.load_pic(file_path_pic)


if __name__ == '__main__':

    import sys

    app = QtGui.QApplication(sys.argv)
    window = Window()
    window.show()
    sys.exit(app.exec_())
Führe ich das Programm unter Python aus, funktioniert der Skript wunderbar. keinerlei Fehlermeldung.

Nun gehe ich einen Schritt weiter, und mache mit Py2Exe aus diesem Skript eine *.exe-Datei.

Hier mein kleines Setup-Skript:

Code: Alles auswählen

from distutils.core import setup
import py2exe, sys, os

sys.argv.append('py2exe')

includes = ["sip", "PyQt4.QtNetwork", 'PyQt4.QtCore','PyQt4.QtGui', 'PyQt4.uic']

setup(
        windows=['example_load_image.py'],
        options={
                "py2exe":{
                        "unbuffered": True,
                        "optimize": 2,
                        'includes': includes,
                        "excludes": ["email"]
                }
        }
)
Es wird eine *.exe-Datei erfolgreich erstellt. Und das Programm wird auch ordnungsgemäß gestartet. Versuche ich aber ein Bild in das QLabel() zu laden, dann passiert einfach gar nichts. Absolut gar nicht. Keinerlei Fehlermeldung. Hier wird zwar das QFileDialog angezeigt, man kann ein Bild auswählen, und beim Klick auf Öffnen passiert gar nichts.

Wieso klappt es, sobald man das Skript "normal" startet, also den Quelltext direkt startet. Aber sobald man mit py2exe daraus eine *.exe-Datei kreiert, dann klappt es nicht. Was habe ich übersehen?
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

@Sophus:
Ich vermute mal, dass Dir die Plugins für die Bildformate fehlen. Bei Qt wird die Unterstützung für JPEG, PNG etc. idR als DLL gelinkt. Diese DLLs müssen mit in das Exe-Paket. Wie das mit Py2exe geht, sagt Dir bestimmt dessen Doku.
BlackJack

@Sophus: Der Fehler ist „taubstumm“ weil Qt das so macht. Wie die Dokumentation von `QPixmap` verrät bekommt man eine „null pixmap“, also eine die 0×0 Pixel gross ist. Darauf kann man mit der `isNull()`-Methode prüfen. Mehr Information gibt Qt nicht her wenn man den Dateinamen beim erstellen des Objekts angibt. Wenn Du mehr Informationen brauchst musst Du über einen `QImageReader` gehen.
Benutzeravatar
Sophus
User
Beiträge: 1109
Registriert: Freitag 25. April 2014, 12:46
Wohnort: Osnabrück

Hallo jerch und BlackJack,

aus Neugier habe ich das Skript mit cx freeze eine *.exe-Datei erstellt. Auch wie bei Py2Exe habe ich hierbei ein Standard-Setup benutzt. Zu meinem Erstaunen klappt das Programm. Bei cx freeze habe ich ge auso wie bei Py2Exe keine *.dll-Dateien angegeben. Komische Sache.
Benutzeravatar
Sophus
User
Beiträge: 1109
Registriert: Freitag 25. April 2014, 12:46
Wohnort: Osnabrück

Mir ist noch eine weitere Sache aufgefallen. Wenn ich mein Skript mit Py2Exe eine *.exe-Datei erstellen, dann ist es möglich eine *.bmp-Datei und eine *.png-Datei in QLabel() zu laden. Ich glaube, Qt mag die *.jpeg-Dateien nicht?
BlackJack

@Sophus: Wenn die JPEG-Dateien ohne das Programm in eine EXE zu wandeln funktionieren, dann fehlt, wie schon geschrieben wurde, sehr wahrscheinlich die entsprechende DLL. Und woran es liegt wenn die Datei nicht geladen werden konnte, kann man, wie ebenfalls schon geschrieben, mit einem `QImageReader` herausfinden. Dieser Typ hat auch eine statische Methode mit der man abfragen kann welche Formate geladen werden können.
Benutzeravatar
Sophus
User
Beiträge: 1109
Registriert: Freitag 25. April 2014, 12:46
Wohnort: Osnabrück

@BlackJack: Nach langem Suchen bin ich auf diese Seite gestoßen. Das ist die Seite von Py2Exe. Ganz unten auf der Seite, im Kapitel "PyQt4 and image loading (JPG, GIF, etc)", steht geschrieben, dass man unter dem Pfad "C:\Python27\Lib\site-packages\PyQt4\plugins" den Ordner "imageformats" in den "dist"-Ordner kopieren soll. dist-Ordner wird von Py2Exe erstellt. Und es funktioniert. Man musste quasi den Ordner nur kopieren, wo die ganzen *.dll-Dateien vorhanden sind.

Allerdings las ich auf einer StackOverFlow-Seite folgendes: I just dropped the imageformats directory directly into my dist directory, without any further modifications to qt.conf or anything like that. I haven’t tried it, but this may work for phonon as well. Jemand hatte gleiches Problem, und bei WinXP scheint der einfache Trick nicht zu greifen.
BlackJack

Mal mit Fehlerbehandlung und nur Formate für die es Plugins gibt:

Code: Alles auswählen

#!/usr/bin/env python
# coding: utf8
from __future__ import absolute_import, division, print_function
import sys
from PyQt4.QtGui import (
    QApplication, QFileDialog, QHBoxLayout, QImageReader, QLabel, QMainWindow,
    QMessageBox, QPixmap, QPushButton, QWidget
)


def get_image_formats():
    return [str(f).lower() for f in QImageReader.supportedImageFormats()]


class MainWindow(QMainWindow):

    def __init__(self):
        QMainWindow.__init__(self)
        widget = QWidget(self)

        load_button = QPushButton('Load image', widget)
        load_button.clicked.connect(self.load_image)

        self.image_label = QLabel(widget)

        layout = QHBoxLayout(widget)
        layout.addWidget(load_button)
        layout.addWidget(self.image_label)

        self.setCentralWidget(widget)

    def load_image(self):
        filename = QFileDialog.getOpenFileName(
            self,
            'Load image',
            filter='Images ({0})'.format(
                ' '.join('*.' + f for f in get_image_formats())
            )
        )
        if filename:
            reader = QImageReader(filename)
            image = reader.read()
            if image.isNull():
                QMessageBox.critical(self, 'Error', reader.errorString())
            else:
                self.image_label.setPixmap(QPixmap.fromImage(image))


def main():
    application = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(application.exec_())


if __name__ == '__main__':
    main()
Antworten