网站导航网学 原创论文 原创专题 网站设计 最新系统 原创论文 论文降重 发表论文 论文发表 UI设计定制 论文答辩PPT格式排版 期刊发表 论文专题
返回网学首页
网学原创论文
最新论文 推荐专题 热门论文 论文专题
当前位置: 网学 > 交易代码 > C语言代码 > 正文

仿QQ悬挂窗口的实现

论文降重修改服务、格式排版等 获取论文 论文降重及排版 论文发表 相关服务
下载源代码

上过QQ的朋友们都知道,当QQ窗口位于桌面的左边界、右边界或顶部的时候,QQ会自动隐藏起来;而一旦鼠标再次接触到上述边界的时候,QQ窗口又会自动展开。QQ的这种特效在一定程度上大大的节约了桌面资源,给使用者带来的方便。
QQ悬挂窗口主要特点就是结合窗口以及鼠标的位置,并通过鼠标事件来调整窗口的显示方式。其中,窗口以及鼠标的位置可以通过GetWindowRect和GetCursorPos这两个函数来获取,故如何获取鼠标事件成为QQ悬挂窗口实现的关键。
对于一个窗口来说,按鼠标事件的触发位置,鼠标事件可以分为三类:
1. 客户区鼠标消息:鼠标在窗口的客户区移动时产生的消息,此消息是标准的鼠标消息,MFC中通过WM_MOUSEMOVE这个事件解决了这个问题。
2. 非客户区鼠标消息:鼠标在非客户区以外(标题栏、框架等)移动时产生的消息,此消息是标准的鼠标消息,MFC中通过WM_NCMOUSEMOVE这个事件解决了这个问题。
3. 窗口以外的鼠标消息:鼠标不在本窗口移动时产生的消息,此消息不是标准的鼠标消息,在MFC中也找不到这样的事件。那该如何捕获这样的鼠标消息呢?
窗口以外的鼠标消息必然是发生在其他窗口上的,此鼠标消息是发往其他窗口的消息队列中,由其他窗口的消息队列所维护。
不过,我们可以通过设置全局鼠标钩子来监视鼠标的位置,并触发鼠标消息。如果将鼠标钩子设置在窗口内部设置的话,那此鼠标钩子仅能够监视到上述鼠标事件的前两类事件,而不能够监视到本窗口以外的鼠标消息,并不是真正的全局鼠标钩子。如果将鼠标钩子设置在DLL中,那么鼠标在整个屏幕上所发生的事件都会被这个鼠标过程所监察到,即可以捕获其他窗口的鼠标消息并将此鼠标消息发往本窗口的所属线程的消息队列中。在本窗口中,必须将本窗口的线程ID传到DLL中,使DLL能够将其他鼠标事件发到指定线程的消息队列中。具体实现如下:

//------------------------------------------------------------------------------------
// Function: SetHook - Creates mouse hook (Exported), called by CAppBarMngr
// Arguments: _id - Calling thread ID, used to send message to it
// _width - Width of window
// _left - True if window is left side docked, false if not
// Returns: False if it is already hooked
// True if hook has been created
//------------------------------------------------------------------------------------
BOOL SetHook(DWORD _id, int _width, BOOL _left)
{
if (s_ThreadID)
return FALSE; // Already hooked!

s_Width = _width;
s_Left = _left;
g_Hook = ::SetWindowsHookEx(WH_MOUSE, (HOOKPROC)MouseProc, g_Instance, 0);
s_ThreadID = _id;
return TRUE; // Hook has been created correctly
}
//-------------------------------------------------------------------------------------
// Function: MouseProc - Callback function for mouse hook
// Arguments: nCode - action code, according to MS documentation, must return
// inmediatly if less than 0
// wParam - not used
// lParam - not used
// Returns: result from next hook in chain
//-------------------------------------------------------------------------------------static LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam)
{
static LRESULT lResult; // Made static to accelerate processing
static POINT pt; // idem if (nCode<0 && g_Hook)
{
::CallNextHookEx(g_Hook, nCode, wParam, lParam); // Call next hook in chain
return 0;
}if (s_ThreadID)
{
// Obtain absolute screen coordinates
::GetCursorPos(&pt);
static POINT ptOld; //只有当鼠标发生移动时候发生鼠标事件,没有想到鼠标不移动也会产生此鼠标过程,
//真让我大吃一惊,必须得防止鼠标消息乱发。
if(ptOld.x!=pt.x && ptOld.y!=pt.y)
{
::PostThreadMessage(s_ThreadID, WM_USER+1000, 0, 0);
ptOld.x = pt.x;
ptOld.y = pt.y;
}
}
return ::CallNextHookEx(g_Hook, nCode, wParam, lParam); // Call next hook in chain
}
//-------------------------------------------------------------------------------------
// Function: UnSetHook - Removes hook from chain
// Arguments: none
// Returns: False if not hook pending to delete (no thread ID defined)
// True if hook has been removed. Also returns true if there is not hook
// handler, this can occur if Init failed when called in second instance
//-------------------------------------------------------------------------------------
BOOL UnSetHook()
{ if (!s_ThreadID) {
return FALSE; // There is no hook pending to close
} if (g_Hook) { // Check if hook handler is valid
::UnhookWindowsHookEx(g_Hook); // Unhook is done here
s_ThreadID = 0; // Remove thread id to avoid continue sending
g_Hook = NULL; // Remove hook handler to avoid to use it again
}return TRUE; // Hook has been removed
}

鼠标消息一旦发到本窗口线程的消息队列后,本窗口过程在鼠标消息未被翻译之前从消息队列中取出消息,并进行处理。故得重载PreTranslateMessage这个虚函数。逻辑判断过程如下:

BOOL CHookTestDlg::PreTranslateMessage(MSG* pMsg) 
{
// TODO: Add your specialized code here and/or call the base class
static int i=0;
int nSrcWidth = ::GetSystemMetrics(SM_CXSCREEN);
int nSrcHeight = ::GetSystemMetrics(SM_CYSCREEN);
switch(pMsg->message)
{
case WM_USER+1000:
{
POINT pt;
CRect rcWindow;
::GetCursorPos(&pt);
GetWindowRect(&rcWindow);

if(pt.x<1 && (pt.y>rcWindow.top && pt.y<rcWindow.bottom))
{
if(rcWindow.left<1 && rcWindow.Width()<1)
{
SliderWindow(LEFT, true);
}
else if(rcWindow.left<1 && rcWindow.Width()>99)
{
}
else if(rcWindow.left>1 && rcWindow.Width()>99)
{
}
else
{
}
}
else if(pt.y<rcWindow.top || pt.y>rcWindow.bottom)
{
if(rcWindow.left<1 && rcWindow.Width()<1)
{
}
else if(rcWindow.left<1 && rcWindow.Width()>99)
{
SliderWindow(LEFT, false);
}
else if(rcWindow.left>1 && rcWindow.Width()>99)
{
}
else
{
}
}
else if(pt.x>0 && pt.x<100)
{
if(rcWindow.left<1 && rcWindow.Width()<1 && (pt.y>rcWindow.top && pt.y<rcWindow.bottom))
{
}
else if(rcWindow.left<1 && rcWindow.Width()>99)
{
//SliderWindow(LEFT, true);
}
else if(rcWindow.left>1 && rcWindow.Width()>99)
{
}
else
{
}
}
else
{
if(rcWindow.left<1 && rcWindow.Width()<1)
{
}
else if(rcWindow.left<1 && rcWindow.Width()>99 && (pt.y>rcWindow.top && pt.y<rcWindow.bottom))
{
SliderWindow(LEFT, false);
}
else if(rcWindow.left>1 && rcWindow.Width()>99)
{
}
else
{
}
}
}
break;
default:
break;
}
return CDialog::PreTranslateMessage(pMsg);
}

void CHookTestDlg::SliderWindow(int nPos, bool bShow)
{
CRect rc;
GetWindowRect(rc);
int nSrcWidth = ::GetSystemMetrics(SM_CXSCREEN);
switch(nPos)
{
case LEFT:
if(bShow)
{
for(int i=0; i<=10; i++)
{
SetWindowPos(&CWnd::wndTopMost, 0, rc.top, i*10, rc.Height(), SWP_SHOWWINDOW);
Sleep(20);
}
}
else
{
for(int i=0; i<=10; i++)
{
SetWindowPos(&CWnd::wndTopMost, 0, rc.top, 100-10*i, rc.Height(), SWP_SHOWWINDOW);
Sleep(20);
}
}
break;
case RIGHT:
break;
case TOP:
break;
case BOTTOM:
break;
default:
break;
}
}

最后运行结果如下:

朋友们,以后若想捕获其他窗口的鼠标事件的时候可以采用这个方法,大家也可以明白MFC中的标准鼠标消息的底层是怎么实现的,大家是否有眼前一亮的感觉呢?最后提出几个问题:
1、 在安装完上述鼠标钩子后,MFC的标准鼠标消息WM_MOUSEMOVE、WM_LBUTTONDOWN等还有作用吗?
2、 通过MFC的ON_MESSAGE将WM_USER+1000这个与指定的处理过程相关联来处理鼠标消息(当然此时不需要重载PreTranslateMessage),这样做可以吗?如:ON_MESSAGE(WM_USER+1000, MouseProc)。
希望大家给我发邮件进行讨论,祝大家编程愉快!
QQ:181484408

  • 下一篇资讯: VC模仿超炫QQ界面的实现
  • 设为首页 | 加入收藏 | 网学首页 | 原创论文 | 计算机原创
    版权所有 网学网 [Myeducs.cn] 您电脑的分辨率是 像素
    Copyright 2008-2020 myeducs.Cn www.myeducs.Cn All Rights Reserved 湘ICP备09003080号 常年法律顾问:王律师