- 效果如下
- 头文件
- CPP文件
- 2.1 宏定义
- 2.2 构造函数
- 2.3 消息响应
- 2.4 代码实现
工具:VS2022
框架:MFC
语言:C++
类型:Dialog 单对话框
假设窗体类为:CBLToolsDlg
效果如下
先展示下效果,否则光凭着嘴上的描述无法形象展示.
//靠窗隐藏 protected: //修正移动时窗口的大小 void FixMoving(UINT fwSide, LPRECT pRect); //修正改改变窗口大小时窗口的大小 void FixSizing(UINT fwSide, LPRECT pRect); //从收缩状态显示窗口 void DoShow(); //从显示状态收缩窗口 void DoHide(); //重载函数,只是为了方便调用 BOOL SetWindowPos(const CWnd* pWndInsertAfter, LPCRECT pCRect, UINT nFlags = SWP_SHOWWINDOW); private: BOOL m_isSizeChanged; //窗口大小是否改变了 BOOL m_isSetTimer; //是否设置了检测鼠标的Timer INT m_oldWndHeight; //旧的窗口宽度 INT m_taskBarHeight; //任务栏高度 INT m_edgeHeight; //边缘高度 INT m_edgeWidth; //边缘宽度 INT m_hideMode; //隐藏模式 BOOL m_hsFinished; //隐藏或显示过程是否完成 BOOL m_hiding; //该参数只有在!m_hsFinished才有效 //真:正在隐藏,假:正在显示 public: afx_msg LRESULT OnNcHitTest(CPoint point); afx_msg void OnMoving(UINT fwSide, LPRECT pRect); afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); afx_msg void OnSizing(UINT fwSide, LPRECT pRect); afx_msg void OnTimer(UINT_PTR nIDEvent);CPP文件 2.1 宏定义
//HIDE功能 收缩模式 #define HM_NONE 0 //不收缩 #define HM_TOP 1 //向上收缩 #define HM_BOTTOM 2 //向下收缩 #define HM_LEFT 3 //向左收缩 #define HM_RIGHT 4 //向右收缩 #define CM_ELAPSE 200 //检测鼠标是否离开窗口的时间间隔 #define HS_ELAPSE 5 //隐藏或显示过程每步的时间间隔 #define HS_STEPS 10 //隐藏或显示过程分成多少步 #define INTERVAL 20 //触发粘附时鼠标与屏幕边界的最小间隔,单位为象素 #define INFALTE 10 //触发收缩时鼠标与窗口边界的最小间隔,单位为象素 #define MINCX 200 //窗口最小宽度 #define MINCY 400 //窗口最小高度2.2 构造函数
CBLToolsDlg::CBLToolsDlg(CWnd* pParent )
: CDialogEx(IDD_BLTOOLS_DIALOG, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
//HIDE功能
//构造函数初始化成员变量
m_isSizeChanged = FALSE;
m_isSetTimer = FALSE;
m_hsFinished = TRUE;
m_hiding = FALSE;
m_oldWndHeight = MINCY;
m_taskBarHeight = 30;
m_edgeHeight = 0;
m_edgeWidth = 0;
m_hideMode = HM_NONE;
}
2.3 消息响应
BEGIN_MESSAGE_MAP(CBLToolsDlg, CDialogEx) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_WM_NCHITTEST() //[Damogu][BEGIN]隐藏 ON_WM_MOVING() ON_WM_CREATE() ON_WM_SIZING() ON_WM_TIMER() //[Damogu][END] END_MESSAGE_MAP()2.4 代码实现
LRESULT CBLToolsDlg::OnNcHitTest(CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
CString str;
str.Format(_T("Mouse (%d,%d)"), point.x, point.y);
//GetDlgItem(IDC_CURSOR)->SetWindowText(str);
if (m_hideMode != HM_NONE && !m_isSetTimer &&
//防止鼠标超出屏幕右边时向右边收缩造成闪烁
point.x < GetSystemMetrics(SM_CXSCREEN) + INFALTE)
{ //鼠标进入时,如果是从收缩状态到显示状态则开启Timer
SetTimer(4, CM_ELAPSE, NULL);
m_isSetTimer = TRUE;
m_hsFinished = FALSE;
m_hiding = FALSE;
SetTimer(5, HS_ELAPSE, NULL); //开启显示过程
}
return CDialogEx::OnNcHitTest(point);
}
void CBLToolsDlg::OnMoving(UINT fwSide, LPRECT pRect)
{
FixMoving(fwSide, pRect); //修正pRect
CDialogEx::OnMoving(fwSide, pRect);
}
int CBLToolsDlg::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CDialogEx::OnCreate(lpCreateStruct) == -1)
return -1;
// TODO:在此添加您专用的创建代码
//获得任务栏高度
CWnd* p;
p = this->FindWindow(_T("Shell_TrayWnd"), NULL);
if (p != NULL)
{
CRect tRect;
p->GetWindowRect(tRect);
m_taskBarHeight = tRect.Height();
}
//修改风格使得他不在任务栏显示
ModifyStyleEx(WS_EX_APPWINDOW, WS_EX_TOOLWINDOW);
//去掉关闭按键(如果想画3个按键的话)
//ModifyStyle(WS_SYSMENU,NULL);
//获得边缘高度和宽度
m_edgeHeight = GetSystemMetrics(SM_CYEDGE);
m_edgeWidth = GetSystemMetrics(SM_CXFRAME);
//可以在这里读取上次关闭后保存的大小
return 0;
}
void CBLToolsDlg::OnSizing(UINT fwSide, LPRECT pRect)
{
FixSizing(fwSide, pRect); //修正pRect
CDialogEx::OnSizing(fwSide, pRect);
}
void CBLToolsDlg::FixMoving(UINT fwSide, LPRECT pRect)
{
POINT curPos;
GetCursorPos(&curPos);
INT screenHeight = GetSystemMetrics(SM_CYSCREEN);
INT screenWidth = GetSystemMetrics(SM_CXSCREEN);
INT height = pRect->bottom - pRect->top;
INT width = pRect->right - pRect->left;
if (curPos.y <= INTERVAL)
{ //粘附在上边
pRect->bottom = height - m_edgeHeight;
pRect->top = -m_edgeHeight;
m_hideMode = HM_TOP;
}
else if (curPos.y >= (screenHeight - INTERVAL - m_taskBarHeight))
{ //粘附在下边
pRect->top = screenHeight - m_taskBarHeight - height;
pRect->bottom = screenHeight - m_taskBarHeight;
m_hideMode = HM_BOTTOM;
}
else if (curPos.x < INTERVAL)
{ //粘附在左边
if (!m_isSizeChanged)
{
CRect tRect;
GetWindowRect(tRect);
m_oldWndHeight = tRect.Height();
}
pRect->right = width;
pRect->left = 0;
pRect->top = -m_edgeHeight;
pRect->bottom = screenHeight - m_taskBarHeight;
m_isSizeChanged = TRUE;
m_hideMode = HM_LEFT;
}
else if (curPos.x >= (screenWidth - INTERVAL))
{ //粘附在右边
if (!m_isSizeChanged)
{
CRect tRect;
GetWindowRect(tRect);
m_oldWndHeight = tRect.Height();
}
pRect->left = screenWidth - width;
pRect->right = screenWidth;
pRect->top = -m_edgeHeight;
pRect->bottom = screenHeight - m_taskBarHeight;
m_isSizeChanged = TRUE;
m_hideMode = HM_RIGHT;
}
else
{ //不粘附
if (m_isSizeChanged)
{ //如果收缩到两边,则拖出来后会变回原来大小
//在"拖动不显示窗口内容下"只有光栅变回原来大小
pRect->bottom = pRect->top + m_oldWndHeight;
m_isSizeChanged = FALSE;
}
if (m_isSetTimer)
{ //如果Timer开启了,则关闭之
if (KillTimer(4) == 1)
m_isSetTimer = FALSE;
}
m_hideMode = HM_NONE;
//GetDlgItem(IDC_TIMER)->SetWindowText(_T("Timer off"));
}
}
void CBLToolsDlg::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 CBLToolsDlg::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);
}
//接着SetWindowPos和FixSizing函数
BOOL CBLToolsDlg::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);
}
void CBLToolsDlg::FixSizing(UINT fwSide, LPRECT pRect)
{
CRect curRect(pRect);
if (curRect.Width() < MINCX || curRect.Height() < MINCY)
{ //小于指定的最小宽度或高度
switch (fwSide)
{
case WMSZ_BOTTOM:
pRect->bottom = pRect->top + MINCY;
break;
case WMSZ_BOTTOMLEFT:
if (curRect.Width() <= MINCX)
pRect->left = pRect->right - MINCX;
if (curRect.Height() <= MINCY)
pRect->bottom = pRect->top + MINCY;
break;
case WMSZ_BOTTOMRIGHT:
if (curRect.Width() < MINCX)
pRect->right = pRect->left + MINCX;
if (curRect.Height() < MINCY)
pRect->bottom = pRect->top + MINCY;
break;
case WMSZ_LEFT:
pRect->left = pRect->right - MINCX;
break;
case WMSZ_RIGHT:
pRect->right = pRect->left + MINCX;
break;
case WMSZ_TOP:
pRect->top = pRect->bottom - MINCY;
break;
case WMSZ_TOPLEFT:
if (curRect.Width() <= MINCX)
pRect->left = pRect->right - MINCX;
if (curRect.Height() <= MINCY)
pRect->top = pRect->bottom - MINCY;
break;
case WMSZ_TOPRIGHT:
if (curRect.Width() < MINCX)
pRect->right = pRect->left + MINCX;
if (curRect.Height() < MINCY)
pRect->top = pRect->bottom - MINCY;
break;
}
}
}
暑期编程PK赛
得CSDN机械键盘等精美礼品!


