如何在pywin32中排列return内容
How to arrange return content in pywin32
我只有几行代码可以使用 pywin32
将作业发送到我的打印机,但是当我发送此命令时,新行的内容不会出现在纸上的行中 (newline)
打印后继续跟随第一行的内容。
当我将其打印到终端时,它会像我想要的那样打印,但当我将作业发送到打印机时却不会。
一直在该网站上搜索如何在发送打印内容时安排我的内容,但无济于事。
import win32con
import win32print
import win32ui
def text():
rows = (("PETER PAUL", "MALE", "100000"), ("MARGARET ", "FEMALE", "1000"), ("MICHAEL JORDAN", "MALE", "1"),("AGNES", "FEMALE", "200"))
return '\r\n'.join('{:20} {:8} {}'.format(*row) for row in rows)
print(text())
def printer():
dc = win32ui.CreateDC()
printername = win32print.GetDefaultPrinter()
dc.CreatePrinterDC(printername)
dc.SetMapMode(win32con.MM_TWIPS)
scale_factor = 20
dc.StartDoc('Win32print ')
pen = win32ui.CreatePen(0, int(scale_factor), 0)
dc.SelectObject(pen)
font = win32ui.CreateFont({
"name": "Lucida Console",
"height": int(scale_factor * 10),
"weight": 400,
})
dc.SelectObject(font)
dc.TextOut(scale_factor * 72, -1 * scale_factor * 72, text())
dc.EndDoc()
printer()
注:[GitHub]: mhammond/pywin32 - Python for Windows (pywin32) Extensions doesn't have an official doc (or at least I couldn't find any), so I'll be using the 2nd best thing available: ActiveState(只能找到古文Python2.4的参考,但是通常他们没问题)
[ActiveState.Docs]: PyCDC.TextOut wraps [MS.Docs]: TextOutW function。该函数不处理 \r\n(当然还有其他特殊的 chars),例如print 确实如此(文档对此没有任何说明),但它只是忽略了它们(它没有 line 的概念).这意味着为了实现 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),所以我使用当前 window (cmd) HDC 输出数据(因此,我删除了打印机特定代码)
- 我对代码进行了一些结构化,添加了函数,使其模块化
- 我将你的 text 功能分成两部分:
- get_data_strings - returns 一个字符串列表,其中每个字符串都是 rows[=116] 中一行的文本表示=](让它成为一个 生成器 会更好,但我不想让事情过于复杂)
- text - 简单地连接它们(与现有界面一致)
- 关于图形(GDI):
- TextOut 不关心笔,它只使用选定的字体、背景颜色(
dc.SetBkColor
)和文本颜色(dc.SetTextColor
), 但我把它留在那里画了一个椭圆 (只是为了好玩)
- 整数参数(基于 scale_factor)太过分了(太大了 - 至少对我的 HDC), 所以我将它们减少到更合适的值
- 如您所见,我正在单独输出每个字符串(并且还将其 Y 增加 scale_factor -这也是字体高度)。我还保留了旧方法(打印整个字符串),你只需要将 print_each_string 参数设置为 False 即可实现结果和你一样
time.sleep
是必需的,因为输出到 HDC 比 print 快很多(因为缓冲),所以即使根据代码它发生在 print 之后,实际上它的效果发生在 print "pushes" window 之前(包括我们的图形输出)向上,所以当图形输出超出可见区域时,它将失效并且该区域将被重新绘制,使其消失。
我不确定我是否说清楚了,但是一旦你玩过代码(注释行),你就会明白我的意思
- 代码中的某些内容可能不适用于打印机(或工作方式不同),因为它是不同类型的设备
- 还有一个替代方案:使用[ActiveState.Docs]: PyCDC.DrawText (wrapper over [MS.Docs]: DrawText function),它可以处理多行字符串,但您仍然需要做一些计算才能调整绘图RECT(我也不想玩那个功能)
输出:
@EDIT0:
添加了一些打印机特定的功能。此外,更改了行为:
- 没有参数,应用程序打印到默认打印机
- 1st 参数(如果给定)可以是打印机名称或“window”(用于初始行为)
- HDC的工作方式不同:
- 对于打印机,缩放比例要高得多(~10 倍)- 我认为这是因为 window HDC 直接使用像素,而对于打印机 HDC 还考虑了 DPI
- 此外,从顶部到底部 Y 坐标的绝对值增加,但是 负值
- 我输入了一些适用于 "Microsoft Print to PDF" 打印机 OK 的值,但我认为应该通过读取打印机属性
相应地设置这些值
输出:
@EDIT1:
- 已根据评论中的要求添加 "multiple font support"
我只有几行代码可以使用 pywin32
将作业发送到我的打印机,但是当我发送此命令时,新行的内容不会出现在纸上的行中 (newline)
打印后继续跟随第一行的内容。
当我将其打印到终端时,它会像我想要的那样打印,但当我将作业发送到打印机时却不会。
一直在该网站上搜索如何在发送打印内容时安排我的内容,但无济于事。
import win32con
import win32print
import win32ui
def text():
rows = (("PETER PAUL", "MALE", "100000"), ("MARGARET ", "FEMALE", "1000"), ("MICHAEL JORDAN", "MALE", "1"),("AGNES", "FEMALE", "200"))
return '\r\n'.join('{:20} {:8} {}'.format(*row) for row in rows)
print(text())
def printer():
dc = win32ui.CreateDC()
printername = win32print.GetDefaultPrinter()
dc.CreatePrinterDC(printername)
dc.SetMapMode(win32con.MM_TWIPS)
scale_factor = 20
dc.StartDoc('Win32print ')
pen = win32ui.CreatePen(0, int(scale_factor), 0)
dc.SelectObject(pen)
font = win32ui.CreateFont({
"name": "Lucida Console",
"height": int(scale_factor * 10),
"weight": 400,
})
dc.SelectObject(font)
dc.TextOut(scale_factor * 72, -1 * scale_factor * 72, text())
dc.EndDoc()
printer()
注:[GitHub]: mhammond/pywin32 - Python for Windows (pywin32) Extensions doesn't have an official doc (or at least I couldn't find any), so I'll be using the 2nd best thing available: ActiveState(只能找到古文Python2.4的参考,但是通常他们没问题)
[ActiveState.Docs]: PyCDC.TextOut wraps [MS.Docs]: TextOutW function。该函数不处理 \r\n(当然还有其他特殊的 chars),例如print 确实如此(文档对此没有任何说明),但它只是忽略了它们(它没有 line 的概念).这意味着为了实现 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),所以我使用当前 window (cmd) HDC 输出数据(因此,我删除了打印机特定代码)
- 我对代码进行了一些结构化,添加了函数,使其模块化
- 我将你的 text 功能分成两部分:
- get_data_strings - returns 一个字符串列表,其中每个字符串都是 rows[=116] 中一行的文本表示=](让它成为一个 生成器 会更好,但我不想让事情过于复杂)
- text - 简单地连接它们(与现有界面一致)
- 关于图形(GDI):
- TextOut 不关心笔,它只使用选定的字体、背景颜色(
dc.SetBkColor
)和文本颜色(dc.SetTextColor
), 但我把它留在那里画了一个椭圆 (只是为了好玩) - 整数参数(基于 scale_factor)太过分了(太大了 - 至少对我的 HDC), 所以我将它们减少到更合适的值
- 如您所见,我正在单独输出每个字符串(并且还将其 Y 增加 scale_factor -这也是字体高度)。我还保留了旧方法(打印整个字符串),你只需要将 print_each_string 参数设置为 False 即可实现结果和你一样
- TextOut 不关心笔,它只使用选定的字体、背景颜色(
time.sleep
是必需的,因为输出到 HDC 比 print 快很多(因为缓冲),所以即使根据代码它发生在 print 之后,实际上它的效果发生在 print "pushes" window 之前(包括我们的图形输出)向上,所以当图形输出超出可见区域时,它将失效并且该区域将被重新绘制,使其消失。
我不确定我是否说清楚了,但是一旦你玩过代码(注释行),你就会明白我的意思- 代码中的某些内容可能不适用于打印机(或工作方式不同),因为它是不同类型的设备
- 还有一个替代方案:使用[ActiveState.Docs]: PyCDC.DrawText (wrapper over [MS.Docs]: DrawText function),它可以处理多行字符串,但您仍然需要做一些计算才能调整绘图RECT(我也不想玩那个功能)
输出:
@EDIT0:
添加了一些打印机特定的功能。此外,更改了行为:
- 没有参数,应用程序打印到默认打印机
- 1st 参数(如果给定)可以是打印机名称或“window”(用于初始行为)
- HDC的工作方式不同:
- 对于打印机,缩放比例要高得多(~10 倍)- 我认为这是因为 window HDC 直接使用像素,而对于打印机 HDC 还考虑了 DPI
- 此外,从顶部到底部 Y 坐标的绝对值增加,但是 负值
- 我输入了一些适用于 "Microsoft Print to PDF" 打印机 OK 的值,但我认为应该通过读取打印机属性 相应地设置这些值
输出:
@EDIT1:
- 已根据评论中的要求添加 "multiple font support"