本部分介绍调用常见对话框的任务:
选择颜色
本主题介绍显示 “颜色 ”对话框的示例代码,以便用户可以选择颜色。 示例代码首先初始化 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 标志,但它仍显示默认的“资源管理器样式 打开 ”对话框。 但是,如果要提供挂钩过程或自定义模板,并且需要资源管理器用户界面,则必须设置 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);
当对话框打开时,主消息循环必须包含对 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;
}