Python编程更改控制台字体大小

iq0todco  于 2023-02-18  发布在  Python
关注(0)|答案(3)|浏览(225)

我发现下面的代码应该是以编程方式改变控制台字体大小。我在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")
vcirk6k6

vcirk6k61#

首先,检查[SO]: C function called from Python via ctypes returns incorrect value (@CristiFati's answer),以了解使用 CTypes(调用函数)时的常见陷阱。

  • CTypes* 主页(也在上面的 URL 中列出):【Python文档】:ctypes -Python的外来函数库

我把你的密码改了“一点点”。

  • 代码00.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 function
  • 为了避免设置无效值,它与其对应项结合使用:[MS.Learn]: GetCurrentConsoleFontEx function。调用该函数以填充 CONSOLE_FONT_INFOEX 结构,然后仅修改所需的值
  • 有一些“更简单”的函数(例如[MS.Learn]: GetCurrentConsoleFont function[MS.Learn]: GetConsoleFontSize function),但遗憾的是没有相应的setter
    *请注意,所有引用的 WinAPI 函数都已过时
  • 使用 ctypes.wintypes 常量(引用标准的 CTypes 类型)(以给予代码具有 Win 风格)
  • 它非常长(几乎令人痛苦)(也因为我添加了适当的错误处理)
  • 另一种方法,如[SO]: Change console font in Windows的答案之一所示(您从中复制代码的位置),就是安装第三方模块(例如[GitHub]: mhammond/pywin32 - Python for Windows (pywin32) Extensions,它是 WINAPIs上的 Python Package 器),这将需要编写更少的代码,因为 PythonC 之间的桥接将已经实现,并且可能上述功能可以在仅仅几行中完成
  • 正如我在代码中所注解的,设置 COORD.X 似乎被忽略了,但是在设置 COORD.Y 时会自动设置它(设置为接近COORD.Y // 2的值-可能是为了保持纵横比)。(Win 10 pc 064 )与当前所选字体匹配时,默认值为16。您可能需要在最后将其设置回来,为了避免控制台处于“受挑战”状态(显然,Win 会调整 Cmd 窗口大小,使其(某种程度上)与字体大小 * 同步 *):

vsmadaxz

vsmadaxz2#

这不是一个纯粹的python问题,但涵盖了Windows API。
请看CONSOLE_FONT_INFOEX结构的文档,其中有一个COORD成员,用于表示每个字符的宽度和高度。
要更改控制台字体大小,可以将这些属性作为适当的值:

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

参考:Change console font in Windows

xwbd5t1u

xwbd5t1u3#

对于将来希望使用控制台作为显示方法的任何人(白色)图像或只是得到尽可能小的字体大小,这是我使用的修改答案代码。我发现高度和宽度为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))

相关问题