Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

创建置顶的窗口程序 #110

Open
imuncle opened this issue Apr 24, 2020 · 0 comments
Open

创建置顶的窗口程序 #110

imuncle opened this issue Apr 24, 2020 · 0 comments
Labels
Win32 Win32编程学习

Comments

@imuncle
Copy link
Owner

imuncle commented Apr 24, 2020

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

先说几个概念:
窗口: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 imuncle added the Win32 Win32编程学习 label Apr 24, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Win32 Win32编程学习
Projects
None yet
Development

No branches or pull requests

1 participant