可伸缩标题栏(鼠标移近对话框边缘标题栏出现,移出边缘标题栏消失)
内容提要:实例特点
原理分析
实现步骤
扩展及建议
关键词:
鼠标事件,区域分割,绘图
实例特点:
本实例可用于对话框增加可伸缩标题栏,可移植性较好,实现简单,且避免了窗口受屏幕挤压而移动的问题。
原理分析:
流程图:
开始 |
[size=12pt]初始化标准区域,确定控件位置。设定在标题栏中出现的控件的样式 |
保持对话框原来大小 |
判断鼠标是否进入触发区域 |
增加标题栏 |
在标题栏上添加背景 |
标题栏消失时重绘背景 |
结束 |
N |
Y |
知识点:
1 WM_MOUSEMOVE
OnMouseMove是系统消息函数,当有鼠标移动时就会发送此消息。还有两种针对按钮的消息WM_MOUSELEAVE鼠标进入按钮时触发,WM_MOUSEHOVER鼠标离开按钮时触发。但这两个消息使用时要手动添加映射。
2 WM_SIZE
OnSize系统消息函数,且在OnInitDialog之前调用,当窗口大小发生变化时就调用。所以不适合在这里处理我们的问题。以为它会不停的调用。而引起抖动。但如果是处理控件的位置变更或类似只在初始化时作一次的操作倒很合适,且效率高
3 绘图操作
要明确以下步骤:
1设定设备环境指针*pDC用于指向目标对象,既要把位图绘制的最终目的地。设定设备环境对象SrcDC。指针说白了知识指向内存中一块地址,并不能带更多信息,但对象却可以包含许多个性化的信息。如颜色,图案。是具体操作的实例。
接下来为该对象创建兼容的设备描述。
2 定义位图对象并加载位图。
3 定义位图指针。把位图选入设备对象SrcDC。
4 把设备对象中的内容绘入(拷贝)到目标区域
5 将位图指针选入设备对象,让对象知道应该到哪里开始找到位图
6 释放对象和设备环境,及指针。
实例原理:
区域1用于标题栏 |
区域3用于显示内容 |
区域2用于触发区域1 |
当鼠标进入区域2时触发区域1显示,鼠标离开时区域2消失,利用重绘实现。
实现步骤
(.h)
public:
CTitleBarOneDlg(CWnd* pParent = NULL);
// standard constructor
//加载标题栏图片
BOOL LoadBKBit(BOOL bShow,UINT lp,CRect rect);
//
BOOL LoadBKBit(UINT lp,CRect rect);
int bitAdd;//区域增量
int bitCtrl;//控件增量
int Lrect,Rrect,Trect,Brect;//标准区域顶点
//标题栏上的按钮
CButton *pBtnMyClose;
CButton *pBtnMyMin;
//加载标题栏图片标志位
BOOL bIsShow;
(.Cpp)
bIsShow = FALSE;//初始化
BOOL CTitleBarOneDlg::OnInitDialog()
{
bitAdd = 35;//标题栏宽度
bitCtrl = 0;
CRect rect;//Dlg区域
GetWindowRect(&rect);
//为顶点付值
Lrect = rect.left;
Rrect = rect.right;
Trect = rect.top;
Brect = rect.bottom;
//确定初始化DLG位置
SetWindowPos(&wndTop,rect.left+rect.Width()/2,
rect.top+bitAdd+rect.Height()/2,
rect.Width(),
rect.Height()-bitAdd,NULL);
//控件
m_btnPlay.SetWindowPos(&wndTop,rect.left+50,rect.top+100+bitCtrl,
60,25,NULL);
m_btnStop.SetWindowPos(&wndTop,rect.left+200,rect.top+100+bitCtrl,
60,25,NULL);
m_EditStr.SetWindowPos(&wndTop,rect.left+50,rect.top+150+bitCtrl,
220,80,NULL);
CEdit *pEditStr = (CEdit*)GetDlgItem(IDC_EDITStr);
CString SomeString = "基于对话框的伸缩工具栏通用性事例";
pEditStr->SetWindowText(SomeString);
pEditStr->ShowWindow(TRUE);
//标题栏上的按钮
pBtnMyMin = (CButton *)GetDlgItem(IDC_BtnMyMin);
pBtnMyClose = (CButton*)GetDlgItem(IDC_BtnMyClose);
CBitmap BitmapClose;
CBitmap BitmapMin;
BitmapClose.LoadBitmap(IDB_BITMAPClose);//按钮上的位图
BitmapMin.LoadBitmap(IDB_BITMAPMin);
HBITMAP hBitClose = (HBITMAP)BitmapClose.Detach();
HBITMAP hBitMin = (HBITMAP)BitmapMin.Detach();
pBtnMyClose->SetBitmap(hBitClose);
pBtnMyMin->SetBitmap(hBitMin);
pBtnMyMin->ShowWindow(FALSE);
pBtnMyClose->ShowWindow(FALSE);
return TRUE;
}
void CTitleBarOneDlg::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
static CRect rect;//标准区域
static CRect rectOn;//触发区域
static CRect rectSmall;//非触发区域
static CRect rectLarge;//加长区域
bitCtrl = bitAdd;
//建立个具体区域
if (rect.IsRectEmpty())
{
rect.left = Lrect;
rect.right = Rrect;
rect.top = Trect;
rect.bottom = Brect;
}
if (rectOn.IsRectEmpty())
{
rectOn.left = rect.left;
rectOn.right = rect.right;
rectOn.top = rect.top;
rectOn.bottom = 1;
}
if (rectSmall.IsRectEmpty())
{
rectSmall.left = rect.left;
rectSmall.right = rect.right;
rectSmall.top = rect.top+bitAdd;
rectSmall.bottom = rect.bottom;
}
//只是一小段
if (rectLarge.IsRectEmpty())
{
rectLarge.left = rect.left;
rectLarge.right = rect.right;
rectLarge.top = rect.top;
rectLarge.bottom = bitAdd;
}
//处理
//如果有点进入非触发区域
if (rectSmall.PtInRect(point))
{
//进入非触发区维持原窗口大小
bIsShow = FALSE;
LoadBKBit(bIsShow,IDB_BK,rectOn);
Sleep(20);
SetWindowPos(&wndTop,rectSmall.left+rect.Width()/2,
rectSmall.top+rect.Height()/2,
rectSmall.Width(),
rectSmall.Height(),NULL);
//增加的按钮不显示
pBtnMyClose->SetWindowPos(&wndTop,
rectLarge.left+rectLarge.Width()-50,
rectLarge.top+2,
24,24,SWP_HIDEWINDOW);
pBtnMyMin->SetWindowPos(&wndTop,
rectLarge.left+rectLarge.Width()-68,
rectLarge.top+2,
24,24,SWP_HIDEWINDOW);
//其余控件
bitCtrl = 0;
m_btnPlay.SetWindowPos(&wndTop,rect.left+50,rect.top+100+bitCtrl,
60,25,NULL);
m_btnStop.SetWindowPos(&wndTop,rect.left+200,rect.top+100+bitCtrl,
60,25,NULL);
m_EditStr.SetWindowPos(&wndTop,rect.left+50,rect.top+150+bitCtrl,
220,80,NULL);
}
//如果有点进入触发区域
if (rectOn.PtInRect(point))
{
//进入触发区域设置加长区域并显示
Sleep(200);
//让标题栏重绘的慢一些,避免闪烁(但感觉不是太好的方法)
//加载图片
bIsShow = TRUE;
LoadBKBit(bIsShow,IDB_BK,rectLarge);
//加长区域
SetWindowPos(&wndTop,rectLarge.left+rect.Width()/2,
rectLarge.top+rect.Height()/2,
rectLarge.Width(),
rectLarge.Height(),NULL);
SetWindowPos(&wndTop,rectSmall.left+rect.Width()/2,
rectSmall.top+rect.Height()/2,
rectSmall.Width(),
rectSmall.Height()+bitAdd,SWP_NOMOVE);
//增加的按钮
pBtnMyClose->SetWindowPos(&wndTop,
rectLarge.left+rectLarge.Width()-35,
rectLarge.top+2,
24,24,SWP_SHOWWINDOW);
pBtnMyMin->SetWindowPos(&wndTop,
rectLarge.left+rectLarge.Width()-63,
rectLarge.top+2,
24,24,SWP_SHOWWINDOW);
//其余控件
m_btnPlay.SetWindowPos(&wndTop,rect.left+50,rect.top+100+bitCtrl,
60,25,NULL);
m_btnStop.SetWindowPos(&wndTop,rect.left+200,rect.top+100+bitCtrl,
60,25,NULL);
m_EditStr.SetWindowPos(&wndTop,rect.left+50,rect.top+150+bitCtrl,
220,80,NULL);
UpdateData(TRUE);
}
//如果加长区域已经弹出单鼠标又不在整个窗口内
CDialog::OnMouseMove(nFlags, point);
}
//关闭按钮
void CTitleBarOneDlg::OnBtnClose()
{
// TODO: Add your control notification handler code here
CDialog::OnCancel();
}
//最小化按钮
void CTitleBarOneDlg::OnBtnMyMin()
{
// TODO: Add your control notification handler code here
ShowWindow(SW_SHOWMINIMIZED);
UpdateWindow();
}
//加载图片
BOOL CTitleBarOneDlg::LoadBKBit(BOOL bShow,UINT lp,CRect rect)
{
BOOL bIsShow;
bIsShow = bShow;
CDC *pDC = this->GetDC();
CDC SrcDC,TransDC;//源和透明DC
BITMAP Bitmap;
CBitmap bmp,TransBmp;
SrcDC.CreateCompatibleDC(pDC);
TransDC.CreateCompatibleDC(pDC);
VERIFY(bmp.LoadBitmap(lp));
bmp.GetObject(sizeof(BITMAP),&Bitmap);
CRect rt;
rt=CRect(rect);
//建立空白位图
TransBmp.CreateCompatibleBitmap(pDC,450,30);
//对象选入环境
CBitmap *pTransBmp = TransDC.SelectObject(&TransBmp);
CBitmap *pBmp = SrcDC.SelectObject(&bmp);
//画图
if (bIsShow)
{
pDC->StretchBlt(rt.left,
rt.top,
rt.Width(),
rt.Height(),
&SrcDC,
0,0,Bitmap.bmWidth,Bitmap.bmHeight,
SRCCOPY);
}
else
{//如果标题栏消失加载在上面的图像会因为找不到区域而下移,
//所以要用背景色盖住下移的位图。起始位置因为重绘是原来的坐标轴不复存在
//而重新建立
pDC->FillSolidRect( 0, 0, 486, 30, RGB(212, 208, 200) );
}
SrcDC.SelectObject(pBmp);
SrcDC.DeleteDC();
TransDC.SelectObject(pTransBmp);
TransDC.DeleteDC();
bmp.DeleteObject();
ReleaseDC(pDC);
return TRUE;
}
扩展及建议
可以考虑在标题栏上加入菜单。或其他控件