Seite 1 von 1

Ein taubstummer Fehler

Verfasst: Donnerstag 14. Januar 2016, 22:27
von Sophus
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?

Re: Ein taubstummer Fehler

Verfasst: Donnerstag 14. Januar 2016, 22:38
von jerch
@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.

Re: Ein taubstummer Fehler

Verfasst: Donnerstag 14. Januar 2016, 23:03
von 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.

Re: Ein taubstummer Fehler

Verfasst: Donnerstag 14. Januar 2016, 23:52
von Sophus
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.

Re: Ein taubstummer Fehler

Verfasst: Freitag 15. Januar 2016, 02:15
von Sophus
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?

Re: Ein taubstummer Fehler

Verfasst: Freitag 15. Januar 2016, 10:04
von 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.

Re: Ein taubstummer Fehler

Verfasst: Freitag 15. Januar 2016, 14:37
von Sophus
@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.

Re: Ein taubstummer Fehler

Verfasst: Samstag 16. Januar 2016, 01:07
von 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()