imuncle.github.io icon indicating copy to clipboard operation
imuncle.github.io copied to clipboard

创建置顶的窗口程序

Open imuncle opened this issue 5 years ago • 0 comments

在一些特定的应用场景中,需要把一个窗口置顶,置顶的窗口可以在其他窗口激活的情况下依然保持在最上面。

先说几个概念: 窗口:Windows是以窗口作为主要交互界面的系统,我们把那个能拖来拖去,一般带有最大化最小化关闭按钮的大方框叫做窗口,但是其实窗口的定义可以更广泛一点,一个按钮是窗口,一个文本框也是窗口。

父窗口:如果一个按钮(Button)被放在一个Panel(面板)上, 那按钮的父窗口就是Pane, 同样Panel的父窗口是Form,Form就是我们平时说的窗口了。

顶级窗口:Form的父窗口是什么? 有人说是桌面(Desktop),也有人说没有父窗口,但是通过实验得知,它没有父窗口,没有父窗口的窗口我们叫做顶级窗口,我们平时说的窗口,都是指的顶级窗口。

句柄:Handle,句柄是一种特殊的指针,指向的是内存里的对象, 通俗得讲它就是一个窗口(事实上远不止窗口)的把手,你有了这个句柄就能开窗关窗,改变窗口的状态。

只要我们获得顶级窗口的句柄,改变它的状态,把"不置顶"改为"置顶",就达成目的了。

实现逻辑

只需要不停地找窗口的父窗口, 直到某个窗口的父窗口的句柄为0(不存在),那就找到了该窗口的顶级窗口。

有函数GetParent(),能取得窗口的父窗口。

取得顶级窗口的句柄后, 有函数SetWindowPos, 指定参数HWND, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_DRAWFRAME | SWP_NOSIZE 就能置顶一个窗口。

所以其实核心代码只有下面几句话:

// 获取顶级窗口句柄
HWND GetHwnd(HWND hwd)
{
	while (GetParent(hwd))
        hwd = GetParent(hwd);
    return hwd;
}

// 置顶窗口
SetWindowPos(GetHwnd(hwnd),HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_DRAWFRAME | SWP_NOSIZE);

置顶只需要一次,所以我在创建窗口的时候调用一下该置顶函数即可。

实现源码

#include <windows.h>
 
#include <string.h>
 
HWND GetHwnd(HWND hwd)
{
	while (GetParent(hwd))
        hwd = GetParent(hwd);
    return hwd;
}

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    PSTR szCmdLine, int iCmdShow)
{
     static TCHAR szAppName[] = TEXT ("TopDemo") ;
     HWND         hwnd ;
     MSG          msg ;
     WNDCLASS     wndclass ;

     wndclass.style         = CS_HREDRAW | CS_VREDRAW ;
     wndclass.lpfnWndProc   = WndProc ;
     wndclass.cbClsExtra    = 0 ;
     wndclass.cbWndExtra    = 0 ;
     wndclass.hInstance     = hInstance ;
     wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;
     wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
     wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
     wndclass.lpszMenuName  = NULL ;
     wndclass.lpszClassName = szAppName ;

     if (!RegisterClass (&wndclass))
     {
          MessageBox (NULL, TEXT ("This program requires Windows NT!"), 
                      szAppName, MB_ICONERROR) ;
          return 0 ;
     }
     
     hwnd = CreateWindow (szAppName,                  // window class name
                          TEXT ("Top Demo"), 		  // window caption
                          WS_OVERLAPPEDWINDOW,        // window style
                          CW_USEDEFAULT,              // initial x position
                          CW_USEDEFAULT,              // initial y position
                          400,              		  // initial x size
                          100,              		  // initial y size
                          NULL,                       // parent window handle
                          NULL,                       // window menu handle
                          hInstance,                  // program instance handle
                          NULL) ;                     // creation parameters
     
     ShowWindow (hwnd, iCmdShow) ;
     UpdateWindow (hwnd) ;
     
     while (GetMessage (&msg, NULL, 0, 0))
     {
          TranslateMessage (&msg) ;
          DispatchMessage (&msg) ;
     }
     return msg.wParam ;
}

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
     HDC         hdc ;
     PAINTSTRUCT ps ;
     RECT        rect ;
     
     switch (message)
     {
     case WM_CREATE:
		  SetWindowPos(GetHwnd(hwnd),HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_DRAWFRAME | SWP_NOSIZE);
          return 0 ;
          
     case WM_PAINT:
          hdc = BeginPaint (hwnd, &ps) ;
          
          GetClientRect (hwnd, &rect) ;
          
          DrawText (hdc, TEXT ("The top window"), -1, &rect,
                    DT_SINGLELINE | DT_CENTER | DT_VCENTER) ;
          
          EndPaint (hwnd, &ps) ;
          return 0 ;
          
     case WM_DESTROY:
          PostQuitMessage (0) ;
          return 0 ;
     }
     return DefWindowProc (hwnd, message, wParam, lParam) ;
}

实现效果

image

图中可以看到,Notepad++处于激活状态,但Top Demo窗口依然在顶层。

参考

imuncle avatar Apr 24 '20 03:04 imuncle