大家都见过以前Sogou歌词窗口的样子吧,感觉是歌词的字体直接贴在windows桌面上一样,但是还可以用鼠标控制,这个是怎么做成的呢?其实我也不知道^_^,估计大家会说不知道还在这里写个啥?首先我不是Sogou公司做这个的人,我当然不知道了。我今天要说的是模仿这种效果,因为要实现这种效果不止一种办法,也许Sogou歌词就是采用这个办法,也可能不是。好了,废话少说了,直接如题吧。
要实现这种效果,有一点一般是需要的,就是窗口透明的效果,所以关键之一就是如何实现windows窗口的透明。Windows API中有一个函数能实现这个效果:
BOOL SetLayeredWindowAttributes( HWND hwnd,
COLORREF crKey,
BYTE bAlpha,
DWORD dwFlags
);
hwnd:要设置透明的窗口句柄。
crKey:指定要实现透明的color key。
bAlpha:指定整个窗口的透明度。
dwFlags:透明标记,LWA_COLORKEY则指定crKey作为透明颜色,LWA_ALPHA则指定bAlpha作为整个窗口的透明色。
我们要实现像Sogou歌词窗口那样,显然是没有标题栏和边框,并且是最顶层窗口,所以我们创建窗口时要指定相应的属性。
CreateWindowEx(WS_EX_TOOLWINDOW|WS_EX_TOPMOST|WS_EX_LAYERED,// extended style
szClassName, // pointer toregistered class name
"SogouLike Win", // pointer towindow name
WS_POPUP, // window style
400, //horizontal position of window
200, // vertical positionof window
500, // windowwidth
240, // windowheight
HWND_DESKTOP, // handle to parent
NULL, // handleto menu, or child-window identifier
hInstance, // handle toapplication instance
NULL); // pointerto window-creation data
由于不需要菜单和边框,所以这里采用WS_POPUP风格,顶层窗口采用WS_EX_TOPMOST属性指定,要实现透明度,需要指定WS_EX_LAYERED属性,由于这个窗口应该是在所以的窗口之上,所以父窗口应该是桌面HWND_DESKTOP。
因为没有菜单,鼠标的拖放以及关闭都没有地方操作,故我们的程序中需要将窗口客户区的点击定向到标题区,并捕获鼠标按键,鼠标按下后移动时,我们相应的移动窗口,所以整个相当于将整个客户区变成标题部分,就可以拖动了。所有代码如下:
#include <windows.h>
charszClassName[] = "Windows App";
HINSTANCE ghApplication = NULL;
HWND ghMainWindow = NULL;
LRESULT CALLBACK WindowProc(HWND hwnd,UINT uMsg, WPARAM wParam, LPARAM lParam);
intAPIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
MSGmessages;
WNDCLASSEXwcex;
//注册窗口类
wcex.cbClsExtra = 0;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.cbWndExtra = 0;
wcex.hbrBackground= (HBRUSH)(COLOR_3DFACE);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hIcon = NULL;
wcex.hIconSm = NULL;
wcex.hInstance = hInstance;
wcex.lpfnWndProc = WindowProc;
wcex.lpszClassName= szClassName;
wcex.lpszMenuName = NULL;
wcex.style = CS_HREDRAW | CS_VREDRAW;
if (!RegisterClassEx(&wcex))
{
return 0;
}
ghApplication= hInstance;
//创建透明、顶层窗口
ghMainWindow= CreateWindowEx(WS_EX_TOOLWINDOW|WS_EX_TOPMOST|WS_EX_LAYERED, szClassName, "Win32App", WS_POPUP,
400, 200, 500, 240,
HWND_DESKTOP,NULL, hInstance, NULL);
HINSTANCEhModule = LoadLibrary("User32.DLL");
typedef BOOL (WINAPI *MYFUNC)(HWND, COLORREF, BYTE,DWORD);
MYFUNCpfn = (MYFUNC)GetProcAddress(hModule, "SetLayeredWindowAttributes");
/* 设置窗口透明 */
pfn(ghMainWindow,RGB(0xFF,0xFF,0xFF), 0xFF, LWA_COLORKEY|LWA_ALPHA); // crkey与字体的颜色一样
FreeLibrary(hModule);
ShowWindow(ghMainWindow,nCmdShow); /* Shows the window */
UpdateWindow(ghMainWindow); /* SendsWM_PAINT message */
while(GetMessage(&messages, NULL, 0, 0))
{
if (!IsDialogMessage(ghMainWindow, &messages))
{
TranslateMessage(&messages);
DispatchMessage(&messages);
}
}
return (int)messages.wParam;
}
// 下面是窗口过程的实现,在其中处理鼠标捕获,点击转发,实现拖放的过程。
LRESULT CALLBACK WindowProc(HWND hwnd,UINT uMsg, WPARAM wParam, LPARAM lParam)
{
HGDIOBJhDefaultFont = NULL;
HFONThFont = NULL;
switch(uMsg)
{
case WM_NCRBUTTONUP: //处理右击菜单时退出
PostQuitMessage(0);
break;
caseWM_NCHITTEST:
return (LRESULT)HTCAPTION ;//始终返回非客户区的标题区域
case WM_LBUTTONDOWN:
SetCapture(hwnd);
break;
case WM_LBUTTONUP:
ReleaseCapture();
break;
case WM_MOUSEMOVE:
{
POINTpoint;
GetCursorPos(&point);
MoveWindow(hwnd,point.x,point.y,32,32,TRUE);
}
break;
case WM_PAINT:
{
PAINTSTRUCTpt;
HDChDC = BeginPaint(hwnd, &pt);
HFONThFont = CreateFont(96, //所创建字体的字符高度
0,//字体的字符平均宽度
200,//字符输出方向与水平向右的方向所成角度,以.1度为单位
0, //字符与基线的角度,以.1度为单位
FW_BOLD,//字符颜色的深浅度
TRUE,//斜体属性标志(FALSE:正常字体,TRUE:斜体)
FALSE,//下划线属性标志(FALSE:无下划线,TRUE:有下划线)
FALSE,//删除线属性标志(FALSE:无删除线,TRUE:有删除线)
ANSI_CHARSET,//字符集标识:ANSI字符集,:系统缺省字符集
OUT_DEFAULT_PRECIS,//输出精度
CLIP_DEFAULT_PRECIS,//剪切精度
DEFAULT_QUALITY,//输出品质
DEFAULT_PITCH|FF_SWISS,//字符间距
"Arial");//现有系统TrueType字体名称
HFONThOldFont = (HFONT)SelectObject(hDC, hFont);
SetBkMode(hDC,TRANSPARENT);
SetTextColor(hDC,RGB(0xFF, 0x00, 0x00)); // red font
TextOut(hDC,0, 50, "Hello", 5);
SetTextColor(hDC,RGB(0x00, 0xFF, 0x00)); // gree font
TextOut(hDC,100, 120, "Hello", 5);
DeleteObject(hFont);
EndPaint(hwnd,&pt);
}
break;
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
return 0L;
}
本程序执行效果如下:
本方法实现的类似Sogou歌词显示窗口的关键有两处:
一是需要实现透明窗口效果,用WS_EX_LAYERED属性和SetLayeredWindowAttributes函数实现,这样就只有窗口上的字出现。
二是将窗口设为zorder的顶层,才会在桌面不被其他窗口盖住,因此本窗口的父窗口是HWND_DESKTOP,也可以通过GetDesktopWindow()函数来获取。
三是创建窗口时要去掉标题栏和边框,这个通过采用WS_POPUP属性和WS_EX_TOOLWINDOW扩展属性来实现。