开发精彩实例:窗体自动隐藏

2016-02-19 20:20 5 1 收藏

下面图老师小编要向大家介绍下开发精彩实例:窗体自动隐藏,看起来复杂实则是简单的,掌握好技巧就OK,喜欢就赶紧收藏起来吧!

【 tulaoshi.com - 编程语言 】

实现窗体自动隐藏方法有多种,可以使用定时器,不断监视鼠标,当鼠标移动到窗体边缘时,显示窗体,当鼠标离开后隐藏窗体。也可以在鼠标收到WM_NCMOUSEMOVE或 WM_MOUSEMOVE(无边框窗体)时激活窗体,然后在窗体消息WM_ACTIVE中设置显示或隐藏,这种方法在窗体未失去焦点时不会隐藏。 !-- frame contents -- !-- /frame contents -- 我在原本的设计中便使用这种方法,只是在设计时发现非主窗体不太合适,激活窗体时会出现两个键盘焦点,而且我所需要的焦点是虚假的,可能我的设计不当,那位朋友若能完美实现,不妨交流一下。
   
    本代码的流程如下:
     
    1. 初始化窗体时设置窗体位置,并设置依靠状态窗体状态。
    2. 当接收到WM_MOUSEMOVE消息时,检查窗体是否显示,若否,显示,并打开定时器。
    3. 在WM_MOVING中检测窗体位置,并自动靠拢边界。
    4. 在定时器中检测鼠标,当鼠标离开窗体后,关闭定时器,隐藏窗体。
  
    当然,在隐藏窗体时首先判定位置,若停靠在边缘,则隐藏,否则,不隐藏。
  
    现在我们一步步看代码。
  
  int alignType; //全局变量,用于记录窗体停靠状态
  enum
  {
   ALIGN_NONE, //不停靠
   ALIGN_TOP, //停靠上边
   ALIGN_LEFT, //停靠左边
   ALIGN_RIGHT //停靠右边
  };
  #define NEAR_SIZE 20 //定义自动停靠有效距离
  #define NEAR_SIDE 2 //窗体隐藏后在屏幕上保留的像素,以使鼠标可以触及
  /*
  下面代码处理窗体消息WM_MOVING,pRect是由参数lParam传来的指针
  */
  voidOnMoving(HWND hWnd, LPRECT pRect)
  {
   //未靠边界由pRect测试
   if (alignType == ALIGN_NONE)
   {
   if (pRect->top NEAR_SIZE) //在上边有效距离内,自动靠拢。
   {
   alignType = ALIGN_TOP;
   pRect->bottom -= pRect->top;
   pRect->top = 0;
   }
   if (pRect->left NEAR_SIZE) //在左边有效距离内
   {
   alignType = ALIGN_LEFT;
   pRect->right -= pRect->left;
   pRect->left = 0;
   }
   else if (pRect->right + NEAR_SIZE ScreenX) //在右边有效距离内,ScreenX为屏幕宽度,可由GetSystemMetrics(SM_CYSCREEN)得到。
   {
   alignType = ALIGN_RIGHT;
   pRect->left += (ScreenX - pRect->right);
   pRect->right = ScreenX;
   }
  
   }
   else
   {
   //靠边界由鼠标测试
   更多内容请看Wlan组网----家庭专题专题,或 POINT pt;
   GetCursorPos(&pt);
   if (alignType == ALIGN_TOP)
   {
   if (pt.y NEAR_SIZE) //由于我们移动窗体时,鼠标在标题栏内,当鼠标位置超过有效距离后,我们可以考虑用户要向下拖动鼠标。我们便解除上部停靠。
   {
   !-- frame contents -- !-- /frame contents -- alignType = ALIGN_NONE;
  pRect->bottom += NEAR_SIZE;
  pRect->top = NEAR_SIZE;
   }
   else
   {
  pRect->bottom -= pRect->top;
  pRect->top = 0;
  if (pRect->left NEAR_SIZE) //在上部停靠时,我们也考虑左右边角。
  {
   pRect->right -= pRect->left;
   pRect->left = 0;
  }
  else if (pRect->right + NEAR_SIZE ScreenX)
  
   {
   pRect->left += (ScreenX - pRect->right);
   pRect->right = ScreenX;
  }
   }
  
   }
   if (alignType == ALIGN_LEFT)
   {
   if (pt.x - pRect->right 0) //鼠标可以在整个标题条往返移动,所以我们不能简单用左边界和鼠标的距离来解除停靠,这里我们在鼠标离开右边界时解除停靠。
   {
  alignType = ALIGN_NONE;
  pRect->right += NEAR_SIZE;
  pRect->left = NEAR_SIZE;
   }
   else
   {
  pRect->right -= pRect->left;
  pRect->left = 0;
  if (pRect->top NEAR_SIZE) //考虑左上角。
  {
   pRect->bottom -= pRect->top;
   pRect->top = 0;
  }
   }
   }
   else if (alignType == ALIGN_RIGHT)
   {
   if (pt.x pRect->left) //当鼠标离开左边界时,解除停靠。
   {
  alignType = ALIGN_NONE;
  pRect->left -= NEAR_SIZE;
  pRect->right -= NEAR_SIZE;
   }
  
   更多内容请看Wlan组网----家庭专题专题,或 else
   {
  pRect->left += (ScreenX - pRect->right);
  pRect->right = ScreenX;
  if (pRect->top NEAR_SIZE) //考虑右上角。
  {
   pRect->bottom -= pRect->top;
   pRect->top = 0;
  }
   }
   }
   }
  }
   !-- frame contents -- !-- /frame contents --   /*
    在窗体初始化是设定窗体状态,假如可以停靠,便停靠在边缘
    我本想寻求其他方法来解决初始化,而不是为它专一寻求一个函数,可是,窗体初始化时不
    发送WM_MOVING消息,我不得不重复类似任务.
    */
  voidNearSide(HWND hWnd)
  {
   int change = 0;
   RECTrect;
   GetWindowRect(hWnd, &rect);
   alignType = ALIGN_NONE;
   if (rect.left NEAR_SIZE)
   {
   alignType = ALIGN_LEFT;
   if ((rect.left != 0) && rect.right != NEAR_SIDE)
   {
   rect.right -= rect.left;
   rect.left = 0;
   change = 1;
   }
   }
   else if (rect.right ScreenX - NEAR_SIZE)
   {
   alignType = ALIGN_RIGHT;
   if (rect.right != ScreenX && rect.left != ScreenX - NEAR_SIDE)
   {
   rect.left += (ScreenX - rect.right);
   rect.right = ScreenX;
   change = 1;
   }
   }
   //调整上
   更多内容请看Wlan组网----家庭专题专题,或 else if (rect.top NEAR_SIZE)
   {
   alignType = ALIGN_TOP;
   if (rect.top != 0 && rect.bottom != NEAR_SIDE)
   {
   rect.bottom -= rect.top;
   rect.top = 0;
   change = 1;
   }
   }
   if (change)
   {
   !-- frame contents -- !-- /frame contents --MoveWindow(hWnd, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, TRUE);
  
  }
  
  }
  /*
  窗体的显示隐藏由该函数完成,参数hide决定显示还是隐藏.
  */
  voidHideSide(HWND hWnd, BOOL hide)
  {
   RECTrc;
   int moves = 20; //动画滚动窗体的步数,假如你觉得不够平滑,可以增大该值.
   int xStep, yStep;
   int xEnd, yEnd;
   int width;
   int height;
   register inti;
   GetWindowRect(hWnd, &rc);
   width = rc.right - rc.left;
   height = rc.bottom - rc.top;
  
  //下边判定窗体该如何移动,由停靠方式决定
   switch (alignType)
   {
   case ALIGN_TOP:
   {
   //向上移藏
   xStep = 0;
   xEnd = rc.left;
   if (hide)
   {
  yStep = -rc.bottom / moves;
  yEnd = -height + NEAR_SIDE;
   }
   else
   {
  yStep = -rc.top / moves;
  yEnd = 0;
   }
   break;
   }
   case ALIGN_LEFT:
   {
   //向左移藏
   更多内容请看Wlan组网----家庭专题专题,或yStep = 0;
   yEnd = rc.top;
   if (hide)
   {
  xStep = -rc.right / moves;
  xEnd = -width + NEAR_SIDE;
   }
   else
   {
  xStep = -rc.left / moves;
  xEnd = 0;
   }
   break;
   }
   !-- frame contents -- !-- /frame contents -- case ALIGN_RIGHT:
   {
   //向右移藏
   yStep = 0;
   yEnd = rc.top;
   if (hide)
   {
  xStep = (ScreenX - rc.left) / moves;
  xEnd = ScreenX - NEAR_SIDE;
   }
   else
   {
  xStep = (ScreenX - rc.right) / moves;
  xEnd = ScreenX - width;
   }
   break;
   }
   default:
   return;
   }
   //动画滚动窗体.
   for (i = 0; i moves; i++)
   {
   rc.left += xStep;
   rc.top += yStep;
   SetWindowPos(hWnd, NULL, rc.left, rc.top, 0, 0, SWP_NOSIZE SWP_NOSENDCHANGING);
   RedrawWindow(hWnd, NULL, NULL, RDW_INVALIDATE RDW_UPDATENOW);
   Sleep(5);
   }
   SetWindowPos(hWnd, NULL, xEnd, yEnd, 0, 0, SWP_NOSIZE);
   if (!hide) //假如窗体已被显示,设置定时器.监视鼠标.
   {
   SetTimer(hWnd, WM_TIMER, 500, NULL);
   }
  }
    //下面就是通过窗体回调函数将这些函数组织起来.
   更多内容请看Wlan组网----家庭专题专题,或   //这里仅列出使用的消息
  case WM_TIMER: //定时器消息
  {
   POINT pt;
   RECTrc;
   GetCursorPos(&pt);
   GetWindowRect(hWnd, &rc);
   if (!PtInRect(&rc, pt)) //若鼠标不在窗体内,隐藏窗体.
   {
   !-- frame contents -- !-- /frame contents --KillTimer(hWnd, WM_TIMER);
  
  HideSide(hWnd, TRUE);
   }
   break;
  }
  case WM_CREATE:
  case WM_INITDIALOG: //初始化消息
  {
   SetWindowPos(...) //程序保存窗体上次靠位置,在这里恢复.
   NearSide(hWnd);
   break;
  }
   //这两个消息是在窗体移动开始时和结束时产生的,我们在窗体开始移动时关闭定时器,移动结束后再打开,这样避免窗体移动时隐藏,金山快译的浮动条就有这种情况出现.
  case WM_ENTERSIZEMOVE:
  {
   KillTimer(hWnd, WM_TIMER);
   break;
  }
  case WM_EXITSIZEMOVE:
  {
   SetTimer(hWnd, WM_TIMER, 500, NULL);
   break;
  }
  case WM_MOUSEMOVE: //受到窗体移动消息时,判定窗体是否显示,
  {
   RECTrc;
   GetWindowRect(hWnd, &rc);
   if (rc.left 0 rc.top 0 rc.right ScreenX) //未显示
   HideSide(hWnd, FALSE);
   break;
  }
  case WM_MOVING: //处理窗体移动时消息,实现自动停靠
  {
   OnMoving(hWnd, (LPRECT) lParam);
   break;
  }
  case WM_MOVE:
  {
   //保存窗体位置
  }
    这些代码是从程序中摘录出来的, 笔者已尽量检查它们的完整性, 但人总有犯错的时候, 假如发现这些代码有问题, 或有更好的建议, 请联系笔者:ggg82@sina.com
   更多内容请看Wlan组网----家庭专题专题,或

来源:http://www.tulaoshi.com/n/20160219/1623385.html

延伸阅读
自动隐藏停泊窗体在商业的MFC图形库中(如Xtreme)已支持得很好,但他们大多都重写了MFC相应的支持代码像Cristi Posea的CSizingControlBar实现VC6界面那样,重用大部分MFC Dock 框架类而实现Vc .Net界面的免费库很少见(偶没发现:)本实现,准确地说是在Cuick 的《轻松实现类MSDN2002界面(二)》基础上的增强版。 其主要更新为: Bugfi...
标签: 办公软件
朋友在用Excel统计学生的成绩时,在E63单元格中输入公式:=AVERAGE(E3:E62),准备计算平均分,由于上面的单元格中还没有输入成绩数据,因而公式返回了一个错误结果(如图1)。朋友问我,如何让这些错误结果不显示或打印出来呢?我向他介绍了下面三种方法。 图1一、函数处理法我们只要用IF和ISERROR函数对公式稍作处理,这个错误值就不再显示出...
文字隐藏应用广泛,但常用的方法没有什么亲和力。常用文字隐藏方法的缺陷: 1、display:none 这种方法搜索引擎可能认为被隐藏的文字属于垃圾信息而被忽略; 屏幕阅读器会忽略被隐藏的文字。 2、visibility: hidden 这种方法隐藏了文字却仍然占据物理空间。 3、推荐大家使用这个更好的方法: ...
标签: 电脑入门
MAC用户在使用Dock自动隐藏功能时,发现隐藏于展示Dock互相切换时,总是会有一些延迟,这个问题该如何修复呢? 解决方法: 打开终端(应用程序文件夹-》实用工具文件夹-》终端),输入以下命令: defaults write com.apple.Dock autohide-delay -float 0 && killall Dock. 很简单吧,现在你去看看还有延迟吗? 如果想恢复默...
标签: 电脑入门
Windows 7 为了改善用户操作体验,强化了鼠标窗口拖拽操作的功能。如果我们用鼠标将某程序窗口拖拽至桌面左侧或右侧,这个程序窗口就会自动以 50% 的宽度在桌面左侧或右侧显示,方便横向比对;如果将程序窗口拖拽至桌面顶部,则可以实现窗口的自动最大化,再次拖拽又会恢复原始窗口大小,这类似于早期版本Windows 的鼠标双击窗口标题栏。者...

经验教程

996

收藏

34
微博分享 QQ分享 QQ空间 手机页面 收藏网站 回到头部