11.3 通用对话框
11.3.1 完善POPAD
(1)通用对话框:#include<commdlg.h>
(2)OPENFILENAME结构
字段 |
含义 |
备注 |
lStructSize |
结构体的大小 |
|
hwndOwner |
所属窗口,可以为NULL |
|
hInstance |
||
lpstrFilter |
文件筛选字符串
TCHAR szFilter[] = TEXT ("Text Files (*.TXT) *.txt ") TEXT ("ASCII Files (*.ASC) *.asc ") TEXT ("All Files (*.*) *.* "); |
①可由多组内容组成,每组包含一个说明字符串(红色)和一个筛选字符串(蓝色),字符串的最后用两个 结束。 ②筛选字符串可以同时指出多个扩展名,中间用分号隔开,如:*.txt;*.doc |
lpstrCustomFilter |
缓冲区,保留用户选择的过滤样式 |
可以为NULL |
nMaxCustFilter |
lpstrCustomFilter准备的以TCHAR为单位的缓冲大小 |
|
nFilterIndex |
当前选择的过滤器的索引 |
0:指出是通过lpstrCustomFilter指定的定制过滤器 1:lpstrFilter缓冲区的第1个索引。2为第2个索引,以此类推 |
lpstrFile |
全路径文件名缓冲区 (包含驱动器、路径、文件名和扩展名) |
①对话框初始化时显示该文件名 ②用户选择时,在些返回新的文件名 |
nMaxFile |
lpstrFile缓冲区的大小 |
|
lpstrFileTitle |
接收不含路径的文件名的缓冲区 |
可以为NULL |
nMaxFileTitle |
lpstrFileTitle缓冲区大小,以TCHAR为单位 |
|
lpstrInitialDir |
在这个字符串中指定初始目录 |
可为NULL |
lpstrTitle |
对话框标题,默认为“打开”或“保存” |
|
Flags |
对话框不同行为的标志 ①OFN_ALLOWMULTISELECT——允许多选 ②OFN_CREATEPROMPT——用户输入不存在的文件名时,会提示“是否建立文件” ③OFN_FILEMUSTESTIST——只能选择一个己经存在的文件 ④OFN_HIDEREADONLY——不显示“以只读方式打开”选择框 ⑤OFN_OVERWRITEPROMPT——保存时,提问“是否覆盖文件” ⑥OFN_PATHMUSTEXIST——输入路径必须存在 ⑦OFN_READONLY——“以只读方式打开”复选择处于选中状态 |
|
nFileOffset |
返回文件名字符串中,文件名的起始位置 |
如,当用户选择文件:“c;dir1file.txt”,时返回8,因为文件名file.txt的起始位置从8开始。 |
nFileExtension |
扩展名在字符串中的起始位置 |
|
lpstrDefExt |
指定默认的扩展名 |
|
lCustData |
||
lpfnHook |
指向一个钩子程序 |
Flags成员中包含OFN_ENABLEHOOK标记 |
lpTemplateName |
是对话框模板资源 |
Flags成员中设置OFN_ENABLETEMPLATE |
(3)“打开”或“保存”对话框函数:GetOpenFileName/GetSaveFileName
11.3.2 Unicode文件
(1)Unicode文件的判断——IsTextUnicode(lpBuffer,cb, lpi)
①lpBuffer参数:要测试的字符串,其缓冲区地址
②cb个参数:lpBuffer指向的字节数(注意是不是字符数)
③lpi:是个in/out类型的,传入时指定哪些测试项目,传出时为符合哪个测试项目。
④返回值:TRUE或FALSE
(2)字符串的转化——这里的多字节是广义的,即可指ANSI,也可指UTF_8等。
①WideCharToMultiByte——将Unicode字符串转为多字节字符串
字段 |
功能 |
CodePage |
CodePage参数用于标识要为转换新的字符串的相关代码页,如CP_ACP实现了Unicode与ANSI的转换;CP_UTF8 实现了Unicode与UTF-8的转换 |
dwFlags |
进行额外的控制,会影响使用了读音符号(比如重音)的字符 |
lpWideCharStr |
转换为宽字节字符串的缓冲区 |
cchWideChar |
lpWideCharStr指向的缓冲区的字符个数。如果-1,字符串将被设定为以NULL为结束符的字符串,并且自动计算长度(含 )。 |
lpMultiByteStr |
接收被转换字符串的缓冲区 |
cchMultiByte |
lpMultiByteStr指向的缓冲区最大值(用字节来计量) |
lpDefaultChar |
遇到一个不能转换的宽字符,函数便会使用该参数指向的字符。 |
pfUsedDefaultChar |
只要遇到任何一个不能被转换的字符,就会被函数设为TRUE。 |
②MultiByteToWideChar——将多字节字符串转为Unicode字符串
字段 |
功能 |
CodePage |
用来标记与一个多字节字符串相关的代码页 |
dwFlags |
进行额外的控制,会影响使用了读音符号(比如重音)的字符 |
lpWideCharStr |
转换为宽字节字符串的缓冲区 |
cchWideChar |
lpWideCharStr指向的缓冲区的字符个数,如果-1,字符串将被设定为以NULL为结束符的字符串,并且自动计算长度(含 )。 |
lpMultiByteStr |
接收被转换字符串的缓冲区 |
cchMultiByte |
lpMultiByteStr指向的缓冲区最大值(用字节来计量) |
lpDefaultChar |
遇到一个不能转换的宽字符,函数便会使用该参数指向的字符。 |
pfUsedDefaultChar |
只要遇到任何一个不能被转换的字符,就会被函数设为TRUE。 |
11.3.3 改变字体
(1)CHOOSEFONT结构体
字段 |
说明 |
lStructSize |
结构长度 |
hwndOwner |
所属窗口 |
hDC |
当Flags标志指定CF_PRINTERFONTS标志时,它是打印机的DC句柄 |
lpLogFont |
指向一个LOGFONT结构 |
iPointSize |
选择的字体的大小,单位是1/10磅 |
rgbColors |
返回选择的字体的颜色。如果Flags字段的CF_EFFECTS被设置,将同时用该颜色初始化“颜色”下拉列表框 |
nFontType |
从ChooseFont函数中返回用户选择的字体:BOLD_FONTTYPE、ITALIC_FONTTYPE、REGULAR_FONTTYPE、ITALIC_FONTTYPE、PRINTER_FONTTYPE、SCREEN_FONTTYPE等。 |
Flags |
对话框显示设置: CF_BOTH:同时列出打印机字体和屏幕字体 CF_TTONLY:只列出TrueType字体 CF_EFFECTS:显示“效果”复选择 CF_FIXEDPITCHONLY:只显示等宽字体 CF_LIMITSIZE:显示字体的尺寸介于nSizeMin到nSizeMax之间 CF_NOSTYLESEL:不显示“字形”组合列表框 CF_NOSIZESEL:不显示“大小”组合列表框 CF_SCREENFONTS:只显示屏幕字体 |
(2)设置编辑框字体:SendMessage(hwndEdit,WM_SETFONT, (WPARAM)hFont, 0)
11.3.4 查找和替换
(1)FINDREPLACE结构的主要字段
字段 |
说明 |
lStructSize |
结构体大小 |
hwndOwner |
所属窗口,不能为NULL,必须设置。因为对话框是非模态的,要向父窗口发送查找或替换的消息。 |
lpstrFindWhat |
查找字符串 |
lpstrReplaceWith |
替换字符串,可为NULL,但在ReplaceText函数中须设置。 |
wFindWhatLen |
查找字符串的长度(至少要80字节) |
wReplaceWithLen |
替换字符串的长度 |
Flags |
①FR_FINDNEXT、FR_REPLACE、FR_REPLACEALL、FR_DIALOGTERM——表示用户单击了“查找下一个”、“替换”、“全部替换”和“取消” ②FR_HIDEUPDOWN、FR_HIDEMATCHCASE、FR_HIDEWHOLEWORD:初始化时,表示对话框不显示“方向”、“区分大小写”、“全字匹配”按钮 ③FR_NOMATCHCASE、FR_NOUPDOWN、FR_NOWHOLEWORD:将“区分大小写”、“方向”、“全字匹配”按钮灰化。 ④FR_DOWN:把“方向”按钮设置为“向下”。 |
(2)对话框是非模态的,所以消息循环应该调用IsDialogMessage。
(3)FINDREPLACE结构不能声明为窗口过程的局部变量,必须是静态变量或全局变量。因为当调用FindText或ReplaceText调出对话框后,PopFindFindDlg(PopFindReplaceDlg)这些函数会立即返回。但该结构会作为消息的lParam参数被发送到父窗口的消息过程。为防止该结构被释放,要声明为静态变量。
(4)“查找”或“替换”对话框与父窗口会进行一种特殊的消息进行通信。
所以程序首先须通过FINDMSGSTR这个名字,向系统申请获得该特殊消息的ID号,即msgID =RegisterWindowMessage (FINDMSGSTRING)后就可以利用msgID进行通信了。
【POPAD3程序】
效果图:
//CommFunc.h
#include<windows.h> //Function in POPFILE.C void PopFileInitialize(HWND); BOOL PopFileOpenDlg(HWND, PTSTR, PTSTR); BOOL PopFileSaveDlg(HWND, PTSTR, PTSTR); BOOL PopFileRead(HWND, PTSTR); BOOL PopFileWrite(HWND, PTSTR); //Function in POPFIND.C HWND PopFindFindDlg(HWND); HWND PopFindReplaceDlg(HWND); BOOL PopFindFindText(HWND, int*, LPFINDREPLACE); BOOL PopFindNextText(HWND, int*); BOOL PopFindReplaceText(HWND, int*, LPFINDREPLACE); BOOL PopFindValidFind(void); //Functions in POPFONT.C void PopFontInitialize(HWND); BOOL PopFontChooseFont(HWND); void PopFontSetFont(HWND); void PopFontDeinitialize(void); //Functions in POPPRINT.C BOOL PopPrntPrintFile(HINSTANCE, HWND, HWND, PTSTR);
//PopPad3.c
/*------------------------------------------------------------ POPPAD3.C -- Popup Editor Version3 (includes menu) (c) Charles Petzold, 1998 ------------------------------------------------------------*/ #include <windows.h> #include "resource.h" #include "CommFunc.h" #define ID_EDIT 1 #define UNTITLED TEXT("(untitled)") static TCHAR szAppName[] = TEXT("PopPad3"); static HWND hDlgModeless; LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { HACCEL hAccel; HWND hwnd; MSG msg; WNDCLASS wndclass; wndclass.style = CS_HREDRAW | CS_VREDRAW; wndclass.lpfnWndProc = WndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = hInstance; wndclass.hIcon = LoadIcon(NULL, szAppName); wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wndclass.lpszMenuName = szAppName; wndclass.lpszClassName = szAppName; if (!RegisterClass(&wndclass)) { MessageBox(NULL, TEXT("This program requires Windows NT!"), szAppName, MB_ICONERROR); return 0; } hwnd = CreateWindow(szAppName, // window class name TEXT("edit3"), // window caption WS_OVERLAPPEDWINDOW, // window style CW_USEDEFAULT, // initial x position CW_USEDEFAULT, // initial y position CW_USEDEFAULT, // initial x size CW_USEDEFAULT, // initial y size NULL, // parent window handle NULL, // window menu handle hInstance, // program instance handle NULL); // creation parameters ShowWindow(hwnd, iCmdShow); UpdateWindow(hwnd); hAccel = LoadAccelerators(hInstance, szAppName); while (GetMessage(&msg, NULL, 0, 0)) { if (hDlgModeless == NULL || !IsDialogMessage(hDlgModeless, &msg)) { //处理键盘加速键 if (!TranslateAccelerator(hwnd, hAccel, &msg)) { //非键盘加速键消息的处理 TranslateMessage(&msg); DispatchMessage(&msg); } } } return msg.wParam; } void OkMessage(HWND hwnd, TCHAR* szMessage, TCHAR* szTitleName) { TCHAR szBuffer[64 + MAX_PATH]; wsprintf(szBuffer, szMessage, szTitleName[0] ? szTitleName : UNTITLED); MessageBox(hwnd, szBuffer, szAppName, MB_OK | MB_ICONEXCLAMATION); } int AskConfirmation(HWND hwnd) { return MessageBox(hwnd, TEXT("Really Want to close PopPad3?"), szAppName, MB_YESNO | MB_ICONQUESTION); } short AskAboutSave(HWND hwnd, TCHAR* szTitleName) { TCHAR szBuffer[64 + MAX_PATH]; int iRet; wsprintf(szBuffer, TEXT("Save current changes in %s?"), szTitleName[0] ? szTitleName : UNTITLED); iRet = MessageBox(hwnd, szBuffer, szAppName, MB_YESNOCANCEL | MB_ICONQUESTION); if (iRet == IDYES) { if (!SendMessage(hwnd, WM_COMMAND, IDM_FILE_SAVE, 0)) //IDM_FILE_SAVE返回0为失败,1成功 iRet = IDCANCEL; } return iRet; } //设置标题 void DoCaption(HWND hwnd, TCHAR* szTitleName) { TCHAR szCaption[64 + MAX_PATH]; wsprintf(szCaption, TEXT("%s - %s"), szAppName, szTitleName[0] ? szTitleName : UNTITLED); SetWindowText(hwnd, szCaption); } LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { static HWND hwndEdit; int iSelect, iEnable; static int iOffset; static TCHAR szFileName[MAX_PATH], szTitleName[MAX_PATH]; static bNeedSave = FALSE; static UINT messageFindReplace; LPFINDREPLACE pfr; switch (message) { case WM_CREATE: hwndEdit = CreateWindow(TEXT("edit"), NULL, WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL | WS_BORDER | ES_LEFT | ES_MULTILINE | ES_NOHIDESEL | //ES_NOHIDESEL,编辑框在没有输入焦点时被选择的文字仍然被加亮 ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0, 0, 0, 0, hwnd, (HMENU)ID_EDIT, ((LPCREATESTRUCT)lParam)->hInstance, NULL); //限制编辑框的文本最大长度 SendMessage(hwndEdit, EM_LIMITTEXT, 32000, 0L); PopFileInitialize(hwnd); PopFontInitialize(hwndEdit); messageFindReplace = RegisterWindowMessage(FINDMSGSTRING); //申请获取“查找”、“替换”发出的特殊消息的ID DoCaption(hwnd, szTitleName); return 0; case WM_SETFOCUS: SetFocus(hwndEdit); return 0; case WM_INITMENUPOPUP: //lParam:item position and indicator switch (lParam) { case 1: //Undo菜单项 EnableMenuItem((HMENU)wParam, IDM_EDIT_UNDO, SendMessage(hwndEdit, EM_CANUNDO, 0, 0) ? MF_ENABLED : MF_GRAYED); //Paste菜单项 EnableMenuItem((HMENU)wParam, IDM_EDIT_PASTE, IsClipboardFormatAvailable(CF_TEXT) ? MF_ENABLED : MF_GRAYED); iSelect = SendMessage(hwndEdit, EM_GETSEL, 0, 0); if (HIWORD(iSelect) == LOWORD(iSelect)) iEnable = MF_GRAYED; else iEnable = MF_ENABLED; EnableMenuItem((HMENU)wParam, IDM_EDIT_CUT, iEnable); EnableMenuItem((HMENU)wParam, IDM_EDIT_COPY, iEnable); EnableMenuItem((HMENU)wParam, IDM_EDIT_CLEAR, iEnable); break; case 2: //“查找”菜单项 //如果非模态对话框==NULL时,激活菜单 iEnable = hDlgModeless == NULL ? MF_ENABLED : MF_GRAYED; EnableMenuItem((HMENU)wParam, IDM_SEARCH_FIND, iEnable); EnableMenuItem((HMENU)wParam, IDM_SEARCH_NEXT, iEnable); EnableMenuItem((HMENU)wParam, IDM_SEARCH_REPLACE, iEnable); break; } return 0; case WM_COMMAND: if (lParam && LOWORD(wParam == ID_EDIT)) //控件消息 { switch (HIWORD(wParam)) //控件通知码 { case EN_UPDATE: bNeedSave = TRUE; return 0; case EN_ERRSPACE: case EN_MAXTEXT: MessageBox(hwnd, TEXT("Edit Control out of space."), szAppName, MB_OK | MB_ICONSTOP); return 0; } break; }; switch (LOWORD(wParam))//加速键ID或菜单ID,这里两个ID相等 { //菜单消息 case IDM_FILE_NEW: //保存旧文件,如果保存时失败,则什么都不做,直接返回。 if (bNeedSave&& IDCANCEL == AskAboutSave(hwnd, szTitleName)) return 0; SetWindowText(hwndEdit, TEXT("