如何使用 Python 在没有窗口的情况下在屏幕上显示文本 [英] How to display text on the screen without a window using Python
问题描述
我需要在没有窗口的情况下直接将文本写入屏幕.文本需要出现在所有其他窗口和全屏应用程序的上方,并且不应以任何方式可点击或交互.
I need to write text directly to the screen without a window. The text needs to appear above all other windows and full-screen applications and should not be clickable or interactable in any way.
示例:如示例中所示,文本不需要具有透明背景.我可以在 Windows 7 上使用 Python 2 或 3.
Example: The text doesn't need to have a transparent background as seen in the example. I can use either Python 2 or 3 on Windows 7.
我尝试使用 Tkinter 制作独立标签:
I tried making a standalone label using Tkinter:
在 Christian Rapp 的帮助下改进
Improved with the help of Christian Rapp
import Tkinter
label = Tkinter.Label(text='Text on the screen', font=('Times','30'), fg='black', bg='white')
label.master.overrideredirect(True)
label.master.geometry("+250+250")
label.master.lift()
label.master.wm_attributes("-topmost", True)
label.master.wm_attributes("-disabled", True)
label.master.wm_attributes("-transparentcolor", "white")
label.pack()
label.mainloop()
什么有效:
- 文本显示时没有窗口
- 文本始终高于所有其他窗口
- 背景可以是透明的
什么不是:
- 文本未显示在全屏应用程序上方
- 文本块上发生的点击事件
- 背景透明度不是 alpha,所以有硬边
推荐答案
事实证明这里有两个完全不同的问题.要在窗口上显示文本,您需要创建一个未修饰的最顶层窗口并为背景设置色度键.但是,当有全屏应用程序(例如游戏)正在运行时,这将不起作用.在全屏应用程序上显示文本的唯一可靠方法是使用 Direct3D 挂钩.
It turns out there are two entirely different problems here. To show text over windows, you'll need to create an undecorated topmost window and chroma key the background. However, this won't work when there's a full-screen application running (such as a game). The only reliable way to show text over a full-screen application is to use a Direct3D hook.
我还没有写过 Direct3D 钩子的例子,但我会针对第一个问题给出两种不同的解决方案.
I haven't written up a Direct3D hook example, but I'll give two different solutions to the first problem.
在这个例子中,我使用 Tkinter 完成大部分工作,并使用 win32api 来防止文本阻止鼠标点击.如果您无法使用 win32api,那么您只需删除该部分代码即可.
In this example, I do the majority of the work with Tkinter and use win32api to prevent the text from blocking mouse clicks. If win32api isn't available to you, then you can just remove that part of the code.
import Tkinter, win32api, win32con, pywintypes
label = Tkinter.Label(text='Text on the screen', font=('Times New Roman','80'), fg='black', bg='white')
label.master.overrideredirect(True)
label.master.geometry("+250+250")
label.master.lift()
label.master.wm_attributes("-topmost", True)
label.master.wm_attributes("-disabled", True)
label.master.wm_attributes("-transparentcolor", "white")
hWindow = pywintypes.HANDLE(int(label.master.frame(), 16))
# http://msdn.microsoft.com/en-us/library/windows/desktop/ff700543(v=vs.85).aspx
# The WS_EX_TRANSPARENT flag makes events (like mouse clicks) fall through the window.
exStyle = win32con.WS_EX_COMPOSITED | win32con.WS_EX_LAYERED | win32con.WS_EX_NOACTIVATE | win32con.WS_EX_TOPMOST | win32con.WS_EX_TRANSPARENT
win32api.SetWindowLong(hWindow, win32con.GWL_EXSTYLE, exStyle)
label.pack()
label.mainloop()
方案二:pywin32
此示例通过 pywin32 完成所有操作.这使得它更复杂,更不便携,但功能更强大.我在整个代码中都包含了指向 Windows API 相关部分的链接.
Solution 2: pywin32
This example does everything through pywin32. This makes it more complicated and less portable, but considerably more powerful. I've included links to the relevant parts of the Windows API throughout the code.
import win32api, win32con, win32gui, win32ui
def main():
hInstance = win32api.GetModuleHandle()
className = 'MyWindowClassName'
# http://msdn.microsoft.com/en-us/library/windows/desktop/ms633576(v=vs.85).aspx
# win32gui does not support WNDCLASSEX.
wndClass = win32gui.WNDCLASS()
# http://msdn.microsoft.com/en-us/library/windows/desktop/ff729176(v=vs.85).aspx
wndClass.style = win32con.CS_HREDRAW | win32con.CS_VREDRAW
wndClass.lpfnWndProc = wndProc
wndClass.hInstance = hInstance
wndClass.hCursor = win32gui.LoadCursor(None, win32con.IDC_ARROW)
wndClass.hbrBackground = win32gui.GetStockObject(win32con.WHITE_BRUSH)
wndClass.lpszClassName = className
# win32gui does not support RegisterClassEx
wndClassAtom = win32gui.RegisterClass(wndClass)
# http://msdn.microsoft.com/en-us/library/windows/desktop/ff700543(v=vs.85).aspx
# Consider using: WS_EX_COMPOSITED, WS_EX_LAYERED, WS_EX_NOACTIVATE, WS_EX_TOOLWINDOW, WS_EX_TOPMOST, WS_EX_TRANSPARENT
# The WS_EX_TRANSPARENT flag makes events (like mouse clicks) fall through the window.
exStyle = win32con.WS_EX_COMPOSITED | win32con.WS_EX_LAYERED | win32con.WS_EX_NOACTIVATE | win32con.WS_EX_TOPMOST | win32con.WS_EX_TRANSPARENT
# http://msdn.microsoft.com/en-us/library/windows/desktop/ms632600(v=vs.85).aspx
# Consider using: WS_DISABLED, WS_POPUP, WS_VISIBLE
style = win32con.WS_DISABLED | win32con.WS_POPUP | win32con.WS_VISIBLE
# http://msdn.microsoft.com/en-us/library/windows/desktop/ms632680(v=vs.85).aspx
hWindow = win32gui.CreateWindowEx(
exStyle,
wndClassAtom,
None, # WindowName
style,
0, # x
0, # y
win32api.GetSystemMetrics(win32con.SM_CXSCREEN), # width
win32api.GetSystemMetrics(win32con.SM_CYSCREEN), # height
None, # hWndParent
None, # hMenu
hInstance,
None # lpParam
)
# http://msdn.microsoft.com/en-us/library/windows/desktop/ms633540(v=vs.85).aspx
win32gui.SetLayeredWindowAttributes(hWindow, 0x00ffffff, 255, win32con.LWA_COLORKEY | win32con.LWA_ALPHA)
# http://msdn.microsoft.com/en-us/library/windows/desktop/dd145167(v=vs.85).aspx
#win32gui.UpdateWindow(hWindow)
# http://msdn.microsoft.com/en-us/library/windows/desktop/ms633545(v=vs.85).aspx
win32gui.SetWindowPos(hWindow, win32con.HWND_TOPMOST, 0, 0, 0, 0,
win32con.SWP_NOACTIVATE | win32con.SWP_NOMOVE | win32con.SWP_NOSIZE | win32con.SWP_SHOWWINDOW)
# http://msdn.microsoft.com/en-us/library/windows/desktop/ms633548(v=vs.85).aspx
#win32gui.ShowWindow(hWindow, win32con.SW_SHOW)
win32gui.PumpMessages()
def wndProc(hWnd, message, wParam, lParam):
if message == win32con.WM_PAINT:
hdc, paintStruct = win32gui.BeginPaint(hWnd)
dpiScale = win32ui.GetDeviceCaps(hdc, win32con.LOGPIXELSX) / 60.0
fontSize = 80
# http://msdn.microsoft.com/en-us/library/windows/desktop/dd145037(v=vs.85).aspx
lf = win32gui.LOGFONT()
lf.lfFaceName = "Times New Roman"
lf.lfHeight = int(round(dpiScale * fontSize))
#lf.lfWeight = 150
# Use nonantialiased to remove the white edges around the text.
# lf.lfQuality = win32con.NONANTIALIASED_QUALITY
hf = win32gui.CreateFontIndirect(lf)
win32gui.SelectObject(hdc, hf)
rect = win32gui.GetClientRect(hWnd)
# http://msdn.microsoft.com/en-us/library/windows/desktop/dd162498(v=vs.85).aspx
win32gui.DrawText(
hdc,
'Text on the screen',
-1,
rect,
win32con.DT_CENTER | win32con.DT_NOCLIP | win32con.DT_SINGLELINE | win32con.DT_VCENTER
)
win32gui.EndPaint(hWnd, paintStruct)
return 0
elif message == win32con.WM_DESTROY:
print 'Closing the window.'
win32gui.PostQuitMessage(0)
return 0
else:
return win32gui.DefWindowProc(hWnd, message, wParam, lParam)
if __name__ == '__main__':
main()
这篇关于如何使用 Python 在没有窗口的情况下在屏幕上显示文本的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!