• <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++初學者

            專注技術開發

            [轉]可在運行時編輯的加速鍵表

            ***簡 介***

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


              一、與加速鍵表有關的幾個API函數和結構。

              操作加速鍵表使用的幾個API函數(關于這幾個函數的詳細說明請參考有關書籍):
              HACCEL LoadAccelerators(HINSTANCE hInstance, LPCTSTR lpTableNAme);
              LoadAccelerators函數從程序的資源中加載一個加速鍵表,加載成功后返回一個加速健表的句柄。其中:
              hInstance  應用程序的實例句柄。
              lpTableName 指向加速鍵表名稱字符串的指針。

              HACCEL CreateAcceleratorTable(LPACCEL lpaccl, int cEntries);
              CreateAcceleratorTable函數根據一個ACCEL結構數組創建一個加速鍵表。該函數與LoadAccelerators不同的是:LoadAccelerators函數加載的加速鍵表在程序結束后系統會自動將該加速鍵表從內存中清除,但CreateAcceleratorTable函數創建的加速鍵表需要使用函數DestoryAceleratorTable函數進行清除。
              lpaccl   一個指向ACCEL結構數組的指針。
              cEntries  數組中元素的個數。

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

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

              ACCEL結構的定義:
            typedef struct tagACCEL{
                BYTE    fVirt;
                WORD    key;
                WORD    cmd;
            }ACCEL,*LPACCEL;

            其中:
              fVirt   加速鍵的標記。
              key    鍵的代碼。如fVirt成員包含FVIRTKEY標志,則key指一個虛鍵碼,否則是一個ASCII碼。
              cmd    命令ID號,該參數將被放入WM_COMMAND或WM_SYSCOMMAND消息的wParam參數的低位字發至窗口。


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

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

            /*例1:使用LoadAccelerators。
             假設你已經建立了一個加速鍵資源,ID為IDR_ACCEL。
             假設你已經定義了初始化函數InitApplication(HINSTANCE hInstance,int nCmdShow),
             該函數執行注冊窗口類和創建窗口操作。
            */
            #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;
                 // 初始化應用程序,并生成主窗口.
                 if (!InitApplication(hInstance, nCmdShow))
                 {
                     return FALSE;           // 初始化失敗
                 }
                  //使用函數LoadAccelerators從程序資源中加載加速鍵
                  hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDR_ACCEL));
                  // 取得并分發消息直到接收到 WM_QUIT 消息.
                 while (GetMessage(&msg, NULL, 0, 0))
                 {
                     //在分發消息前首先試著用加速鍵表進行翻譯,如果是一個加速鍵則由
                     //TranslateAccelerator函數進行翻譯,不再繼續處理該消息。
                     if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
                     {
                         TranslateMessage(&msg);
                         DispatchMessage(&msg);
                     }
                 }
                 return msg.wParam;  // Returns the value from PostQuitMessage
            }
             


            /*例2:使用CreateAcceleratorTable。
             假設你已經定義了初始化函數InitApplication(HINSTANCE hInstance,int nCmdShow),
             該函數執行注冊窗口類和創建窗口操作。
            */

            #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

            //定義了七個加速鍵,請在消息回調函數中處理這七個命令ID。
            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;
                 // 初始化應用程序,并生成主窗口.
                 if (!InitApplication(hInstance, nCmdShow))
                 {
                     return FALSE;           // 初始化失敗
                 }
                  //使用函數CreateAcceleratorTable從數組accel中加載加速鍵
                  hAccelTable = CreateAcceleratorTable(accel, sizeof(accel)/sizeof(ACCEL));
                  // 取得并分發消息直到接收到 WM_QUIT 消息.
                 while (GetMessage(&msg, NULL, 0, 0))
                 {
                     //在分發消息前首先試著用加速鍵表進行翻譯,如果是一個加速鍵則由
                     //TranslateAccelerator函數進行翻譯,不再繼續處理該消息。
                     if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
                     {
                         TranslateMessage(&msg);
                         DispatchMessage(&msg);
                     }
                 }
                 //刪除加速鍵
                 DestoryAcceleratorTable(hAccelTable);
                 return msg.wParam;  // Returns the value from PostQuitMessage
            }
             


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

               方法1:(IDR_MYACCEL為你定義的加速鍵表資源號)
               m_hMyAccel=LoadAccelerators(AfxGetApp()->m_hInstance,MAKEINTRESOURCE(IDR_MYACCEL));

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

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

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

              通過前面的三步,加速鍵表已經能正確地被創建和刪除了,但是它還沒有工作。下面就是要讓我們剛才所創建的加速鍵表工作起來。
              在API程序設計中大家已經知道了加速鍵是如何工作的。也就是在消息還沒有分發出去之前先檢查是不是一個加速鍵。我們通過API函數TranslateAccelerator來實現。在MFC中,消息機制已經被封裝了,我們不能去修改消息循環。但是,框架在分發消息前會調用虛擬函數PerTranslateMessage,并且如果該函數返回TRUE,則不再處理該消息。這正是我們所需要的。
              讓我們再回到CMainFrame類,生成PerTranslateMessage函數的覆蓋版本。修改函數體如下:

            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);
            }

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


              三、可在運行時編輯的加速鍵表。

              通過上面的敘述,你可能已經對可編輯的加速鍵表有了一定的輪廓。其實其實現思想很簡單:只要對一個ACCEL數組進行修改,然后重新生成加速鍵表就行了。
              為了區分命令,我們為每個命令取一個名字。在CMainFrame類定義的前面加上下面的一個結構定義:

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

              我們將使用該結構來保存加速鍵表的數據。在CMainFrame類中添加兩個保護成員變量:

                LPACCELITEM m_lpAccel;
                DWORD m_dwAccelCount;

              在構造函數中將m_lpAccel初始化為NULL,m_dwAccelCount初始化為0。在數組accel的定義下面增加一個字符串數組的靜態變量的定義(用來指定命令的名稱,請仿照下面自己定義,個數多少不限,字符串長度不要超過31個字符):

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


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

            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函數中原來創建加速鍵表的代碼,改成對LoadAccel()的調用:

                LoadAccel();

              在CMainFrame的析構函數中增加以下內容:

                if(m_lpAccel)
                    delete[] m_lpAccel;

              為了能夠對加速鍵數據進行編輯,我們在工程中添加一個對話框資源,ID為“IDD_ACCELEDIT”,在對話框上放置三個成組框(Group Box),左邊一個標題為“命令”;中間一個標題為“組合鍵”;右邊一個標題為“虛鍵值”。在左邊成組框中放置一個列表框(List Box),ID為“IDC_LST_CMD”。在中間成組框中放置三個核選框(Check Box),上下排列。上面的核選框的ID為“IDC_CHK_ALT”,標題為“Alt”,并勾選“Group”屬性;中間的核選框的ID為“IDC_CHK_SHIFT”,標題為“Shift”,取消“Group”屬性;下面的核選框的ID為“IDC_CHK_CTRL”,標題為“Ctrl”,取消“Group”屬性。在右邊的成組框中放置一個列表框,ID為“IDC_LST_KEY”。調整各個控件的尺寸及位置至合適。設置控件的TAB跳轉順序,從左至右、從上到下。依次為:左成組框、IDC_LST_CMD列表框、中成組框、IDC_CHK_ALT核選框、IDC_CHK_SHIFT核選框、IDC_CHK_CTRL核選框、右成組框、IDC_LST_KEY列表框、OK按鈕、CANCEL按鈕。
              打開類向導,為對話框新建一個類,類名為“CDlgEditAccel”。為兩個列表框和三個核選框映射變量,如下:
              控件ID:ID_LST_CMD;類型:Control/CListBox;名稱:m_LstCmd;
              控件ID:ID_LST_KEY;類型:Control/CListBox;名稱:m_LstKey;
              控件ID:ID_CHK_ALT;類型:Control/CButton;名稱:m_ChkAlt;
              控件ID:ID_CHK_SHIFT;類型:Control/CButton;名稱:m_ChkShift;
              控件ID:ID_CHK_CTRL;類型:Control/CButton;名稱:m_ChkCtrl;

              在類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文件中定義類CActAccelList的成員函數,代碼如下:
            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文件頭部定義全局變量--數組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("`",'`')
            };


              在類CDlgAccelEdit中響應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
            }


              為類CDglAccelEdit增加一個保護成員函數:
                void SaveChange(int index=-1);

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

            void CDlgEditAccel::SaveChange(int index)
            {
                if(index>=0||(index=m_LstCmd.GetCurSel())>=0)
                {
                    if(m_LstKey.GetCurSel()<0){
                        AfxMessageBox("你必需選擇一個鍵碼!");
                        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;
                }
            }

              響應列表框ID_LST_CMD的通知消息“LBN_SELCHANGE”,函數代碼如下:
            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);

            }

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

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

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

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

              至此,用于編輯加速鍵的對話框已經完成。我們現在要做的就是在程序中打開對話框來編輯了。讓我們回到CMainFrame類中。我們將在該類中響應一個命令來打開編輯對話框,對加速鍵表進行編輯。完成后點按OK回到主程序中,然后更新加速鍵表。這樣后,我們剛剛編輯好的加速鍵表就開始起作用了。
              首先,打開菜單。在“查看”項后增加一個“工具(&T)”下拉菜單,在下拉菜單中增加一個了菜單:“編輯加速鍵表(&A)...”,ID為“ID_TOOL_ACCELEDIT”。打開類向導,選擇CMainFrame類,響應“ID_TOOL_ACCELEDIT”命令。編輯響應函數如下:

            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);
                }
            }

              在該文件的頭部包含類CDlgEditAccel的頭文件:

            #include "DlgEditAccel.h"

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

              三、將加速鍵表保存至文件,并在程序運行時自動從文件中加載。

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

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

              定義一個DWORD值作為文件頭,我們通過該DWORD值來判斷是否是一個有效格式的文件:

            #define ACCEL_FILE_HEAD 0x00434341


              其次,為CMainFrame類添加一個保護的成員函數:“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\" 中時發生錯誤!\n"
                                 "錯 誤 號:%d\n"
                                 "錯誤描述:%s\n"
                                 "\0",
                                 strAccelFileName,iError,buf);
                    AfxMessageBox(buf2,MB_OK|MB_ICONSTOP|MB_DEFBUTTON1);
                    return FALSE;
                }
            }

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

            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\" 中加載加速鍵表時發生錯誤!\n"
                                 "錯 誤 號:%d\n"
                                 "錯誤描述:%s\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()函數頭部增加對SaveAccel()函數的調用:

                SaveAccel();
                ...

              好了,你自己的加速鍵數據已經能保存在文件中了,并能從中正確加載。如果文件不存在或程序讀取時發現錯誤則提醒你是否建立缺省的加速鍵表,如你確認的話則生成缺省的加速鍵表并立刻保存至文件中。
              由于水平有限,其中難免有誤,歡迎批評指正、發表你的意見。本人不勝感激。

            posted on 2009-01-12 17:22 大海 閱讀(1104) 評論(0)  編輯 收藏 引用 所屬分類: VC++

            久久久久亚洲av成人无码电影 | 久久久久久国产精品免费免费| 国产麻豆精品久久一二三| 中文字幕一区二区三区久久网站| 91精品国产高清91久久久久久| 99久久亚洲综合精品网站| 久久影院亚洲一区| 好久久免费视频高清| 亚洲国产成人精品无码久久久久久综合| 国内精品久久久久影院薰衣草| 久久精品一区二区三区不卡| 久久夜色精品国产www| 精品久久久久中文字幕日本| 武侠古典久久婷婷狼人伊人| 国产69精品久久久久777| 热久久最新网站获取| 久久精品国产免费| 久久综合久久自在自线精品自| 久久久久婷婷| 情人伊人久久综合亚洲| 亚洲中文字幕无码久久2017| 久久精品亚洲精品国产欧美| 狠狠色婷婷综合天天久久丁香 | 国产精品久久一区二区三区| 欧美成人免费观看久久| 久久综合狠狠综合久久97色| 国内精品久久久久久久影视麻豆| 国产精品久久久久jk制服| 香蕉久久夜色精品升级完成| 午夜精品久久影院蜜桃| 亚洲成av人片不卡无码久久| 国产成人精品久久综合| 色噜噜狠狠先锋影音久久| 久久这里只精品国产99热| 麻豆精品久久久一区二区| 国产精品毛片久久久久久久| 国内精品久久久久伊人av| 狠狠色丁香久久综合五月| 日韩亚洲欧美久久久www综合网| 久久精品无码一区二区三区| 久久亚洲高清观看|