Python编程:以编程方式更改控制台字体大小

5
我找到了下面的代码,它应该可以以编程方式更改控制台字体大小。我在使用Windows 10。
然而,无论我调整什么值,似乎都无法对字体大小进行任何控制,而且由于某种原因,运行此脚本时打开的控制台非常宽。
我不知道ctypes如何工作 - 我想做的就是从Python内部修改控制台字体的大小。
有没有实际可行的解决方案?
import ctypes

LF_FACESIZE = 32
STD_OUTPUT_HANDLE = -11

class COORD(ctypes.Structure):
    _fields_ = [("X", ctypes.c_short), ("Y", ctypes.c_short)]

class CONSOLE_FONT_INFOEX(ctypes.Structure):
    _fields_ = [("cbSize", ctypes.c_ulong),
                ("nFont", ctypes.c_ulong),
                ("dwFontSize", COORD),
                ("FontFamily", ctypes.c_uint),
                ("FontWeight", ctypes.c_uint),
                ("FaceName", ctypes.c_wchar * LF_FACESIZE)]

font = CONSOLE_FONT_INFOEX()
font.cbSize = ctypes.sizeof(CONSOLE_FONT_INFOEX)
font.nFont = 12
font.dwFontSize.X = 11
font.dwFontSize.Y = 18
font.FontFamily = 54
font.FontWeight = 400
font.FaceName = "Lucida Console"

handle = ctypes.windll.kernel32.GetStdHandle(STD_OUTPUT_HANDLE)
ctypes.windll.kernel32.SetCurrentConsoleFontEx(
        handle, ctypes.c_long(False), ctypes.pointer(font))


print("Foo")
3个回答

7
在开始之前,请查看[SO]: C function called from Python via ctypes returns incorrect value (@CristiFati's answer),了解在使用CTypes(调用函数)时常见的陷阱。 CTypes主页(也列在上述URL中):[Python.Docs]: ctypes - A foreign function library for Python 我稍微修改了你的代码。 code00.py:
#!/usr/bin/env python

import ctypes as cts
import ctypes.wintypes as wts
import sys


LF_FACESIZE = 32
STD_OUTPUT_HANDLE = -11


class CONSOLE_FONT_INFOEX(cts.Structure):
    _fields_ = (
        ("cbSize", wts.ULONG),
        ("nFont", wts.DWORD),
        ("dwFontSize", wts._COORD),
        ("FontFamily", wts.UINT),
        ("FontWeight", wts.UINT),
        ("FaceName", wts.WCHAR * LF_FACESIZE)
    )


def main(*argv):
    kernel32 = cts.WinDLL("Kernel32.dll")

    GetLastError = kernel32.GetLastError
    GetLastError.argtypes = ()
    GetLastError.restype = wts.DWORD

    GetStdHandle = kernel32.GetStdHandle
    GetStdHandle.argtypes = (wts.DWORD,)
    GetStdHandle.restype = wts.HANDLE

    GetCurrentConsoleFontEx = kernel32.GetCurrentConsoleFontEx
    GetCurrentConsoleFontEx.argtypes = (wts.HANDLE, wts.BOOL, cts.POINTER(CONSOLE_FONT_INFOEX))
    GetCurrentConsoleFontEx.restype = wts.BOOL

    SetCurrentConsoleFontEx = kernel32.SetCurrentConsoleFontEx
    SetCurrentConsoleFontEx.argtypes = (wts.HANDLE, wts.BOOL, cts.POINTER(CONSOLE_FONT_INFOEX))
    SetCurrentConsoleFontEx.restype = wts.BOOL

    # Get stdout handle
    stdout = GetStdHandle(STD_OUTPUT_HANDLE)
    if not stdout:
        print("{:s} error: {:d}".format(GetStdHandle.__name__, GetLastError()))
        return
    # Get current font characteristics
    font = CONSOLE_FONT_INFOEX()
    font.cbSize = cts.sizeof(CONSOLE_FONT_INFOEX)
    res = GetCurrentConsoleFontEx(stdout, False, cts.byref(font))
    if not res:
        print("{:s} error: {:d}".format(GetCurrentConsoleFontEx.__name__, GetLastError()))
        return
    # Display font information
    print("Console information for {:}".format(font))
    for field_name, _ in font._fields_:
        field_data = getattr(font, field_name)
        if field_name == "dwFontSize":
            print("    {:s}: {{X: {:d}, Y: {:d}}}".format(field_name, field_data.X, field_data.Y))
        else:
            print("    {:s}: {:}".format(field_name, field_data))
    while 1:
        try:
            height = int(input("\nEnter font height (invalid to exit): "))
        except:
            break
        # Alter font height
        font.dwFontSize.X = 10  # Changing X has no effect (at least on my machine)
        font.dwFontSize.Y = height
        # Display font information
        res = SetCurrentConsoleFontEx(stdout, False, cts.byref(font))
        if not res:
            print("{:s} error: {:d}".format(SetCurrentConsoleFontEx.__name__, GetLastError()))
            return
        print("OMG! The window changed :)")
        # Get current font characteristics again
        res = GetCurrentConsoleFontEx(stdout, False, cts.byref(font))
        if not res:
            print("{:s} error: {:d}".format(GetCurrentConsoleFontEx.__name__, GetLastError()))
            return
        print("\nNew sizes    X: {:d}, Y: {:d}".format(font.dwFontSize.X, font.dwFontSize.Y))


if __name__ == "__main__":
    print("Python {:s} {:03d}bit on {:s}\n".format(" ".join(elem.strip() for elem in sys.version.split("\n")),
                                                   64 if sys.maxsize > 0x100000000 else 32, sys.platform))
    rc = main(*sys.argv[1:])
    print("\nDone.\n")
    sys.exit(rc)

注意事项:

  • CTypes允许类似于C的底层访问(只有语法是Python

  • 代码使用[MS.Learn]: SetConsoleTextAttribute函数

  • 使用ctypes.wintypes常量(引用标准的CTypes类型)(以给代码一种Win的风味)

  • 它非常(几乎令人痛苦)冗长(也因为我添加了适当的错误处理)

  • 作为[SO]: Change console font in Windows答案之一建议的替代方法是安装第三方模块(例如[GitHub]: mhammond/pywin32 - Python for Windows (pywin32) Extensions,这是一个Python包装器,可以在上面实现WINAPI),这将需要编写较少的代码,因为PythonC之间的桥接已经实现,并且可能只需几行代码即可完成上述功能

  • 正如我在代码中所评论的,在设置COORD.X时似乎被忽略了。但是当设置COORD.Y时(到接近COORD.Y // 2的值-可能是为了保持纵横比),它会自动设置。在我的机器(Win 10 pc064)上,默认值为16。您可能希望在最后将其恢复,以避免将控制台留在“挑战”状态下(显然,Win调整Cmd 窗口大小,以与字体大小“同步”):

Img0


0

这不是一个纯Python问题,而是涉及到Windows API。

查看CONSOLE_FONT_INFOEX结构的文档。其中有一个COORD成员,用于表示每个字符的宽度和高度。

要更改控制台字体大小,您可以将这些属性设置为适当的值:

font.dwFontSize.X = 11
font.dwFontSize.Y = 18

参考资料:在Windows中更改控制台字体


0

对于未来想要使用控制台作为显示(黑白)图像或获取最小可能字体大小的人,这是我使用的修改后的答案代码。我发现2px的高度和宽度是最好的最小尺寸,但要小心,所有尺寸都会扭曲图片,有些比其他尺寸更严重。至于字体,我使用唯一可用的“rasterfont”。(个人遇到了巨大的问题,无法确定原因...而且这与被接受的答案不同)

def changeFontSize(size=2): #Changes the font size to *size* pixels (kind of, but not really. You'll have to try it to chack if it works for your purpose ;) )
    from ctypes import POINTER, WinDLL, Structure, sizeof, byref
    from ctypes.wintypes import BOOL, SHORT, WCHAR, UINT, ULONG, DWORD, HANDLE

    LF_FACESIZE = 32
    STD_OUTPUT_HANDLE = -11

    class COORD(Structure):
        _fields_ = [
            ("X", SHORT),
            ("Y", SHORT),
        ]

    class CONSOLE_FONT_INFOEX(Structure):
        _fields_ = [
            ("cbSize", ULONG),
            ("nFont", DWORD),
            ("dwFontSize", COORD),
            ("FontFamily", UINT),
            ("FontWeight", UINT),
            ("FaceName", WCHAR * LF_FACESIZE)
        ]

    kernel32_dll = WinDLL("kernel32.dll")

    get_last_error_func = kernel32_dll.GetLastError
    get_last_error_func.argtypes = []
    get_last_error_func.restype = DWORD

    get_std_handle_func = kernel32_dll.GetStdHandle
    get_std_handle_func.argtypes = [DWORD]
    get_std_handle_func.restype = HANDLE

    get_current_console_font_ex_func = kernel32_dll.GetCurrentConsoleFontEx
    get_current_console_font_ex_func.argtypes = [HANDLE, BOOL, POINTER(CONSOLE_FONT_INFOEX)]
    get_current_console_font_ex_func.restype = BOOL

    set_current_console_font_ex_func = kernel32_dll.SetCurrentConsoleFontEx
    set_current_console_font_ex_func.argtypes = [HANDLE, BOOL, POINTER(CONSOLE_FONT_INFOEX)]
    set_current_console_font_ex_func.restype = BOOL

    stdout = get_std_handle_func(STD_OUTPUT_HANDLE)
    font = CONSOLE_FONT_INFOEX()
    font.cbSize = sizeof(CONSOLE_FONT_INFOEX)

    font.dwFontSize.X = size
    font.dwFontSize.Y = size

    set_current_console_font_ex_func(stdout, False, byref(font))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接