[PyQt] deploying PyQt5 app for the first time using pyqtdeploy
umbertofilippo at tiscali.it
umbertofilippo at tiscali.it
Tue Oct 25 11:26:15 BST 2016
Hello everybody.
I am new to this mailing list and to app
deployment.
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.
I am
currently working on Ubuntu 16.04, in an python virtual environment
(created through conda), where I installed PyQt5 and pyqtdeploy.
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).
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.
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.
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?
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.
Finally, I attach my script so that everybody can use it, and
possibly help me better.
#!/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_())
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! http://casa.tiscali.it/mobile/
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://www.riverbankcomputing.com/pipermail/pyqt/attachments/20161025/a2109632/attachment.html>
More information about the PyQt
mailing list