星期五, 九月 08, 2006

MFC窗口中各控件的上下层次的设置


BOOL SetWindowPos(
const CWnd* pWndInsertAfter,
int x,
int y,
int cx,
int cy,
UINT nFlags
);

  • wndBottom

  • ウィンドウを Z オーダーの一番下に置きます。このCWnd が最上位のウィンドウの場合、
    ウィンドウの最上位ステータスは失われます。
    システムでは、このウィンドウをほかのすべてのウィンドウよりも下に置きます。

    将窗口(控件也是窗口)置于Z坐标的最下层

  • wndTop

  • ウィンドウを Z オーダーの先頭に置きます。

    将窗口(控件也是窗口)置于Z坐标的最上层

  • wndTopMost

  • ウィンドウを最上位でないすべてのウィンドウの上に置きます。ウィンドウは、非アクティブになったときも、最上位の位置を保持します。

    始终最上层

  • wndNoTopMost

  • ウィンドウを最上位でないすべてのウィンドウの先頭に再配置します (つまり、一番手前のすべてのウィンドウの後ろに置きます)。
    ウィンドウが既に非最上位ウィンドウとなっているときは、このフラグは無効です。



    BOOL ModifyStyle(
    DWORD dwRemove,
    DWORD dwAdd,
    UINT nFlags = 0
    );


    窗口中各控件的描画顺序
    top的最先描画
    bottom的最后描画
    导致控件的消息响应和显示矛盾

    可以通过以下方法的设置解决
    GetDlgItem(IDC_SCREEN_SWITCH_BACK)->SetWindowPos(&wndBottom, 0, 0, 50, 592, SWP_SHOWWINDOW);
    GetDlgItem(IDC_SCREEN_SWITCH_BACK)->ModifyStyle(0, WS_CLIPSIBLINGS, 0);

    星期三, 九月 06, 2006

    为OpenFile通用对话框增添预展功能

    为OpenFile通用对话框增添预展功能
      用户使用Window应用程序时,经常要打开文件,可有时用户打开文件时却打开了一个不是要求的文件,这显得非常麻烦。因此,许多应用程序便给OpenFile通用对话框增添了预展功能,使得用户在选择文件时,可以先预视其内容。在这里,笔者也向你介绍这种功能的编程方法。  WINDOW的通用对话框OpenFile,在使用,可以安装用户定义的勾子函数。这样,原OpenFile窗口的消息先通过用户的勾子函数过滤。若用户在通用对话框中增加一个Edit控制(此处,以预展文本文件内容为例),处理OpenFile通用对话框中的 CDN_SELCHANGE消息(文件名选择更改消息),即可完成这种功能。  用户定义的勾子函数,WINDOW要求其原形定义如下:  typedef UINT (APIENTRY *LPCCHOOKPROC) (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);  对于OpenFile通用对话框中的一些常见消息,WINDOWS会向用户定义的勾子发送WM_NOTIFY消息,此时,lParam指向一数据结构如下的指针:  typedef struct _OFNOTIFYA
      { NMHDR hdr;
      LPOPENFILENAMEA lpOFN;
      LPSTR pszFile; // May be NULL
      } OFNOTIFYA, FAR *LPOFNOTIFYA;
      而NMHDR在WINDOWS定义如下:  typedef struct tagNMHDR {
      HWND hwndFrom;
      UINT idFrom;
      UINT code;
      } NMHDR;
      其中:hwndFrom 表示发送消息控件的句柄;idFrom表示控件的ID值,而且code表示通告的消息。  在WINDOWS95中通告的消息在commdlg.h中定义如下  #define CDN_SELCHANGE (CDN_FIRST-0x0001) //文件名列表中的文件名更改时发送的消息
      #define CDN_FOLDERCHANGE (CDN_FIRST - 0x0002) //路径更改时发送的消息
      #define CDN_SHAREVIOLATION (CDN_FIRST - 0x0003) //共享按钮改更时发送的消息
      #define CDN_HELP (CDN_FIRST - 0x0004) //HELP按钮按下消息
      #define CDN_FILEOK (CDN_FIRST - 0x0005) //OK按钮按下消息
      因为此处,我们仅处理用户选择的文件名发生更改时,才预展,因此我们定义的勾子函数中,仅处理CDN_SELCHANGE消息。  另外,当什么文件都预展时,用户会发现WINDOWS的速度明显减慢,因此,我决定在OpenFile对话框中增加一个"是否预展"的CheckBox按钮。只有当用户选中了它时才预展。当然,此时,还需要我们自己处理这个CheckBox发送的消息。  以上问题解决后,我们只需要将一个Edit和一个CheckBox增加到一个无窗体的对话框中,并将WINDOWS本身的OpenFile对话框用一个TEXT控件代替,ID值设置为stc32(定义在dlgs.h中)。  此时还需要将OPENFILENAME结构中的lpfnHook成员,设置成用户定义的勾子函数,将lpTemplateName成员设置成用户定义对话框的ID值(需要用MAKEINTRESOURCE),此外,成员Flags需要设置成OFN_EXPLORER(WINDOW32中使用) OFN_ENABLEHOOK(允许使用用户定义的勾子函数) OFN_ENABLETEMPLATE(允许用户定义的对话框模板)。  现在一切就绪,剩下的工作便是着手编写这一程序,看看这动人的一幕。  以下为我设计的全部源程序。此程序在PWIN95,Borland C++5.0中通过。 //OpenFile.rh
    #ifndef _OPENFILE_RH
    #define _OPENFILE_RH
    #define IDD_OPENFILE 100 //打开文件
    #define IDM_FILEOPEN 106 //打开文件菜单命令
    #define IDM_EXIT 107 //退出
    #define IDE_EDIT 1022 //预展EDIT
    #define ID_PRESHOW 1023 //预展CheckBox按钮
    #endif
    //OpenFile.h
    #define STRICT
    #ifdef RC_INVOKED
    #include
    #else
    #include
    #endif
    #define MAX_PATH 260
    long APIENTRY MainWndProc(HWND, UINT, UINT, LONG);
    BOOL CALLBACK OpenFileNameDlgProc(HWND ,UINT,UINT,LONG);
    BOOL InitApplication(HANDLE);
    BOOL InitInstance(HANDLE, int);
    void CALLBACK SetErrorMsg(HWND,UINT,const char *,char *);
    BOOL OpenTheFile( OPENFILENAME *);
    BOOL NEAR PASCAL TestNotify(HWND, LPOFNOTIFY);
    //OpenFile.RC
    #include "openfile.rh"
    #include

    IDD_OPENFILE DIALOG 0, 0, 251, 130
    STYLE DS_3DLOOK DS_CONTROL WS_CHILD WS_VISIBLE WS_CLIPSIBLINGS
    FONT 9, "MS Sans Serif"
    {
    LTEXT "", stc32, 4, 4, 124, 125
    CONTROL "以文本方式预展", ID_PRESHOW, "button", BS_AUTOCHECKBOX WS_CHILD
    WS_VISIBLE WS_TABSTOP, 132, 121, 104, 9
    CONTROL "", IDE_EDIT, "edit", ES_LEFT ES_MULTILINE ES_AUTOVSCROLL
    ES_AUTOHSCROLL WS_CHILD WS_VISIBLE WS_BORDER WS_TABSTOP,
    132, 4, 116, 112
    }
    OPENFILEMENU MENU
    {
    POPUP "&Options"
    {
    MENUITEM "&File Open...", IDM_FILEOPEN
    MENUITEM "E&xit", IDM_EXIT
    }
    }
    //OpenFile.h
    #include
    #include
    #include
    #include "openfile.rh"
    #include "openfile.h"
    HINSTANCE g_hInst; //应用程序的实例句柄
    OPENFILENAME OpenFileName; //打开文件结构
    char szFile[MAX_PATH]; //文件名
    #pragma argsused
    int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
    LPSTR lpCmdLine, int nCmdShow )
    { MSG msg;
    OSVERSIONINFO osVer;
    osVer.dwOSVersionInfoSize = sizeof(osVer);
    if (!GetVersionEx(&osVer)) //取版本信息不成功返回
    return (FALSE);
    if (osVer.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS)
    {//不在Window95环境下
    MessageBox(NULL, "此程序需要在Windows 95下运行.", "警告", MB_OK );
    return (FALSE);
    }
    if (!InitApplication(hInstance)) //初始化应用程序失败
    return (FALSE);
    if (!InitInstance(hInstance, nCmdShow))
    return (FALSE);
    while (GetMessage(&msg,NULL,0,0))
    { TranslateMessage(&msg);
    DispatchMessage(&msg);
    }
    return (msg.wParam);
    }
    BOOL InitApplication(HANDLE hInstance)
    { WNDCLASS wc;
    wc.style = 0;
    wc.lpfnWndProc = (WNDPROC)MainWndProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = hInstance;
    wc.hIcon = NULL;
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = GetStockObject(WHITE_BRUSH);
    wc.lpszMenuName = "OpenFileMenu";
    wc.lpszClassName = "OpenFileNameClass";
    return (RegisterClass(&wc));
    }
    BOOL InitInstance( HANDLE hInstance, int nCmdShow)
    { HWND hWnd;
    g_hInst = hInstance; //保存当前应用程序的实例句柄
    hWnd = CreateWindow(
    "OpenFileNameClass",
    "为你的OpenFile增加预视功能",
    WS_OVERLAPPEDWINDOW,
    CW_USEDEFAULT,
    CW_USEDEFAULT,
    CW_USEDEFAULT,
    CW_USEDEFAULT,
    NULL,
    NULL,
    g_hInst,
    NULL
    );
    if (!hWnd) //窗口不能建立
    return (FALSE);
    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);
    return (TRUE);
    }
    LONG APIENTRY MainWndProc( HWND hWnd, UINT message, UINT wParam, LONG lParam)
    { static HWND hwndEdit;
    CHAR lpszHello[] = "请从菜单上选择Open File,可看到OpenFile中的预视功能.";
    switch (message) {
    case WM_CREATE:
    OpenFileName.lStructSize = sizeof(OPENFILENAME); //结构大小
    OpenFileName.hwndOwner = hWnd;
    OpenFileName.hInstance = g_hInst;
    OpenFileName.lpstrFilter= "文本文件名(*.txt)\0*.TXT\0所有文件(*.*)\0*.*\0\0";
    OpenFileName.lpstrCustomFilter =NULL;
    OpenFileName.nMaxCustFilter = 0;
    OpenFileName.nFilterIndex = 0;
    OpenFileName.lpstrFile = szFile;
    OpenFileName.nMaxFile = sizeof(szFile);
    OpenFileName.lpstrFileTitle = NULL;
    OpenFileName.nMaxFileTitle = 0;
    OpenFileName.lpstrInitialDir = NULL;
    OpenFileName.lpstrTitle = "打开文件"; //窗口标题
    OpenFileName.nFileOffset = 0;
    OpenFileName.nFileExtension = 0;
    OpenFileName.lpstrDefExt = "txt"; //扩展文件名
    hwndEdit = CreateWindow( //建立一编辑窗口
    "EDIT", NULL,
    WS_CHILD WS_VISIBLE WS_VSCROLL
    ES_LEFT ES_MULTILINE ES_AUTOVSCROLL,
    0, 0, 0, 0,
    hWnd,
    NULL,
    (HINSTANCE) GetWindowLong(hWnd, GWL_HINSTANCE),
    NULL);
    //设置信息
    SendMessage(hwndEdit, WM_SETTEXT, 0, (LPARAM) lpszHello);
    return 0;
    case WM_SIZE:
    MoveWindow(hwndEdit, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE);
    return 0;
    case WM_COMMAND:
    switch( LOWORD( wParam ))
    { case IDM_FILEOPEN: //选中了打开文件菜单项
    if(OpenTheFile( &OpenFileName))
    SendMessage(hwndEdit, WM_SETTEXT, 0,
    (LPARAM)OpenFileName.lpstrFile);
    break;
    case IDM_EXIT:
    PostQuitMessage(0);
    break;
    default:
    return (DefWindowProc(hWnd, message, wParam, lParam));
    }
    break;
    case WM_DESTROY:
    PostQuitMessage(0);
    break;
    default:
    return (DefWindowProc(hWnd, message, wParam, lParam));
    }
    return (0);
    }
    //函数作用:打开文件
    BOOL OpenTheFile(OPENFILENAME *OpenFileName)
    { OpenFileName->lCustData = NULL;
    OpenFileName->lpfnHook = (LPOFNHOOKPROC) OpenFileNameDlgProc;
    OpenFileName->lpTemplateName = MAKEINTRESOURCE(IDD_OPENFILE);
    OpenFileName->Flags =OFN_EXPLORER OFN_HIDEREADONLY
    OFN_ENABLEHOOK OFN_ENABLETEMPLATE;
    return(GetOpenFileName(OpenFileName));
    }
    BOOL NEAR PASCAL TestNotify(HWND hDlg, LPOFNOTIFY pofn)
    { HFILE hFile; //打开文件名柄
    long dwBytesRead; long dwFileSize;
    LPSTR lpBuf; char szFile[MAX_PATH];
    if (pofn->hdr.code!=CDN_SELCHANGE) //文件选择改变
    return(FALSE);
    if (SendDlgItemMessage(hDlg,ID_PRESHOW,BM_GETCHECK,0,0L)==0)
    //用户没有选中预展按钮,则直接返回
    return(FALSE);
    if (CommDlg_OpenSave_GetSpec(GetParent(hDlg), //获取选中的文件名
    szFile, sizeof(szFile)) <= sizeof(szFile))
    { hFile =_lopen((LPSTR)szFile,OF_READ);
    if (hFile==HFILE_ERROR)
    {SetErrorMsg(hDlg,IDE_EDIT,"文件[%s]不能开",szFile);
    return FALSE; //打开文件失败失败,返回
    }
    dwFileSize =_llseek(hFile,0L,FILE_END); //取文件大小
    if (dwFileSize == HFILE_ERROR) //失败,则返回
    { SetErrorMsg(hDlg,IDE_EDIT,"移动文件[%s]指针出错.",szFile);
    _lclose(hFile); return FALSE;
    }
    _llseek(hFile,0L,FILE_BEGIN);
    lpBuf = (char *)GlobalAlloc( GMEM_FIXED, dwFileSize );
    if (lpBuf == NULL ) //分配内存失败失败
    {SetErrorMsg(hDlg,IDE_EDIT,"不能为文件[%s],分配内存",szFile);
    _lclose( hFile );
    return FALSE;
    }
    dwBytesRead= _lread(hFile,(LPVOID)lpBuf, dwFileSize);
    //读文件到lpBUf处
    if (dwBytesRead ==HFILE_ERROR) //读文件失败
    { SetErrorMsg(hDlg,IDE_EDIT,"读文件[%s]失败",szFile);
    GlobalFree(lpBuf);
    _lclose( hFile );
    return FALSE;
    }
    SetDlgItemText(hDlg,IDE_EDIT,lpBuf);
    _lclose(hFile); //关闭文件
    GlobalFree(lpBuf);//释放分配的内存
    return TRUE;
    }
    else return(TRUE);
    }
    #pragma argsused
    void CALLBACK SetErrorMsg(HWND hDlg,UINT id,const char *format,char *msg)
    { char buf[MAX_PATH];
    wsprintf(buf,format,msg);
    SetDlgItemText(hDlg,id,buf);
    }
    #pragma argsused
    BOOL CALLBACK OpenFileNameDlgProc(HWND hDlg, UINT uMsg,
    WPARAM wParam,
    LPARAM lParam)
    { char buf=0;
    OFNOTIFY of;
    switch (uMsg)
    { case WM_COMMAND: //用户在PreShow按钮上改变了显示
    if(wParam==ID_PRESHOW)
    { if (!SendDlgItemMessage(hDlg,ID_PRESHOW,BM_GETCHECK,0,0L))
    //没有选中,则将预展EDIT窗口设置为空
    SetDlgItemText(hDlg,IDE_EDIT,&buf);
    else
    {of.hdr.code=CDN_SELCHANGE; //否则,调用TestNotify处理
    TestNotify(hDlg,(LPOFNOTIFY)&of);
    }
    }
    return FALSE;
    case WM_NOTIFY:
     TestNotify(hDlg, (LPOFNOTIFY)lParam);
     return(TRUE);
    default:
    return FALSE;
    }
    }

    通过文件路径获取文件名和扩展名 _tsplitpath

    _tsplitpath
    通过文件路径获取文件名和扩展名
    // crt_makepath.c
    #include
    #include
    int main( void )
    {
    char path_buffer[_MAX_PATH];
    char drive[_MAX_DRIVE];
    char dir[_MAX_DIR];
    char fname[_MAX_FNAME];
    char ext[_MAX_EXT];
    _makepath( path_buffer, "c", "file:////sample//crt//", "makepath", "c" );
    printf( "Path created with _makepath: %s\n\n", path_buffer );
    _splitpath( path_buffer, drive, dir, fname, ext );
    printf( "Path extracted with _splitpath:\n" );
    printf( " Drive: %s\n", drive );
    printf( " Dir: %s\n", dir );
    printf( " Filename: %s\n", fname );
    printf( " Ext: %s\n", ext );
    }
    パス名を構成要素に分解します。
    void _splitpath(const char *path,char *drive,char *dir,
    char *fname,char *ext );
    void _wsplitpath(const wchar_t *path,wchar_t *drive,
    wchar_t *dir,wchar_t *fname,wchar_t *ext );
    パラメータ
    path
    完全パス。
    drive
    ドライブを表す文字 (省略可能)。後ろにコロン (:) を付けます。
    dir
    ディレクトリ パスと末尾のスラッシュ (省略可能)。後ろにスラッシュ (/)、円記号 (\) を付けます (混在可)。
    fname
    ベース ファイル名 (拡張子なし)。
    ext
    ファイル名の拡張子 (省略可能)。先頭にピリオド (.) が付きます。
    解説-〉详见msdn