• <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>

            c++初學(xué)者

            專(zhuān)注技術(shù)開(kāi)發(fā)

            【轉(zhuǎn)】加速鍵表的使用

            ***簡(jiǎn) 介***

              本文首先簡(jiǎn)要介紹了一下Windows中的幾個(gè)與加速鍵表有關(guān)的API函數(shù)及結(jié)構(gòu)。然后對(duì)在WIN32位程序中實(shí)現(xiàn)加速鍵表進(jìn)行了探討,分別就API下的程序設(shè)計(jì)及MFC下的程序設(shè)計(jì)進(jìn)行了敘述。
              對(duì)于運(yùn)行時(shí)可編輯的加速鍵表僅在MFC下進(jìn)行了詳細(xì)描述。包括其實(shí)現(xiàn)原理,并引導(dǎo)大家建立了一個(gè)用于編輯加速鍵的對(duì)話框,含詳細(xì)的代碼。關(guān)于在API下實(shí)現(xiàn)運(yùn)行時(shí)的可編輯加速鍵表不再敘述,可參考MFC下的代碼。
              我們通常希望將編輯過(guò)的加速鍵表保存起來(lái),以便下次運(yùn)行程序時(shí)保持我們編輯后的風(fēng)格。在本文的最后,介紹了如何將加速鍵表保存至文件中,并從文件中讀取我們保存的加速鍵表。你若是有意將加速鍵表保存至注冊(cè)表或其它什么地方,可參考其它的有關(guān)資料。本人建議保存至文件比較恰當(dāng)。
              本文介紹的所有方法及代碼都是在 Windows98SE + Microsoft Visual C++ 6.0 中進(jìn)行編制和調(diào)試的。 


              一、與加速鍵表有關(guān)的幾個(gè)API函數(shù)和結(jié)構(gòu)。

              操作加速鍵表使用的幾個(gè)API函數(shù)(關(guān)于這幾個(gè)函數(shù)的詳細(xì)說(shuō)明請(qǐng)參考有關(guān)書(shū)籍):
              HACCEL LoadAccelerators(HINSTANCE hInstance, LPCTSTR lpTableNAme);
              LoadAccelerators函數(shù)從程序的資源中加載一個(gè)加速鍵表,加載成功后返回一個(gè)加速健表的句柄。其中:
              hInstance  應(yīng)用程序的實(shí)例句柄。
              lpTableName 指向加速鍵表名稱(chēng)字符串的指針。

              HACCEL CreateAcceleratorTable(LPACCEL lpaccl, int cEntries);
              CreateAcceleratorTable函數(shù)根據(jù)一個(gè)ACCEL結(jié)構(gòu)數(shù)組創(chuàng)建一個(gè)加速鍵表。該函數(shù)與LoadAccelerators不同的是:LoadAccelerators函數(shù)加載的加速鍵表在程序結(jié)束后系統(tǒng)會(huì)自動(dòng)將該加速鍵表從內(nèi)存中清除,但CreateAcceleratorTable函數(shù)創(chuàng)建的加速鍵表需要使用函數(shù)DestoryAceleratorTable函數(shù)進(jìn)行清除。
              lpaccl   一個(gè)指向ACCEL結(jié)構(gòu)數(shù)組的指針。
              cEntries  數(shù)組中元素的個(gè)數(shù)。

              BOOL DestoryAcceleratorTable(HACCEL hAccel);
              DestoryAcceleratorTable函數(shù)清除由CreateAcceleratorTable函數(shù)創(chuàng)建的加速鍵表,成功則返回TRUE。其中:
              hAccel   需要清除的加速鍵表句柄。

              int TranslateAccelerator(HWND hWd, HACCEL hAccTable, LPMSG lpMsg);
              TranslateAccelerator函數(shù)負(fù)責(zé)翻譯加速鍵。其中:
              hWnd     窗口句柄,翻譯后的消息將被發(fā)往該窗口
              hAccTable  加速鍵表句柄。
              lpMsg    指向MSG結(jié)構(gòu)的指針。

              ACCEL結(jié)構(gòu)的定義:
            typedef struct tagACCEL{
                BYTE    fVirt;
                WORD    key;
                WORD    cmd;
            }ACCEL,*LPACCEL;

            其中:
              fVirt   加速鍵的標(biāo)記。
              key    鍵的代碼。如fVirt成員包含F(xiàn)VIRTKEY標(biāo)志,則key指一個(gè)虛鍵碼,否則是一個(gè)ASCII碼。
              cmd    命令I(lǐng)D號(hào),該參數(shù)將被放入WM_COMMAND或WM_SYSCOMMAND消息的wParam參數(shù)的低位字發(fā)至窗口。


              二、在windows下如何使用加速鍵表。

              在window下使用加速鍵表一般有兩種方法:1,創(chuàng)建一個(gè)加速鍵資源,在程序中使用API函數(shù)LoadAccelerators來(lái)將加速鍵表加載入內(nèi)存。并在消息循環(huán)中使用API函數(shù)TranslateAccelerator來(lái)翻譯該加速鍵表。2、在程序中填充一個(gè)ACCEL數(shù)組。然后調(diào)用API函數(shù)CreateAcceleratorTable來(lái)創(chuàng)建加速表,翻譯加速鍵同上,但不要忘記在退出程序前使用API函數(shù)DestoryAcceleratorTable來(lái)清除它。下面分別給出一個(gè)例子:

            /*例1:使用LoadAccelerators。
             假設(shè)你已經(jīng)建立了一個(gè)加速鍵資源,ID為IDR_ACCEL。
             假設(shè)你已經(jīng)定義了初始化函數(shù)InitApplication(HINSTANCE hInstance,int nCmdShow),
             該函數(shù)執(zhí)行注冊(cè)窗口類(lèi)和創(chuàng)建窗口操作。
            */
            #include <windows.h>
            #include "rc/resource.h"
            BOOL InitApplication(HINSTANCE hInstance,int nCmdShow);

            int APIENTRY WinMain(HINSTANCE hInstance,
                                 HINSTANCE hPrevInstance,
                                 LPSTR     lpCmdLine,
                                 int       nCmdShow)
            {
                 MSG msg;
                 HANDLE hAccelTable;
                 // 初始化應(yīng)用程序,并生成主窗口.
                 if (!InitApplication(hInstance, nCmdShow))
                 {
                     return FALSE;           // 初始化失敗
                 }
                  //使用函數(shù)LoadAccelerators從程序資源中加載加速鍵
                  hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDR_ACCEL));
                  // 取得并分發(fā)消息直到接收到 WM_QUIT 消息.
                 while (GetMessage(&msg, NULL, 0, 0))
                 {
                     //在分發(fā)消息前首先試著用加速鍵表進(jìn)行翻譯,如果是一個(gè)加速鍵則由
                     //TranslateAccelerator函數(shù)進(jìn)行翻譯,不再繼續(xù)處理該消息。
                     if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
                     {
                         TranslateMessage(&msg);
                         DispatchMessage(&msg);
                     }
                 }
                 return msg.wParam;  // Returns the value from PostQuitMessage
            }
             


            /*例2:使用CreateAcceleratorTable。
             假設(shè)你已經(jīng)定義了初始化函數(shù)InitApplication(HINSTANCE hInstance,int nCmdShow),
             該函數(shù)執(zhí)行注冊(cè)窗口類(lèi)和創(chuàng)建窗口操作。
            */

            #include <windows.h>
            #include "rc/resource.h"

            #define ID_CMD_A      0x00000230
            #define ID_CMD_B      0x00000231
            #define ID_CMD_C      0x00000232
            #define ID_CMD_D      0x00000233
            #define ID_CMD_E      0x00000234
            #define ID_CMD_F      0x00000235
            #define ID_CMD_G      0x00000236

            //定義了七個(gè)加速鍵,請(qǐng)?jiān)谙⒒卣{(diào)函數(shù)中處理這七個(gè)命令I(lǐng)D。
            static ACCEL accel[]={
                {FVIRTKEY|FCONTROL,VK_F5,ID_CMD_A},
                {FVIRTKEY|FCONTROL,VK_F6,ID_CMD_B},
                {FVIRTKEY|FCONTROL,VK_HOME,ID_CMD_C},
                {FVIRTKEY|FCONTROL,VK_END,ID_CMD_D},
                {FVIRTKEY|FCONTROL,"G",ID_CMD_E},
                {FVIRTKEY|FCONTROL,VK_SPACE,ID_CMD_F},
                {FVIRTKEY|FCONTROL,"K",ID_CMD_G},
            };   

            BOOL InitApplication(HINSTANCE hInstance,int nCmdShow);

            int APIENTRY WinMain(HINSTANCE hInstance,
                                 HINSTANCE hPrevInstance,
                                 LPSTR     lpCmdLine,
                                 int       nCmdShow)
            {
                 MSG msg;
                 HANDLE hAccelTable;
                 // 初始化應(yīng)用程序,并生成主窗口.
                 if (!InitApplication(hInstance, nCmdShow))
                 {
                     return FALSE;           // 初始化失敗
                 }
                  //使用函數(shù)CreateAcceleratorTable從數(shù)組accel中加載加速鍵
                  hAccelTable = CreateAcceleratorTable(accel, sizeof(accel)/sizeof(ACCEL));
                  // 取得并分發(fā)消息直到接收到 WM_QUIT 消息.
                 while (GetMessage(&msg, NULL, 0, 0))
                 {
                     //在分發(fā)消息前首先試著用加速鍵表進(jìn)行翻譯,如果是一個(gè)加速鍵則由
                     //TranslateAccelerator函數(shù)進(jìn)行翻譯,不再繼續(xù)處理該消息。
                     if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
                     {
                         TranslateMessage(&msg);
                         DispatchMessage(&msg);
                     }
                 }
                 //刪除加速鍵
                 DestoryAcceleratorTable(hAccelTable);
                 return msg.wParam;  // Returns the value from PostQuitMessage
            }
             


              在MFC程序設(shè)計(jì)中,有關(guān)于加速鍵表的操作已經(jīng)被CFrameWnd類(lèi)進(jìn)行了封裝。通常,我們的程序的主框架類(lèi)CMainFrame從CFrameWnd類(lèi)派生(SDI界面程序),或者從CMDIFrameWnd類(lèi)派生(MDI界面程序),而CMDIFrameWnd類(lèi)也是從CFrameWnd類(lèi)派生的。所以,我們并不用去關(guān)心那個(gè)資源號(hào)為IDR_MAINFRAME的加速鍵表是如何加載的,如果你只是需要一個(gè)這樣的靜態(tài)的加速鍵表的話。
              那么我們能不能使用自己的加速鍵表呢?答案是:可以的。
              創(chuàng)建加速鍵表的方法同前。由于在MFC中,WinMain函數(shù)被隱藏,我們不能直接修改WinMain函數(shù),所以,加速鍵表的創(chuàng)建將在CMainFrame的OnCreate函數(shù)中創(chuàng)建。
              1、在CMainFrame類(lèi)中添加一個(gè)HACCEL類(lèi)型保護(hù)成員變量:m_hMyAccel。在構(gòu)造函數(shù)中初始化為NULL。
              2、在CMainFrame::OnCreate函數(shù)的 “return 0;”句前增加創(chuàng)建加速鍵表的代碼。返回的加速鍵表句柄保存在m_hMyAccel中:

               方法1:(IDR_M(jìn)YACCEL為你定義的加速鍵表資源號(hào))
               m_hMyAccel=LoadAccelerators(AfxGetApp()->m_hInstance,MAKEINTRESOURCE(IDR_MYACCEL));

               方法2:(accel同前面的例子一樣在本文件的開(kāi)頭部分進(jìn)行定義)
               m_hMyAccel=CreateAcceleratorTable(accel,sizeof(accel)/sizeof(ACCEL));

              3、如果是使用CreateAccelTable函數(shù)創(chuàng)建的,則重載虛擬函數(shù)DestoryWindow()。在該函數(shù)的“return CMDIFrameWnd::DestroyWindow();”前增加如下代碼:

                if(m_hMyAccel!=NULL){
                    DestroyAcceleratorTable(m_hMyAccel);
                    m_hMyAccel=NULL;
                }

              通過(guò)前面的三步,加速鍵表已經(jīng)能正確地被創(chuàng)建和刪除了,但是它還沒(méi)有工作。下面就是要讓我們剛才所創(chuàng)建的加速鍵表工作起來(lái)。
              在API程序設(shè)計(jì)中大家已經(jīng)知道了加速鍵是如何工作的。也就是在消息還沒(méi)有分發(fā)出去之前先檢查是不是一個(gè)加速鍵。我們通過(guò)API函數(shù)TranslateAccelerator來(lái)實(shí)現(xiàn)。在MFC中,消息機(jī)制已經(jīng)被封裝了,我們不能去修改消息循環(huán)。但是,框架在分發(fā)消息前會(huì)調(diào)用虛擬函數(shù)PerTranslateMessage,并且如果該函數(shù)返回TRUE,則不再處理該消息。這正是我們所需要的。
              讓我們?cè)倩氐紺MainFrame類(lèi),生成PerTranslateMessage函數(shù)的覆蓋版本。修改函數(shù)體如下:

            BOOL CMainFrame::PreTranslateMessage(MSG* pMsg)
            {
                // TODO: Add your specialized code here and/or call the base class
                if(m_hMyAccel&&TranslateAccelerator(m_hWnd, m_hMyAccel, pMsg))
                    return TRUE;
                return CMDIFrameWnd::PreTranslateMessage(pMsg);
            }

              好了,現(xiàn)在我們的加速鍵已經(jīng)能正常地工作了。以上方法用在其它窗口同樣有效(如對(duì)話框中,你不妨在對(duì)話框中試試)。


              三、可在運(yùn)行時(shí)編輯的加速鍵表。

              通過(guò)上面的敘述,你可能已經(jīng)對(duì)可編輯的加速鍵表有了一定的輪廓。其實(shí)其實(shí)現(xiàn)思想很簡(jiǎn)單:只要對(duì)一個(gè)ACCEL數(shù)組進(jìn)行修改,然后重新生成加速鍵表就行了。
              為了區(qū)分命令,我們?yōu)槊總€(gè)命令取一個(gè)名字。在CMainFrame類(lèi)定義的前面加上下面的一個(gè)結(jié)構(gòu)定義:

            typedef struct{
                char cCmd[32];
                ACCEL accel;
            }ACCELITEM,*LPACCELITEM;

              我們將使用該結(jié)構(gòu)來(lái)保存加速鍵表的數(shù)據(jù)。在CMainFrame類(lèi)中添加兩個(gè)保護(hù)成員變量:

                LPACCELITEM m_lpAccel;
                DWORD m_dwAccelCount;

              在構(gòu)造函數(shù)中將m_lpAccel初始化為NULL,m_dwAccelCount初始化為0。在數(shù)組accel的定義下面增加一個(gè)字符串?dāng)?shù)組的靜態(tài)變量的定義(用來(lái)指定命令的名稱(chēng),請(qǐng)仿照下面自己定義,個(gè)數(shù)多少不限,字符串長(zhǎng)度不要超過(guò)31個(gè)字符):

            static char strCmd[][32]={
                "Command One",
                "Command Two",
                "Command Three",
                "Command Four",
                "Command Five"
            };


              在CMainFrame類(lèi)中添加一個(gè)保護(hù)成員函數(shù)LoadAccel(),該函數(shù)用來(lái)將加速鍵表裝入,定義如下:

            BOOL CMainFrame::LoadAccel()
            {
                ASSERT(m_hActAccel==NULL);
                ASSERT(m_lpAccel==NULL);
                m_dwAccelCount=sizeof(accel)/sizeof(ACCEL);
                m_lpAccel=new ACCELITEM[m_dwAccelCount];
                memset(m_lpAccel,0,sizeof(ACCELITEM)*m_dwAccelCount);
                DWORD dwCmdStr=sizeof(strCmd)/sizeof(char[32]);
                for(DWORD dw=0;dw<m_dwAccelCount;dw++){
                    m_lpAccel[dw].accel=accel[dw];
                    strcpy(m_lpAccel[dw].cCmd,dw<dwCmdStr?strCmd[dw]:"Command Unknow");
                }

                m_hActAccel=CreateAcceleratorTable(accel,m_dwAccelCount);
                return TRUE;

            }

              刪除OnCreate函數(shù)中原來(lái)創(chuàng)建加速鍵表的代碼,改成對(duì)LoadAccel()的調(diào)用:

                LoadAccel();

              在CMainFrame的析構(gòu)函數(shù)中增加以下內(nèi)容:

                if(m_lpAccel)
                    delete[] m_lpAccel;

              為了能夠?qū)?strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">加速鍵數(shù)據(jù)進(jìn)行編輯,我們?cè)诠こ讨刑砑右粋€(gè)對(duì)話框資源,ID為“IDD_ACCELEDIT”,在對(duì)話框上放置三個(gè)成組框(Group Box),左邊一個(gè)標(biāo)題為“命令”;中間一個(gè)標(biāo)題為“組合鍵”;右邊一個(gè)標(biāo)題為“虛鍵值”。在左邊成組框中放置一個(gè)列表框(List Box),ID為“IDC_LST_CMD”。在中間成組框中放置三個(gè)核選框(Check Box),上下排列。上面的核選框的ID為“IDC_CHK_ALT”,標(biāo)題為“Alt”,并勾選“Group”屬性;中間的核選框的ID為“IDC_CHK_SHIFT”,標(biāo)題為“Shift”,取消“Group”屬性;下面的核選框的ID為“IDC_CHK_CTRL”,標(biāo)題為“Ctrl”,取消“Group”屬性。在右邊的成組框中放置一個(gè)列表框,ID為“IDC_LST_KEY”。調(diào)整各個(gè)控件的尺寸及位置至合適。設(shè)置控件的TAB跳轉(zhuǎn)順序,從左至右、從上到下。依次為:左成組框、IDC_LST_CMD列表框、中成組框、IDC_CHK_ALT核選框、IDC_CHK_SHIFT核選框、IDC_CHK_CTRL核選框、右成組框、IDC_LST_KEY列表框、OK按鈕、CANCEL按鈕。
              打開(kāi)類(lèi)向?qū)В瑸閷?duì)話框新建一個(gè)類(lèi),類(lèi)名為“CDlgEditAccel”。為兩個(gè)列表框和三個(gè)核選框映射變量,如下:
              控件ID:ID_LST_CMD;類(lèi)型:Control/CListBox;名稱(chēng):m_LstCmd;
              控件ID:ID_LST_KEY;類(lèi)型:Control/CListBox;名稱(chēng):m_LstKey;
              控件ID:ID_CHK_ALT;類(lèi)型:Control/CButton;名稱(chēng):m_ChkAlt;
              控件ID:ID_CHK_SHIFT;類(lèi)型:Control/CButton;名稱(chēng):m_ChkShift;
              控件ID:ID_CHK_CTRL;類(lèi)型:Control/CButton;名稱(chēng):m_ChkCtrl;

              在類(lèi)CDlgEditAccel的定義前加入下面的定義:
            typedef struct tag_KeyName{
                CString m_strName;
                WORD m_wID;
                tag_KeyName(CString str,WORD id){m_strName=str,m_wID=id;}
            }KEYNAME,*LPKEYNAME;

            typedef struct tag_ActAccel{
                CString m_strCmd;
                ACCEL m_Accel;
            }ACTACCEL,*LPACTACCEL;

            class CActAccelList
            {
            public:
                CActAccelList();
                ~CActAccelList();

            protected:
                LPACTACCEL m_lpActAccel;
                int m_iCount;

            public:
                ACTACCEL& operator[](int index);
                BOOL SetSize(int iSize);
                int GetSize();
            };


              在文件DlgEditAccel.cpp文件中定義類(lèi)CActAccelList的成員函數(shù),代碼如下:
            CActAccelList::CActAccelList()
            {
                m_lpActAccel=NULL;
               m_iCount=0;
            }

            CActAccelList::~CActAccelList()
            {
                if(m_iCount>0&&m_lpActAccel)
                    delete[] m_lpActAccel;
            }

            int CActAccelList::GetSize()
            {
                return m_iCount;
            }

            ACTACCEL& CActAccelList::operator []( int index)
            {
                if(!(index>=0&&index<m_iCount))
                AfxThrowMemoryException();
                return m_lpActAccel[index];
            }

            BOOL CActAccelList::SetSize(int iSize)
            {
                if(iSize<0)
                    return FALSE;
                if(m_iCount>0&&m_lpActAccel)
                    delete[] m_lpActAccel;
                m_iCount=0;
                m_lpActAccel=new ACTACCEL[iSize];
                if(m_lpActAccel==NULL)
                    return FALSE;
                m_iCount=iSize;
                return TRUE;
            }


              在DlgAccelEdit.cpp文件頭部定義全局變量--數(shù)組key:
            static KEYNAME key[]={
                KEYNAME("Left mouse button",VK_LBUTTON),
                KEYNAME("Right mouse button",VK_RBUTTON),
                KEYNAME("Control-break processing",VK_CANCEL),
                KEYNAME("Middle mouse button",VK_MBUTTON),
                KEYNAME("Back Space",VK_BACK),
                KEYNAME("Tab",VK_TAB),
                KEYNAME("Clear",VK_CLEAR),
                KEYNAME("Enter",VK_RETURN),
                KEYNAME("Shift",VK_SHIFT),
                KEYNAME("Ctrl",VK_CONTROL),
                KEYNAME("Alt",VK_MENU),
                KEYNAME("Pause",VK_PAUSE),
                KEYNAME("Caps Lock",VK_CAPITAL),
                KEYNAME("Esc",VK_ESCAPE),
                KEYNAME("Space",VK_SPACE),
                KEYNAME("Page Up",VK_PRIOR), 
                KEYNAME("Page Down",VK_NEXT),
                KEYNAME("End",VK_END),
                KEYNAME("Home",VK_HOME),
                KEYNAME("Left",VK_LEFT),
                KEYNAME("Up",VK_UP),
                KEYNAME("Right",VK_RIGHT),
                KEYNAME("Down",VK_DOWN),
                KEYNAME("Select",VK_SELECT),
                KEYNAME("Excute",VK_EXECUTE),
                KEYNAME("Print Screen",VK_SNAPSHOT),
                KEYNAME("Insert",VK_INSERT),
                KEYNAME("Delete",VK_DELETE),
                KEYNAME("Help",VK_HELP),
                KEYNAME("0",'0'),
                KEYNAME("1",'1'),
                KEYNAME("2",'2'),
                KEYNAME("3",'3'),
                KEYNAME("4",'4'),
                KEYNAME("5",'5'),
                KEYNAME("6",'6'),
                KEYNAME("7",'7'),
                KEYNAME("8",'8'),
                KEYNAME("9",'9'),
                KEYNAME("A",'A'),
                KEYNAME("B",'B'),
                KEYNAME("C",'C'),
                KEYNAME("D",'D'),
                KEYNAME("E",'E'),
                KEYNAME("F",'F'),
                KEYNAME("G",'G'),
                KEYNAME("H",'H'),
                KEYNAME("I",'I'),
                KEYNAME("J",'J'),
                KEYNAME("K",'K'),
                KEYNAME("L",'L'),
                KEYNAME("M",'M'),
                KEYNAME("N",'N'),
                KEYNAME("O",'O'),
                KEYNAME("P",'P'),
                KEYNAME("Q",'Q'),
                KEYNAME("R",'R'),
                KEYNAME("S",'S'),
                KEYNAME("T",'T'),
                KEYNAME("U",'U'),
                KEYNAME("V",'V'),
                KEYNAME("W",'W'),
                KEYNAME("X",'X'),
                KEYNAME("Y",'Y'),
                KEYNAME("Z",'Z'),
                KEYNAME("Left windows",VK_LWIN),
                KEYNAME("Right windows",VK_RWIN),
                KEYNAME("Applications",VK_APPS),
                KEYNAME("Numeric keypad 0", VK_NUMPAD0),
                KEYNAME("Numeric keypad 1", VK_NUMPAD1),
                KEYNAME("Numeric keypad 2", VK_NUMPAD2),
                KEYNAME("Numeric keypad 3", VK_NUMPAD3),
                KEYNAME("Numeric keypad 4", VK_NUMPAD4),
                KEYNAME("Numeric keypad 5", VK_NUMPAD5),
                KEYNAME("Numeric keypad 6", VK_NUMPAD6),
                KEYNAME("Numeric keypad 7", VK_NUMPAD7),
                KEYNAME("Numeric keypad 8", VK_NUMPAD8),
                KEYNAME("Numeric keypad 9", VK_NUMPAD9),
                KEYNAME("Multiply",VK_MULTIPLY),
                KEYNAME("Add",VK_ADD),
                KEYNAME("Separator",VK_SEPARATOR),
                KEYNAME("Subtract",VK_SUBTRACT),
                KEYNAME("Decimal Point",VK_DECIMAL),
                KEYNAME("Divide",VK_DIVIDE),
                KEYNAME("F1",VK_F1),
                KEYNAME("F2",VK_F2),
                KEYNAME("F3",VK_F3),
                KEYNAME("F4",VK_F4),
                KEYNAME("F5",VK_F5),
                KEYNAME("F6",VK_F6),
                KEYNAME("F7",VK_F7),
                KEYNAME("F8",VK_F8),
                KEYNAME("F9",VK_F9),
                KEYNAME("F10",VK_F10),
                KEYNAME("F11",VK_F11),
                KEYNAME("F12",VK_F12),
                KEYNAME("F13",VK_F13),
                KEYNAME("F14",VK_F14),
                KEYNAME("F15",VK_F15),
                KEYNAME("F16",VK_F16),
                KEYNAME("F17",VK_F17),
                KEYNAME("F18",VK_F18),
                KEYNAME("F19",VK_F19),
                KEYNAME("F20",VK_F20),
                KEYNAME("F21",VK_F21),
                KEYNAME("F22",VK_F22),
                KEYNAME("F23",VK_F23),
                KEYNAME("F24",VK_F24),
                KEYNAME("Attn",VK_ATTN),
                KEYNAME("CrSel",VK_CRSEL),
                KEYNAME("ExSel",VK_EXSEL),
                KEYNAME("Erase",VK_EREOF),
                KEYNAME("Play",VK_PLAY),
                KEYNAME("Zoom",VK_ZOOM),
                KEYNAME("Reserved for future use",VK_NONAME ),
                KEYNAME("PA1",VK_PA1),
                KEYNAME("Clear(OEM)",VK_OEM_CLEAR ),

                KEYNAME("file://",'//'),
                KEYNAME("-",'-'),
                KEYNAME("=",'='),
                KEYNAME("[",'['),
                KEYNAME("]",']'),
                KEYNAME(";",';'),
                KEYNAME("\'",'\''),
                KEYNAME(",",','),
                KEYNAME(".",'.'),
                KEYNAME("/",'/'),
                KEYNAME("`",'`')
            };


              在類(lèi)CDlgAccelEdit中響應(yīng)Windows消息:WM_INITDIALOD,代碼如下:
            BOOL CDlgEditAccel::OnInitDialog()
            {
                CDialog::OnInitDialog();

                // TODO: Add extra initialization here
                SetWindowText("Edit Accelerator Table");

                int iCount=m_AccelList.GetSize();
                int i;
                for(i=0;i<iCount;i++){
                    m_LstCmd.AddString(m_AccelList[i].m_strCmd);
                }
                for(i=0;i<sizeof(key)/sizeof(KEYNAME);i++)
                {
                    m_LstKey.AddString(key[i].m_strName);
                }
                m_LstCmd.SetCurSel(0);
                OnSelchangeLstCmd();
                return TRUE;  // return TRUE unless you set the focus to a control
                              // EXCEPTION: OCX Property Pages should return FALSE
            }


              為類(lèi)CDglAccelEdit增加一個(gè)保護(hù)成員函數(shù):
                void SaveChange(int index=-1);

              在文件DlgAccelEdit中定義該函數(shù),代碼如下:

            void CDlgEditAccel::SaveChange(int index)
            {
                if(index>=0||(index=m_LstCmd.GetCurSel())>=0)
                {
                    if(m_LstKey.GetCurSel()<0){
                        AfxMessageBox("你必需選擇一個(gè)鍵碼!");
                        return;
                    }
                    BYTE btCmp=((m_ChkAlt.GetCheck()==1)?FALT:NULL)|
                               ((m_ChkCtrl.GetCheck()==1)?FCONTROL:NULL)|
                               ((m_ChkShift.GetCheck()==1)?FSHIFT:NULL)|FVIRTKEY;
                    WORD wKey=key[m_LstKey.GetCurSel()].m_wID;

                    m_AccelList[index].m_Accel.fVirt=btCmp;
                    m_AccelList[index].m_Accel.key=wKey;
                    return;
                }
            }

              響應(yīng)列表框ID_LST_CMD的通知消息“LBN_SELCHANGE”,函數(shù)代碼如下:
            void CDlgEditAccel::OnSelchangeLstCmd()
            {
                // TODO: Add your control notification handler code here
                int iCmd=m_LstCmd.GetCurSel();
                WORD wKey=m_AccelList[iCmd].m_Accel.key;
                BYTE btCmp=m_AccelList[iCmd].m_Accel.fVirt;
                m_ChkAlt.SetCheck(btCmp&FALT);
                m_ChkCtrl.SetCheck(btCmp&FCONTROL);
                m_ChkShift.SetCheck(btCmp&FSHIFT);
                int iCount=sizeof(key)/sizeof(KEYNAME);
                int id=-1;
                for(int i=0;i<iCount;i++)
                {
                    if(key[i].m_wID==wKey){
                        id=i;
                        break;
                    }
                }
                m_LstKey.SetCurSel(id);

            }

              響應(yīng)列表框ID_LST_KEY的通知消息“LBN_SELCHANGE”,函數(shù)代碼如下:
            void CDlgEditAccel::OnSelchangeLstKey()
            {
                SaveChange(); 
            }

              響應(yīng)核選框ID_CHK_ALT的通知消息“BN_CLICKED”,函數(shù)代碼如下:
            void CDlgEditAccel::OnChkAlt()
            {
                SaveChange();
            }

              響應(yīng)核選框ID_CHK_SHIFT的通知消息“BN_CLICKED”,函數(shù)代碼如下:
            void CDlgEditAccel::OnChkShift()
            {
                SaveChange();
            }

              響應(yīng)核選框ID_CHK_CTRL的通知消息“BN_CLICKED”,函數(shù)代碼如下:
            void CDlgEditAccel::OnChkCtrl()
            {
                SaveChange();
            }

              至此,用于編輯加速鍵的對(duì)話框已經(jīng)完成。我們現(xiàn)在要做的就是在程序中打開(kāi)對(duì)話框來(lái)編輯了。讓我們回到CMainFrame類(lèi)中。我們將在該類(lèi)中響應(yīng)一個(gè)命令來(lái)打開(kāi)編輯對(duì)話框,對(duì)加速鍵表進(jìn)行編輯。完成后點(diǎn)按OK回到主程序中,然后更新加速鍵表。這樣后,我們剛剛編輯好的加速鍵表就開(kāi)始起作用了。
              首先,打開(kāi)菜單。在“查看”項(xiàng)后增加一個(gè)“工具(&T)”下拉菜單,在下拉菜單中增加一個(gè)了菜單:“編輯加速鍵表(&A)...”,ID為“ID_TOOL_ACCELEDIT”。打開(kāi)類(lèi)向?qū)Вx擇CMainFrame類(lèi),響應(yīng)“ID_TOOL_ACCELEDIT”命令。編輯響應(yīng)函數(shù)如下:

            void CMainFrame::OnToolAcceledit()
            {
                // TODO: Add your command handler code here
                CDlgEditAccel dlg;

                DWORD i;
                dlg.m_AccelList.SetSize(m_dwAccelCount);
                for(i=0;i<m_dwAccelCount;i++){
                    dlg.m_AccelList[i].m_strCmd=m_lpAccel[i].cCmd;
                    dlg.m_AccelList[i].m_Accel=m_lpAccel[i].accel;
                }
                if(IDOK==dlg.DoModal()){
                    ACCEL* pAccel=new ACCEL[m_dwAccelCount];
                    for(DWORD dw=0;dw<m_dwAccelCount;dw++){
                        m_lpAccel[dw].accel=pAccel[dw]=dlg.m_AccelList[dw].m_Accel;
                    }

                    if(m_hActAccel!=NULL)
                    DestroyAcceleratorTable(m_hActAccel);
                    m_hActAccel=CreateAcceleratorTable(pAccel,m_dwAccelCount);
                }
            }

              在該文件的頭部包含類(lèi)CDlgEditAccel的頭文件:

            #include "DlgEditAccel.h"

              至此,可編輯的加速鍵表已經(jīng)完成了。不妨試試看。

              三、將加速鍵表保存至文件,并在程序運(yùn)行時(shí)自動(dòng)從文件中加載。

              上面我們實(shí)現(xiàn)了可編輯的加速鍵表。但是,當(dāng)程序退出后,我們編輯過(guò)的加速鍵數(shù)據(jù)就消失了,下次運(yùn)行程序時(shí)還是和以前一樣了。將加速鍵表保存起來(lái)以備下次使用,這是我們所希望的。下面討論的方法是使用文件來(lái)保存我們的加速鍵表。
              首先,在MainFrm.cpp文件的頭部定義一個(gè)全局字符串,也就是用于保存加速鍵的文件名:

            static char strAccelFileName[]="Accel.cus";

              定義一個(gè)DWORD值作為文件頭,我們通過(guò)該DWORD值來(lái)判斷是否是一個(gè)有效格式的文件:

            #define ACCEL_FILE_HEAD 0x00434341


              其次,為CMainFrame類(lèi)添加一個(gè)保護(hù)的成員函數(shù):“BOOL SaveAccel()”,編輯其代碼如下:
            BOOL CMainFrame::SaveAccel()
            {
                char lpAppName[256];
                char lpAppPath[256];
                char* lpFilePart=NULL;
                GetModuleFileName(AfxGetInstanceHandle(),lpAppName,255);
                GetFullPathName(lpAppName,255,lpAppPath,&lpFilePart);
                TRACE1("Application File Name:%s.\n",lpAppName);
                strcpy(lpFilePart,strAccelFileName);
                TRACE1("Accelerator File Name:%s.\n",lpAppPath);
                try
                {
                    DWORD dwHead=ACCEL_FILE_HEAD;
                    DWORD dwCount=m_dwAccelCount;

                    CFile fAccel(lpAppPath,CFile::modeCreate|CFile::modeWrite);
                    fAccel.SeekToBegin();
                    fAccel.Write(&dwHead,sizeof(DWORD));
                    fAccel.Write(&dwCount,sizeof(DWORD));
                    for(DWORD dw=0;dw<dwCount;dw++)
                    {
                        fAccel.Write(m_lpAccel+dw,sizeof(ACCELITEM));
                    }

                    return TRUE;

                }

                catch(CFileException* e)
                {
                    char buf[256];
                    char buf2[512];
                    int iError;
                    iError=e->m_cause;
                    e->GetErrorMessage(buf,256);
                    sprintf(buf2,"將加速鍵表保存到文件 \"%s\" 中時(shí)發(fā)生錯(cuò)誤!\n"
                                 "錯(cuò) 誤 號(hào):%d\n"
                                 "錯(cuò)誤描述:%s\n"
                                 "\0",
                                 strAccelFileName,iError,buf);
                    AfxMessageBox(buf2,MB_OK|MB_ICONSTOP|MB_DEFBUTTON1);
                    return FALSE;
                }
            }

              再次,修改LoadAccel()函數(shù)如下:

            BOOL CMainFrame::LoadAccel()
            {
                char lpAppName[256];
                char lpAppPath[256];
                char* lpFilePart=NULL;
                GetModuleFileName(AfxGetInstanceHandle(),lpAppName,255);
                GetFullPathName(lpAppName,255,lpAppPath,&lpFilePart);
                TRACE1("Application File Name:%s.\n",lpAppName);
                strcpy(lpFilePart,strAccelFileName);
                TRACE1("Accelerator File Name:%s.\n",lpAppPath);
                try
                {
                    DWORD dwHead;
                    DWORD dwCount;

                    CFile fAccel(lpAppPath,CFile::modeRead);
                    fAccel.SeekToBegin();
                    if(fAccel.Read(&dwHead,sizeof(DWORD))!=sizeof(DWORD))
                        AfxThrowFileException(CFileException::endOfFile,12,lpAppPath);
                    if(dwHead!=ACCEL_FILE_HEAD)
                        AfxThrowFileException(CFileException::invalidFile,13,lpAppPath);

                    if(fAccel.Read(&dwCount,sizeof(DWORD))!=sizeof(DWORD))
                        AfxThrowFileException(CFileException::endOfFile,12,lpAppPath);
                   
                    ASSERT(m_lpAccel==NULL);
                   
                    m_lpAccel=new ACCELITEM[dwCount];
                    memset(m_lpAccel,0,sizeof(ACCELITEM)*dwCount);
                    m_dwAccelCount=dwCount;

                    for(DWORD dw=0;dw<dwCount;dw++)
                    {
                        if(fAccel.Read(m_lpAccel+dw,sizeof(ACCELITEM))!=sizeof(ACCELITEM))
                            AfxThrowFileException(CFileException::endOfFile,12,lpAppPath);
                    }

                    ACCEL* pAccel=new ACCEL[dwCount];
                    for(dw=0;dw<dwCount;dw++){
                        pAccel[dw]=m_lpAccel[dw].accel;
                    }

                    m_hActAccel=CreateAcceleratorTable(pAccel,dwCount);

                    return TRUE;

                }

                catch(CFileException* e)
                {
                    char buf[256];
                    char buf2[512];
                    int iError;
                    iError=e->m_cause;
                    e->GetErrorMessage(buf,256);
                    sprintf(buf2,"從文件 \"%s\" 中加載加速鍵表時(shí)發(fā)生錯(cuò)誤!\n"
                                 "錯(cuò) 誤 號(hào):%d\n"
                                 "錯(cuò)誤描述:%s\n"
                                 "是否生成默認(rèn)的加速鍵表?\n\0",
                                 strAccelFileName,iError,buf);
                    if(IDYES==AfxMessageBox(buf2,MB_YESNO|MB_SYSTEMMODAL|MB_ICONSTOP|MB_DEFBUTTON1))
                    {
                        ASSERT(m_hActAccel==NULL);
                        ASSERT(m_lpAccel==NULL);
                        m_dwAccelCount=sizeof(accel)/sizeof(ACCEL);
                        m_lpAccel=new ACCELITEM[m_dwAccelCount];
                        memset(m_lpAccel,0,sizeof(ACCELITEM)*m_dwAccelCount);
                        DWORD dwCmdStr=sizeof(strCmd)/sizeof(char[30]);
                        for(DWORD dw=0;dw<m_dwAccelCount;dw++){
                            m_lpAccel[dw].accel=accel[dw];
                            strcpy(m_lpAccel[dw].cCmd,dw<dwCmdStr?strCmd[dw]:"Command Unknow");
                        }
                       
                        m_hActAccel=CreateAcceleratorTable(accel,m_dwAccelCount);
                        SaveAccel();
                        return TRUE;
                    }
                    return FALSE;
                }
            }

              最后,在DestroyWindow()函數(shù)頭部增加對(duì)SaveAccel()函數(shù)的調(diào)用:

                SaveAccel();
                ...

              好了,你自己的加速鍵數(shù)據(jù)已經(jīng)能保存在文件中了,并能從中正確加載。如果文件不存在或程序讀取時(shí)發(fā)現(xiàn)錯(cuò)誤則提醒你是否建立缺省的加速鍵表,如你確認(rèn)的話則生成缺省的加速鍵表并立刻保存至文件中。

            posted on 2008-04-11 11:57 大海 閱讀(716) 評(píng)論(0)  編輯 收藏 引用


            只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問(wèn)   Chat2DB   管理


            久久人人爽人人爽人人AV| 久久精品女人天堂AV麻| 精品久久无码中文字幕| 久久综合狠狠综合久久激情 | 青青青国产成人久久111网站| 久久99精品久久久久久噜噜| 91精品国产高清久久久久久国产嫩草 | 精产国品久久一二三产区区别| 国产精品久久久久久吹潮| 欧美久久精品一级c片片| 一级a性色生活片久久无少妇一级婬片免费放 | 伊人久久大香线蕉av一区| 麻豆精品久久精品色综合| 久久久久免费精品国产| 狠狠综合久久综合中文88| 999久久久免费精品国产| 亚洲国产精品一区二区久久| 久久99精品久久久久久9蜜桃 | 人人狠狠综合久久亚洲88| 国产毛片欧美毛片久久久| 久久九九全国免费| 久久99久久99精品免视看动漫| 99久久99久久精品国产片| 狠狠色丁香婷综合久久| 久久天天躁狠狠躁夜夜avapp | 伊人热人久久中文字幕| 国产综合久久久久久鬼色| 久久天天躁狠狠躁夜夜2020一| 三级韩国一区久久二区综合 | 亚洲天堂久久精品| 久久综合久久综合久久| 狠狠狠色丁香婷婷综合久久五月| 欧美va久久久噜噜噜久久| 日日躁夜夜躁狠狠久久AV| 人妻精品久久久久中文字幕一冢本| 精品久久久久久国产| 日韩人妻无码精品久久免费一 | 国产成人AV综合久久| 国産精品久久久久久久| 久久久久久国产精品无码下载| 久久久久亚洲AV成人网人人软件 |