I have this PyQt5 custom widget:
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QWidget, QGraphicsScene
from PyQt5.QtGui import QPixmap,QImage
from .MostrarBarcode import MostrarBarcode
import barcode
from barcode.writer import ImageWriter
from PIL import Image
import io
class ResponsiveDataWidget(QWidget):
def mousePressEvent(self, event):
self.mostrarBarcode()
def __init__(self,datos,botonEditar,botonEliminar,botonReponer,anchoTabla,indiceBarcode):
super().__init__()
self.datos = datos
self.cantidadBotones = 0
self.hayBotonEditar = False
self.hayBotonEliminar = False
self.hayBotonReponer = False
self.indiceBarcode = indiceBarcode
if botonEditar:
self.hayBotonEditar = True
self.cantidadBotones = self.cantidadBotones+1
if botonEliminar:
self.hayBotonEliminar = True
self.cantidadBotones = self.cantidadBotones+1
if botonReponer:
self.hayBotonReponer = True
self.cantidadBotones = self.cantidadBotones+1
espacioBotones = self.cantidadBotones*30
self.anchoWidget = anchoTabla-25 # restamos 25 para dar espacio al scrollbar
self.anchoRegistro = int(((self.anchoWidget-espacioBotones)/len(datos))-3) #restamos 3 para dar espacio a los separadores
self.labels = []
self.setupUi(self)
def generar_codigo_barras(self,numero):
# Genera el código de barras
codigo = barcode.get('code39', numero, writer=ImageWriter())
# Guarda el código de barras en un archivo
ruta_temporal = codigo.save('codigo_barras_temp')
imagen = Image.open(ruta_temporal)
redim_imagen = imagen.resize((190,100),Image.Resampling.LANCZOS)
ruta_imagen = 'codigo_barras.png'
redim_imagen.save(ruta_imagen)
return ruta_imagen
def mostrarBarcode(self):
if self.indiceBarcode!=None:
self.widgetBarcode = MostrarBarcode()
scene = QGraphicsScene(self.widgetBarcode.barcodePlaceholder)
self.widgetBarcode.barcodePlaceholder.setScene(scene)
pixmap = QPixmap(self.generar_codigo_barras(self.labels[self.indiceBarcode].text().strip()))
scene.addPixmap(pixmap)
self.widgetBarcode.show()
def self_destruct(self):
if self.layout() is not None:
while self.layout().count():
child = self.layout().takeAt(0)
if child.widget() is not None:
child.widget().deleteLater()
self.setParent(None)
self.deleteLater()
def setupUi(self, Form):
Form.setObjectName("Form")
Form.setFixedSize(self.anchoWidget, 30)
x = 0
for i in range(len(self.datos)):
label = QtWidgets.QLabel(Form)
label.setGeometry(QtCore.QRect(x, 0, self.anchoRegistro, 30))
label.setText(" "+str(self.datos[i]))
x = x + self.anchoRegistro
self.labels.append(label)
separador = QtWidgets.QFrame(Form)
separador.setGeometry(QtCore.QRect(x, 0, 3, 30))
separador.setFrameShape(QtWidgets.QFrame.VLine)
separador.setFrameShadow(QtWidgets.QFrame.Sunken)
x = x+3
if self.hayBotonEliminar:
self.butEliminar = QtWidgets.QPushButton(Form)
self.butEliminar.setGeometry(QtCore.QRect(x,0,30,30))
self.butEliminar.setStyleSheet("background:red;font-size:20px")
self.butEliminar.setText("x")
self.butEliminar.clicked.connect(self.self_destruct)
x = x + 30
if self.hayBotonReponer:
self.butReponer = QtWidgets.QPushButton(Form)
self.butReponer.setGeometry(QtCore.QRect(x, 0, 30, 30))
font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(15)
self.butReponer.setFont(font)
self.butReponer.setStyleSheet("background-color:cyan;color:white")
self.butReponer.setObjectName("butReponer")
self.butReponer.setText("+")
x = x + 30
if self.hayBotonEditar:
self.butEditar = QtWidgets.QPushButton(Form)
self.butEditar.setGeometry(QtCore.QRect(x, 0, 30, 30))
font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(8)
self.butEditar.setFont(font)
self.butEditar.setStyleSheet("background-color:lightgreen;color:green")
self.butEditar.setText("edit")
self.butEditar.setObjectName("butEditar")
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
Form = QtWidgets.QWidget()
ui = ResponsiveDataWidget(["hola","adios","buenas","tardes","amigo","qué tal"],True,True,True,500)
ui.setupUi(Form)
Form.show()
sys.exit(app.exec_())
And this is MostrarBarcode class:
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QWidget
class MostrarBarcode(QWidget):
def __init__(self):
super().__init__()
self.setupUi(self)
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(190, 130)
self.barcodePlaceholder = QtWidgets.QGraphicsView(Form)
self.barcodePlaceholder.setGeometry(QtCore.QRect(0, 0, 190, 100))
self.barcodePlaceholder.setObjectName("barcodePlaceholder")
self.butDescargar = QtWidgets.QPushButton(Form)
self.butDescargar.setGeometry(QtCore.QRect(115, 100, 75, 30))
self.butDescargar.setObjectName("butDescargar")
self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "Form"))
self.butDescargar.setText(_translate("Form", "descargar"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
Form = QtWidgets.QWidget()
ui = MostrarBarcode()
ui.setupUi(Form)
Form.show()
sys.exit(app.exec_())
the project is bigger so I cant give all the classes, but my issue lies in those two. My problem is that, when executing my app via 'python app.py', this classes work as intended: when clicking a 'ResponsiveDataWidget', a 'MostrarBarcode' window is displayed containing the image of the generated barcode. But when I generate a .exe of the project with 'pyinstaller --onefile app.py' and I execute the app via the .exe, It gives the following error:
error on cmd line I'm lost here.
I tried other methods of compilation but none of them worked. I wanna stick with pyinstaller because it seems like the easiest and fastest one to use.
EDIT: I tried the sugestion from the first answer but I get the error above The code is now:
def generar_codigo_barras(self, numero):
# Generar el código de barras con un archivo temporal
with tempfile.NamedTemporaryFile(mode="wb", delete=False, suffix=".png") as tmp:
codigo = barcode.get('code39', numero, writer=ImageWriter())
codigo.write(tmp)
tmp_path = tmp.name # Guardar la ruta del archivo temporal
# Abrir, redimensionar y guardar la imagen redimensionada en la ruta temporal
with Image.open(tmp_path) as imagen:
redim_imagen = imagen.resize((190, 100), Image.Resampling.LANCZOS)
redim_imagen.save(tmp_path)
return tmp_path
def mostrarBarcode(self):
if self.indiceBarcode is not None:
self.widgetBarcode = MostrarBarcode() # Asegúrate de que MostrarBarcode esté definido correctamente
scene = QGraphicsScene(self.widgetBarcode.barcodePlaceholder)
self.widgetBarcode.barcodePlaceholder.setScene(scene)
ruta_imagen = self.generar_codigo_barras(self.labels[self.indiceBarcode].text().strip())
pixmap = QPixmap(ruta_imagen)
scene.addPixmap(pixmap)
self.widgetBarcode.show()
EDIT #2:
SOLVED!! It seems that python-barcode uses a font not supported by pyinstaller's default packaging. Changing this line from it's source code to an OS' default font like arial solves the issue:
self.font_path = os.path.join(PATH, "fonts", "calibri.ttf")
It appears like you are creating a new file in the 'generar_codigo_barras' function. When you compile to the exe, it's possible it's trying to create the QR code, but I don't believe you can create new files in an executable for security/integrity reasons, You may have to create the QR code in the user's temp folder. How to save a temporarily jpg file by using python?
You can add some sanity checks with the print() function to make sure everything is working correctly.