超强仿QQ自动伸缩窗口
2007-09-10 21:34:48 来源:WEB开发网收缩模式和位置决定后,剩下的工作就由最后两个核心函数完成了:实现收缩的DoHide(),实现伸展的DoShow()。在这两个过程中m_hsFinished,m_hiding 这两个变量起到很重要的控制作用。由于伸缩过程没完成时,hsFinished始终为FALSE,所以Timer 2 不会关闭,于是在OnTimer中会重复调用这两个函数之一,在这两个函数体内,窗口位置有规律地递减或递增就可以达到QQ的“抽屉”效果了,有趣的是即使伸缩过程还没完成,你也可以在这个过程中改变m_hiding这个值来决定他是伸还是缩,正如QQ一样。你可以把Timer 2 的事件间隔调大一点,然后在窗口伸缩时,鼠标来回地进出窗口就会很容易看到这样有趣的效果(还没缩进去又被拉了出来,或者还没拉出来又缩进去了)。
void CQQHideWndDlg::DoHide()
{
if(m_hideMode == HM_NONE)
return;
CRect tRect;
GetWindowRect(tRect);
INT height = tRect.Height();
INT width = tRect.Width();
INT steps = 0;
switch(m_hideMode)
{
case HM_TOP:
steps = height/HS_STEPS;
tRect.bottom -= steps;
if(tRect.bottom <= m_edgeWidth)
{ //你可以把下面一句替换上面的 ...+=|-=steps 达到取消抽屉效果
//更好的办法是添加个BOOL值来控制,其他case同样.
tRect.bottom = m_edgeWidth;
m_hsFinished = TRUE; //完成隐藏过程
}
tRect.top = tRect.bottom - height;
break;
case HM_BOTTOM:
steps = height/HS_STEPS;
tRect.top += steps;
if(tRect.top >= (GetSystemMetrics(SM_CYSCREEN) - m_edgeWidth))
{
tRect.top = GetSystemMetrics(SM_CYSCREEN) - m_edgeWidth;
m_hsFinished = TRUE;
}
tRect.bottom = tRect.top + height;
break;
case HM_LEFT:
steps = width/HS_STEPS;
tRect.right -= steps;
if(tRect.right <= m_edgeWidth)
{
tRect.right = m_edgeWidth;
m_hsFinished = TRUE;
}
tRect.left = tRect.right - width;
tRect.top = -m_edgeHeight;
tRect.bottom = GetSystemMetrics(SM_CYSCREEN) - m_taskBarHeight;
break;
case HM_RIGHT:
steps = width/HS_STEPS;
tRect.left += steps;
if(tRect.left >= (GetSystemMetrics(SM_CXSCREEN) - m_edgeWidth))
{
tRect.left = GetSystemMetrics(SM_CXSCREEN) - m_edgeWidth;
m_hsFinished = TRUE;
}
tRect.right = tRect.left + width;
tRect.top = -m_edgeHeight;
tRect.bottom = GetSystemMetrics(SM_CYSCREEN) - m_taskBarHeight;
break;
default:
break;
}
SetWindowPos(&wndTopMost,tRect);
}
void CQQHideWndDlg::DoShow()
{
if(m_hideMode == HM_NONE)
return;
CRect tRect;
GetWindowRect(tRect);
INT height = tRect.Height();
INT width = tRect.Width();
INT steps = 0;
switch(m_hideMode)
{
case HM_TOP:
steps = height/HS_STEPS;
tRect.top += steps;
if(tRect.top >= -m_edgeHeight)
{ //你可以把下面一句替换上面的 ...+=|-=steps 达到取消抽屉效果
//更好的办法是添加个BOOL值来控制,其他case同样.
tRect.top = -m_edgeHeight;
m_hsFinished = TRUE; //完成显示过程
}
tRect.bottom = tRect.top + height;
break;
case HM_BOTTOM:
steps = height/HS_STEPS;
tRect.top -= steps;
if(tRect.top <= (GetSystemMetrics(SM_CYSCREEN) - height))
{
tRect.top = GetSystemMetrics(SM_CYSCREEN) - height;
m_hsFinished = TRUE;
}
tRect.bottom = tRect.top + height;
break;
case HM_LEFT:
steps = width/HS_STEPS;
tRect.right += steps;
if(tRect.right >= width)
{
tRect.right = width;
m_hsFinished = TRUE;
}
tRect.left = tRect.right - width;
tRect.top = -m_edgeHeight;
tRect.bottom = GetSystemMetrics(SM_CYSCREEN) - m_taskBarHeight;
break;
case HM_RIGHT:
steps = width/HS_STEPS;
tRect.left -= steps;
if(tRect.left <= (GetSystemMetrics(SM_CXSCREEN) - width))
{
tRect.left = GetSystemMetrics(SM_CXSCREEN) - width;
m_hsFinished = TRUE;
}
tRect.right = tRect.left + width;
tRect.top = -m_edgeHeight;
tRect.bottom = GetSystemMetrics(SM_CYSCREEN) - m_taskBarHeight;
break;
default:
break;
}
SetWindowPos(&wndTopMost,tRect);
}
BOOL CQQHideWndDlg::SetWindowPos(const CWnd* pWndInsertAfter, LPCRECT pCRect, UINT nFlags)
{
return CDialog::SetWindowPos(pWndInsertAfter,pCRect->left, pCRect->top,
pCRect->right - pCRect->left, pCRect->bottom - pCRect->top, nFlags);
}
到此,程序终于完成了。在我的源代码中还有对WM_SIZING的处理和定义了与之相关的宏,这些主要是控制窗口在调整大小时不能超过最小的宽度和高度,与QQ的自动伸缩无关,所以不在这里提及了。
三、结束语
虽然还不能算是完美的模仿,但效果已经非常非常的接近了。也许有人会奇怪为什么要用Tool Window 风格,这是因为,这样在任务栏中不会显示窗口。从QQ的标题栏高度也可以判断出他也是这种风格,但这样一来就不能拥有最小化、最大化按键了。实际上QQ的最大化、最小化和关闭按键都是用DC画上去的。如何在Caption上增加按键,外国一些开源网站有源代码,我下载并看了一下,发现里面有个知识点很有趣,那就是更改消息路由,有兴趣的可以去下载来学习一下。
QQ的成功很大部分在于他的界面比较人性化(用了MSN后深有感受),而这些界面实现起来原理也许很简单,难的是观察东西心要细、设计东西心要密、开发东西心要异。废话就不多说了,在vckbase偷师那么久,这是第一次在vckbase上发表原创,看了“投稿须知”,对其格式要求似懂非懂的,也不知道这篇文章会不会被采纳。不论结果如何,希望这篇文章对你们有所帮助。
更多精彩
赞助商链接