mfc 對話框常用小技巧

1. 在任務欄隱藏對話框


      ModifyStyleEx(WS_EX_APPWINDOW, WS_EX_TOOLWINDOW);


2. 使對話框爲頂層窗口


        SetWindowPos(&this->wndTopMost, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);


3. 在運行時添加最大化,最小化按鈕


    SetWindowLong(this->m_hWnd, GWL_STYLE,
                  GetWindowLong(this->m_hWnd, GWL_STYLE) |
                  WS_MINIMIZEBOX | WS_MAXIMIZEBOX); 
     UpdateWindow();




4. 使能對話框右上角關閉按鈕




    在OnInitDialog中


    方法一:
       CMenu* menu = GetSystemMenu(FALSE);
       menu->ModifyMenu(SC_CLOSE, MF_BYCOMMAND | MF_GRAYED );


    方法二:
       CMenu* menu = GetSystemMenu(FALSE);
       menu->EnableMenuItem(SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);


5. 當對話框一部分在屏幕外時,顯示全部對話框


    SendMessage(DM_REPOSITION);


6. 改變鼠標外形




    添加 WM_SETCURSOR 消息映射函數


    BOOL CTest6Dlg::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
    {
         SetCursor(AfxGetApp()->LoadStandardCursor(IDC_HELP));


         return 0;  
    }


7. 改變對話框背景色和文本顏色




    在CTest6App的InitInstance中添加


    SetDialogBkColor(RGB(255,0,0), RGB(0,255,0));


8. 改變對話框caption上的圖標




    導入自己的圖標資源到工程中,把原來ID爲 IDR_MAINFRAME 的資源刪除,把新的圖標的ID命名爲IDR_MAINFRAME


9. 在主對話框顯示前,顯示一個login對話框


     BOOL CTest6App::InitInstance()
     {
          //...
          int nResponse;
          CLoginDlg loginDlg;


          nResponse = loginDlg.DoModal();
          if (nResponse == IDOK)
          {
          }
          if (nResponse == IDCANCEL)
          {
               return FALSE;
          }
  
          CTest6Dlg dlg;
          m_pMainWnd = &dlg;
          int nResponse = dlg.DoModal();
          if (nResponse == IDOK )
          {
          }
          else if (nResponse == IDCANCEL)
          {
          }
          return FALSE;
     }


然後重載CLoginDlg對話框的哦OnOK(),在其中判斷條件
void CLoginDlg::OnOK() 
{
     if (條件滿足)
        CDialog::OnOK();
     else 
        AfxMessageBox(_T("invalid password!"));
}




10. 在對話框中添加工具欄


    方法一:添加以下代碼到 OnInitDialog 中
 
     if ( !m_wndToolBar.Create(this) || !m_wndToolBar.LoadToolBar(IDR_TOOLBAR1) )
     {
          TRACE0("Failed to Create Dialog Toolbar\n");
          EndDialog(IDCANCEL);
     }


     CRect rcClientOld; // 久客戶區RECT
     CRect rcClientNew; // 加入TOOLBAR後的CLIENT RECT
     GetClientRect(rcClientOld); //
     // Called to reposition and resize control bars in the client area of a window
     // The reposQuery FLAG does not really traw the Toolbar.  It only does the calculations.
     // And puts the new ClientRect values in rcClientNew so we can do the rest of the Math.
     //重新計算RECT大小
     RepositionBars(AFX_IDW_CONTROLBAR_FIRST,
                       AFX_IDW_CONTROLBAR_LAST,
                       0,
                       reposQuery,
                       rcClientNew);


    // All of the Child Windows (Controls) now need to be moved so the Tollbar does not cover them up.
     //所有的子窗口將被移動,以免被TOOLBAR覆蓋
     // Offest to move all child controls after adding Tollbar
     //計算移動的距離
     CPoint ptOffset(rcClientNew.left-rcClientOld.left,
       rcClientNew.top-rcClientOld.top);


     CRect rcChild;
     CWnd* pwndChild = GetWindow(GW_CHILD);  //得到子窗口
     while(pwndChild) // 處理所有子窗口
     {
          //移動所有子窗口
         pwndChild->GetWindowRect(rcChild);
          ScreenToClient(rcChild);
          rcChild.OffsetRect(ptOffset);
          pwndChild->MoveWindow(rcChild,FALSE);
          pwndChild = pwndChild->GetNextWindow();
     }


     CRect rcWindow;
     GetWindowRect(rcWindow); // 得到對話框RECT
     rcWindow.right += rcClientOld.Width() - rcClientNew.Width(); // 修改對話框尺寸
     rcWindow.bottom += rcClientOld.Height() - rcClientNew.Height();
     MoveWindow(rcWindow,FALSE); // Redraw Window
RepositionBars(AFX_IDW_CONTROLBAR_FIRST,AFX_IDW_CONTROLBAR_LAST,0);


    方法二:


    http://www.codeproject.com/dialog/dlgtoolstatusbar.asp


11.響應對話框的最大化、最小化、關閉、恢復事件


     方法一:添加 WM_SYSCOMMAND 消息映射函數


     void CTest6Dlg::OnSysCommand(UINT nID, LPARAM lParam)
     {
          if ( (nID & 0xFFF0) == IDM_ABOUTBOX )
          {
               CAboutDlg dlgAbout;
               dlgAbout.DoModal();
      }
     else
     {
          if ( nID == SC_MAXIMIZE )
          {
               AfxMessageBox(_T("最大化"));
          }
          else if ( nID == SC_MINIMIZE )  
          {
               AfxMessageBox(_T("最小化"));
          }
          else if ( nID == SC_CLOSE )
          {
               AfxMessageBox(_T("關閉"));
          }


          CDialog::OnSysCommand(nID, lParam);
    }


     方法二:添加 WM_SIZE 消息映射函數


     void CTest6Dlg::OnSize(UINT nType, int cx, int cy)
     {
          CDialog::OnSize(nType, cx, cy);


          if ( nType == SIZE_MAXIMIZED )
          {
               AfxMessageBox(_T("最大化"));
          }
          else if ( nType == SIZE_MINIMIZED )
          {
               AfxMessageBox(_T("最小化"));
          }  
          else if ( nType == SIZE_RESTORED )
          {
               AfxMessageBox(_T("恢復"));
          }
     }


12.代碼實現窗口最小化,最大化,關閉


PostMessage(WM_SYSCOMMAND,  SC_MINIMIZE);
PostMessage(WM_SYSCOMMAND,  SC_MAXIMIZE);
PostMessage(WM_SYSCOMMAND,  SC_CLOSE);


13.按下ESC和ENTER鍵時禁止關閉對話框


    方法一:


     (1) 重載OnCancel和OnOk,屏蔽其中的CDialog::OnCancel()和CDialog::OnOk();
     (2) 添加以下代碼 
     void CTest6Dlg::OnSysCommand(UINT nID, LPARAM lParam)
     {
         if ((nID & 0xFFF0) == IDM_ABOUTBOX)
          {
             CAboutDlg dlgAbout;   //if you have an about dialog
              dlgAbout.DoModal();
          }
          else if ((nID & 0xFFF0) == SC_CLOSE)
          {
              //用戶點擊右上角"X"
              EndDialog(IDOK);  
       
          }
          else
          {
              CDialog::OnSysCommand(nID, lParam);
          }
     }


    方法二:


     BOOL CTest6Dlg::PreTranslateMessage(MSG* pMsg)
     {
          if ( pMsg->message == WM_KEYDOWN )
          {
               switch(pMsg->wParam)
               {
               case VK_ESCAPE:
                return TRUE; //直接返回TRUE
                break;
               case VK_RETURN:
                return TRUE;
                break;
               }
          }
          return CDialog::PreTranslateMessage(pMsg);
     }


     方法三:
         Q122489:
         How to Disable Default Pushbutton Handling for MFC Dialog
         http://support.microsoft.com/kb/122489/en-us


14.在對話框中處理鍵盤鼠標消息


處理PreTranslateMessage消息


以下代碼示例只演示了鍵盤WM_KEYDOWN消息,你也可以處理鼠標消息,比如WM_LBUTTONDOWN,WM_LBUTTONUP,WM_RBUTTONDOWN等。


BOOL CTest6Dlg::PreTranslateMessage(MSG* pMsg)  

   
     
     
    if ( pMsg->message == WM_KEYDOWN ) 
    {         
        switch( pMsg->wParam ) 
        { 
        case VK_RETURN: 
            CEdit *pEdit = (CEdit*)m_combo1.GetWindow(GW_CHILD); 
            if(pMsg->hwnd == pEdit->m_hWnd ) 
            {  
                 AfxMessageBox("在combobox的edit中按下了Enter!"); 
            }             
            return TRUE; 
        } 
    } 
 
     
     
   
    if( pMsg->message == WM_SYSKEYDOWN ) 
    {    
        switch( pMsg->wParam ) 
        { 
        case VK_F1:     
            if(::GetKeyState(VK_MENU) < 0)//ALT+F1
            { 
                AfxMessageBox("按下了ALT+F1"); 
                return TRUE; 
            }             
        }         
    } 
    
     
     
     
    if( pMsg->message == WM_KEYDOWN ) 
    {    
        if(pMsg->hwnd == GetDlgItem(IDC_LIST1)->m_hWnd) 
        { 
            switch( pMsg->wParam ) 
            { 
            case 65://A     
              if(::GetKeyState(VK_CONTROL) < 0)//Shift+enter 
              { 
                    for(int i=0; i<m_list.GetItemCount(); i++) 
                    { 
                        m_list.SetItemState(i, LVIS_SELECTED|LVIS_FOCUSED, 
                                            LVIS_SELECTED|LVIS_FOCUSED); 
                    } 
              } 
              return TRUE; 
            } 
        } 
    }  
 
     
     
         
    if(pMsg->message == WM_RBUTTONDOWN) 
    { 
        CEdit *pEdit = (CEdit*)m_combo1.GetWindow(GW_CHILD); 
        if(pMsg->hwnd == pEdit->m_hWnd) 
        { 
            DWORD dwPos = GetMessagePos(); 
            CPoint point( LOWORD(dwPos), HIWORD(dwPos) ); 
            ScreenToClient(&point); 
            ClientToScreen(&point); 
             
            CMenu menu; 
            VERIFY( menu.LoadMenu( IDR_MENU1 ) ); 
            CMenu* popup = menu.GetSubMenu(0); 
            ASSERT( popup != NULL ); 
            popup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, this ); 
        }         
    } 
 
    return CDialog::PreTranslateMessage(pMsg); 
}


15.對話框啓動即隱藏


    添加 WM_SHOWWINDOW 的消息映射


     void CTest6Dlg::OnShowWindow(BOOL bShow, UINT nStatus)
     {
          if ( GetStyle() & WS_VISIBLE )
          {
               CDialog::OnShowWindow(bShow, nStatus);
          }
          else
          {
               long Style = ::GetWindowLong(*this, GWL_STYLE);
               ::SetWindowLong(*this, GWL_STYLE, Style | WS_VISIBLE);
               CDialog::OnShowWindow(SW_HIDE, nStatus);
          }
     }


16.對話框自動停靠在屏幕邊


    const int DETASTEP = 50;
     BOOL AdjustPos(CWnd *pWnd, CRect* lpRect)
     {
        //自動靠邊
        int iSX = GetSystemMetrics(SM_CXFULLSCREEN);
        int iSY = GetSystemMetrics(SM_CYFULLSCREEN);
        RECT rWorkArea;
        BOOL bResult = SystemParametersInfo(SPI_GETWORKAREA, sizeof(RECT), &rWorkArea, 0);


        CRect rcWA;
        if ( !bResult )
        {
            //如果調用不成功就利用GetSystemMetrics獲取屏幕面積
            rcWA = CRect(0,0,iSX,iSY);
        }
        else
            rcWA = rWorkArea;


        int iX = lpRect->left;
        int iY = lpRect->top;
        if ( iX < rcWA.left + DETASTEP && iX!=rcWA.left )
        {
            //調整左
            pWnd->SetWindowPos(NULL,rcWA.left,iY,0,0,SWP_NOSIZE);
            lpRect->OffsetRect(rcWA.left-iX,0);
            AdjustPos(lpRect);
            return TRUE;
        }
        if ( iY < rcWA.top + DETASTEP && iY!=rcWA.top )
        {
            //調整上
            pWnd->SetWindowPos(NULL ,iX,rcWA.top,0,0,SWP_NOSIZE);
            lpRect->OffsetRect(0,rcWA.top-iY);
            AdjustPos(lpRect);
            return TRUE;
        }
        if ( iX + lpRect->Width() > rcWA.right - DETASTEP && iX !=rcWA.right-lpRect->Width() )
        {
            //調整右
            pWnd->SetWindowPos(NULL ,rcWA.right-rcW.Width(),iY,0,0,SWP_NOSIZE);
            lpRect->OffsetRect(rcWA.right-lpRect->right,0);
            AdjustPos(lpRect);
            return TRUE;
        }
        if ( iY + lpRect->Height() > rcWA.bottom - DETASTEP && iY !=rcWA.bottom-lpRect->Height() )
        {
            //調整下
            pWnd->SetWindowPos(NULL ,iX,rcWA.bottom-rcW.Height(),0,0,SWP_NOSIZE);
            lpRect->OffsetRect(0,rcWA.bottom-lpRect->bottom);
            return TRUE;
        }
        return FALSE;
    }
    //然後在ONMOVEING事件中使用如下過程調用
    CRect r=*pRect;
    AdjustPos(this, &r);
    *pRect=(RECT)r;


17.單擊窗口任意位置都可拖動窗口


 方法一:


     添加 WM_LBUTTONDOWN 的消息映射
     void CTest6Dlg::OnLButtonDown(UINT nFlags, CPoint point)
     {
          PostMessage(WM_NCLBUTTONDOWN, HTCAPTION, 0);


          CDialog::OnLButtonDown(nFlags, point);
     }


    方法二:
    添加 WM_NCHITTEST 的消息映射
    注意:在classwizard->message中找不到WM_NCHITTEST的,需要在選項卡class info->message filter中選擇window後該消息纔會出現在message中。
      void CTest6Dlg::OnNCHitTest(CPoint point)
     {
            return HTCAPTION;
      //    return CDialog::OnNCHitTest(point);
     }


     或者參考
        http://msdn.microsoft.com/msdnmag/issues/02/12/CQA/default.aspx


18.用Enter鍵替換Tab鍵實現焦點切換


     BOOL CTest6Dlg::PreTranslateMessage(MSG* pMsg)
     {
        if ( pMsg->message == WM_KEYDOWN )
          {
              if ( pMsg->wParam == VK_RETURN )
                   pMsg->wParam = VK_TAB;
          } 
          return CDialog::PreTranslateMessage(pMsg);
     } 


19.在對話框添加快捷鍵


     (1) 在CXXXApp中類中添加聲明
        HACCEL m_haccel;
     (2) 在resource view中右鍵點擊樹的根目錄,選擇insert,添加一個新的Accelerator,默認ID爲IDR_ACCELERATOR1。
         在其中添加相應菜單的快捷鍵。
     (3) 在BOOL CXXXApp::InitInstance()中添加代碼
        m_haccel = LoadAccelerators(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_ACCELERATOR1));
     (4) 添加CXXXApp類的 ProcessMessageFilter 消息映射函數
         BOOL CTest6App::ProcessMessageFilter(int code, LPMSG lpMsg)
         {
              if ( m_haccel )
              {
                  if ( ::TranslateAccelerator(m_pMainWnd->m_hWnd, m_haccel, lpMsg) )
                       return TRUE;
              }
              return CWinApp::ProcessMessageFilter(code, lpMsg);
         }


或者參考
Q100770:
How to use accelerator keys and a main menu on the dialog box in Visual C++
http://support.microsoft.com/kb/100770/en-us


Adding Hot Keys to your Application
http://msdn.microsoft.com/msdnmag/issues/1200/c/default.aspx


20.對話框全屏


    int cx, cy;
    HDC dc = ::GetDC(NULL);
    cx = GetDeviceCaps(dc,HORZRES) + GetSystemMetrics(SM_CXBORDER);
    cy = GetDeviceCaps(dc,VERTRES) + GetSystemMetrics(SM_CYBORDER);
    ::ReleaseDC(0,dc);


    // Remove caption and border
    SetWindowLong(m_hWnd, GWL_STYLE,
                    GetWindowLong(m_hWnd, GWL_STYLE) & (~(WS_CAPTION | WS_BORDER)));


    // Put window on top and expand it to fill screen
    ::SetWindowPos(m_hWnd, HWND_TOPMOST,
          -(GetSystemMetrics(SM_CXBORDER)+1),
          -(GetSystemMetrics(SM_CYBORDER)+1),
          cx+1,cy+1, SWP_NOZORDER);
    或參考
        http://www.codeguru.com/cpp/w-d/dislog/dialog-basedapplications/article.php/c1837/


21.控制對話框最大最小尺寸


    (1) 對話框的屬性的必須是resizing的
    (2) 打開classwizard->class info標籤頁->message filter中選擇window
    (3) 添加 WM_GETMINMAXINFO 消息映射
        void CTest6Dlg::OnGetMinMaxInfo(MINMAXINFO *lpMMI)
        {
             lpMMI->ptMinTrackSize = CPoint(200, 200);
        }


22. 創建無模式對話框


Creating a Modeless Dialog Box with MFC Libraries
http://support.microsoft.com/kb/103788/EN-US/


Visual C++ MFC Samples      
MODELESS Sample: Uses a CDialog Object as a Modeless Dialog Box
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vcsample/html/_sample_mfc_MODELESS.asp


23.在對話框中改變菜單項狀態(enable/disable, check/uncheck, change text)


You cannot change the state of a menu item from its command user-interface handler if the menu is attached to a dialog box in Visual C++
http://support.microsoft.com/kb/242577/en-us


24. 按下F1出現幫助




Context-Sensitive Help in a CDialog Object
http://support.microsoft.com/kb/141724/en-us


msdn中的介紹
http://msdn2.microsoft.com/en-us/library/dyd1yfww.aspx


或者如果你要屏蔽按下F1後出現的“找不到*.hlp文件”的提示對話框
添加 WM_HELPINFO 消息映射
BOOL CTest6Dlg::OnHelpInfo(HELPINFO* pHelpInfo) 
{
     return TRUE;
    //return CDialog::OnHelpInfo(pHelpInfo);//屏蔽該句
}




25. 對話框初始化設置輸入焦點的問題


默認情況下,對話框初始化顯示的焦點按照在對話框編輯期間設置的tab order的第一個控件來設置的。(設置tab order可在對話框的resource view中用Ctrl+D顯示出來,點鼠標進行順序設置)。如果想人爲的改變初始化時的輸入焦點,可在對話框的OnInitDialog中把return  TRUE; 改爲 return  FALSE;




MSDN上的解釋如下:


Return Value


Specifies whether the application has set the input focus to one of the controls in the dialog box. If OnInitDialog returns nonzero, Windows sets the input focus to the first control in the dialog box. The application can return 0 only if it has explicitly set the input focus to one of the controls in the dialog box.


26. 在對話框間傳遞數據


CDlg1::OnButton1() 

      CDlg2 dlg2; 
      dlg2.m_str = _T("你好"; )
      dlg2.m_bJudge = TRUE; 
      dlg2.DoModal(); 

 
//Dlg2.h 
public: 
     CString m_str; 
     BOOL m_bJudge; 
 
 
//Dlg2.cpp 
CDlg2::OnInitDialog() 

    if (m_bJudge) 
        GetDlgItem(IDC_EDIT1)->SetWindowText(m_str); 



27. 在 dlg1 中打開 dlg2 時,dlg2 能修改 dlg1 中的成員變量


//dlg1.cpp
    #include "dlg2.h"
    CDlg1::OnButton1()
    {
          CDlg2 dlg2;
          dlg2.m_pDlg1 = this;
          dlg2.DoModal();
    }


//dlg2.h
class CDlg1;//添加dlg1類的聲明
class CDlg2 : public CDialog
{
...
public:
    CDlg1 *m_pDlg1;
}


//dlg2.cpp
#include "dlg1.h"


至此,你可以在dlg2.cpp中通過m_pDlg1操作CDlg1類中的成員變量了。


28. 改變對話框字體,對話框大小改變的問題


How to calculate dialog box units based on the current font in Visual C++


http://support.microsoft.com/kb/q145994/




How To Calculate Dialog Base Units with Non-System-Based Font
http://support.microsoft.com/kb/125681/en-us 


29. 進行大數據量計算的時候,導致界面掛起無響應的問題


    當在程序中需要進行大數據量計算的時候(比如搜索磁盤,大數據量傳輸等),由於這些計算過程是在界面線程(UI Process)中,由此引發了界面線程的消息阻塞。我們創建一個工作線程(worker thread)來處理計算過程,以解決該問題。
下面是一個簡單的創建一個工作線程的實現:
//xxxdlg.h
static UINT MyThread(LPVOID pParam);
CWinThread* pMyThread;


//xxxdlg.cpp
CXXXDlg::OnButton1()
{
     pMyThread = AfxBeginThread(MyThread, this);
     pMyThread = NULL;
}


UINT CXXXDlg::MyThread(LPVOID pParam)
{
     CXXXDlg *pDlg = (CXXXDlg *)pParam;


     //這裏添加計算過程


     return 0;
}


30. 工程資源的合併


以把B對話框的資源插入到A對話框爲例:


(1) 生成一個*.ogx文件
    打開B工程,在ClassView中鼠標右鍵點擊所需的對話框類,單擊"Add to Gallery"。
    這時,會在 " C:\Program Files\Microsoft Visual Studio\Common\MSDev98\Gallery\工程B " 的目錄下產生一個ogx文件。


(2) 插入該*.ogx文件
    打開A工程,選擇菜單Project->Add To Project->components and controls... ,選擇剛生成的ogx文件,然後Insert。


這時B對話框資源和對話框類就插入到A中了。。


31. 在網上可以找到很多有用的代碼,我只是把一些常用的功能列出鏈接,方便查看


http://support.microsoft.com               
http://www.codeproject.com/dialog/
http://www.codeguru.com/Cpp/W-D/dislog/




改變對話框大小時同時改變控件大小


http://www.codeproject.com/dialog/easysize.asp
http://www.codeproject.com/dialog/resizabledialog.asp
http://www.vchelp.net/vchelp/archive.asp?type_id=5&class_id=1&cata_id=1&article_id=548&search_term=
http://www.vchelp.net/vchelp/archive.asp?type_id=5&class_id=1&cata_id=1&article_id=538&search_term=


如何在可變大小(resizing)的對話框中實現滾動窗口


Q262954:
How to create a resizeable dialog box with scroll bars in Visual C++
http://support.microsoft.com/default.aspx?scid=kb;en-us;262954
http://www.codeproject.com/dialog/scrollablechilddialog.asp


從某一點或某一邊逐漸變大顯示對話框


http://www.codeproject.com/dialog/canidialog.asp


一個重載的MessageBox類
http://www.codeproject.com/dialog/xmessagebox.asp
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章