Warning: Undefined array key "DOKU_PREFS" in /home/clients/a4e6fc1ce1761b72982b805de0f418c4/web/python/mesrecettespython/inc/common.php on line 2082
cx_freeze_pyqt4_windows [Les recettes Python de Tyrtamos]

Outils pour utilisateurs

Outils du site


cx_freeze_pyqt4_windows

Warning: Undefined array key -1 in /home/clients/a4e6fc1ce1761b72982b805de0f418c4/web/python/mesrecettespython/inc/html.php on line 1458

Différences

Ci-dessous, les différences entre deux révisions de la page.

Lien vers cette vue comparative

Les deux révisions précédentes Révision précédente
Prochaine révision
Révision précédente
cx_freeze_pyqt4_windows [2013/03/29 08:34]
tyrtamos
cx_freeze_pyqt4_windows [2014/08/09 08:01]
tyrtamos
Ligne 1: Ligne 1:
 ====== Diffusion de programmes PyQt4 autonomes sous Windows grâce à cx_freeze ====== ====== Diffusion de programmes PyQt4 autonomes sous Windows grâce à cx_freeze ======
  
-[modernisation du setup.py le 29/3/2013]+[modernisation de la page le 9/8/2014]
  
 ===== Problématique ===== ===== Problématique =====
Ligne 13: Ligne 13:
 On va utiliser le logiciel cx_freeze pour cela ([[http://cx-freeze.sourceforge.net/]]). Il a l'avantage d'être multiplateforme (Windows-Linux). Il faudra bien sûr l'utiliser sous Windows pour avoir la version Windows et sous Linux pour avoir la version Linux, car les bibliothèques ne sont pas les mêmes. On va utiliser le logiciel cx_freeze pour cela ([[http://cx-freeze.sourceforge.net/]]). Il a l'avantage d'être multiplateforme (Windows-Linux). Il faudra bien sûr l'utiliser sous Windows pour avoir la version Windows et sous Linux pour avoir la version Linux, car les bibliothèques ne sont pas les mêmes.
  
-On va étudier ici l'utilisation de cx_freeze sur Windows XP, Vista ou 7.+On va étudier ici l'utilisation de cx_freeze sur Windows (XP, Vistaou 8).
  
 ===== Utilisation de cx_freeze sur Windows ===== ===== Utilisation de cx_freeze sur Windows =====
- 
-Pour mettre au point ce tuto, j'ai utilisé deux Windows:  
- 
-  * l'un, Windows XP, que j'ai laissé "brut d'install" (sans même Python),  
- 
-  * et l'autre, Windows 7, sur lequel j'ai installé tout ce qu'il fallait pour faire fonctionner un programme Python-PyQt4 complexe (avec QtSql).  
-  
-Mon but est de pouvoir transporter sur la version "brute d'install", le programme traité par cx_freeze. 
- 
-==== Que faut-il installer pour qu'un programme PyQt4 fonctionne? ==== 
  
 Pour qu'un programme PyQt4 fonctionne sous Windows, il faut peu de choses: Pour qu'un programme PyQt4 fonctionne sous Windows, il faut peu de choses:
  
-  * Python 2.7 ([[http://www.python.org/download/]])+  * Python ([[http://www.python.org/download/]])
  
   * PyQt4 ([[http://www.riverbankcomputing.co.uk/software/pyqt/download]])   * PyQt4 ([[http://www.riverbankcomputing.co.uk/software/pyqt/download]])
    
-Ces 2 logiciels existent sous forme de binaire, et donc sont très faciles à installer.+Pour Windows, ces 2 logiciels existent sous forme de binaires, et sont donc très faciles à installer.
  
 Et c'est tout! Et c'est tout!
Ligne 41: Ligne 31:
 cx_freeze est aussi présenté sous forme de binaire facile à installer.  cx_freeze est aussi présenté sous forme de binaire facile à installer. 
  
-Choisir de préférence une verson >=4.2.1. ([[http://cx-freeze.sourceforge.net/]])+Téléchargement ici: [[http://cx-freeze.sourceforge.net/]] (choisir de préférence une verson >=4.2.1).
  
 Voilà, vous avez le cx_freeze le plus récent! Voilà, vous avez le cx_freeze le plus récent!
Ligne 51: Ligne 41:
 J'utilise un "modèle" de setup.py que je fais évoluer au gré de mes programmes, et, il faut bien le dire, au gré de mes (nombreux et longs) tâtonnements.  J'utilise un "modèle" de setup.py que je fais évoluer au gré de mes programmes, et, il faut bien le dire, au gré de mes (nombreux et longs) tâtonnements. 
  
-Voilà les particularités des options de setup.py pour des programmes complexes PyQt4 avec QtSql (se reporter au code plus bas):+Voilà les particularités des options de setup.py pour des programmes complexes PyQt4:
  
   * Si votre programme comporte des modules à intégrer, placés dans des sous-répertoires, il faut citer ces sous-répertoires dans l'option "path"   * Si votre programme comporte des modules à intégrer, placés dans des sous-répertoires, il faut citer ces sous-répertoires dans l'option "path"
  
-  * Pour PyQt4, il faut dire que la bibliothèque sip.pyd soit intégrée avec l'option "includes": ["sip"]+  * les fichiers et répertoires à copier en plus (ex: les fichiers d'aide) sont mentionnés avec l'option "include_files". Chaque copie demandée est un tuple composé du chemin source (absolu ou relatif) et du chemin destination (toujours relatif). Par exemple pour recopier un répertoire comportant les fichiers d'aide: "include_files": [("aide", "aide")]
  
-  * les fichiers et répertoires à copier en plus (ex: les fichiers d'aide) sont mentionnés avec l'option "include_files". Chaque copie demandée est un tuple composé du chemin source (absolu ou relatif) et du chemin destination (toujours relatif). Par exemple pour recopier un répertoire comportant les fichiers d'aide: "include_files": [("aide", "aide")]. Notez que les options comportent un blanc souligné et pas un tiret comme dit dans la notice de cx_freeze!+  * c'est le cas pour les plugins de PyQt4 (y compris les drivers sql de QtSql)
  
-  * Et c'est le cas pour QtSql: dans la version "standalone"les drivers SQL seront cherchés dans le sous-répertoire "sqldrivers(j'ai mis une 1/2 journée à trouver cela...). Il faut donc demander la recopie des drivers avec l'option "include_files": [(r"C:\Python27\Lib\site-packages\PyQt4\plugins\sqldrivers","sqldrivers")].+  * c'est aussi le cas pour les fichiers de traductionpour avoir "ouiou "nonau lieu de "yesou "nodans les messagebox.
  
 Et c'est tout: avec ça, vous récupérez un répertoire avec tout ce qu'il faut pour une exécution "standalone" sur un Windows dans lequel il n'y a ni Python, ni PyQt4! Et c'est tout: avec ça, vous récupérez un répertoire avec tout ce qu'il faut pour une exécution "standalone" sur un Windows dans lequel il n'y a ni Python, ni PyQt4!
  
-Voilà un exemple de code du setup.py que j'ai utilisé pour un logiciel de concours photos pour un photo-club (environ 25000 lignes de code et utilisation de QtSql).+Voilà un exemple
 + 
 +On a un projet dans un répertoire. Ce répertoire contiendra: 
 + 
 +  * programme1.pyw 
 +  * programme2.pyw 
 +  * setup.py 
 +  * cx_freeze.bat 
 + 
 +Les 2 programmes programme1.pyw sont identiques, sauf le nom de leur fichier et le titre de leur fenêtre. Cela permettra de tester la construction de 2 fenêtres différentes avec un seul setup. 
 + 
 +Voilà le code du 1er programme programme1.pyw: 
 + 
 +\\ 
 +<code python>#!/usr/bin/python 
 +# -*- coding: utf-8 -*- 
 +# Python 3 
 + 
 +import sys 
 +from PyQt4 import QtCore, QtGui 
 +  
 +############################################################################# 
 +class Fenetre(QtGui.QWidget): 
 + 
 +    def __init__(self, parent=None): 
 +        super(Fenetre, self).__init__(parent) 
 + 
 +        self.resize(400, 300) 
 +        self.setWindowTitle("Programme 1") 
 +         
 +        self.bouton = QtGui.QPushButton(u"bouton", self) 
 +        self.bouton.clicked.connect(self.clictest) 
 +         
 +        posit = QtGui.QGridLayout() 
 +        posit.addWidget(self.bouton, 0, 0) 
 +        self.setLayout(posit) 
 +         
 +    def clictest(self): 
 +        QtGui.QMessageBox.information(self, 
 +            u"Pour information", 
 +            u"Le bouton a été cliqué"
 + 
 +    def closeEvent(self, event): 
 +        reponse = QtGui.QMessageBox.question(self,  
 +            "Fermeture de la fenêtre", 
 +            "Etes-vous sûr(e) de vouloir quitter?",  
 +            QtGui.QMessageBox.Yes, QtGui.QMessageBox.No) 
 + 
 +        if reponse == QtGui.QMessageBox.Yes: 
 +            event.accept() 
 +        else: 
 +            event.ignore() 
 +             
 +############################################################################# 
 +if __name__ == "__main__": 
 +     
 +    app = QtGui.QApplication(sys.argv) 
 + 
 +    # mettre la même icone pour toutes les fenêtres de l'application 
 +    #app.setWindowIcon(QtGui.QIcon('icone.png')) 
 +     
 +    # mettre le style des fenêtres     
 +    style = 'Plastique' 
 +    app.setStyle(QtGui.QStyleFactory.create(style)) 
 +    app.setPalette(QtGui.QApplication.style().standardPalette()) 
 +     
 +    # pour assurer la traduction automatique du conversationnel à la locale 
 +    locale = QtCore.QLocale.system().name() 
 +    translator = QtCore.QTranslator () 
 +    if getattr(sys, 'frozen', False): 
 +        # exécution de la version exécutable avec cx_freeze (ou équivalent):  
 +        #=>les fichiers de traduction doivent se trouver dans "translations" 
 +        reptrad = "translations" 
 +    else: 
 +        # exécution par l'interpréteur normal 
 +        reptrad = QtCore.QLibraryInfo.location(QtCore.QLibraryInfo.TranslationsPath) 
 +    translator.load("qt_" + locale, reptrad) 
 +    app.installTranslator(translator) 
 + 
 +    # 
 +    fen = Fenetre() 
 +    fen.setAttribute(QtCore.Qt.WA_DeleteOnClose) 
 +    fen.show() 
 +    sys.exit(app.exec_()) 
 +</code> 
 + 
 +le fichier cx_freeze.bat ne servira qu"à lancer le traitement par cx_freeze. On prendra l'explorateur Windows, et on naviguera jusqu'au répertoire du projet, et on double-cliquera sur ce nom. Une console s'affichera avec toutes les lignes crées par cx_freeze: on vérifiera l'absence d'erreur, et sinon, on saura modifier le setup pour corriger. Voilà le contenu du cx_freeze.bat: 
 + 
 +\\ 
 +<code>python setup.py build 
 +pause 
 +</code> 
 + 
 +Le setup.py contient les instructions destinées au traitement par cx_freeze
  
 Pour que le setup.py puisse, sans modification, servir sous Windows et sous Linux, il faudra utiliser à plusieurs endroits les tests habituels de plateforme (if sys.platform == "win32" ou if sys.platform == "linux2") puisque certaines adresses de bibliothèques seront différentes. Peut-être que des adaptations mineures permettraient l'utilisation sur Mac OSX et plus (Solaris, ...) mais je n'ai pas essayé. Pour que le setup.py puisse, sans modification, servir sous Windows et sous Linux, il faudra utiliser à plusieurs endroits les tests habituels de plateforme (if sys.platform == "win32" ou if sys.platform == "linux2") puisque certaines adresses de bibliothèques seront différentes. Peut-être que des adaptations mineures permettraient l'utilisation sur Mac OSX et plus (Solaris, ...) mais je n'ai pas essayé.
  
 \\ \\
-<code python> +<code python>#!/usr/bin/python
-#!/usr/bin/python+
 # -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
-# Python 2.7 +# Python 3
-# 03/2013+
  
 """ """
-Pas d'accent dans le setup, ni dans la description, ni dans les commentaires+Pas d'accent dans le setup.py, ni dans la description, ni dans les commentaires
  
 Icone sous Windows: il faut: Icone sous Windows: il faut:
Ligne 89: Ligne 170:
  
 # chemins de recherche des modules # chemins de recherche des modules
-path = sys.path + ["bordereaux", "etiquettes", "fenetre", "integrebase",  +path = sys.path
-                   "jugement", "publications", "retourcolis"]+
  
 # options d'inclusion/exclusion des modules # options d'inclusion/exclusion des modules
-includes = ["sip", "atexit"]+includes = []
 excludes = [] excludes = []
-packages = ["biblio"]+packages = []
  
 # copier les fichiers et/ou repertoires et leur contenu: # copier les fichiers et/ou repertoires et leur contenu:
-includefiles = [("aide", "aide"), +includefiles = [] # recopier l'icone.png de la fenetre ici
-                ("fichiers", "fichiers"), +
-                ("navigweb", "navigweb"), +
-                ("simplediteur", "simplediteur"), +
-                'adresse.ini',  +
-                "concoursphotos.png", +
-                ("etiquettes/CODE39.TTF", "etiquettes/CODE39.TTF"), +
-                ("qt_cx.conf", "qt.conf")]+
  
 if sys.platform == "linux2": if sys.platform == "linux2":
Ligne 111: Ligne 184:
     includefiles += [(r"/usr/share/qt4/translations","translations")]     includefiles += [(r"/usr/share/qt4/translations","translations")]
 elif sys.platform == "win32": elif sys.platform == "win32":
-    includefiles += [(r"C:\Python27\Lib\site-packages\PyQt4\plugins","plugins")] +    includefiles += [(r"E:\Python34\Lib\site-packages\PyQt4\plugins","plugins")] 
-    includefiles += [(r"C:\Python27\Lib\site-packages\PyQt4\translations","translations")]+    includefiles += [(r"E:\Python34\Lib\site-packages\PyQt4\translations","translations")]
 else: else:
     pass     pass
          
-# inclure les fichiers non-py et non-pyw dans library.zip 
-zipincludes = [] 
- 
-# pour que les bibliotheques de /usr/lib soient copiees aussi sous Linux 
 binpathincludes = [] binpathincludes = []
 if sys.platform == "linux2": if sys.platform == "linux2":
 +    # Linux: pour que les bibliotheques de /usr/lib soient copiees aussi
     binpathincludes += ["/usr/lib"]     binpathincludes += ["/usr/lib"]
    
Ligne 130: Ligne 200:
            "packages": packages,            "packages": packages,
            "include_files": includefiles,            "include_files": includefiles,
-           "zip_includes": zipincludes, 
            "bin_path_includes": binpathincludes,            "bin_path_includes": binpathincludes,
-           "create_shared_zip": True+           "create_shared_zip": False
-           "include_in_shared_zip": True,+           "include_in_shared_zip": False,
            "compressed": False            "compressed": False
            }            }
 + 
 # pour inclure sous Windows les dll system necessaires # pour inclure sous Windows les dll system necessaires
 if sys.platform == "win32": if sys.platform == "win32":
Ligne 145: Ligne 214:
 base = None base = None
 if sys.platform == "win32": if sys.platform == "win32":
-    base = "Win32GUI" +    # plateforme Windows 
-    #base = "Console" +    base = "Win32GUI" # pour les programmes graphiques 
 +    #base = "Console" # pour les programmes en console 
 + 
 icone = None icone = None
 if sys.platform == "win32": if sys.platform == "win32":
-    icone = "concoursphotos.ico" +    icone = None # mettre ici l'icone.ico pour integration dans l'exe 
- +
 cible_1 = Executable( cible_1 = Executable(
-    script = "bordereaux.pyw",+    script = "programme1.pyw",
     base = base,     base = base,
     compress = False,     compress = False,
Ligne 163: Ligne 233:
    
 cible_2 = Executable( cible_2 = Executable(
-    script = "jugement.pyw",+    script = "programme2.pyw",
     base = base,     base = base,
     compress = False,     compress = False,
Ligne 171: Ligne 241:
     icon = icone     icon = icone
     )     )
- 
-cible_3 = Executable( 
-    script = "publications.pyw", 
-    base = base, 
-    compress = False, 
-    copyDependentFiles = True, 
-    appendScriptToExe = True, 
-    appendScriptToLibrary = False, 
-    icon = icone 
-    ) 
- 
-cible_4 = Executable( 
-    script = "retourcolis.pyw", 
-    base = base, 
-    compress = False, 
-    copyDependentFiles = True, 
-    appendScriptToExe = True, 
-    appendScriptToLibrary = False, 
-    icon = icone 
-    ) 
- 
-cible_5 = Executable( 
-    script = "etiquettes.pyw", 
-    base = base, 
-    compress = False, 
-    copyDependentFiles = True, 
-    appendScriptToExe = True, 
-    appendScriptToLibrary = False, 
-    icon = icone 
-    ) 
- 
 ############################################################################# #############################################################################
 # creation du setup # creation du setup
 setup( setup(
-    name = "concoursphotos", +    name = "Programme", 
-    version = "1", +    version = "1.00", 
-    description = "concoursphotos",+    description = "essai",
     author = "Tyrtamos",     author = "Tyrtamos",
     options = {"build_exe": options},     options = {"build_exe": options},
-    executables = [cible_1, cible_2, cible_3, cible_4, cible_5]+    executables = [cible_1, cible_2]
     )     )
 </code> </code>
  
-Une fois le setup.py écrit et mis dans la racine du répertoire du programme à traiter (\chemin par exemple): +Une fois le setup.py écrit et mis dans la racine du répertoire du programme à traiteron double-clique sur cx_freeze.bat. Une console s'affichele traitement se déroule et les programmes ".exe" se construisent dans le sous-répertoire "build\exe.win32-3.4"Nous auront ici programme1.exe et programme2.exe, accompagnés de toutes les bibliothèques nécessaires.
- +
-  * on fait venir une console, et on se place dans ce répertoire (cd \chemin) +
- +
-  * on fait alors: +
- +
-<code python> +
-python setup.py build +
-</code> +
- +
-  * Une longue liste de messages indique ce que cx_freeze faitIl faut seulement vérifier qu'il n'y a pas d'erreurSinon, il faut modifier le setup.py jusqu'à ce que les erreurs aient disparu+
  
-  * Dans le répertoire dans lequel on est (\chemin), il vient le sous-répertoire build\exe.win32-2.7 dans lequel il y a la version "standalone" pouvant être diffuséeVous pouvezbien entendu, la proposer sous forme d'archive en un seul fichier.+Dans tous les cas, il faudra lire attentivement la longue liste du traitement dans la console pour vérifier qu'il n'y a pas d'erreurSinonil faudra modifier le setup.py jusqu'à ce que les erreurs aient disparu
  
-  * Il ne reste plus qu'à l'essayer sur un Windows sans Python ni PyQt4On le copie donc, et on peut le lancer. Dans un premier temps, il faut le lancer à partir d'une console pour avoir tous les éventuels messages d'erreur. +Il ne reste plus qu'à essayer de lancer les programmes ".exe". Ce serait bien de le faire sur un autre PC qui n'a pas Python. Enfindans un premier temps, il faut lancer les programmes ".exe" à partir de la console pour avoir tous les éventuels messages d'erreur. 
  
-  * Si c'est ok, on peut alors le lancer directement avec une icône (à créer) du bureau.+Si c'est ok, on peut alors le lancer directement avec une icône (à créer) du bureau.
  
-On peut aussi aller plus loin en encapsulant les fichiers obtenus dans un programme d'installation comme "innosetup" ([[http://www.jrsoftware.org/isinfo.php]]). Vous avez un bon tutoriel en français ici: [[ftp://ftp-developpez.com/jlelong/tutoriels/delphi/deployer-votre-application-innosetup/installation-innosetup.pdf]]. Vous obtiendrez alors un programme diffusé par un seul fichier qui s'installera et se désinstallera comme n'importe quel logiciel Windows: **//les utilisateurs se sauront même pas que c'est du Python...//**+On peut aussi aller plus loin en encapsulant les fichiers obtenus dans un programme d'installation comme "innosetup" ([[http://www.jrsoftware.org/isinfo.php]]). Vous obtiendrez alors un programme diffusé par un seul fichier qui s'installera et se désinstallera comme n'importe quel logiciel Windows: **//les utilisateurs se sauront même pas que c'est du Python...//**
  
 \\ \\
cx_freeze_pyqt4_windows.txt · Dernière modification: 2014/08/09 08:01 de tyrtamos