程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> VC >> 關於VC++ >> 智能ABC窗口的實現

智能ABC窗口的實現

編輯:關於VC++

高級頂層窗口是一種無標題欄、菜單、工具條的一種常居頂層的窗口,最常見的例子就是輸入法窗口,比如智能ABC窗口。這類窗口的特點除了上邊所說的,最重要的就是窗口移動。普通窗口移動是通過標題欄由系統自動實現的,對於這類窗口就無法依靠系統了,需要手工實現。實現的方法有兩種:

手工處理WM_MOVE、WM_LBUTTONUP消息,並根據鼠標的移動自己實現窗口移動過程中的繪制;

在WM_MOVE消息處理函數中通過向自己發送參數wParam為HTCAPTION lParam為鼠標位置的WM_NCLBUTTONDOWN消息實現窗口移動,此時窗口移動過程的繪制由系統實現。

顯然,後者較前者簡單。本文采用後者。

為了實現移動,還要對窗口定義有效移動區域,就是當鼠標移動到窗口中哪部分時鼠標變為十字箭頭,暗示現在可以按下左鍵開始拖動。本文實現的窗口中有四個緊密排列的位圖“按鈕”,它們之間沒有空隙,所以我定義位圖以外窗口以內為有效移動區域。鼠標進入這片區域時將變為十字箭頭形狀,提示用戶現在可以進行拖動。

在定義窗口類時,如果窗口有邊框,那麼當鼠標在邊框上時,接收到的是WM_NCMOUSEMOVE消息,所以為了在WM_MOUSEMOVE消息處理函數中統一處理,本文窗口沒有使用邊框,只要鼠標進入窗口,就開始接收到WM_MOUSEMOVE消息了。但這又引入另一個問題:如何繪制3D邊框?本文使用了函數 :

void Draw3dRect( LPCRECT lpRect, COLORREF clrTopLeft, COLORREF clrBottomRight)

實現了3D邊框的繪制。

本文實現的基本原理:

從CWnd直接派生一個窗口類CMainWnd,並添加一個共有函數bool CreateMainWnd()用來創建窗口;

在相應WM_PAINT時,在客戶區中根據四個標記變量繪制相應的四個位圖;

在WM_LBUTTONDOWN 消息處理中,檢測鼠標是否落入某個“按鈕”位圖,設置相應標志,並強制系統重繪客戶區;

在WM_MOUSEMOVE消息處理中,檢測鼠標是否落入有效移動區域,並設置相應光標。如果按下了左鍵,就開始發送WM_NCLBUTTONDOWN消息,實現窗口移動;

為了關閉窗口,本程序設置了加速鍵F12,按F12可關閉程序;

代碼如下:

1、創建窗口:

bool CMainWnd::CreateMainWnd(void)
  {
    if(!CreateEx(0,
          ::AfxRegisterWndClass(0,
                     ::LoadCursor(NULL,MAKEINTRESOURCE(IDC_ARROW)),
                     GetSysColorBrush(COLOR_ACTIVEBORDER)
                     ),
           NULL,
           WS_POPUP,
           0,0,300,50,
           NULL,
           NULL))
      return false;
   return true;
  }

2、窗口繪制:根據四個位圖“按鈕”標志變量繪制相應的位圖。

void CMainWnd::OnPaint()
  {
   CPaintDC dc(this); // device context for painting
   // TODO: 在此處添加消息處理程序代碼
   // 不為繪圖消息調用 CWnd::OnPaint()
   CBitmap* pOldBmp;
   CDC CompatibleDC;
   CompatibleDC.CreateCompatibleDC(&dc);
   //繪制第一個按鈕
   if(m_bBTState[0])
   pOldBmp=CompatibleDC.SelectObject(&m_BT1_1);
   else
   pOldBmp=CompatibleDC.SelectObject(&m_BT1_2);
   dc.BitBlt(m_rcBT1.left,m_rcBT1.top,m_rcBT1.Width(),m_rcBT1.Height(),&CompatibleDC,0,0,SRCCOPY);
   //繪制第二個按鈕
   if(m_bBTState[1])
    CompatibleDC.SelectObject(&m_BT2_1);
   else
    CompatibleDC.SelectObject(&m_BT2_2);
   dc.BitBlt(m_rcBT2.left,m_rcBT2.top,m_rcBT2.Width(),m_rcBT2.Height(),&CompatibleDC,0,0,SRCCOPY);
   //繪制第三個按鈕
   if(m_bBTState[2])
    CompatibleDC.SelectObject(&m_BT3_1);
   else
    CompatibleDC.SelectObject(&m_BT3_2);
   dc.BitBlt(m_rcBT3.left,m_rcBT3.top,m_rcBT3.Width(),m_rcBT3.Height(),&CompatibleDC,0,0,SRCCOPY);
   //繪制第四個按鈕
   if(m_bBTState[3])
    CompatibleDC.SelectObject(&m_BT4_1);
   else
    CompatibleDC.SelectObject(&m_BT4_2);
   dc.BitBlt(m_rcBT4.left,m_rcBT4.top,m_rcBT4.Width(),m_rcBT4.Height(),&CompatibleDC,0,0,SRCCOPY);
   //繪制第五個按鈕
   if(m_bBTState[4])
    CompatibleDC.SelectObject(&m_BT5_1);
   else
    CompatibleDC.SelectObject(&m_BT5_2);
   dc.BitBlt(m_rcBT5.left,m_rcBT5.top,m_rcBT5.Width(),m_rcBT5.Height(),&CompatibleDC,0,0,SRCCOPY);
   //繪制邊框
   CRect rcClient;
   GetClientRect(&rcClient);
   dc.Draw3dRect(&rcClient,RGB(192,192,192),RGB(0,0,0));
   rcClient.DeflateRect(1,1,1,1);
   dc.Draw3dRect(&rcClient,RGB(255,255,255),RGB(144,144,144));
   CompatibleDC.SelectObject(pOldBmp);
  }

3、WM_MOUSEMOVE 消息處理函數void CMainWnd::OnMouseMove(UINT nFlags, CPoint point)
  {
    // TODO: 在此添加消息處理程序代碼和/或調用默認值
    bool bInRegionNow=IsInRegion(point);
    TRACE("Mouse move:(%d,%d) InRegion=%d\n",point.x,point.y,bInRegionNow);
    if(bInRegionNow)
    {
     SetCursor(m_hCrossCursor);//設置十字形光標
     if(nFlags&MK_LBUTTON)
     {
      POINT pt;
      pt.x=point.x;pt.y=point.y;
      ClientToScreen(&pt);
   //發送移動消息
      SendMessage(WM_NCLBUTTONDOWN,HTCAPTION,(LPARAM)(pt.x|(pt.y>>16)));
     }
    }
    CWnd::OnMouseMove(nFlags, point);
  }

程序運行效果

效果如下:

你可以用鼠標拖動它到任意位置。

結束語

本文只是實現了和智能ABC類似的窗口,但我在用spy++查找智能ABC窗口時發現並不能找到它,不知為什麼,難道它根本就不是一個真正的窗口?那它又是怎麼實現的呢?有誰知道的能否告訴我,謝謝!

本文配套源碼

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved