pythonprintingpyqt6

QPrintPreviewDialog doesn't pass orientation to Windows print dialog


I'm running into a problem in setting the default print orientation using PyQt6. I set up a QPrintPreviewDialog attached to a QPrinter using this code:

printer = QPrinter(QPrinter.PrinterMode.HighResolution)
printer.setDocName('Bulletin')
printer.setPageSize(QPageSize(QPageSize.PageSizeId.Letter))
printer.setPageMargins(QMarginsF(0.25, 0.25, 0.25, 0.25))
printer.setPageOrientation(QPageLayout.Orientation.Landscape)

print_preview_dialog = QPrintPreviewDialog(printer)
print_preview_dialog.paintRequested.connect(lambda: self.do_print(pdf_doc, printer, preview=True))
result = print_preview_dialog.exec()

When the preview dialog comes up, everything looks right. It is showing in landscape: enter image description here

However, after clicking the print button, the Windows print dialog comes up and is defaulting to "Portrait": enter image description here

I've been Googling around for a couple of days trying to find the solution, but I'm just not seeing anything, aside from general comments that calling setPageOrientation on the QPrinter should properly set the orientation.

FWIW, I also tried using just QPrintDialog called with that same QPrinter, and it still defaults to portrait.

How do I get that (second) print dialog to respect the orientation shown in the QPrintPreviewDialog?

FYI: Qt is version 6.7.0 and Windows is 23H2, build 22631.4541


Solution

  • Ok, so it seems that neither QPrinter nor QPrintPreviewDialog passes landscape orientation on to the QPrintDialog. It seems, then, that the best way to get around this is to use the win32print module from pywin32 to set the orientation before calling the QPrintDialog, returning the printer to portrait orientation when done. Here's what is working:

    import win32print
    from PyQt6.QtPdf import QPdfDocument
    from PyQt6.QtPrintSupport import QPrinter, QPrintDialog
    
    """
    use win32print to access the printer at the system level and set 
    the orientation there first
    TODO: get the current orientation of the printer in case it's defaulting 
    to a different orientation so that it doesn't get arbitrarily set to 
    portrait afterwards
    """
    
    defaults = { 'DesiredAccess': win32print.PRINTER_ALL_ACCESS }
    printer_handle = win32print.OpenPrinter(win32print.GetDefaultPrinter(), defaults)
    properties = win32print.GetPrinter(printer_handle, 2)
    properties['pDevMode'].Orientation = 2
    win32print.SetPrinter(printer_handle, 2, properties, 0)
    
    *** create landscape pdf using ReportLab ***
    
    pdf_doc = QPdfDocument(self)
    pdf_doc.load(pdf_file_path)
    
    printer = QPrinter(QPrinter.PrinterMode.HighResolution)
    printer.setDocName('Bulletin')
    printer.setPageSize(QPageSize(QPageSize.PageSizeId.Letter))
    printer.setPageMargins(QMarginsF(0.25, 0.25, 0.25, 0.25))
    printer.setPageOrientation(QPageLayout.Orientation.Landscape)
    
    print_dialog = QPrintDialog(printer)
    result = print_dialog.exec()
    
    if result == QPrintDialog.DialogCode.Accepted:
        self.do_print(pdf_doc, printer)
    
    # set the printer's orientation back to portrait
    properties['pDevMode'].Orientation = 1
    win32print.SetPrinter(printer_handle, 2, properties, 0)
    win32print.ClosePrinter(printer_handle)
    
    def do_print(self, pdf_doc, printer):
        range_list = printer.pageRanges().toRangeList()
        pages_to_print = []
        if len(range_list) > 0:
            for i in range(len(range_list)):
                for j in range(range_list[i].from_, range_list[i].to + 1):
                    pages_to_print.append(j - 1)
        else:
            for i in range(pdf_doc.pageCount()):
                pages_to_print.append(i)
    
        painter = QPainter(printer)
        do_new_page = False
        for page in pages_to_print:
            if do_new_page:
                printer.newPage()
    
            # orientation from the QPrintDialog is given back to the QPrinter 
            # instance and will be reflected in the pageRect
            page_rect_inch = printer.pageRect(QPrinter.Unit.Inch)
            dpi_x = printer.physicalDpiX()
            dpi_y = printer.physicalDpiY()
            rect = QRectF(
                page_rect_inch.x() * dpi_x,
                page_rect_inch.y() * dpi_y,
                page_rect_inch.width() * dpi_x,
                page_rect_inch.height() * dpi_y
            )
            render = pdf_doc.render(page, QSize(int(rect.width()), int(rect.height())))
            painter.drawImage(rect, render)
            do_new_page = True