Python 以编程方式更改控制台字体大小
Python Programmatically Change Console font size
我发现下面的代码应该以编程方式更改控制台字体大小。我在 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 问题,而是涵盖了 Windows API。
查看CONSOLE_FONT_INFOEX structure. There is a COORD成员的文档,了解每个字符的宽度和高度。
要更改控制台字体大小,您可以为这些属性赋予适当的值:
font.dwFontSize.X = 11
font.dwFontSize.Y = 18
参考:Change console font in Windows
我想首先指出 ,它描述了大多数 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
- 为了避免设置无效值,它与它的对应物一起使用:[MS.Docs]: GetCurrentConsoleFontEx function。调用该函数以填充 CONSOLE_FONT_INFOEX 结构,然后仅修改所需的值
- 有“更简单”的函数(例如[MS.Docs]: GetCurrentConsoleFont function or [MS.Docs]: GetConsoleFontSize function),可惜没有对应的setter
ctypes.wintypes 常量(引用标准 CTypes 类型)用于(给出代码有点像 Win 的味道)
它非常(几乎是痛苦的)长(也是因为我添加了适当的错误处理)
另一种选择,如 [SO]: Change console font in Windows (where you copied the code from), would be to install a 3rd-party module (e.g. [GitHub]: mhammond/pywin32 - Python for Windows (pywin32) Extensions 的一个答案中所建议的,它是 Python 的包装器]WINAPIs) 这将需要更少的代码来编写,因为 Python 和 C 之间的桥接已经实现了,估计上面的功能几行就可以完成
正如我在代码中评论的那样,设置 COORD.X 似乎被忽略了。但它会在设置 COORD.Y 时自动设置(接近 COORD.Y // 2
的值 - 可能是为了保持纵横比)。在我的机器上 (Win 10 pc064) 默认值是 16。您可能希望在最后将其设置回来,以避免让控制台处于“受挑战”状态(显然,Win 调整 cmd window 大小,与字体大小同步(有点):
对于将来想要使用控制台作为显示(黑白)图像或只是获得尽可能小的字体大小的方法的任何人,这是我使用的修改后的答案代码。我发现 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))
我发现下面的代码应该以编程方式更改控制台字体大小。我在 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 问题,而是涵盖了 Windows API。
查看CONSOLE_FONT_INFOEX structure. There is a COORD成员的文档,了解每个字符的宽度和高度。
要更改控制台字体大小,您可以为这些属性赋予适当的值:
font.dwFontSize.X = 11
font.dwFontSize.Y = 18
参考:Change console font in Windows
我想首先指出
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
- 为了避免设置无效值,它与它的对应物一起使用:[MS.Docs]: GetCurrentConsoleFontEx function。调用该函数以填充 CONSOLE_FONT_INFOEX 结构,然后仅修改所需的值
- 有“更简单”的函数(例如[MS.Docs]: GetCurrentConsoleFont function or [MS.Docs]: GetConsoleFontSize function),可惜没有对应的setter
ctypes.wintypes 常量(引用标准 CTypes 类型)用于(给出代码有点像 Win 的味道)
它非常(几乎是痛苦的)长(也是因为我添加了适当的错误处理)
另一种选择,如 [SO]: Change console font in Windows (where you copied the code from), would be to install a 3rd-party module (e.g. [GitHub]: mhammond/pywin32 - Python for Windows (pywin32) Extensions 的一个答案中所建议的,它是 Python 的包装器]WINAPIs) 这将需要更少的代码来编写,因为 Python 和 C 之间的桥接已经实现了,估计上面的功能几行就可以完成
正如我在代码中评论的那样,设置 COORD.X 似乎被忽略了。但它会在设置 COORD.Y 时自动设置(接近
COORD.Y // 2
的值 - 可能是为了保持纵横比)。在我的机器上 (Win 10 pc064) 默认值是 16。您可能希望在最后将其设置回来,以避免让控制台处于“受挑战”状态(显然,Win 调整 cmd window 大小,与字体大小同步(有点):
对于将来想要使用控制台作为显示(黑白)图像或只是获得尽可能小的字体大小的方法的任何人,这是我使用的修改后的答案代码。我发现 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))