Erich
Erich

Reputation: 41

Python send PIL Image to printer using PrinterDialog from PYQT5 - Problem PyQT5 windows closes

Im trying to send a PIL image using a print button (self.printBtn.clicked.connect(self.do_printout) ...) from my PYQt5.

The problem is that the main window closes if I press "Cancel" and also when I press "Print". Closing the subroutine using app.exec() was also not successful. (Python 3.7, PyQT5 and Windows OS)

import sys
from PyQt5 import QtGui, QtWidgets, QtPrintSupport
from PyQt5.QtGui import QPixmap
from PyQt5 import QtCore
from PIL import Image
from PIL.ImageQt import ImageQt

class App():
    def __init__(self, im):
        super().__init__()

        self.im = im
        dialog = QtPrintSupport.QPrintDialog()
        printer = QtPrintSupport.QPrinter()
        if dialog.exec_() == QtWidgets.QDialog.Accepted:
            self.handle_paint_request(printer, im)

    def handle_paint_request(self, printer, im):

        printer.setOrientation(QtPrintSupport.QPrinter.Landscape)
        printer.setPaperSize(QtPrintSupport.QPrinter.A4)
        printer.setPageSize(QtPrintSupport.QPrinter.A4)
        printer.setPageMargins(0, 0, 0, 0, QtPrintSupport.QPrinter.Millimeter)

        painter = QtGui.QPainter(printer)
        painter.begin(printer)

        im = ImageQt(im)
        image = QtGui.QPixmap.fromImage(im)
        screen = image
        painter.drawPixmap(10, 10, screen)
        painter.end()

def do_print(im):
    app = QtWidgets.QApplication(sys.argv)
    gui = App(im)

if __name__ == '__main__':
    im = Image.open("shot.png").convert("RGB")
    do_print(im)

I tried different approaches - using win32print, win32ui, win32gui could be an alternative: if you have knowledge to print PIL image this way let me know. Timgolden was nor working for me (http://timgolden.me.uk/python/win32_how_do_i/print.html). I dont want to use other gui packages just for printing. Important is to be able to select the printer using a PrinterDialog. Thx for your help!

Here is a more complete setup:

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QLabel,  QPushButton
from PyQt5.QtGui import QIcon, QPixmap
from PyQt5 import QtGui, QtWidgets, QtPrintSupport, QtCore
from PIL import Image
from PIL.ImageQt import ImageQt

class App(QWidget):

    def __init__(self, im):
        super().__init__()
        self.title = 'PyQt5 image'
        self.left = 100
        self.top = 100
        self.width = 640
        self.height = 480
        self.im = im

        self.setWindowTitle(self.title)
        self.setGeometry(self.left, self.top, self.width, self.height)

        label = QLabel(self)

        qim = ImageQt(self.im).copy()
        self.im = QtGui.QPixmap.fromImage(qim)

        print(type(self.im))
        label.setPixmap(self.im)
        self.resize(self.im.width(), self.im.height())

        cb = QPushButton('Print', self)
        cb.move(self.width, self.height +200)
        cb.setGeometry(QtCore.QRect(0, 550, 799, 40))
        cb.clicked.connect(self.show_cat)
        self.show()

    def show_cat(self):
        printer = QtPrintSupport.QPrinter()
        dialog = QtPrintSupport.QPrintDialog(printer)

        if dialog.exec_() == QtWidgets.QDialog.Accepted:
            self.handle_paint_request(printer)

    def handle_paint_request(self, printer):
        printer.setOrientation(QtPrintSupport.QPrinter.Landscape)
        printer.setPaperSize(QtPrintSupport.QPrinter.A4)
        printer.setPageSize(QtPrintSupport.QPrinter.A4)
        printer.setPageMargins(0, 0, 0, 0, QtPrintSupport.QPrinter.Millimeter)

        # Create painter
        painter = QtGui.QPainter(printer)        # Start painter
        painter.drawPixmap(10, 10, self.im)
        painter.end()

class Ui_MainWindow(object):

    def setupUi(self, MainWindow):
        MainWindow.resize(506, 312)
        self.centralwidget = QtWidgets.QWidget(MainWindow)

        # adding pushbutton
        self.pushButton = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton.setText("Print")
        self.pushButton.setGeometry(QtCore.QRect(200, 150, 93, 28))

        # adding signal and slot
        self.pushButton.clicked.connect(self.do_print)

        MainWindow.setCentralWidget(self.centralwidget)
        #self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def do_print(self):
        app = QApplication(sys.argv)
        im = Image.open("shot.png").convert("RGB")
        ex = App(im)

if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)

    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())

Upvotes: 0

Views: 900

Answers (1)

eyllanesc
eyllanesc

Reputation: 243955

ou have to set the QPrinter in the QPrintDialog, also painter = QtGui.QPainter(print) andpainter = QtGui.QPainter() painter.begin(printer) are equivalent so you should only use one of these options

import sys

from PyQt5 import QtCore, QtGui, QtWidgets, QtPrintSupport

from PIL import Image
from PIL.ImageQt import ImageQt


class App:
    def __init__(self, im):
        printer = QtPrintSupport.QPrinter()
        dialog = QtPrintSupport.QPrintDialog(printer)
        if dialog.exec_() == QtWidgets.QDialog.Accepted:
            self.handle_paint_request(printer, im)

    def handle_paint_request(self, printer, im):
        printer.setOrientation(QtPrintSupport.QPrinter.Landscape)
        printer.setPaperSize(QtPrintSupport.QPrinter.A4)
        printer.setPageSize(QtPrintSupport.QPrinter.A4)
        printer.setPageMargins(0, 0, 0, 0, QtPrintSupport.QPrinter.Millimeter)

        im = ImageQt(im).copy()

        painter = QtGui.QPainter(printer)
        image = QtGui.QPixmap.fromImage(im)
        painter.drawPixmap(10, 10, image)
        painter.end()


def do_print(im):
    app = QtWidgets.QApplication(sys.argv)
    gui = App(im)


if __name__ == "__main__":
    im = Image.open("shot.png").convert("RGB")
    do_print(im)

Update:

The new code has other problems compared to the initial code, which are:

  • You just have to create a QApplication.
  • A local variable is destroyed at the end of the scope, in your case "ex" is a local variable that will be destroyed so quickly that for our view it will be like it never appeared.

On the other hand, you should not modify the class generated by Qt Designer but use it as an interface for another class, considering the above then the solution is:

import sys

from PyQt5 import QtCore, QtGui, QtWidgets, QtPrintSupport

from PIL import Image
from PIL.ImageQt import ImageQt


class App(QtWidgets.QWidget):
    def __init__(self, im):
        super().__init__()
        self.title = "PyQt5 image"
        self.left = 100
        self.top = 100
        self.width = 640
        self.height = 480
        self.im = im

        self.setWindowTitle(self.title)
        self.setGeometry(self.left, self.top, self.width, self.height)

        label = QtWidgets.QLabel(self)

        qim = ImageQt(self.im).copy()
        self.im = QtGui.QPixmap.fromImage(qim)

        print(type(self.im))
        label.setPixmap(self.im)
        self.resize(self.im.width(), self.im.height())

        cb = QtWidgets.QPushButton("Print", self)
        cb.move(self.width, self.height + 200)
        cb.setGeometry(QtCore.QRect(0, 550, 799, 40))
        cb.clicked.connect(self.show_cat)
        self.resize(800, 600)
        self.show()

    def show_cat(self):
        printer = QtPrintSupport.QPrinter()
        dialog = QtPrintSupport.QPrintDialog(printer)

        if dialog.exec_() == QtWidgets.QDialog.Accepted:
            # pass
            self.handle_paint_request(printer)

    def handle_paint_request(self, printer):
        printer.setOrientation(QtPrintSupport.QPrinter.Landscape)
        printer.setPaperSize(QtPrintSupport.QPrinter.A4)
        printer.setPageSize(QtPrintSupport.QPrinter.A4)
        printer.setPageMargins(0, 0, 0, 0, QtPrintSupport.QPrinter.Millimeter)

        # Create painter
        painter = QtGui.QPainter(printer)  # Start painter
        painter.drawPixmap(10, 10, self.im)
        painter.end()


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.resize(506, 312)
        self.centralwidget = QtWidgets.QWidget(MainWindow)

        # adding pushbutton
        self.pushButton = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton.setGeometry(QtCore.QRect(200, 150, 93, 28))

        self.label = QtWidgets.QLabel(self.centralwidget)
        self.label.setGeometry(QtCore.QRect(140, 90, 221, 20))
        self.label.setText("")

        MainWindow.setCentralWidget(self.centralwidget)
        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.pushButton.setText(_translate("MainWindow", "Push Button"))


class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setupUi(self)
        self.pushButton.clicked.connect(self.do_print)

    def do_print(self):
        im = Image.open("shot.png").convert("RGB")
        self.ex = App(im)


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)

    w = MainWindow()
    w.show()

    sys.exit(app.exec_())

Upvotes: 1

Related Questions