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:
However, after clicking the print button, the Windows print dialog comes up and is defaulting to "Portrait":
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
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