首页 | IT新闻 | 硬件 | 操作系统 | 开发 | 网络编程 | 数据库 | 热门框架 | 网络安全 | 组网 | 建站指南 | 网页制作 | 特效 | 实用技巧 | 服务器 | 办公 | QQ | 探索 | 社区

  • 技术部落
  • 部落首页 > 程序开发 > C/C#/C++ > 正文
  • QQ2006界面编程之鸡蛋里挑骨头
      2007-4-19  来源:VCKBASE  编辑:Jsbulo  热度:

    2007新的一年即将来临,新版本的QQ估计也要跟我们相见。在此献上本人写于8月份的一个练习程序。主要是希望腾讯做界面的同志能否把创建异形窗体函数 SetWindowRgn 放到合适的位置,别让拖动窗体改变大小时出现用做 MASK 的紫色区域;再者与大家分享不指定窗体风格 WS_THICKFRAME(对于对话框,相当指定其属性 Border 为 Resizing ),用代码实现窗体拖放,任意改变其尺寸。

      一、SetWindowRgn的合适位置

      1、在void C**Dlg::OnPaint()里调用SetWindowRgn,可以在内存画图完毕准备显示到屏幕前调用,如下:

    void C**Dlg::OnPaint()
    {
     if (IsIconic())
     {
      CPaintDC dc(this);
      ...
     }
     else
     {
      CPaintDC dc(this); // 用于绘制的设备上下文

      CRect rcClient;
      GetClientRect(&rcClient);

      //构造内存DC,用于画图
      CDC m_MemDC;
      m_MemDC.CreateCompatibleDC(&dc);

      CBitmap btScreen;
      btScreen.CreateCompatibleBitmap(&dc, rcClient.Width(), rcClient.Height());

      m_MemDC.SelectObject(&btScreen);
      btScreen.DeleteObject();

      //这里画图
      ...

      //创建不规则窗体
      ChangeWindowRgn(&m_MemDC);//这里面调用了SetWindowRgn

      //画到显示器上
      dc.BitBlt(rcClient.left, rcClient.top, rcClient.Width(), rcClient.Height(), &m_MemDC, 0, 0, SRCCOPY);

      m_MemDC.DeleteDC();
     }
    }

    void C**Dlg::ChangeWindowRgn(CDC *pDC)
    {
     COLORREF col = RGB(255,0,255);
     CRect rcClient;
     GetClientRect (rcClient);

     CRgn rgn;
     rgn.CreateRectRgn (0, 0, rcClient.Width(), rcClient.Height());

     ...

     SetWindowRgn (rgn, TRUE);
    }

      2、在void C**Dlg::OnShowWindow()里调用SetWindowRgn, 如下:

    void C**Dlg::OnShowWindow(BOOL bShow, UINT nStatus)
    {
     CWnd::OnShowWindow(bShow, nStatus);
     // TODO: 在此处添加消息处理程序代码
     if(bShow)
     {
      CRect rc;
      this->GetClientRect(&rc);
      CRgn rgnMain;
      rgnMain.CreateRoundRectRgn(0, 0, rcClient.Width(), rcClient.Height());
      ...
      SetWindowRgn( rgnMain, TRUE );
     }
    }

      二、手动做“Resizing对话框”

      该思路启发于徐景周的精灵特效窗体。要想点击窗体客户区不放能移动窗体,传统的做法是模拟消息点击标题。

    void C**Dlg::OnLButtonDown(UINT nFlags, CPoint point)
    {
     // TODO: 在此添加消息处理程序代码

     PostMessage(WM_NCLBUTTONDOWN,HTCAPTION,0);
     CDialog::OnLButtonDown(nFlags, point);
    }

      这样很方便实现效果。但不足是窗体被移到屏幕上方,大部分在屏幕所能显示以外以后放开鼠标,窗体会自动向下对齐。徐景周的精灵特效窗体用了SetTimer和MoveWindow结合使用,这样窗体想被移到哪里都可以。正因为如此,让我想到拖放窗体的好思路。当然我们完全可以利用窗体风格WS_THICKFRAME,让系统来为我们做事。

      但是如果我们要指定窗体某个部位可以拖放窗体时,像QQ切换主题后,拖放很不方便。可以拖放的区域不是最左,最右,最上,最下,没有别的地方可以点击拖放窗体了。

      如何实现,简单说就是在鼠标按下时判断是否点在规定区域内,是的话启动记时器。然后在记时器里面定时器里面对光标判断当前位置与之前位置,从而调用MoveWindow让窗体朝响应方向拉伸或收缩。代码较琐碎,请见例子。

    void C**Dlg::OnLButtonDown(UINT nFlags, CPoint point)
    {
     CRect rc(*,*,*,*);
     if(rc.PtInRect(point))
     {
      SetTimer(1,20,NULL);//启动记时器
      return;
     }
     CDialog::OnLButtonDown(nFlags, point);
    }
    void C**Dlg::OnTimer(UINT_PTR nIDEvent)
    {
     // TODO: 在此添加消息处理程序代码和/或调用默认值
     switch(nIDEvent)
     {
      case(1):
      {
       CRect rcW;
       POINT point;
       GetWindowRect(rcW);//

       //实现拖动时窗体跟着右下角拉伸
       ::GetCursorPos(&point); //得到“当前位置”
       if(point.y<rcW.bottom-400)
       {
        MoveWindow(m_rcCurRect.left ,point.y-m_ptCurPoint.y, rcW.Width(),
    m_rcCurRect.bottom-(point.y-m_ptCurPoint.y), true);
        CRect rc;
        GetWindowRect(rc);
        m_rcCurRect = rc;//保存“之前位置”
       }
       Invalidate();
      }
      break;
       ...
      Default:
       break;
     }
     Dialog::OnTimer(nIDEvent);
    }

      代码在Visual2005下编译,在WindowXP运行通过。