【问题标题】:Python Programmatically Change Console font sizePython 以编程方式更改控制台字体大小
【发布时间】:2018-09-14 16:50:49
【问题描述】:

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

【问题讨论】:

    标签: python cmd fonts ctypes


    【解决方案1】:

    我想首先指出[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

    我“稍微”改变了你的代码。

    code.py

    #!/usr/bin/env python
    
    import sys
    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
    
    
    def main():
        # Get stdout handle
        stdout = get_std_handle_func(STD_OUTPUT_HANDLE)
        if not stdout:
            print("{:s} error: {:d}".format(get_std_handle_func.__name__, get_last_error_func()))
            return
        # Get current font characteristics
        font = CONSOLE_FONT_INFOEX()
        font.cbSize = sizeof(CONSOLE_FONT_INFOEX)
        res = get_current_console_font_ex_func(stdout, False, byref(font))
        if not res:
            print("{:s} error: {:d}".format(get_current_console_font_ex_func.__name__, get_last_error_func()))
            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
            # Apply changes
            res = set_current_console_font_ex_func(stdout, False, byref(font))
            if not res:
                print("{:s} error: {:d}".format(set_current_console_font_ex_func.__name__, get_last_error_func()))
                return
            print("OMG! The window changed :)")
            # Get current font characteristics again and display font size
            res = get_current_console_font_ex_func(stdout, False, byref(font))
            if not res:
                print("{:s} error: {:d}".format(get_current_console_font_ex_func.__name__, get_last_error_func()))
                return
            print("\nNew sizes    X: {:d}, Y: {:d}".format(font.dwFontSize.X, font.dwFontSize.Y))
    
    
    if __name__ == "__main__":
        print("Python {:s} on {:s}\n".format(sys.version, sys.platform))
        main()
    

    注意事项

    • CTypes 允许类似于 C 的低级访问(只是语法是 Python

    • 代码使用[MS.Docs]: SetConsoleTextAttribute function

    • ctypes.wintypes 常量(它引用了标准的CTypes 类型)被用来(给代码一个类似Win 的味道)

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

    • 正如[SO]: Change console font in Windows(您从中复制代码)的答案之一所建议的那样,另一种方法是安装一个 3rd 方模块(例如 [GitHub]: mhammond/pywin32 - Python for Windows (pywin32) Extensions,它是Python 包装器在 WINAPIs) 上需要更少的代码来编写,因为 PythonC 之间的桥接会已经实现了,可能上面的功能只需要几行就可以完成

    • 正如我在代码中评论的那样,设置 COORD.X 似乎被忽略了。但在设置 COORD.Y 时会自动设置(接近COORD.Y // 2 的值 - 可能是为了保持纵横比)。在我的机器 (Win 10 pc064) 上,默认值为 16。您可能希望在最后将其设置回来,以避免使控制台处于“挑战”状态(显然,Win 调整 cmd 窗口大小,为(有点) 在 sync 中与字体大小):

    【讨论】:

      【解决方案2】:

      这不是纯粹的 Python 问题,而是涉及 Windows API。

      查看CONSOLE_FONT_INFOEX结构的文档。每个字符的宽度和高度都有一个COORD 成员。

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

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

      参考:Change console font in Windows

      【讨论】:

        【解决方案3】:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-05-06
          • 2016-10-30
          • 1970-01-01
          • 2013-01-20
          • 2013-01-09
          • 2016-05-24
          • 2015-01-22
          • 1970-01-01
          相关资源
          最近更新 更多