Windows API:以屏幕显示方式写入屏幕
我正在编写一个(非常)小的应用程序,它一开始只执行一些小的操作,应该在屏幕上写一条类似于屏幕显示的消息:大的字母,没有任何窗口,最重要的是,在一段时间内可见,然后消失 如果可能的话,我不想为它创建一个窗口 正确的方法是什么Windows API:以屏幕显示方式写入屏幕,windows,winapi,screen,Windows,Winapi,Screen,我正在编写一个(非常)小的应用程序,它一开始只执行一些小的操作,应该在屏幕上写一条类似于屏幕显示的消息:大的字母,没有任何窗口,最重要的是,在一段时间内可见,然后消失 如果可能的话,我不想为它创建一个窗口 正确的方法是什么 (我希望不需要DirectX、direct graphics access等特殊工具包)如评论中所述,您可以直接绘制到屏幕上。提供返回适当的设备上下文: hWnd[in] 要检索其DC的窗口的句柄如果此值为空,则GetDC检索整个屏幕的DC。 直接渲染到屏幕会产生至少两个需要
(我希望不需要DirectX、direct graphics access等特殊工具包)如评论中所述,您可以直接绘制到屏幕上。提供返回适当的设备上下文: hWnd[in] 要检索其DC的窗口的句柄如果此值为空,则GetDC检索整个屏幕的DC。 直接渲染到屏幕会产生至少两个需要解决的问题:
WS\u弹出窗口| WS\u可见
要使窗口显示在所有其他窗口之前,需要将其标记为最顶部(使用WS\u EX\u topmest
)。请注意,这会将窗口放置在Z顺序中所有其他非最上面的窗口之上。你仍然需要与其他最顶级的窗口进行斗争(这是一场你无法赢得的军备竞赛)
要实现透明,窗口必须具有WS_EX_LAYERED
扩展窗口样式,才能创建透明窗口。然后启用Alpha透明度。要保持窗口背景完全透明,而不考虑窗口的alpha透明度,还需要启用颜色关键帧。一种简单的方法是设置to的hbrBackground
成员,并将RGB(0,0,0)
指定为调用SetLayeredWindowAttributes
中的crKey
参数。
概念证明(为简洁起见,省略了错误检查): 这是实例化窗口并调整其属性所需的所有设置代码。启用Alpha透明度以准备淡出效果,而颜色关键帧遮罩窗口中未渲染到的区域
HWND hWnd = ::CreateWindowExW( WS_EX_TOPMOST | WS_EX_LAYERED,
k_WndClassName,
L"Overlay Window",
WS_POPUP | WS_VISIBLE,
CW_USEDEFAULT, CW_USEDEFAULT,
800, 600,
NULL, NULL,
hInstance,
NULL );
// Make window semi-transparent, and mask out background color
::SetLayeredWindowAttributes( hWnd, RGB( 0, 0, 0 ), 128, LWA_ALPHA | LWA_COLORKEY );
wWinMain的其余部分是样板windows应用程序代码
::ShowWindow( hWnd, nCmdShow );
::UpdateWindow( hWnd );
// Main message loop:
MSG msg = { 0 };
while ( ::GetMessageW( &msg, NULL, 0, 0 ) > 0 )
{
::TranslateMessage( &msg );
::DispatchMessageW( &msg );
}
return (int)msg.wParam;
}
窗口过程执行简单的渲染。为了演示alpha和关键点颜色的透明度,代码渲染了一个白色椭圆,客户区域作为边界矩形。此外,还处理了,以提供使用鼠标或其他定点设备在屏幕上拖动窗口的简单方法。请注意,对于所有完全透明的区域,鼠标输入都会传递到下面的窗口
const wchar_t k_WndClassName[] = L"OverlayWindowClass";
// Register window class
WNDCLASSEXW wcex = { 0 };
wcex.cbSize = sizeof( wcex );
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.hInstance = hInstance;
wcex.hCursor = ::LoadCursorW( NULL, IDC_ARROW );
wcex.hbrBackground = (HBRUSH)::GetStockObject( BLACK_BRUSH );
wcex.lpszClassName = k_WndClassName;
::RegisterClassExW( &wcex );
LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
switch ( message )
{
case WM_PAINT:
{
PAINTSTRUCT ps = { 0 };
HDC hDC = ::BeginPaint( hWnd, &ps );
RECT rc = { 0 };
::GetClientRect( hWnd, &rc );
HBRUSH hbrOld = (HBRUSH)::SelectObject( hDC,
::GetStockObject( WHITE_BRUSH ) );
::Ellipse( hDC, rc.left, rc.top, rc.right, rc.bottom );
::SelectObject( hDC, hbrOld );
::EndPaint( hWnd, &ps );
}
return 0;
case WM_NCHITTEST:
return HTCAPTION;
case WM_DESTROY:
::PostQuitMessage( 0 );
return 0;
default:
break;
}
return ::DefWindowProc( hWnd, message, wParam, lParam );
}
可选的
WM_PAINT
处理程序,用于输出文本。使用不同于键颜色的文本颜色非常重要。如果要使用黑色文本,则必须使用不同的键颜色
case WM_PAINT:
{
PAINTSTRUCT ps = { 0 };
HDC hDC = ::BeginPaint( hWnd, &ps );
RECT rc = { 0 };
::GetClientRect( hWnd, &rc );
::SetTextColor( hDC, RGB( 255, 255, 255 ) );
::SetBkMode( hDC, TRANSPARENT );
::DrawTextExW( hDC, L"Hello, World!", -1, &rc,
DT_SINGLELINE | DT_CENTER | DT_VCENTER, NULL );
::EndPaint( hWnd, &ps );
}
return 0;
创建一个窗口是正常的方法。窗口可以是透明的,不需要有一个可见的框架等,如果这是让你推迟使用的原因。一个透明的顶级窗口是最好的,但是如果你绝对需要直接在屏幕上写,你可以使用
GetDC(0)
来获取屏幕的HDC
画布句柄,然后你可以根据需要画出来。谢谢。我想我会选择窗户的。一般来说,这真的很棒。但是,当我使用DrawText
显示文本时,背景始终为白色,尽管窗口本身是透明的。在DrawText
之前使用SetBkMode(hDC,透明)
时,不会显示任何内容。有解决办法吗?@divB:我想你是用关键颜色(黑色)渲染文本的。关键颜色将替换为窗口下方的任何颜色。文本基本上是完全透明的。我更新了答案,改为包含代码呈现文本。@IInspectable,如果不设置“颜色键控”,是否可以达到相同的效果?如果我想使用所有颜色(因此我不能使用任何颜色作为“透明颜色”),该怎么办?当我在绘图时可以指定alpha通道值时,是否可以对其进行配置(这样我可以绘制所需的形状,然后用带有alpha chnanel的“画笔”填充窗口的其余部分?或者指定默认情况下窗口由透明颜色填充,然后在其顶部绘制形状?)
case WM_PAINT:
{
PAINTSTRUCT ps = { 0 };
HDC hDC = ::BeginPaint( hWnd, &ps );
RECT rc = { 0 };
::GetClientRect( hWnd, &rc );
::SetTextColor( hDC, RGB( 255, 255, 255 ) );
::SetBkMode( hDC, TRANSPARENT );
::DrawTextExW( hDC, L"Hello, World!", -1, &rc,
DT_SINGLELINE | DT_CENTER | DT_VCENTER, NULL );
::EndPaint( hWnd, &ps );
}
return 0;