使用通用对话框
本部分介绍调用常见对话框的任务:
选择颜色
本主题介绍显示 “颜色 ”对话框以便用户可以选择颜色的示例代码。 示例代码首先初始化 CHOOSECOLOR 结构,然后调用 ChooseColor 函数以显示对话框。 如果函数返回 TRUE,指示用户选择了一种颜色,则示例代码使用所选颜色创建新的纯色画笔。
此示例使用 CHOOSECOLOR 结构初始化对话框,如下所示:
- 使用指向静态值数组的指针初始化 lpCustColors 成员。 数组中的颜色最初为黑色,但静态数组保留用户为后续 ChooseColor 调用创建的自定义颜色。
- 设置 CC_RGBINIT 标志并初始化 rgbResult 成员以指定打开对话框时最初选择的颜色。 如果未指定,则初始选择为黑色。 该示例使用 rgbCurrent 静态变量在调用 ChooseColor 之间保留所选值。
- 设置 CC_FULLOPEN 标志,以便始终显示对话框的自定义颜色扩展。
CHOOSECOLOR cc; // common dialog box structure
static COLORREF acrCustClr[16]; // array of custom colors
HWND hwnd; // owner window
HBRUSH hbrush; // brush handle
static DWORD rgbCurrent; // initial color selection
// Initialize CHOOSECOLOR
ZeroMemory(&cc, sizeof(cc));
cc.lStructSize = sizeof(cc);
cc.hwndOwner = hwnd;
cc.lpCustColors = (LPDWORD) acrCustClr;
cc.rgbResult = rgbCurrent;
cc.Flags = CC_FULLOPEN | CC_RGBINIT;
if (ChooseColor(&cc)==TRUE)
{
hbrush = CreateSolidBrush(cc.rgbResult);
rgbCurrent = cc.rgbResult;
}
选择字体
本主题介绍显示 “字体 ”对话框的示例代码,以便用户可以选择字体的属性。 示例代码首先初始化 CHOOSEFONT 结构,然后调用 ChooseFont 函数以显示对话框。
本示例设置 CF_SCREENFONTS 标志以指定对话框应仅显示屏幕字体。 它设置 CF_EFFECTS 标志以显示允许用户选择删除线、下划线和颜色选项的控件。
如果 ChooseFont 返回 TRUE,指示用户单击了“确定”按钮,则 CHOOSEFONT 结构将包含描述用户选择的字体和字体属性的信息,包括 lpLogFont 成员指向的 LOGFONT 结构的成员。 rgbColors 成员包含所选文本颜色。 示例代码使用此信息设置与所有者窗口关联的设备上下文的字体和文本颜色。
HWND hwnd; // owner window
HDC hdc; // display device context of owner window
CHOOSEFONT cf; // common dialog box structure
static LOGFONT lf; // logical font structure
static DWORD rgbCurrent; // current text color
HFONT hfont, hfontPrev;
DWORD rgbPrev;
// Initialize CHOOSEFONT
ZeroMemory(&cf, sizeof(cf));
cf.lStructSize = sizeof (cf);
cf.hwndOwner = hwnd;
cf.lpLogFont = &lf;
cf.rgbColors = rgbCurrent;
cf.Flags = CF_SCREENFONTS | CF_EFFECTS;
if (ChooseFont(&cf)==TRUE)
{
hfont = CreateFontIndirect(cf.lpLogFont);
hfontPrev = SelectObject(hdc, hfont);
rgbCurrent= cf.rgbColors;
rgbPrev = SetTextColor(hdc, rgbCurrent);
.
.
.
}
打开文件
注意
从 Windows Vista 开始,通用文件对话框在用于打开文件时已被通用项对话框取代。 建议使用通用项对话框 API 而不是通用文件对话框 API。 有关详细信息,请参阅 通用项对话框。
本主题介绍显示“ 打开 ”对话框的示例代码,以便用户可以指定要打开的文件的驱动器、目录和名称。 示例代码首先初始化 OPENFILENAME 结构,然后调用 GetOpenFileName 函数以显示对话框。
在此示例中, lpstrFilter 成员是指向缓冲区的指针,该缓冲区指定两个文件名筛选器,用户可以选择这些筛选器来限制显示的文件名。 缓冲区包含以双 null 结尾的字符串数组,其中每对字符串指定一个筛选器。 nFilterIndex 成员指定在创建对话框时使用第一个模式。
本示例设置 Flags 成员中的OFN_PATHMUSTEXIST和OFN_FILEMUSTEXIST标志。 这些标志会导致对话框在返回之前验证用户指定的路径和文件名是否确实存在。
如果用户单击“确定”按钮且存在指定的路径和文件名,则 GetOpenFileName 函数将返回 TRUE。 在这种情况下, lpstrFile 成员指向的缓冲区包含路径和文件名。 示例代码在调用 函数时使用此信息打开文件。
虽然此示例未设置 OFN_EXPLORER 标志,但仍显示默认的“资源管理器”样式 的“打开 ”对话框。 但是,如果要提供挂钩过程或自定义模板,并且需要 Explorer 用户界面,则必须设置 OFN_EXPLORER 标志。
注意
在 C 编程语言中,用引号括起来的字符串以 null 结尾。
OPENFILENAME ofn; // common dialog box structure
char szFile[260]; // buffer for file name
HWND hwnd; // owner window
HANDLE hf; // file handle
// Initialize OPENFILENAME
ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = hwnd;
ofn.lpstrFile = szFile;
// Set lpstrFile[0] to '\0' so that GetOpenFileName does not
// use the contents of szFile to initialize itself.
ofn.lpstrFile[0] = '\0';
ofn.nMaxFile = sizeof(szFile);
ofn.lpstrFilter = "All\0*.*\0Text\0*.TXT\0";
ofn.nFilterIndex = 1;
ofn.lpstrFileTitle = NULL;
ofn.nMaxFileTitle = 0;
ofn.lpstrInitialDir = NULL;
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
// Display the Open dialog box.
if (GetOpenFileName(&ofn)==TRUE)
hf = CreateFile(ofn.lpstrFile,
GENERIC_READ,
0,
(LPSECURITY_ATTRIBUTES) NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
(HANDLE) NULL);
显示“打印”对话框
本主题介绍显示“ 打印 ”对话框的示例代码,以便用户可以选择打印文档的选项。 示例代码首先初始化 PRINTDLG 结构,然后调用 PrintDlg 函数以显示对话框。
本示例设置 PRINTDLG 结构的 Flags 成员中的 PD_RETURNDC 标志。 这会导致 PrintDlg 将设备上下文句柄返回到 hDC 成员中的所选打印机。 可以使用 句柄在打印机上呈现输出。
输入时,示例代码将 hDevMode 和 hDevNames 成员设置为 NULL。 如果函数返回 TRUE,则这些成员会将句柄返回到包含用户输入和打印机相关信息的 DEVNAMES 结构。 可以使用此信息准备要发送到所选打印机的输出。
PRINTDLG pd;
HWND hwnd;
// Initialize PRINTDLG
ZeroMemory(&pd, sizeof(pd));
pd.lStructSize = sizeof(pd);
pd.hwndOwner = hwnd;
pd.hDevMode = NULL; // Don't forget to free or store hDevMode.
pd.hDevNames = NULL; // Don't forget to free or store hDevNames.
pd.Flags = PD_USEDEVMODECOPIESANDCOLLATE | PD_RETURNDC;
pd.nCopies = 1;
pd.nFromPage = 0xFFFF;
pd.nToPage = 0xFFFF;
pd.nMinPage = 1;
pd.nMaxPage = 0xFFFF;
if (PrintDlg(&pd)==TRUE)
{
// GDI calls to render output.
// Delete DC when done.
DeleteDC(pd.hDC);
}
使用打印属性表
本主题介绍显示 Print 属性表的示例代码,以便用户可以选择用于打印文档的选项。 示例代码首先初始化 PRINTDLGEX 结构,然后调用 PrintDlgEx 函数以显示属性表。
示例代码在 PRINTDLG 结构的 Flags 成员中设置PD_RETURNDC标志。 这会导致 PrintDlgEx 函数将设备上下文句柄返回到 hDC 成员中的所选打印机。
输入时,示例代码将 hDevMode 和 hDevNames 成员设置为 NULL。 如果函数返回 S_OK,则这些成员会将句柄返回到包含用户输入和打印机相关信息的 DEVNAMES 结构。 可以使用此信息准备要发送到所选打印机的输出。
完成打印操作后,示例代码释放 DEVMODE、 DEVNAMES 和 PRINTPAGERANGE 缓冲区,并调用 DeleteDC 函数以删除设备上下文。
// hWnd is the window that owns the property sheet.
HRESULT DisplayPrintPropertySheet(HWND hWnd)
{
HRESULT hResult;
PRINTDLGEX pdx = {0};
LPPRINTPAGERANGE pPageRanges = NULL;
// Allocate an array of PRINTPAGERANGE structures.
pPageRanges = (LPPRINTPAGERANGE) GlobalAlloc(GPTR, 10 * sizeof(PRINTPAGERANGE));
if (!pPageRanges)
return E_OUTOFMEMORY;
// Initialize the PRINTDLGEX structure.
pdx.lStructSize = sizeof(PRINTDLGEX);
pdx.hwndOwner = hWnd;
pdx.hDevMode = NULL;
pdx.hDevNames = NULL;
pdx.hDC = NULL;
pdx.Flags = PD_RETURNDC | PD_COLLATE;
pdx.Flags2 = 0;
pdx.ExclusionFlags = 0;
pdx.nPageRanges = 0;
pdx.nMaxPageRanges = 10;
pdx.lpPageRanges = pPageRanges;
pdx.nMinPage = 1;
pdx.nMaxPage = 1000;
pdx.nCopies = 1;
pdx.hInstance = 0;
pdx.lpPrintTemplateName = NULL;
pdx.lpCallback = NULL;
pdx.nPropertyPages = 0;
pdx.lphPropertyPages = NULL;
pdx.nStartPage = START_PAGE_GENERAL;
pdx.dwResultAction = 0;
// Invoke the Print property sheet.
hResult = PrintDlgEx(&pdx);
if ((hResult == S_OK) && pdx.dwResultAction == PD_RESULT_PRINT)
{
// User clicked the Print button, so use the DC and other information returned in the
// PRINTDLGEX structure to print the document.
}
if (pdx.hDevMode != NULL)
GlobalFree(pdx.hDevMode);
if (pdx.hDevNames != NULL)
GlobalFree(pdx.hDevNames);
if (pdx.lpPageRanges != NULL)
GlobalFree(pPageRanges);
if (pdx.hDC != NULL)
DeleteDC(pdx.hDC);
return hResult;
}
设置打印页
本主题介绍显示 “页面设置 ”对话框的示例代码,以便用户可以选择打印页面的属性,例如纸张类型、纸张源、页面方向和页边距。 示例代码首先初始化 PAGESETUPDLG 结构,然后调用 PageSetupDlg 函数以显示对话框。
本示例设置 Flags 成员中的 PSD_MARGINS 标志,并使用 rtMargin 成员指定初始边距值。 它设置 PSD_INTHOUSANDTHSOFINCHES 标志,以确保对话框以千分之一英寸为单位表示边距尺寸。
输入时,示例代码将 hDevMode 和 hDevNames 成员设置为 NULL。 如果函数返回 TRUE,则函数使用这些成员将句柄返回到包含用户输入和打印机相关信息的 DEVNAMES 结构。 可以使用此信息准备要发送到所选打印机的输出。
以下示例还允许 PagePaintHook 挂钩过程自定义绘制示例页面的内容。
PAGESETUPDLG psd; // common dialog box structure
HWND hwnd; // owner window
// Initialize PAGESETUPDLG
ZeroMemory(&psd, sizeof(psd));
psd.lStructSize = sizeof(psd);
psd.hwndOwner = hwnd;
psd.hDevMode = NULL; // Don't forget to free or store hDevMode.
psd.hDevNames = NULL; // Don't forget to free or store hDevNames.
psd.Flags = PSD_INTHOUSANDTHSOFINCHES | PSD_MARGINS |
PSD_ENABLEPAGEPAINTHOOK;
psd.rtMargin.top = 1000;
psd.rtMargin.left = 1250;
psd.rtMargin.right = 1250;
psd.rtMargin.bottom = 1000;
psd.lpfnPagePaintHook = PaintHook;
if (PageSetupDlg(&psd)==TRUE)
{
// check paper size and margin values here.
}
以下示例演示在示例页面区域中绘制边距矩形的示例 PagePaintHook 挂钩过程:
BOOL CALLBACK PaintHook(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
LPRECT lprc;
COLORREF crMargRect;
HDC hdc, hdcOld;
switch (uMsg)
{
// Draw the margin rectangle.
case WM_PSD_MARGINRECT:
hdc = (HDC) wParam;
lprc = (LPRECT) lParam;
// Get the system highlight color.
crMargRect = GetSysColor(COLOR_HIGHLIGHT);
// Create a dash-dot pen of the system highlight color and
// select it into the DC of the sample page.
hdcOld = SelectObject(hdc, CreatePen(PS_DASHDOT, .5, crMargRect));
// Draw the margin rectangle.
Rectangle(hdc, lprc->left, lprc->top, lprc->right, lprc->bottom);
// Restore the previous pen to the DC.
SelectObject(hdc, hdcOld);
return TRUE;
default:
return FALSE;
}
return TRUE;
}
查找文本
本主题介绍显示和管理 “查找 ”对话框的示例代码,以便用户可以指定搜索操作的参数。 对话框将消息发送到窗口过程,以便您可以执行搜索操作。
显示和管理 替换 对话框的代码类似,只不过它使用 ReplaceText 函数来显示对话框。 “ 替换 ”对话框还会发送消息,以响应用户单击“ 替换” 和“ 全部替换 ”按钮。
若要使用“ 查找 或 替换 ”对话框,必须执行三个单独的任务:
- 获取 FINDMSGSTRING 已注册消息的消息标识符。
- 显示对话框。
- 打开对话框时处理 FINDMSGSTRING 消息。
初始化应用程序时,调用 RegisterWindowMessage 函数以获取 FINDMSGSTRING 已注册消息的消息标识符。
UINT uFindReplaceMsg; // message identifier for FINDMSGSTRING
uFindReplaceMsg = RegisterWindowMessage(FINDMSGSTRING);
若要显示“ 查找 ”对话框,请先初始化 FINDREPLACE 结构,然后调用 FindText 函数。 请注意, FINDREPLACE 结构和搜索字符串的缓冲区应该是全局变量或静态变量,以便在对话框关闭之前它不会超出范围。 必须设置 hwndOwner 成员以指定接收已注册消息的窗口。 创建对话框后,可以使用返回的句柄移动或操作对话框。
FINDREPLACE fr; // common dialog box structure
HWND hwnd; // owner window
CHAR szFindWhat[80]; // buffer receiving string
HWND hdlg = NULL; // handle to Find dialog box
// Initialize FINDREPLACE
ZeroMemory(&fr, sizeof(fr));
fr.lStructSize = sizeof(fr);
fr.hwndOwner = hwnd;
fr.lpstrFindWhat = szFindWhat;
fr.wFindWhatLen = 80;
fr.Flags = 0;
hdlg = FindText(&fr);
当对话框打开时,main消息循环必须包含对 IsDialogMessage 函数的调用。 在 IsDialogMessage 调用中将句柄作为参数传递给对话框。 这可确保对话框正确处理键盘消息。
若要监视从对话框发送的消息,窗口过程必须为 FINDMSGSTRING 注册的消息检查,并处理在 FINDREPLACE 结构中传递的值,如以下示例所示。
LPFINDREPLACE lpfr;
if (message == uFindReplaceMsg)
{
// Get pointer to FINDREPLACE structure from lParam.
lpfr = (LPFINDREPLACE)lParam;
// If the FR_DIALOGTERM flag is set,
// invalidate the handle that identifies the dialog box.
if (lpfr->Flags & FR_DIALOGTERM)
{
hdlg = NULL;
return 0;
}
// If the FR_FINDNEXT flag is set,
// call the application-defined search routine
// to search for the requested string.
if (lpfr->Flags & FR_FINDNEXT)
{
SearchFile(lpfr->lpstrFindWhat,
(BOOL) (lpfr->Flags & FR_DOWN),
(BOOL) (lpfr->Flags & FR_MATCHCASE));
}
return 0;
}