<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN">
<html><body>
Hello everybody.<br /><br />I am new to this mailing list and to app deployment.<br />I just finished my first app with PyQt5: it's a basic Memory game, made of one python script, a folder of images and a folder of sound effects. The app is working fine (although something might still be missing), and I now would like to deploy it using pyqtdeploy.<br />I am currently working on Ubuntu 16.04, in an python virtual environment (created through conda), where I installed PyQt5 and pyqtdeploy.<br />I'd like to be able to set up a deployment framework so that I would be able to deploy to different platforms (desktop and mobile) the easiest way. I am beginning with Windows (as most of my friends have it).<br />However, as I am completlely new to this kind of stuff, I am finding difficult to follow the tutorial at http://pyqt.sourceforge.net/Docs/pyqtdeploy/tutorial.html.<br />First of all, I downloaded and installed pyqtdeploy to my virtual env succesfully (using pip after activating the conda env) and I am able to run the GUI.<br />There are many things I miss anyway. For example: how do I add my folders to my project (images and sounds)? And, should I be able to produce an executable which I can simply pass to my friends who can try it by simpling double clicking it, or is there much work I will be supposed to do after using pyqtdeploy?<br />Any suggestion would be highly appreciated, as I was super happy to have finally produced my very first app, but now I am kind of lost with regards to the deployment argument.<br />Finally, I attach my script so that everybody can use it, and possibly help me better.<br /><br />
<pre>#!/usr/bin/python3
# -*- coding: utf-8 -*-

"""
Memory game 4

My first memory game in PyQt5.

author: Umberto Minora
last edited: October 2016
"""

import os, sys, glob, math, random
from PyQt5.QtWidgets import (QMainWindow, QWidget,
    QGridLayout, QPushButton, QApplication,
    QAction, QFileDialog, QMessageBox)
from PyQt5.QtGui import QPixmap, QIcon, QCloseEvent
from PyQt5.QtMultimedia import QSound
from PyQt5 import QtCore

class MemoryGame(QMainWindow):
    def __init__(self):
        super().__init__()
        self.back_card = r'./back' # remove the extension from the image name if present
        self.status = {}
        self.cell_width = 100
        self.cell_height = 150
        self.initUI()

    def initUI(self):
        self.statusBar()

        self.sounds = {
            'success': QSound(r'./sound/success.wav'),
            'fail': QSound(r'sound/fail.wav'),
            'end': QSound(r'sound/end.wav')
            }

        openFile = QAction('Open', self)
        openFile.setShortcut('Ctrl+O')
        openFile.setStatusTip('Search image folder')
        openFile.triggered.connect(self.showDialog)

        menubar = self.menuBar()
        self.fileMenu = menubar.addMenu('&File')
        self.fileMenu.addAction(openFile)

        self.gridWidget = QWidget(self)
        self.gridLayout = QGridLayout(self.gridWidget)
        self.setCentralWidget(self.gridWidget)

        self.setGeometry(0, 0, 350, 300)
        self.setWindowTitle('Memory Game!')
        self.show()
        # self.showFullScreen()

    def showDialog(self):
        """Seacrh for a folder of images, and create two dictionaries:
        - one with grid_position : image
        - one with grid_position : back_card"""

        if self.status:
            self.status = {}

        folder = str(QFileDialog.getExistingDirectory(self, "Select Directory",
            '.', QFileDialog.ShowDirsOnly))

        # if the user selected a folder
        if folder:
            self.list_images(folder)

            # if the selected foldser contains images, limit the number to 16
            if self.n_img > 0:
                if self.n_img >16:
                    del self.images[16:]
                self.fill_dict(self.images) # create the grid_position:image Dict
                self.empty_dict()
                self.init_grid()

    def list_images(self, folder):
        """List the (JPEG) images within the selected folder"""
        extensions = ('.jpg', '.jpeg', '.gif', '.png')
        images = [os.path.join(folder, f) for f in os.listdir(folder) if f.lower().endswith(extensions)]
        n_img = len(images)

        self.images = images
        self.n_img = n_img

    def fill_dict(self, images):
        grid_cell = images * 2
        random.shuffle(grid_cell)
        self.card_dict = {}
        n_cols = math.ceil(math.sqrt(len(grid_cell)))
        n_rows = math.ceil(math.sqrt(len(grid_cell)))
        max_rows = 4
        if n_rows > max_rows:
            n_cols += n_rows - max_rows
            n_rows = max_rows

        positions = [(i,j) for i in range(n_rows) for j in range(n_cols)]
        for p, cell in zip(positions, grid_cell):
            if cell == '':
                continue
            self.card_dict[p] = cell

    def empty_dict(self):
        # copy the card_dict to make a back_dict (with the back_card)
        self.back_dict = dict(self.card_dict)
        for k, v in self.back_dict.items():
            self.back_dict[k] = self.back_card

    def init_grid(self):
        """Initialize the grid according to the number of images
        found in the selected folder."""

        for pos, img in self.back_dict.items():
            btn = QPushButton(self)
            btn.clicked.connect(self.buttonClicked)
            pixmap = QPixmap(self.back_dict[pos])
            scaled = pixmap.scaled(self.cell_width, self.cell_height)
            btn.setIcon(QIcon(scaled))
            btn.setIconSize(scaled.rect().size())
            btn.setFixedSize(scaled.rect().size())
            del(pixmap)

            self.gridLayout.addWidget(btn, *pos)

    def restart(self):
        self.status = {}
        self.init_grid()

        return

    def turn_card(self, btn, location):
        """When a button (image) is clicked, turn the card."""

        pixmap = QPixmap(self.card_dict[location])
        scaled = pixmap.scaled(self.cell_width, self.cell_height)
        btn.setIcon(QIcon(scaled))
        btn.setIconSize(scaled.rect().size())
        btn.setFixedSize(scaled.rect().size())
        del(pixmap)

        n_cards = len(self.status.keys())

        # if game just started, turn the card
        if n_cards == 0:
            self.status[location] = self.card_dict[location]

            return

        # if the number of card is odd
        elif n_cards % 2 != 0:
            # if card already present, keep it...
            if self.card_dict[location] in self.status.values() and location not in self.status.keys():
                self.status[location] = self.card_dict[location]
                if self.status == self.card_dict:
                    self.end_game()
                    return
                self.sounds['success'].play()
                return

            # if the same card is clicked, do nothing...
            elif location in self.status.keys():
                pass
            # ...otherwise restart the game
            else:
                ''' wait 1 sec and restart (second argument MUST be a method;
                cannot use time.sleep, because GUI freezes)'''
                QtCore.QTimer.singleShot(1000, self.restart)
                self.sounds['fail'].play()
                return

        self.status[location] = self.card_dict[location]

    def buttonClicked(self):
        button = self.sender()
        idx = self.gridLayout.indexOf(button)
        location = self.gridLayout.getItemPosition(idx)
        self.turn_card(button, location[:2])

    def end_game(self):
        self.sounds['end'].play()

        msgBox = QMessageBox()
        msgBox.setIcon(QMessageBox.Question)
        msgBox.setWindowTitle("!!!You won!!!")
        msgBox.setInformativeText("What's next now?")
        quit = msgBox.addButton('quit', QMessageBox.RejectRole)
        restartBtn = msgBox.addButton('play again', QMessageBox.ActionRole)
        changeBtn = msgBox.addButton('change cards', QMessageBox.ActionRole)
        msgBox.setDefaultButton(restartBtn)

        msgBox.exec_()
        msgBox.deleteLater()

        if msgBox.clickedButton() == quit:
            self.close()
        elif msgBox.clickedButton() == restartBtn:
            self.restart()
        elif msgBox.clickedButton() == changeBtn:
            self.showDialog()

        return

    def closeEvent(self, event):

        reply = QMessageBox.question(self, 'Message',
            "Are you sure to quit?", QMessageBox.Yes |
            QMessageBox.No, QMessageBox.No)

        if reply == QMessageBox.Yes:
            event.accept()
        else:
            event.ignore()

if __name__ == '__main__':

    app = QApplication(sys.argv)
    ex = MemoryGame()
    sys.exit(app.exec_())</pre>
<br /><br />
</body></html>
<br><br/><br/>Con Smart 3 Giga a 9 euro/4 sett navighi veloce, chiami e invii SMS dal tuo smartphone verso tutti i fissi e mobili in Italia. Passa a Tiscali Mobile! <a href='http://casa.tiscali.it/mobile/' target='_blank'>http://casa.tiscali.it/mobile/</a><br/><br/>