如何在Win32 API中拖动透明窗口而不留下边缘痕迹?

时间:2014-08-19 17:02:16

标签: winapi visual-c++

我正在尝试使用Win32 API创建一个透明窗口,该窗口可以在屏幕上拖动,窗口的背景将保持透明并显示其背后的窗口。

我通过执行以下操作来执行此操作:

ATOM MyRegisterClass(HINSTANCE hInstance){  
WNDCLASSEX wcex;

wcex.cbSize = sizeof(WNDCLASSEX);

wcex.style          = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc    = WndProc;
wcex.cbClsExtra     = 0;
wcex.cbWndExtra     = 0;
wcex.hInstance      = hInstance;
wcex.hIcon          = NULL;
wcex.hCursor        = NULL;
wcex.hbrBackground  = NULL;
wcex.lpszMenuName   = NULL;
wcex.lpszClassName  = szWindowClass;
wcex.hIconSm        = NULL;

return RegisterClassEx(&wcex);}

wcex.hbrBackground = NULL; 行负责在初始化时使窗口透明。

在以下位置创建窗口:

BOOL InitInstance(HINSTANCE hInstance, int nCmdShow){
HWND hWnd;

hInst = hInstance; // Store instance handle in our global variable

hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

if (!hWnd)
{
   return FALSE;
}

ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);

return TRUE;}

窗口在拖动时保持透明的方式是:

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;

switch (message)
{
case WM_PAINT:
    hdc = BeginPaint(hWnd, &ps);
    // TODO: Add any drawing code here...
    EndPaint(hWnd, &ps);
    break;
case WM_DESTROY:
    PostQuitMessage(0);
    break;
case WM_MOVING:
    InvalidateRect(hWnd, NULL, TRUE); 
    break;
default:
    return = DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;}

其中: InvalidateRect(hWnd,NULL,TRUE); line会导致在移动事件时重绘窗口。

问题是窗口的背景不会在不是" new"的区域中重新渲染。

单词示例,

假设我打开一个应用程序(word,chrome等 - 我们称之为WindowB),而不是我运行我的应用程序打开覆盖WindowB的WindowA,但我可以在后台看到WindowB的内容(因为WindowA是透明窗口) )。如果我在屏幕上拖动WindowA,我仍然会在后台看到WindowB,这很棒。

如果我最小化WindowB,我仍然会看到与WindowA区域相交的WindowB部分(这里没问题,因为我没有重绘WindowA)。

如果我开始拖动WindowA,我认为WindowA中显示的WindowB部分将消失,我将看到当前桌面中最顶层的窗口是WindowA的背景,因为我调用 InvalidateRect(hWnd,NULL,TRUE); 移动事件。

实际发生的是我仍然在所有不是"新区域"的区域中看到WindowB。 - 按照新区域,我指的是WindowA移动到的屏幕中的区域,并且在移动之前不是WindowA区域的一部分。

似乎调用 InvalidateRect(hWnd,NULL,TRUE); 是不够的,因为它只渲染"新区域"。

可以在以下链接中找到说明问题的快照: http://imgur.com/gallery/2uVX4yj/new

我非常感谢在此问题上给予的任何帮助。

我的应用程序的主要功能是Visual Studio 2010为Win32应用程序项目创建的默认函数:

int APIENTRY _tWinMain(HINSTANCE hInstance,
                 HINSTANCE hPrevInstance,
                 LPTSTR    lpCmdLine,
                 int       nCmdShow){
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);

// TODO: Place code here.
MSG msg;
HACCEL hAccelTable;

// Initialize global strings
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_TEST2, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);

// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
    return FALSE;
}

hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_TEST2));

// Main message loop:
while (GetMessage(&msg, NULL, 0, 0))
{
    if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
}

return (int) msg.wParam;}

0 个答案:

没有答案