1.需求
(1)实现一个无边框的窗口,不需要窗口能够拖动,不需要放大缩小按钮,但是需要右上角的关闭按钮;
(2)静态文本框背景透明,显示的文字能够频繁刷新并且不能够有重影;
2.实现方式
2.1无边框窗口
实现去除边框是在窗口过程函数的WM_SIZE消息处理时实现的。
case WM_SIZE: { LONG_PTR Style = ::GetWindowLongPtr(hWnd, GWL_STYLE); Style = Style & ~WS_CAPTION &~WS_SYSMENU &~WS_SIZEBOX; ::SetWindowLongPtr(hWnd, GWL_STYLE, Style); return 0; }如果在创建窗口时直接设置去除这些属性,会导致窗口顶部的标题栏无法彻底去除,虽然不显示左上角的图标和右上角的放大缩小按钮,但是标题栏仍然存在。
2.2关闭按钮
“关闭”按钮没有采用windows默认提供的,自己创建了一个按钮,加载了带"x"的icon实现。之前尝试屏蔽“放大”和“缩小”按钮来实现,但是只能使之失效无法消失不见,所以选择自己创建按钮。
这一功能的实现有两个重要步骤,一是加载icon图片;二是对关闭消息的响应。
(1)加载icon图片
HANDLE close_icon = LoadImage(NULL, L"close_button.ico", IMAGE_ICON, 32, 32, LR_LOADFROMFILE); if (close_icon == NULL) { int error_code = GetLastError(); return; } SendMessage(close_button_, BM_SETIMAGE, IMAGE_ICON, (LPARAM)close_icon);
在调试过程中,出现1813的错误码,问题的原因是将LoadImage的最后一个参数设置为LR_DEFAULTCOLOR,改为LR_LOADFROMFILE即可正常加载。
(2)响应关闭消息
在父窗口的窗口过程函数中,增加对如下命令的响应。
case WM_COMMAND: if ((HWND)lParam == close_hwnd_) { ::SendMessage(parent_hwnd_, WM_CLOSE, 0, 0); } return 0;
2.3静态文本框背景透明
实现这个功能需要在两处添加代码:一是静态文本框创建完成的时候,需要增加一个透明的属性;二是在窗口的过程函数中增加对WM_CTLCOLORSTATIC消息的处理。
(1)增加透明属性
LONG nRet = ::GetWindowLong(progress_handle_, GWL_EXSTYLE); nRet = nRet | WS_EX_TRANSPARENT; ::SetWindowLong(progress_handle_, GWL_EXSTYLE, nRet);
(2)处理WM_CTLCOLORSTATIC消息
在父窗口的窗口过程函数中,增加对如下命令的响应。
case WM_CTLCOLORSTATIC: hDC = (HDC)wParam; SetTextColor(hDC, RGB(0, 0, 0)); SetBkMode(hDC, TRANSPARENT); //break; return (LRESULT)GetStockObject(NULL_BRUSH);在这里如果返回一个非空画刷,也就是这里break,而不是后面的return空画刷,无法实现静态文本控件透明,至少我的实践效果是这样。
2.4文字刷新重影
在静态文本框背景透明的情况下,如果刷新静态文本框的文本,会出现重影现象,以下代码在我的机器上可以解决重影问题。
void ProgressControl::OnStartButtonPressed() const { ::SetWindowPos(progress_handle_, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); ::SendMessage(parent_handle_, WM_CTLCOLORSTATIC, 0, 0); SetWindowText(progress_handle_, L"1%"); ::ShowWindow(progress_handle_, 1); for (int i = 1; i < 97;) { i += rand() % 4; wchar_t buffer[10]; _itow_s(i, buffer, 10, 10); std::wstring progress(buffer); progress += L"%"; SetWindowText(progress_handle_, progress.c_str()); ::ShowWindow(progress_handle_, 1); ::InvalidateRect(parent_handle_, NULL, TRUE); ::UpdateWindow(parent_handle_); Sleep(100); } }
注意:InvalidateRect和UpdateWindow中给出的句柄一定是父窗口的,而不是静态文本控件的,否则会出现文本刷新显示时的重影问题。