Win32 试验网上流传的 "窗口居中" 方案,到底哪种现在还有效

举报
福州司马懿 发表于 2022/11/18 17:34:53 2022/11/18
【摘要】 方案一:DS_CENTER(行不通)原理:通过在注册类的时候,将起风格属性设置为居中,来使窗体居中实验结果:失败 修改WNDCLASSEXW的style查了很多种方案后,有人说最简单的方法,是将WNDCLASSEXW的风格添加上DS_CENTER,就能实现居中,修改后的代码如下。经过测试发现,依旧无法居中ATOM MyRegisterClass(HINSTANCE hInstance){ ...

方案一:DS_CENTER(行不通)

原理:通过在注册类的时候,将起风格属性设置为居中,来使窗体居中
实验结果:失败

修改WNDCLASSEXWstyle

查了很多种方案后,有人说最简单的方法,是将WNDCLASSEXW的风格添加上DS_CENTER,就能实现居中,修改后的代码如下。经过测试发现,依旧无法居中

ATOM MyRegisterClass(HINSTANCE hInstance)
{
    WNDCLASSEXW wcex;

    wcex.cbSize = sizeof(WNDCLASSEX);
	wcex.style = CS_HREDRAW | CS_VREDRAW;
    wcex.style = CS_HREDRAW | CS_VREDRAW | DS_CENTER;
    wcex.lpfnWndProc    = WndProc;
    wcex.cbClsExtra     = 0;
    wcex.cbWndExtra     = 0;
    wcex.hInstance      = hInstance;
    wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_TEST4));
    wcex.hCursor        = LoadCursor(nullptr, IDC_ARROW);
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName   = MAKEINTRESOURCEW(IDC_TEST4);
    wcex.lpszClassName  = szWindowClass;
    wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

    return RegisterClassExW(&wcex);
}

修改CreateWindowxy

CreateWindow该函数创建一个重叠式窗口、弹出式窗口或子窗口。它指定窗口类,窗口标题,窗口风格,以及窗口的初始位置及大小(可选的)。函数也指该窗口的父窗口或所属窗口(如果存在的话),及窗口的菜单。

若要使用除 CreateWindow 函数支持的风格外的扩展风格,则使用 CreateWindowEx 函数代替 CreateWindow 函数。

CreateWindow的函数原型为

HWND CreateWindow(
  LPCTSTR lpClassName,
  LPCTSTR lpWindowName,
  DWORD dwStyle,
  int x,
  int y,
  int nWidth,
  int nHeight,
  HWND hWndParent,
  HMENU hMenu,
  HANDLE hlnstance,
  LPVOID lpParam
);

即使在创建窗口的函数 InitInstance 中,把 CreateWindowW 函数的 xy都改成CW_USEDEFAULT,依旧无法实现居中

BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   hInst = hInstance; // 将实例句柄存储在全局变量中

   HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, nullptr, nullptr, hInstance, nullptr);

   if (!hWnd)
   {
      return FALSE;
   }

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

   return TRUE;
}

方案二:GetSystemMetrics(可行)

原理:先获取屏幕大小,然后根据窗口大小进行计算,求出居中的x和y值
实验结果:窗口成功居中

屏幕整体尺寸,有以下三种方法

HDC hdc;
int cx, cy;

hdc = GetDC(NULL);
cx = GetDeviceCaps(hdc, DESKTOPHORZRES);
cy = GetDeviceCaps(hdc, DESKTOPVERTRES);
ReleaseDC(NULL, hdc);
//或
hdc = GetDC(NULL);
cx = GetDeviceCaps(hdc, HORZRES);
cy = GetDeviceCaps(hdc, VERTRES);
ReleaseDC(NULL, hdc);
//或
cx = GetSystemMetrics(SM_CXSCREEN);
cy = GetSystemMetrics(SM_CYSCREEN);

获取不包含任务栏的屏幕尺寸

int cx, cy;
cx = GetSystemMetrics(SM_CXFULLSCREEN);
cy = GetSystemMetrics(SM_CYFULLSCREEN);

修改InitInstance函数,居中窗口的坐标值如下

  • x坐标为x = (屏幕宽度 - 窗口宽度) / 2
  • y坐标为y = (屏幕高度 - 窗口高度) / 2
//
//   函数: InitInstance(HINSTANCE, int)
//
//   目标: 保存实例句柄并创建主窗口
//
//   注释:
//
//        在此函数中,我们在全局变量中保存实例句柄并
//        创建和显示主程序窗口。
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   hInst = hInstance; // 将实例句柄存储在全局变量中

   int cx = GetSystemMetrics(SM_CXSCREEN);
   int cy = GetSystemMetrics(SM_CYSCREEN);

   int width = 500;
   int height = 500;

   HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
       (cx - width) / 2, (cy - height) / 2, width, height, nullptr, nullptr, hInstance, nullptr);

   if (!hWnd)
   {
      return FALSE;
   }

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

   return TRUE;
}

实验结果:窗口成功居中

方案二:SetWindowPos(可行)

原理:在窗体创建完成后,根据屏幕大小和窗口位置进行调整,让窗口居中
实验结果:窗口成功居中

在注册窗口类的时候,会将事件绑定到WNDCLASSEXW结构体的lpfnWndProc属性上。这是一个函数指针,以后凡是有消息,都会发送给该函数

//
//  函数: MyRegisterClass()
//
//  目标: 注册窗口类。
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
    WNDCLASSEXW 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          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_TEST4));
    wcex.hCursor        = LoadCursor(nullptr, IDC_ARROW);
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName   = MAKEINTRESOURCEW(IDC_TEST4);
    wcex.lpszClassName  = szWindowClass;
    wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

    return RegisterClassExW(&wcex);
}

然后修改接收消息的WndProc函数,在收到窗口创建完毕的消息后,根据屏幕大小,计算居中所需的窗口位置即可。通过SetWindowPos函数,设置窗口位置

//
//  函数: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  目标: 处理主窗口的消息。
//
//  WM_COMMAND  - 处理应用程序菜单
//  WM_PAINT    - 绘制主窗口
//  WM_DESTROY  - 发送退出消息并返回
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_CREATE:
        int scrWidth, scrHeight;
        RECT rect;
        //获得屏幕尺寸
        scrWidth = GetSystemMetrics(SM_CXSCREEN);
        scrHeight = GetSystemMetrics(SM_CYSCREEN);
        //取得窗口尺寸
        GetWindowRect(hWnd, &rect);
        //重新设置rect里的值
        rect.left = (scrWidth - rect.right) / 2;
        rect.top = (scrHeight - rect.bottom) / 2;
        //移动窗口到指定的位置
        SetWindowPos(hWnd, HWND_TOP, rect.left, rect.top, rect.right, rect.bottom, SWP_SHOWWINDOW);
        break;
    case WM_PAINT:
        {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hWnd, &ps);
            // TODO: 在此处添加使用 hdc 的任何绘图代码...
            EndPaint(hWnd, &ps);
        }
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。