青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

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 2008-04-11 11:57 大海 閱讀(725) 評論(0)  編輯 收藏 引用


只有注冊用戶登錄后才能發表評論。
網站導航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            久久久久成人网| 夜夜嗨av一区二区三区四季av| 亚洲激情影院| 亚洲美女黄色片| 国产精品理论片| 久久综合伊人| 欧美三级日本三级少妇99| 欧美一级久久久久久久大片| 久久久精品一区二区三区| 日韩午夜精品| 亚洲欧美一区二区视频| 激情婷婷久久| 日韩网站在线| 在线观看视频日韩| 一个人看的www久久| 国产综合色产在线精品| 91久久综合| 国产免费成人av| 欧美激情一区三区| 国产美女一区| 亚洲精品中文在线| 亚洲国产精品第一区二区三区| 在线视频你懂得一区二区三区| 在线不卡中文字幕播放| 亚洲男人的天堂在线aⅴ视频| 亚洲精品国产精品久久清纯直播| 亚洲一二三四久久| 欧美日韩一区二区三区免费看 | 亚洲视频在线观看| **性色生活片久久毛片| 亚洲香蕉成视频在线观看| 亚洲精品久久久久中文字幕欢迎你| 亚洲一区二区三区国产| 日韩亚洲在线观看| 美玉足脚交一区二区三区图片| 羞羞视频在线观看欧美| 欧美日韩中文字幕精品| 亚洲欧洲在线看| 亚洲国产美女精品久久久久∴| 午夜精品偷拍| 欧美一区二区三区成人| 国产精品国产三级国产aⅴ9色| 亚洲激情在线激情| 亚洲精品欧洲| 欧美成人乱码一区二区三区| 久久男女视频| 国内精品久久久久久 | 亚洲精品日本| 可以看av的网站久久看| 久久夜色精品国产欧美乱极品| 国产日韩av高清| 亚洲女与黑人做爰| 性做久久久久久| 国产欧美日韩在线观看| 午夜精品理论片| 久久国产精品99国产精| 国产乱码精品一区二区三| 亚洲综合导航| 久久精品青青大伊人av| 国产一区二区三区日韩欧美| 久久国产精品第一页| 免费观看在线综合| 亚洲激情网址| 欧美日韩亚洲综合| 亚洲一级片在线看| 久久精品国产成人| 亚洲第一页中文字幕| 欧美高清你懂得| 一区二区免费在线播放| 香蕉免费一区二区三区在线观看| 国产精品亚洲综合久久| 久久久久久久一区| 18成人免费观看视频| 欧美成人国产va精品日本一级| 亚洲级视频在线观看免费1级| 亚洲免费不卡| 国产精品久久久久久久一区探花| 亚洲欧美中日韩| 老鸭窝91久久精品色噜噜导演| 伊人久久噜噜噜躁狠狠躁| 欧美激情 亚洲a∨综合| 国产精品99久久99久久久二8| 久久精品亚洲| 99国产精品| 国产一区亚洲| 欧美区高清在线| 欧美一区二区日韩| 亚洲国产精品一区二区尤物区| 亚洲自拍16p| 亚洲电影在线观看| 欧美日韩一视频区二区| 免费欧美日韩| 欧美中文字幕在线观看| 1024精品一区二区三区| 欧美破处大片在线视频| 性色av香蕉一区二区| 欧美高清视频一区二区三区在线观看 | 伊大人香蕉综合8在线视| 久久婷婷国产综合国色天香| 亚洲国产精品日韩| 久久精品国产一区二区三区| 亚洲精品乱码久久久久久| 国产精品亚洲综合色区韩国| 牛牛影视久久网| 午夜精品视频在线| 日韩视频一区二区三区在线播放免费观看 | 最新中文字幕亚洲| 欧美综合国产| 一区二区三区久久网| 国产午夜精品视频免费不卡69堂| 欧美成人综合一区| 欧美亚洲综合网| 一区二区久久| 亚洲国产精品久久精品怡红院| 久久精品二区亚洲w码| 中文一区在线| 亚洲国产精品一区| 国产日韩欧美三区| 欧美视频中文在线看 | 亚洲一区三区视频在线观看| 亚洲电影第三页| 国产亚洲高清视频| 国产精品久久久久久久免费软件 | 一本大道久久a久久综合婷婷| 国产主播一区二区| 国产精品免费观看视频| 欧美激情国产日韩精品一区18| 欧美综合国产| 亚洲一区激情| 亚洲国产视频一区| 精品成人一区二区三区| 国产精品视频精品| 国产精品va在线播放| 欧美日韩一区二区视频在线| 免费亚洲一区二区| 久久一区二区三区超碰国产精品| 性做久久久久久久免费看| 一区二区三欧美| 日韩网站在线观看| 亚洲免费电影在线观看| 亚洲第一页在线| 欧美韩日一区| 欧美高清视频一区| 亚洲国产精品久久| 亚洲精品看片| 日韩一区二区久久| 亚洲视频网在线直播| 亚洲先锋成人| 欧美一区二区在线免费播放| 久久av二区| 噜噜噜躁狠狠躁狠狠精品视频| 久久男人av资源网站| 国产精品美女久久久久久久| 欧美韩国一区| 亚洲午夜一区二区| 亚洲一区二区在线| 国产欧美精品一区二区三区介绍| 午夜精品区一区二区三| 欧美丰满高潮xxxx喷水动漫| 久久久欧美精品| aa级大片欧美| 欧美成人午夜| 午夜精品福利一区二区蜜股av| 好吊妞**欧美| 欧美日韩中国免费专区在线看| 欧美亚洲日本国产| 一本色道久久综合| 亚洲国产精品第一区二区三区| 久久国产精彩视频| 欧美夜福利tv在线| 在线视频亚洲一区| 99热这里只有成人精品国产| 好吊妞这里只有精品| 国产精品网红福利| 国产精品综合久久久| 欧美性猛交xxxx免费看久久久 | 亚洲黄色成人| 亚洲国产天堂久久国产91| 免费亚洲电影在线| 久久一区二区精品| 久久综合九九| 欧美jizzhd精品欧美巨大免费| 久久婷婷蜜乳一本欲蜜臀| 欧美一区二区视频在线观看2020| 亚洲女同性videos| 欧美诱惑福利视频| 久久人人爽爽爽人久久久| 葵司免费一区二区三区四区五区| 久久天堂国产精品| 欧美粗暴jizz性欧美20| 亚洲精品视频在线观看网站| 99精品欧美一区| 久久aⅴ国产紧身牛仔裤| 男男成人高潮片免费网站| 欧美日本亚洲| 国产欧美激情| 日韩天堂在线视频| 香蕉免费一区二区三区在线观看| 久久精品国产一区二区三区| 欧美成人免费观看|