如何在pywin32中安排返回内容

时间:2018-04-11 15:13:24

标签: python printing pywin32

我有几行代码可以使用pywin32将作业发送到我的打印机但是当我发送此命令时,新行的内容不会显示在纸张的{{1}行上打印后但继续跟随第一行的内容。 当我将其打印到终端时,它打印出我想要的但不是当我将作业发送到打印机时。 image description of the printed result

一直在搜索本网站上有关如何在发送内容时安排我的内容,但无济于事。

(newline)

1 个答案:

答案 0 :(得分:2)

注意[GitHub]: mhammond/pywin32 - Python for Windows (pywin32) Extensions没有官方文档(或者至少我找不到任何文档),所以我将使用2 nd 最好的东西可用:ActiveState(我只能找到古代 Python2.4 的参考文献,但通常它们都可以)

[ActiveState.Docs]: PyCDC.TextOut换行[MS.Docs]: TextOutW function。该函数不处理 \ r \ n (以及其他特殊的 char ),如 print (文档没有说明这一点),但它只是忽略了它们(它没有的概念)。这意味着,为了实现 print - 类似的功能,用户负责单独输出每一行(当然是在不同的 Y 坐标 - 以避免输出前一个)。

为了更好地说明行为,我创建了一个示例(基于您的代码)。

code.py

#!/usr/bin/env python3

import sys
import time
import win32ui
import win32con
import win32print


def get_data_strings():
    rows = (("PETER PAUL", "MALE", "100000"), ("MARGARET ", "FEMALE", "1000"), ("MICHAEL JORDAN", "MALE", "1"),("AGNES", "FEMALE", "200"))
    return ["{:20} {:8} {}".format(*row) for row in rows]


def text():
    return "\r\n".join(get_data_strings())


def paint_dc(dc, printer_dc, paint_each_string=True):
    scale_factor = 20
    if printer_dc:
        x_y = 100, 0  # TopLeft of the page. In order to move away from the point, X increases to positives, while Y to negatives
        font_scale = 10
        y_direction_scale = -1  # For printers, the Y axis is "reversed"
        y_ellipsis = -100
    else:
        x_y = 100, 150  # TopLeft from wnd's client area
        font_scale = 1
        y_direction_scale = 1
        y_ellipsis = 100

    font0 = win32ui.CreateFont(
        {
            "name": "Lucida Console",
            "height": scale_factor * font_scale,
            "weight": 400,
        })
    font1 = win32ui.CreateFont(
        {
            "name": "algerian",
            "height": scale_factor * font_scale,
            "weight": 400,
        })
    fonts = [font0, font1]
    dc.SelectObject(font0)
    dc.SetTextColor(0x0000FF00) # 0BGR
    #dc.SetBkColor(0x000000FF)
    dc.SetBkMode(win32con.TRANSPARENT)
    if paint_each_string:
        for idx, txt in enumerate(get_data_strings()):
            dc.SelectObject(fonts[idx % len(fonts)])
            dc.TextOut(x_y[0], x_y[1] + idx * scale_factor * font_scale * y_direction_scale, txt)
    else:
        dc.TextOut(*x_y, text())
    pen = win32ui.CreatePen(0, 0, 0)
    dc.SelectObject(pen)
    dc.Ellipse((50, y_ellipsis, *x_y))


def paint_wnd(wnd, paint_each_string=True):
    dc = wnd.GetWindowDC()
    paint_dc(dc, False, paint_each_string=paint_each_string)
    wnd.ReleaseDC(dc)


def paint_prn(printer_name, paint_each_string=True):
    printer_name = printer_name or win32print.GetDefaultPrinter()
    dc = win32ui.CreateDC()
    dc.CreatePrinterDC(printer_name)
    dc.SetMapMode(win32con.MM_TWIPS)
    dc.StartDoc("Win32print")
    #dc.StartPage()
    paint_dc(dc, True, paint_each_string=paint_each_string)
    #dc.EndPage()
    dc.EndDoc()


def main():
    print("Python {:s} on {:s}\n".format(sys.version, sys.platform))
    print(text())
    time.sleep(0.1)
    if len(sys.argv) > 1:
        if sys.argv[1] == "window":
            paint_func = paint_wnd
            paint_func_dc_arg = win32ui.GetForegroundWindow()
        else:
            paint_func = paint_prn
            paint_func_dc_arg = sys.argv[1]
    else:
        paint_func = paint_prn
        paint_func_dc_arg = None
    paint_func(paint_func_dc_arg, paint_each_string=True)


if __name__ == "__main__":
    main()

备注

  • 我没有连接打印机(实际上我这样做,但我不想每次运行程序时都打印smth),所以我使用的是当前窗口( cmd HDC 输出数据(因此,我删除了打印机特定代码)
  • 我稍微构建了代码,添加了函数,因此它是模块化的
  • 我将 text 功能拆分为2:
    • get_data_strings - 返回一个字符串列表,其中每个字符串都是来自 rows 的一行的文本表示形式(将它变为生成器会更好< / em>,但我不想过于复杂化的事情)
    • text - 只是加入它们(与现有界面保持一致)
  • 关于图形( GDI ):
    • TextOut 不关心笔,它只使用选定的字体,背景颜色(dc.SetBkColor)和文字颜色(dc.SetTextColor),但我离开了在那里画了一个椭圆(只是为了好玩)
    • 整数参数(基于 scale_factor )是脱节的(太大了 - 至少对于我的 HDC ),所以我把它们减少到更合适的值< / LI>
    • 正如您所看到的,我正在单独输出每个字符串(并且还通过 scale_factor 增加其 Y - 它也是字体高度)。我还保留旧方式(打印整个字符串),你只需要将 print_each_string 参数设置为 False 以达到与你相同的结果
  • time.sleep是必需的,因为输出到 HDC 的速度比 print 要快得多(因为缓冲),所以即使根据代码它发生在之后 print ,实际上它的效果发生之前, print “推”窗口内容(包括我们的图形输出),所以当图形输出超出可见区域时,它将被无效,该区域将被重新粉刷,使其消失。我不确定自己是否清楚,但是一旦你玩了代码(评论一下),你就会明白我的意思
  • 代码中的某些内容可能无法与打印机一起工作(或以不同的方式工作),因为它是一种不同类型的设备
  • 还有另一种方法:使用[ActiveState.Docs]: PyCDC.DrawText[MS.Docs]: DrawText function上的包装器),它可以处理多行字符串,但你仍然需要做一些计算才能调整绘图 RECT (我也不喜欢玩这个功能)

<强>输出

Program Output

<强> @ EDIT0

添加了一些特定于打印机的功能。此外,改变了行为:

  • 不带参数,应用程序将打印到默认打印机
  • 1 st 参数(如果给出)可以是打印机名称或“ window ”(用于初始行为)
  • HDC 的工作方式不同:
    • 对于打印机,缩放比例要高得多(~10倍) - 我认为这是因为窗口 HDC 直接与像素一起工作,而对于打印机 HDC 也需要 DPI 到账
    • 此外,在 Y 坐标的顶部&gt;底部增加绝对值,但
    • 我为“Microsoft Print to PDF”打印机设置了一些 OK 的值,但我认为应该通过读取打印机属性来相应地设置这些值

<强>输出

Img1

<强> @ EDIT1

  • 在评论中添加了“多字体支持”