• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            tqsheng

            go.....
            隨筆 - 366, 文章 - 18, 評(píng)論 - 101, 引用 - 0
            數(shù)據(jù)加載中……

            Visual C++窗體設(shè)計(jì)技巧集

            [前言:]有好的界面軟件就成功了一半,本文將向您介紹怎樣設(shè)計(jì)一些有“稀奇古怪”形狀的窗體,如何設(shè)定窗體的顏色、如何設(shè)置任務(wù)欄和狀態(tài)欄以及菜單圖標(biāo)等等,通過(guò)這些技巧能更深入的理解VC的文檔-視圖結(jié)構(gòu)。   如何制作透明窗體   使用SetLayeredWindowAttributes可以方便的制作透明窗體,此函數(shù)在w2k以上才支持,而且如果希望直接使用的話,可能需要下載最新的SDK。不過(guò)此函數(shù)在w2k的user32.dll里有實(shí)現(xiàn),所以如果你不希望下載巨大的sdk的話,可以直接使用GetProcAddress獲取該函數(shù)的指針。   SetLayeredWindowAttributes的函數(shù)原型如下: BOOL SetLayeredWindowAttributes( HWND hwnd, // handle to the layered window COLORREF crKey, // specifies the color key BYTE bAlpha, // value for the blend function DWORD dwFlags // action ); Windows NT/2000/XP: Included in Windows 2000 and later. Windows 95/98/Me: Unsupported.(注意了,在win9x里沒(méi)法使用的) Header: Declared in Winuser.h; include Windows.h. Library: Use User32.lib.   一些常量: WS_EX_LAYERED = 0x80000; LWA_ALPHA = 0x2; LWA_COLORKEY=0x1;   其中dwFlags有LWA_ALPHA和LWA_COLORKEY   LWA_ALPHA被設(shè)置的話,通過(guò)bAlpha決定透明度.   LWA_COLORKEY被設(shè)置的話,則指定被透明掉的顏色為crKey,其他顏色則正常顯示.   要使使窗體擁有透明效果,首先要有WS_EX_LAYERED擴(kuò)展屬性(舊的sdk沒(méi)有定義這個(gè)屬性,所以可以直接指定為0x80000).   例子代碼:   在OnInitDialog()加入: //加入WS_EX_LAYERED擴(kuò)展屬性 SetWindowLong(this->GetSafeHwnd(),GWL_EXSTYLE, GetWindowLong(this->GetSafeHwnd(),GWL_EXSTYLE)|0x80000); HINSTANCE hInst = LoadLibrary("User32.DLL"); if(hInst) {  typedef BOOL (WINAPI *MYFUNC)(HWND,COLORREF,BYTE,DWORD);  MYFUNC fun = NULL;  //取得SetLayeredWindowAttributes函數(shù)指針  fun=(MYFUNC)GetProcAddress(hInst, "SetLayeredWindowAttributes");  if(fun)fun(this->GetSafeHwnd(),0,128,2);  FreeLibrary(hInst); }   稍加修改還可以作出淡出淡入的效果. 注意第三個(gè)參數(shù)(128)不要取得太小了,為0的話就完全透明,看不到了。   如何使框架窗口的圖標(biāo)為動(dòng)畫(huà)顯示   可以用TIMER,但是TIMER不能有效的定時(shí)。因?yàn)門(mén)IMER發(fā)送的是窗口消息,當(dāng)窗口忙于處理鍵盤(pán)、鼠標(biāo)等消息時(shí)就不能及時(shí)處理TIMER,會(huì)使間隔時(shí)間變得很長(zhǎng) 。   可以考慮用一個(gè)單獨(dú)得TIMER線程,用Sleep()定時(shí)來(lái)解決此問(wèn)題。 UINT Timer(LPVOID param) {  HWND hWnd=(HWND)param;  while(1)  {   Sleep(ms);   PostMessage(hWnd,CH_PICTURE,NULL,NULL)  } }   Sleep(ms)后發(fā)送自定義消息。消息處理函數(shù)就選擇某一個(gè)ICON或BITMAP來(lái)顯示。如 : MyBotton.SetBitmap((HBITMAP)Bitmap[i]);   Bitmap是一個(gè)位圖數(shù)組,存放有j個(gè)位圖。消息處理函數(shù)運(yùn)行一次,i就累加一次,當(dāng)i==j時(shí),i就回到0;   防止窗口閃爍的方法   1、將Invalidate()替換為InvalidateRect()。   Invalidate()會(huì)導(dǎo)致整個(gè)窗口的圖象重畫(huà),需要的時(shí)間比較長(zhǎng),而InvalidateRect()僅僅重畫(huà)Rect區(qū)域內(nèi)的內(nèi)容,所以所需時(shí)間會(huì)少一些。蟲(chóng)蟲(chóng)以前很懶,經(jīng)常為一小塊區(qū)域的重畫(huà)就調(diào)用Invalidate(),不愿意自己去計(jì)算需要重畫(huà)的Rect,但是事實(shí)是,如果你確實(shí)需要改善閃爍的情況,計(jì)算一個(gè)Rect所用的時(shí)間比起重畫(huà)那些不需要重畫(huà)的內(nèi)容所需要的時(shí)間要少得多。   2、禁止系統(tǒng)搽除你的窗口。   系統(tǒng)在需要重畫(huà)窗口的時(shí)候會(huì)幫你用指定的背景色來(lái)搽除窗口??墒?,也許需要重畫(huà)的區(qū)域也許非常小?;蛘?,在你重畫(huà)這些東西之間還要經(jīng)過(guò)大量的計(jì)算才能開(kāi)始。這個(gè)時(shí)候你可以禁止系統(tǒng)搽掉原來(lái)的圖象。直到你已經(jīng)計(jì)算好了所有的數(shù)據(jù),自己把那些需要搽掉的部分用背景色覆蓋掉(如:dc.FillRect(rect,&brush);rect是需要搽除的區(qū)域,brush是帶背景色的刷子),再畫(huà)上新的圖形。要禁止系統(tǒng)搽除你的窗口,可以重載OnEraseBkgnd()函數(shù),讓其直接返回TRUE就可以了。如 BOOL CMyWin::OnEraseBkgnd(CDC* pDC) { return TRUE; //return CWnd::OnEraseBkgnd(pDC);//把系統(tǒng)原來(lái)的這條語(yǔ)句注釋掉。 }   3、有效的進(jìn)行搽除。   搽除背景的時(shí)候,不要該搽不該搽的地方都搽。比如,你在一個(gè)窗口上放了一個(gè)很大的Edit框,幾乎占了整個(gè)窗口,那么你頻繁的搽除整個(gè)窗口背景將導(dǎo)致Edit不停重畫(huà)形成劇烈的閃爍。事實(shí)上你可以CRgn創(chuàng)建一個(gè)需要搽除的區(qū)域,只搽除這一部分。如 GetClientRect(rectClient); rgn1.CreateRectRgnIndirect(rectClient); rgn2.CreateRectRgnIndirect(m_rectEdit); if(rgn1.CombineRgn(&rgn1,&rgn2,RGN_XOR) == ERROR)//處理后的rgn1只包括了Edit框之外的客戶區(qū)域,這樣,Edit將不會(huì)被我的背景覆蓋而導(dǎo)致重畫(huà)。 { ASSERT(FALSE); return ; } brush.CreateSolidBrush(m_clrBackgnd); pDC->FillRgn(&rgn1,&brush); brush.DeleteObject();   注意:在使用這個(gè)方法的時(shí)候要同時(shí)使用方法二。別忘了,到時(shí)候又說(shuō)蟲(chóng)蟲(chóng)的辦法不靈。   4、使用MemoryDC先在內(nèi)存里把圖畫(huà)好,再?gòu)?fù)制到屏幕上。   這對(duì)于一次畫(huà)圖過(guò)程很長(zhǎng)的情況比較管用。畢竟內(nèi)存操作比較快,而且復(fù)制到屏幕又是一次性的,至少不會(huì)出現(xiàn)可以明顯看出一個(gè)東東從左畫(huà)到右的情況。 void CMyWin::OnPaint() { CPaintDC dc1(this); // device context for painting dcMemory.CreateCompatibleDC(&dc1); CBitmap bmp;//這里的Bitmap是必須的,否則當(dāng)心弄出一個(gè)大黑塊哦。 bmp.CreateCompatibleBitmap(&dc1,rectClient.Width(),rectClient.Height()); dcMemory.SelectObject(&bmp); //接下來(lái)你想怎么畫(huà)就怎么畫(huà)吧。 //dcMemory.FillRect(rectClient,&brush); dc1.BitBlt(0,0,rectClient.Width(),rectClient.Height(),&dcMemory,0,0,SRCCOPY); dcMemory.DeleteDC(); // Do not call CWnd::OnPaint() for painting messages }   如何實(shí)現(xiàn)全屏顯示   全屏顯示是一些應(yīng)用軟件程序必不可少的功能。比如在用VC++編輯工程源文件或編輯對(duì)話框等資源時(shí),選擇菜單“ViewFull Screen”,即可進(jìn)入全屏顯示狀態(tài),按“Esc”鍵后會(huì)退出全屏顯示狀態(tài)。   在VC++6.0中我們用AppWizard按默認(rèn)方式生成單文檔界面的應(yīng)用程序框架。下面將先討論點(diǎn)擊菜單項(xiàng)“ViewFull Screen”實(shí)現(xiàn)全屏顯示的方法,再講述按“Esc”鍵后如何退出全屏顯示狀態(tài)。   1) 在CMainFrame類(lèi)中,增加如下三個(gè)成員變量。   private:     WINDOWPLACEMENT m_OldWndPlacement; //用來(lái)保存原窗口位置     BOOL m_bFullScreen; //全屏顯示標(biāo)志     CRect m_FullScreenRect; //表示全屏顯示時(shí)的窗口位置   2)在資源編輯器中編輯菜單IDR_MAINFRAME。在“View”菜單欄下添加菜單項(xiàng)“Full Screen”。在其屬性框中,ID設(shè)置為ID_FULL_SCREEN,Caption為“Full Screen”。還可以在工具欄中添加新的工具圖標(biāo),并使之與菜單項(xiàng)“Full Screen”相關(guān)聯(lián),即將其ID值也設(shè)置為ID_FULL_SCREEN。   3)設(shè)計(jì)全屏顯示處理函數(shù),在CMainFrame類(lèi)增加上述菜單項(xiàng)ID_FULL_SCREEN消息的響應(yīng)函數(shù)。響應(yīng)函數(shù)如下:   void CMainFrame::OnFullScreen()   { GetWindowPlacement(&m_OldWndPlacement);    CRect WindowRect;    GetWindowRect(&WindowRect);    CRect ClientRect;    RepositionBars(0, 0xffff, AFX_IDW_PANE_FIRST, reposQuery, &ClientRect);    ClientToScreen(&ClientRect);    // 獲取屏幕的分辨率    int nFullWidth=GetSystemMetrics(SM_CXSCREEN);    int nFullHeight=GetSystemMetrics(SM_CYSCREEN);    // 將除控制條外的客戶區(qū)全屏顯示到從(0,0)到(nFullWidth, nFullHeight)區(qū)域, 將(0,0)和(nFullWidth, nFullHeight)兩個(gè)點(diǎn)外擴(kuò)充原窗口和除控制條之外的 客戶區(qū)位置間的差值, 就得到全屏顯示的窗口位置    m_FullScreenRect.left=WindowRect.left-ClientRect.left;    m_FullScreenRect.top=WindowRect.top-ClientRect.top;    m_FullScreenRect.right=WindowRect.right-ClientRect.right+nFullWidth;    m_FullScreenRect.bottom=WindowRect.bottom-ClientRect.bottom+nFullHeight;    m_bFullScreen=TRUE; // 設(shè)置全屏顯示標(biāo)志為 TRUE    // 進(jìn)入全屏顯示狀態(tài)    WINDOWPLACEMENT wndpl;    wndpl.length=sizeof(WINDOWPLACEMENT);    wndpl.flags=0;    wndpl.showCmd=SW_SHOWNORMAL;    wndpl.rcNormalPosition=m_FullScreenRect;    SetWindowPlacement(&wndpl); }   4)重載CMainFrame類(lèi)的OnGetMinMaxInfo函數(shù),在全屏顯示時(shí)提供全屏顯示的位置信息。   void CMainFrame::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI)   { if(m_bFullScreen)    { lpMMI->ptMaxSize.x=m_FullScreenRect.Width();    lpMMI->ptMaxSize.y=m_FullScreenRect.Height();    lpMMI->ptMaxPosition.x=m_FullScreenRect.Width();    lpMMI->ptMaxPosition.y=m_FullScreenRect.Height();    //最大的Track尺寸也要改變    lpMMI->ptMaxTrackSize.x=m_FullScreenRect.Width();    lpMMI->ptMaxTrackSize.y=m_FullScreenRect.Height();    } CFrameWnd::OnGetMinMaxInfo(lpMMI) ;   }   完成上面的編程后,可以聯(lián)編執(zhí)行FullScreen.exe,選擇菜單“ViewFull Screen”或點(diǎn)擊與之關(guān)聯(lián)的工具欄按鈕即可進(jìn)入全屏顯示狀態(tài)。但現(xiàn)在還需要增加用戶退出全屏顯示狀態(tài)的操作接口,下面講述如何編程實(shí)現(xiàn)按“Esc”鍵退出全屏顯示狀態(tài)。   1)在ClassView中選中CMainFrame并單擊鼠標(biāo)右鍵,選擇“Add Member Function...”,添加public類(lèi)型的成員函數(shù)EndFullScreen,該函數(shù)將完成退出全屏顯示的操作。   void CMainFrame::EndFullScreen()   { if(m_bFullScreen)    {// 退出全屏顯示, 恢復(fù)原窗口顯示   ShowWindow(SW_HIDE);    SetWindowPlacement(&m_OldWndPlacement); } }   2)函數(shù)EndFullScreen可以退出全屏顯示狀態(tài),問(wèn)題是如何在“Esc”鍵被按下之后調(diào)用執(zhí)行此函數(shù)。由于視圖類(lèi)可以處理鍵盤(pán)輸入的有關(guān)消息(如WM_KEYDOWN表示用戶按下了某一個(gè)鍵),我們將在視圖類(lèi)CFullScreenView中添加處理按鍵消息WM_KEYDOWN的響應(yīng)函數(shù)OnKeyDown。判斷如果按的鍵為“Esc”鍵,則調(diào)用CMainFrame類(lèi)的函數(shù)EndFullScreen,便可退出全屏顯示狀態(tài)。   void CFullScreenView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)   { if(nChar==VK_ESCAPE) // 如果按的鍵為Esc鍵    {// 獲取主框架窗口的指針    CMainFrame *pFrame=(CMainFrame*)AfxGetApp()->m_pMainWnd;    // 調(diào)用主窗口類(lèi)的自定義函數(shù) EndFullScreen ,便可退出全屏顯示狀態(tài)   pFrame->EndFullScreen(); }   CView::OnKeyDown(nChar, nRepCnt, nFlags); }   更改窗口圖標(biāo)并將其顯示在任務(wù)欄   以下兩個(gè)函數(shù)可以為應(yīng)用程序中的各子窗口顯示一個(gè)任務(wù)條到任務(wù)欄并更改它們的圖標(biāo)。對(duì)那些象QQ一樣隱藏主窗口的應(yīng)用程序特別有用。 //函數(shù)用途:更改一個(gè)窗口的圖標(biāo)并將其顯示在任務(wù)欄、任務(wù)切換條、任務(wù)管理器里 //參數(shù)說(shuō)明: //hWnd 要改變圖標(biāo)的窗口句柄 //hLargeIcon 顯示到任務(wù)切換條上的圖標(biāo) 32*32 //hSmallIcon 顯示到除任務(wù)切換條之外的圖標(biāo) 16*16 //hIcon 顯示的圖標(biāo),32*32,在顯示到任務(wù)切換條之外的其余地方時(shí)會(huì)被自動(dòng)壓縮成16*16的。 //注釋?zhuān)? //此函數(shù)對(duì)于模式對(duì)話框無(wú)能為力。 //如果HICON 為NULL,函數(shù)不改變窗口圖標(biāo),但是將原有圖標(biāo)顯示到任務(wù)欄、 // 任務(wù)切換條、任務(wù)管理器里。 //此函數(shù)是通過(guò)將窗口的父窗口指針置空來(lái)實(shí)現(xiàn)將圖標(biāo)顯示到任務(wù)欄、任務(wù)切換條、 // 任務(wù)管理器里的,所以調(diào)用完成后,其父窗口指針不再可用。 BOOL SendWndIconToTaskbar(HWND hWnd,HICON hLargeIcon,HICON hSmallIcon); BOOL SendWndIconToTaskbar(HWND hWnd,HICON hIcon); BOOL CUIApp::SendWndIconToTaskbar(HWND hWnd,HICON hLargeIcon,HICON hSmallIcon) {  BOOL ret = TRUE;  ASSERT(hWnd);  if(!::IsWindow(hWnd))   return FALSE;  //獲取窗口指針  CWnd* pWnd;  pWnd = pWnd->FromHandle(hWnd);  ASSERT(pWnd);  if(!pWnd)   return FALSE;  //將父窗口設(shè)為NULL  if(pWnd->GetParent())   if(::SetWindowLong(hWnd,GWL_HWNDPARENT,NULL) == 0)    return FALSE;   if(!(pWnd->ModifyStyle(NULL,WS_OVERLAPPEDWINDOW)))    ret = FALSE;   //設(shè)置窗口圖標(biāo)   if(hLargeIcon && hSmallIcon)   {    pWnd->SetIcon(hSmallIcon,FALSE);    pWnd->SetIcon(hLargeIcon,TRUE);   }   return ret;  } BOOL CUIApp::SendWndIconToTaskbar(HWND hWnd,HICON hIcon) {  BOOL ret = TRUE;  ASSERT(hWnd);  if(!::IsWindow(hWnd))   return FALSE;   //獲取窗口指針  CWnd* pWnd;  pWnd = pWnd->FromHandle(hWnd);  ASSERT(pWnd);  if(!pWnd)   return FALSE;  //將父窗口設(shè)為NULL  if(pWnd->GetParent())   if(::SetWindowLong(hWnd,GWL_HWNDPARENT,NULL) == 0)    return FALSE;  if(!(pWnd->ModifyStyle(NULL,WS_OVERLAPPEDWINDOW)))   ret = FALSE;  //設(shè)置窗口圖標(biāo)  pWnd->SetIcon(hIcon,TRUE);  pWnd->SetIcon(hIcon,FALSE);  return ret; }   如何隱藏應(yīng)用程序在任務(wù)欄上的顯示   對(duì)于CFrameWnd可以在PreCreateWindow()函數(shù)中修改窗口的風(fēng)格。 BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs) { cs.style |=WS_POPUP;//使主窗口不可見(jiàn) cs.dwExStyle |=WS_EX_TOOLWINDOW;//不顯示任務(wù)按鈕 return CFrameWnd::PreCreateWindow(cs); }   對(duì)于其他窗口,可以在窗口被Create出來(lái)之后ShowWindow之前使用ModifyStyle()和ModifyStyleEx()來(lái)修改它的風(fēng)格。   如何控制窗口框架的最大最小尺寸?   要控制一個(gè)框架的的最大最小尺寸,你需要做兩件事情。   第一步:在CFrameWnd的繼承類(lèi)中處理消息WM_GETMINMAXINFO,結(jié)構(gòu)MINMAXINFO設(shè)置了整個(gè)窗口類(lèi)的限制,因此記住要考慮工具條,滾動(dòng)條等等的大小。 // 最大最小尺寸的象素點(diǎn) - 示例 #define MINX 200 #define MINY 300 #define MAXX 300 #define MAXY 400 void CMyFrameWnd::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI) {  CRect rectWindow;  GetWindowRect(&rectWindow);  CRect rectClient;  GetClientRect(&rectClient);  // get offset of toolbars, scrollbars, etc.  int nWidthOffset = rectWindow.Width() - rectClient.Width();  int nHeightOffset = rectWindow.Height() - rectClient.Height();  lpMMI->ptMinTrackSize.x = MINX + nWidthOffset;  lpMMI->ptMinTrackSize.y = MINY + nHeightOffset;  lpMMI->ptMaxTrackSize.x = MAXX + nWidthOffset;  lpMMI->ptMaxTrackSize.y = MAXY + nHeightOffset; }   第二步:在CFrameWnd的繼承類(lèi)的PreCreateWindow函數(shù)中去掉WS_MAXIMIZEBOX消息,否則在最大化時(shí)你將得不到預(yù)料的結(jié)果. BOOL CMyFrameWnd::PreCreateWindow(CREATESTRUCT& cs) {  cs.style &= ~WS_MAXIMIZEBOX;  return CFrameWnd::PreCreateWindow(cs); }   如何修改frame窗口的背景顏色?   MDI窗口的客戶區(qū)是由frame窗口擁有的另一個(gè)窗口覆蓋的。為了改變frame窗口背景的顏色,只需要這個(gè)客戶區(qū)的背景顏色就可以了。你必須自己處理WM_ERASEBKND消息。下面是工作步驟:   創(chuàng)建一個(gè)從CWnd類(lèi)繼承的類(lèi),就叫它CMDIClient吧;   在CMDIFrameWnd中加入CMDIClient變量;(具體情況看下面的代碼) #include "MDIClient.h" class CMainFrame : public CMDIFrameWnd { ... protected: CMDIClient m_wndMDIClient; }   重載CMDIFrameWnd::OnCreateClient,下面是這段代碼,請(qǐng)注意其中的SubclassWindow(); BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext) { if ( CMDIFrameWnd::OnCreateClient(lpcs, pContext) ) { m_wndMDIClient.SubclassWindow(m_hWndMDIClient); return TRUE; } else return FALSE; }   最后要在CMDIClient中加入處理WM_ERASEBKGND的函數(shù)。   如何改變view的背景顏色?   若要改變CView,CFrameWnd或CWnd對(duì)象的背景顏色需要處理WM_ERASEBKGND消息,下面就是一個(gè)范例代碼: BOOL CSampleView::OnEraseBkgnd(CDC* pDC) { //設(shè)置brush為希望的背景顏色 CBrush backBrush(RGB(255, 128, 128)); //保存舊的brush CBrush* pOldBrush = pDC->SelectObject(&backBrush); CRect rect; pDC->GetClipBox(&rect); //畫(huà)需要的區(qū)域 pDC->PatBlt(rect.left, rect.top, rect.Width(), rect.Height(), PATCOPY); pDC->SelectObject(pOldBrush); return TRUE; }   若要改變CFromView繼承類(lèi)的背景顏色,下面是一個(gè)范例代碼: HBRUSH CMyFormView::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) {  switch (nCtlColor)  {   case CTLCOLOR_BTN:   case CTLCOLOR_STATIC:   {    pDC->SetBkMode(TRANSPARENT);    //不加任何處理或設(shè)置背景為透明   }   case CTLCOLOR_DLG:   {    CBrush* back_brush;    COLORREF color;    color = (COLORREF) GetSysColor(COLOR_BTNFACE);    back_brush = new CBrush(color);    return (HBRUSH) (back_brush->m_hObject);   }  }  return(CFormView::OnCtlColor(pDC, pWnd, nCtlColor)); } 在任務(wù)欄狀態(tài)區(qū)如何顯示應(yīng)用程序圖標(biāo)   有關(guān)的數(shù)據(jù)由NOTIFYICONDATA結(jié)構(gòu)描述: typedef struct _NOTIFYICONDATA { DWORD cbSize; //結(jié)構(gòu)的大小,必須設(shè)置 HWND hWnd; //接受回調(diào)消息的窗口的句柄 UINT uID; //應(yīng)用程序定義的圖標(biāo)標(biāo)志 UINT uFlags; //標(biāo)志,可以是NIF_ICON、NIF_MESSAGE、NIF_TIP或其組合 UINT uCallbackMessage;//應(yīng)用程序定義的回調(diào)消息標(biāo)志 HICON hIcon; //圖標(biāo)句柄 char szTip[64]; //提示字串 } NOTIFYICONDATA, *PNOTIFYICONDATA;   函數(shù)說(shuō)明   由Shell_NotifyIcon()函數(shù)向系統(tǒng)發(fā)送添加、刪除、更改圖標(biāo)的消息。 WINSHELLAPI BOOL WINAPI Shell_NotifyIcon(DWORD dwMessage,PNOTIFYICONDATA pnid);   DwMessage為所發(fā)送消息的標(biāo)志:    NIM_ADD 添加圖標(biāo)到任務(wù)欄通知區(qū);    NIM_DELETE 刪除任務(wù)欄通知區(qū)的圖標(biāo);    NIM_MODIFY 更改任務(wù)欄通知區(qū)的圖標(biāo)、回調(diào)消息標(biāo)志、回調(diào)窗口句柄或提示字串;    pnid為NOTIFYICONDATA結(jié)構(gòu)的指針。   回調(diào)信息的獲得及處理   如果一個(gè)任務(wù)欄圖標(biāo)有應(yīng)用程序定義的回調(diào)消息,那么當(dāng)這個(gè)圖標(biāo)有鼠標(biāo)操作時(shí),系統(tǒng)將給hWnd所標(biāo)志的窗口發(fā)送下列的消息: messageID = uCallbackMessage wParam = uID lParam = mouse event(例如WM_LBUTTONDOWN)   通過(guò)這種方式,系統(tǒng)通知應(yīng)用程序用戶對(duì)圖標(biāo)的操作。如果一個(gè)應(yīng)用程序生成了兩個(gè)以上的圖標(biāo),那么你可以根據(jù)wParam來(lái)判斷是哪個(gè)圖標(biāo)返回的鼠標(biāo)操作。通常,標(biāo)準(zhǔn)的Win95任務(wù)欄圖標(biāo)有以下鼠標(biāo)操作響應(yīng):   當(dāng)鼠標(biāo)停留在圖標(biāo)上時(shí),系統(tǒng)應(yīng)顯示提示信息tooltip;   當(dāng)使用鼠標(biāo)右鍵單擊圖標(biāo)時(shí),應(yīng)用程序應(yīng)顯示快捷菜單;   當(dāng)使用鼠標(biāo)左鍵雙擊圖標(biāo)時(shí),應(yīng)用程序應(yīng)執(zhí)行快捷菜單的缺省菜單項(xiàng)。   在Microsoft Windows環(huán)境中,0x8000到0xBFFF的消息是保留的,應(yīng)用程序可以定義自定義消息。   關(guān)于消息處理的詳細(xì)內(nèi)容,請(qǐng)參考下一部分。   源碼及實(shí)現(xiàn)   在本文中關(guān)于任務(wù)欄圖標(biāo)的類(lèi)叫做CTrayIcon,這個(gè)類(lèi)由CCmdTarget(或CObject)類(lèi)派生,它有如下的成員變量和成員函數(shù): // TrayIcon.h // CTrayIcon command target class CTrayIcon : public CCmdTarget { public: NOTIFYICONDATA m_nid;//NOTIFYICONDATA結(jié)構(gòu),你的圖標(biāo)要用的啊 BOOL m_IconExist;//標(biāo)志,看看圖標(biāo)是不是已經(jīng)存在了 CWnd* m_NotificationWnd;//接受回調(diào)消息的窗口,有它就不必經(jīng)常AfxGetMainWnd了 public: CWnd* GetNotificationWnd() const;//得到m_NotificationWnd BOOL SetNotificationWnd(CWnd* pNotifyWnd);//設(shè)置(更改)m_NotificationWnd CTrayIcon();//構(gòu)造函數(shù) virtual ~CTrayIcon();//析構(gòu)函數(shù) BOOL CreateIcon(CWnd* pNotifyWnd, UINT uID, HICON hIcon, LPSTR lpszTip, UINT CallBackMessage);//在任務(wù)欄上生成圖標(biāo) BOOL DeleteIcon();//刪除任務(wù)欄上的圖標(biāo) virtual LRESULT OnNotify(WPARAM WParam, LPARAM LParam);//消息響應(yīng)函數(shù) BOOL SetTipText(UINT nID);//設(shè)置(更改)提示字串 BOOL SetTipText(LPCTSTR lpszTip);//設(shè)置(更改)提示字串 BOOL ChangeIcon(HICON hIcon);//更改圖標(biāo) BOOL ChangeIcon(UINT nID);//更改圖標(biāo) BOOL ChangeIcon(LPCTSTR lpszIconName);//更改圖標(biāo) BOOL ChangeStandardIcon(LPCTSTR lpszIconName);//更改為標(biāo)準(zhǔn)圖標(biāo) ...... };   下面是成員函數(shù)的定義: // TrayIcon.cpp // CTrayIcon CTrayIcon::CTrayIcon() {//初始化參數(shù) m_IconExist = FALSE; m_NotificationWnd = NULL; memset(&m_nid, 0, sizeof(m_nid)); m_nid.cbSize = sizeof(m_nid);//這個(gè)參數(shù)不會(huì)改變 } CTrayIcon::~CTrayIcon() { if (m_IconExist) DeleteIcon();//刪除圖標(biāo) } BOOL CTrayIcon::CreateIcon(CWnd* pNotifyWnd, UINT uID, HICON hIcon, LPSTR lpszTip, UINT CallBackMessage) { //確定接受回調(diào)消息的窗口是有效的 ASSERT(pNotifyWnd && ::IsWindow(pNotifyWnd->GetSafeHwnd())); ASSERT(CallBackMessage >= WM_USER);//確定回調(diào)消息不發(fā)生沖突 ASSERT(_tcslen(lpszTip) <= 64);//提示字串不能超過(guò)64個(gè)字符 m_NotificationWnd = pNotifyWnd;//獲得m_NotificationWnd //設(shè)置NOTIFYICONDATA結(jié)構(gòu) m_nid.hWnd = pNotifyWnd->GetSafeHwnd(); m_nid.uID = uID; m_nid.hIcon = hIcon; m_nid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP; m_nid.uCallbackMessage = CallBackMessage; //設(shè)置NOTIFYICONDATA結(jié)構(gòu)的提示字串 if (lpszTip) lstrcpyn(m_nid.szTip, lpszTip, sizeof(m_nid.szTip)); else m_nid.szTip[0] = '\0'; //顯示圖標(biāo) m_IconExist = Shell_NotifyIcon(NIM_ADD, &m_nid); return m_IconExist; } BOOL CTrayIcon::DeleteIcon() {//刪除圖標(biāo) if (!m_IconExist) return FALSE; m_IconExist = FALSE; return Shell_NotifyIcon(NIM_DELETE, &m_nid); } LRESULT CTrayIcon::OnNotify(WPARAM WParam, LPARAM LParam) {//處理圖標(biāo)返回的消息 if (WParam != m_nid.uID)//如果不是該圖標(biāo)的消息則迅速返回 return 0L; //準(zhǔn)備快捷菜單 CMenu menu; if (!menu.LoadMenu(IDR_POPUP))//你必須確定資源中有ID為IDR_POPUP的菜單 return 0; CMenu* pSubMenu = menu.GetSubMenu(0);//獲得IDR_POPUP的子菜單 if (!pSubMenu) return 0; if (LParam == WM_RBUTTONUP) {//右鍵單擊彈出快捷菜單 //設(shè)置第一個(gè)菜單項(xiàng)為缺省 ::SetMenuDefaultItem(pSubMenu->m_hMenu, 0, TRUE); CPoint pos; GetCursorPos(&pos); //顯示并跟蹤菜單 m_NotificationWnd->SetForegroundWindow(); pSubMenu->TrackPopupMenu(TPM_RIGHTALIGN|TPM_LEFTBUTTON |TPM_RIGHTBUTTON, pos.x, pos.y, m_NotificationWnd, NULL); } else if (LParam == WM_LBUTTONDOWN) {//左鍵單擊恢復(fù)窗口 m_NotificationWnd->ShowWindow(SW_SHOW);//恢復(fù)窗口 m_NotificationWnd->SetForegroundWindow();//放置在前面 } else if (LParam == WM_LBUTTONDBLCLK) {//左鍵雙擊執(zhí)行缺省菜單項(xiàng) m_NotificationWnd->SendMessage(WM_COMMAND, pSubMenu->GetMenuItemID(0), 0); } return 1L; } BOOL CTrayIcon::SetTipText(LPCTSTR lpszTip) {//設(shè)置提示文字 if (!m_IconExist) return FALSE; _tcscpy(m_nid.szTip, lpszTip); m_nid.uFlags |= NIF_TIP; return Shell_NotifyIcon(NIM_MODIFY, &m_nid); } BOOL CTrayIcon::SetTipText(UINT nID) {//設(shè)置提示文字  CString szTip;  VERIFY(szTip.LoadString(nID));  return SetTipText(szTip); } BOOL CTrayIcon::ChangeIcon(HICON hIcon) {//更改圖標(biāo) if (!m_IconExist) return FALSE; m_nid.hIcon = hIcon; m_nid.uFlags |= NIF_ICON; return Shell_NotifyIcon(NIM_MODIFY, &m_nid); } BOOL CTrayIcon::ChangeIcon(UINT nID) {//更改圖標(biāo)  HICON hIcon = AfxGetApp()->LoadIcon(nID);  return ChangeIcon(hIcon); } BOOL CTrayIcon::ChangeIcon(LPCTSTR lpszIconName) {//更改圖標(biāo)  HICON hIcon = AfxGetApp()->LoadIcon(lpszIconName);  return ChangeIcon(hIcon); } BOOL CTrayIcon::ChangeStandardIcon(LPCTSTR lpszIconName) {//更改為標(biāo)準(zhǔn)圖標(biāo)  HICON hIcon = AfxGetApp()->LoadStandardIcon(lpszIconName);  return ChangeIcon(hIcon); } BOOL CTrayIcon::SetNotificationWnd(CWnd * pNotifyWnd) {//設(shè)置接受回調(diào)消息的窗口  if (!m_IconExist)   return FALSE;  //確定窗口是有效的  ASSERT(pNotifyWnd && ::IsWindow(pNotifyWnd->GetSafeHwnd()));  m_NotificationWnd = pNotifyWnd;  m_nid.hWnd = pNotifyWnd->GetSafeHwnd();  m_nid.uFlags |= NIF_MESSAGE;  return Shell_NotifyIcon(NIM_MODIFY, &m_nid); } CWnd* CTrayIcon::GetNotificationWnd() const {//返回接受回調(diào)消息的窗口  return m_NotificationWnd; }   三點(diǎn)補(bǔ)充:   關(guān)于使用回調(diào)消息的補(bǔ)充說(shuō)明:   首先,在MainFrm.cpp中加入自己的消息代碼; // MainFrm.cpp : implementation of the CMainFrame class // #define MYWM_ICONNOTIFY WM_USER + 10//定義自己的消息代碼   第二步增加消息映射和函數(shù)聲明,對(duì)于自定義消息不能由ClassWizard添加消息映射,只能手工添加。 // MainFrm.cpp : implementation of the CMainFrame class BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWnd) //{{AFX_MSG_MAP(CMainFrame) //其他的消息映射 ...... //}}AFX_MSG_MAP ON_MESSAGE(WM_ICONNOTIFY,OnNotify) END_MESSAGE_MAP() 并且在頭文件中添加函數(shù)聲明 // MainFrm.h afx_msg LRESULT OnNotify(WPARAM WParam, LPARAM LParam);   第三步增加消息處理函數(shù)定義 LRESULT CMainFrame::OnNotify(WPARAM WParam, LPARAM LParam) { return trayicon.OnNotify(WParam, LParam);//調(diào)用CTrayIcon類(lèi)的處理函數(shù) }   如何隱藏任務(wù)欄上的按鈕   可以使用下列兩種方法:   1.在CreateWindowEx函數(shù)中使用WS_EX_TOOLWINDOW窗口式樣(相反的如果要確保應(yīng)用程序在任務(wù)欄上生成按鈕,可以使用WS_EX_APPWINDOW窗口式樣)。 The problem with this is that the window decorations are as for a small floating toolbar, which isn't normally what's wanted.   2.生成一個(gè)空的隱藏的top-level窗口,并使其作為可視窗口的父窗口。   3.在應(yīng)用程序的InitInstance()函數(shù)中使用SW_HIDE式樣調(diào)用ShowWindow()函數(shù)。 //pMainFrame->ShowWindow(m_nCmdShow); pMainFrame->ShowWindow(SW_HIDE); pMainFrame->UpdateWindow();   如何動(dòng)畫(huà)任務(wù)欄上的圖標(biāo)   在TrayIcon類(lèi)中加入下列兩個(gè)函數(shù): BOOL CTrayIcon::SetAnimateIcons(HICON* hIcon, UINT Number) {//設(shè)置動(dòng)畫(huà)圖標(biāo)  ASSERT(Number >= 2);//圖標(biāo)必須為兩個(gè)以上  ASSERT(hIcon);//圖標(biāo)必須不為空  m_AnimateIcons = new HICON[Number];  CopyMemory(m_AnimateIcons, hIcon, Number * sizeof(HICON));  m_AnimateIconsNumber = Number;  return TRUE; } BOOL CTrayIcon::Animate(UINT Index) {//動(dòng)畫(huà)TrayIcon  UINT i = Index % m_AnimateIconsNumber;  return ChangeIcon(m_AnimateIcons[i]); }   怎樣在應(yīng)用程序中添加相應(yīng)的菜單和函數(shù) void CMainFrame::OnMenuAnimate() {//動(dòng)畫(huà)TrayIcon,設(shè)置圖標(biāo)及定時(shí)器  SetTimer(1, 500, NULL);  HICON hIcon[3];  hIcon[0] = AfxGetApp()->LoadIcon(IDR_MAINFRAME);  hIcon[1] = AfxGetApp()->LoadIcon(IDR_MYTURNTYPE);  hIcon[2] = AfxGetApp()->LoadStandardIcon(IDI_HAND);  trayicon.SetAnimateIcons(hIcon, 3); } void CMainFrame::OnTimer(UINT nIDEvent) {//動(dòng)畫(huà)TrayIcon  UINT static i;  i += 1;  trayicon.Animate(i);  CMDIFrameWnd::OnTimer(nIDEvent); }

            posted on 2006-02-10 11:13 tqsheng 閱讀(284) 評(píng)論(0)  編輯 收藏 引用

            青青草原精品99久久精品66| 欧美黑人激情性久久| 精品久久久久久国产91| 国产精品久久免费| 久久无码精品一区二区三区| 天天影视色香欲综合久久| 欧美午夜精品久久久久免费视 | 一本色综合网久久| 久久99精品国产自在现线小黄鸭| 青青久久精品国产免费看| 久久99精品久久久大学生| 亚洲色欲久久久久综合网| 久久久精品久久久久久| 狠狠色丁香久久综合婷婷| 女同久久| 国产成人精品综合久久久| 人妻无码αv中文字幕久久琪琪布 人妻无码久久一区二区三区免费 人妻无码中文久久久久专区 | 区久久AAA片69亚洲| 久久久久亚洲?V成人无码| 久久人人爽人人爽人人AV东京热 | 性做久久久久久久| 亚洲AV日韩精品久久久久久久| 久久免费国产精品一区二区| 国产99久久久久久免费看| 囯产极品美女高潮无套久久久 | 精品免费久久久久国产一区| 99热都是精品久久久久久| 亚洲精品无码久久久久| 久久91精品国产91| 久久精品免费大片国产大片| 1000部精品久久久久久久久| 亚洲精品乱码久久久久久按摩| 久久亚洲国产成人影院| 精品国产婷婷久久久| 狠狠色丁香久久婷婷综| 国产精品久久久久天天影视| www性久久久com| 国内精品久久久久| 51久久夜色精品国产| 伊人久久大香线蕉成人| 欧美精品一区二区久久|