Windows编程系列:通用对话框
打开文件对话框
打开文件对话框,主要用到GetOpenFileName函数,参数为指向OPENFILENAME结构体的指针
1 BOOL GetOpenFileName( 2 LPOPENFILENAME Arg1 3 );
使用方法如下:
1 #include <windows.h>
2 #include<iostream>
3
4 int main()
5 {
6 OPENFILENAME ofn{};
7 TCHAR szFile[260]{}; //文件名缓冲区
8
9 ofn.lStructSize = sizeof(ofn);
10 ofn.hwndOwner = NULL; //设置对话框拥有者句柄
11 ofn.lpstrFile = szFile; //设置文件名缓冲区
12 ofn.lpstrFile[0] = '\0';
13 ofn.nMaxFile = sizeof(szFile); //设置所选文件路径缓冲区最大长度
14 ofn.lpstrFilter = L"全部文件\0*.*\0文本文件\0*.txt\0"; //指定文件类型
15 ofn.nFilterIndex = 1; //文件类型选中的索引 从1开始
16 ofn.lpstrFileTitle = NULL; //选中的文件名(不包含路径,包含扩展名)
17 ofn.nMaxFileTitle = 0; //选中的文件名缓冲区最大长度
18 ofn.lpstrInitialDir = NULL; //初始路径
19 ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; //用于初始化对话框的标志位
20
21
22 if (GetOpenFileName(&ofn) == TRUE)
23 std::wcout << ofn.lpstrFile << std::endl;
24 }

保存文件对话框
保存文件对话框和打开文件对话框的使用差不多,只需要把GetOpenFileName换成GetSaveFileName即可。
1 #include <windows.h>
2 #include<iostream>
3
4 int main()
5 {
6 OPENFILENAME ofn{};
7 TCHAR szFile[260]{}; //文件名缓冲区
8
9 ofn.lStructSize = sizeof(ofn);
10 ofn.hwndOwner = NULL; //设置对话框拥有者句柄
11 ofn.lpstrFile = szFile; //设置文件名缓冲区
12 ofn.lpstrFile[0] = '\0';
13 ofn.nMaxFile = sizeof(szFile); //设置所选文件路径缓冲区最大长度
14 ofn.lpstrFilter = L"全部文件\0*.*\0文本文件\0*.txt\0"; //指定文件类型
15 ofn.nFilterIndex = 1; //文件类型选中的索引 从1开始
16 ofn.lpstrFileTitle = NULL; //选中的文件名(不包含路径,包含扩展名)
17 ofn.nMaxFileTitle = 0; //选中的文件名缓冲区最大长度
18 ofn.lpstrInitialDir = NULL; //初始路径
19 ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; //用于初始化对话框的标志位
20
21
22 if (GetSaveFileName(&ofn) == TRUE)
23 std::wcout << ofn.lpstrFile << std::endl;
24 }
选择文件夹对话框
1 #include <iostream>
2 #include<Windows.h>
3 #include<shlobj_core.h>
4
5 int main()
6 {
7 TCHAR szBuffer[MAX_PATH]{};
8 BROWSEINFO bi{};
9 bi.hwndOwner = ::GetForegroundWindow(); //对话框的拥有者名柄
10 bi.pszDisplayName = szBuffer; //设置选中路径缓冲区
11 bi.pidlRoot = NULL; //默认选中的根路径
12 bi.lpszTitle = L"标题"; //标题
13 bi.ulFlags = BIF_NEWDIALOGSTYLE; //对话框的选项
14
15 LPITEMIDLIST idl = SHBrowseForFolder(&bi); //显示对话框,并获取快捷方式
16
17 if (NULL == idl)
18 {
19 return 0;
20 }
21
22 SHGetPathFromIDList(idl, szBuffer); //从快捷方式获取路径
23 std::wcout << szBuffer << std::endl;
24
25 return 0;
26 }
字体选择对话框
选择字体对话框主要用到ChooseFont函数,参数为指向CHOOSEFONTA结构体的指针。
1 BOOL WINAPI ChooseFont( 2 _Inout_ LPCHOOSEFONT lpcf 3 );
使用方法如下:
1 CHOOSEFONT cf{};
2 static LOGFONT lf{}; // 逻辑字体结构
3 static DWORD rgbCurrent = 0; // 当前字体颜色
4 HFONT hfont;
5
6 cf.lStructSize = sizeof(cf);
7 cf.hwndOwner = NULL;
8 cf.lpLogFont = &lf; //指向一个逻辑 字体
9 cf.rgbColors = rgbCurrent;
10 cf.Flags = CF_SCREENFONTS | CF_EFFECTS; //设置字体对话框选项
11
12 if (ChooseFont(&cf) == TRUE)
13 {
14 hfont = CreateFontIndirect(cf.lpLogFont); //创建逻辑字体
15 rgbCurrent = cf.rgbColors; //保存字体颜色
16 }
颜色选择对话框
颜色选择对话框主要用到ChooseColor函数,参数为指向CHOOSECOLOR 结构体的指针。
1 BOOL WINAPI ChooseColor( 2 _Inout_ LPCHOOSECOLOR lpcc 3 );
使用方法如下:
1 #include <windows.h>
2 #include<iostream>
3
4 int main()
5 {
6 CHOOSECOLOR cc{};
7 static COLORREF acrCustClr[16]; //颜色对话框下面的16个自定义颜色存储空间
8 HBRUSH hbrush;
9 static COLORREF rgbCurrent = 0;
10
11 cc.lStructSize = sizeof(cc);
12 cc.hwndOwner = NULL;
13 cc.lpCustColors = (LPDWORD)acrCustClr;
14 cc.rgbResult = rgbCurrent;
15 cc.Flags = CC_FULLOPEN | CC_RGBINIT;
16
17 if (ChooseColor(&cc) == TRUE)
18 {
19 hbrush = CreateSolidBrush(cc.rgbResult);
20 rgbCurrent = cc.rgbResult;
21 }
22 }
打印对话框
打印对话框主要用到PrintDlg函数,参数为指向PRINTDLG结构体的指针。
1 BOOL WINAPI PrintDlg( 2 _Inout_ LPPRINTDLG lppd 3 );
使用方法如下:
1 PRINTDLG pd{};
2
3 pd.lStructSize = sizeof(pd);
4 pd.hwndOwner = NULL;
5 pd.hDevMode = NULL;
6 pd.hDevNames = NULL;
7 pd.Flags = PD_USEDEVMODECOPIESANDCOLLATE || PD_RETURNDC;
8 pd.nCopies = 1; //设置打印份数
9 pd.nFromPage = 0xFFFF; //设置打印起始页号
10 pd.nToPage = 0xFFFF; //设置打印结束页号
11 pd.nMinPage = 1;
12 pd.nMaxPage = 0xFFFF;
13
14 if (PrintDlg(&pd) == TRUE)
15 {
16 //打印操作
17
18 //释放dc
19 DeleteDC(pd.hDC);
20 }

打印属性页对话框(打印对话框增强版)
主要用到PrintDlgEx函数,参数为指向PRINTDLGEX结构体的指针。
1 HRESULT WINAPI PrintDlgEx( 2 _Inout_ LPPRINTDLGEX lppd 3 );
使用方法:
1 #include <windows.h>
2 #include<iostream>
3
4 int main()
5 {
6 HRESULT hResult;
7 PRINTDLGEX pdx = { 0 };
8 LPPRINTPAGERANGE pPageRanges = NULL;
9
10 //分配PRINTPAGERANGE结构体数组内存
11 pPageRanges = (LPPRINTPAGERANGE)GlobalAlloc(GPTR, 10 * sizeof(PRINTPAGERANGE));
12
13 if (!pPageRanges)
14 return 0;
15
16 // 初始化PRINTDLGEX结构体
17 pdx.lStructSize = sizeof(PRINTDLGEX);
18 pdx.hwndOwner = GetConsoleWindow(); //拥有者窗体句柄 不能为NULL (这里使用控制台程序测试,所以传入控制台窗体句柄)
19 pdx.hDevMode = NULL;
20 pdx.hDevNames = NULL;
21 pdx.hDC = NULL; //设备上下文句柄
22 pdx.Flags = PD_RETURNDC | PD_COLLATE;
23 pdx.Flags2 = 0;
24 pdx.ExclusionFlags = 0;
25 pdx.nPageRanges = 0;
26 pdx.nMaxPageRanges = 10;
27 pdx.lpPageRanges = pPageRanges;
28 pdx.nMinPage = 1;
29 pdx.nMaxPage = 1000;
30 pdx.nCopies = 1;
31 pdx.hInstance = 0;
32 pdx.lpPrintTemplateName = NULL;
33 pdx.lpCallback = NULL;
34 pdx.nPropertyPages = 0;
35 pdx.lphPropertyPages = NULL;
36 pdx.nStartPage = START_PAGE_GENERAL;
37 pdx.dwResultAction = 0;
38
39 hResult = PrintDlgEx(&pdx);
40
41 if ((hResult == S_OK) && pdx.dwResultAction == PD_RESULT_PRINT)
42 {
43 //打印操作
44 }
45
46 //资源释放
47 if (pdx.hDevMode != NULL)
48 GlobalFree(pdx.hDevMode);
49 if (pdx.hDevNames != NULL)
50 GlobalFree(pdx.hDevNames);
51 if (pdx.lpPageRanges != NULL)
52 GlobalFree(pPageRanges);
53
54 //删除dc
55 if (pdx.hDC != NULL)
56 DeleteDC(pdx.hDC);
57
58 return 0;
59 }

页面设置对话框
页面设置对话框主要用到PageSetupDlg函数,参数为指向PAGESETUPDLG结构体的指针。
1 BOOL WINAPI PageSetupDlg( 2 _Inout_ LPPAGESETUPDLG lppsd 3 );
这里在进行页面预览时,需要设置一个钩子函数,用于对页面进行绘制。如下:
1 UINT_PTR CALLBACK PaintHook(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
2 {
3 LPRECT lprc;
4 COLORREF crMargRect;
5 HDC hdc, hdcOld;
6
7 switch (uMsg)
8 {
9 case WM_PSD_MARGINRECT:
10 hdc = (HDC)wParam;
11 lprc = (LPRECT)lParam;
12
13 // 获取系统High light颜色
14 crMargRect = GetSysColor(COLOR_HIGHLIGHT);
15
16 //创建系统突出显示颜色的点划线笔,然后将其选择到示例页面的DC中。
17 hdcOld = (HDC)SelectObject(hdc, CreatePen(PS_DASHDOT, 1, crMargRect));
18
19 //绘制Rectangle
20 Rectangle(hdc, lprc->left, lprc->top, lprc->right, lprc->bottom);
21
22 //还原dc
23 SelectObject(hdc, hdcOld);
24 return TRUE;
25
26 default:
27 return FALSE;
28 }
29 return TRUE;
30 }
使用方法:
1 PAGESETUPDLG psd{};
2
3 psd.lStructSize = sizeof(psd);
4 psd.hwndOwner = GetConsoleWindow(); // 演示使用控制台窗体
5 psd.hDevMode = NULL;
6 psd.hDevNames = NULL;
7 psd.Flags = PSD_INTHOUSANDTHSOFINCHES | PSD_MARGINS |
8 PSD_ENABLEPAGEPAINTHOOK;
9 psd.rtMargin.top = 1000;
10 psd.rtMargin.left = 1250;
11 psd.rtMargin.right = 1250;
12 psd.rtMargin.bottom = 1000;
13 psd.lpfnPagePaintHook = PaintHook;
14
15 if (PageSetupDlg(&psd) == TRUE)
16 {
17 //获取纸张尺寸和边距值。
18
19 }

有趣的是,按照MSDN文档上的说明,上述部分函数已经不推荐使用了。但在最新的.NET 5中,依旧使用了这些函数。
推荐阅读:
GetOpenFileName API
https://docs.microsoft.com/en-us/windows/win32/api/commdlg/nf-commdlg-getopenfilenamea
SHBrowseForFolder
https://docs.microsoft.com/en-us/windows/win32/api/shlobj_core/nf-shlobj_core-shbrowseforfoldera
ChooseFont API
https://docs.microsoft.com/en-us/previous-versions/windows/desktop/legacy/ms646914(v=vs.85)
ChooseColor API
https://docs.microsoft.com/en-us/previous-versions/windows/desktop/legacy/ms646912(v=vs.85)
PrintDlgEx API
https://docs.microsoft.com/en-us/previous-versions/windows/desktop/legacy/ms646942(v=vs.85)


浙公网安备 33010602011771号