Windows编程系列:通用对话框

获取中...

打开文件对话框

打开文件对话框,主要用到GetOpenFileName函数,参数为指向OPENFILENAME结构体的指针

 BOOL GetOpenFileName(
   LPOPENFILENAME Arg1
 );

使用方法如下:

#include <windows.h>
#include<iostream>

int main()
{
    OPENFILENAME ofn{};
    TCHAR szFile[260]{};       //文件名缓冲区

    ofn.lStructSize = sizeof(ofn);
    ofn.hwndOwner = NULL; //设置对话框拥有者句柄
    ofn.lpstrFile = szFile; //设置文件名缓冲区
    ofn.lpstrFile[0] = '\0';
    ofn.nMaxFile = sizeof(szFile); //设置所选文件路径缓冲区最大长度
    ofn.lpstrFilter = L"全部文件\0*.*\0文本文件\0*.txt\0";  //指定文件类型
    ofn.nFilterIndex = 1;  //文件类型选中的索引 从1开始
    ofn.lpstrFileTitle = NULL;  //选中的文件名(不包含路径,包含扩展名)
    ofn.nMaxFileTitle = 0;  //选中的文件名缓冲区最大长度
    ofn.lpstrInitialDir = NULL;  //初始路径
    ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; //用于初始化对话框的标志位


    if (GetOpenFileName(&ofn) == TRUE)
        std::wcout << ofn.lpstrFile << std::endl;
}

lzw1gjds.png
保存文件对话框

保存文件对话框和打开文件对话框的使用差不多,只需要把GetOpenFileName换成GetSaveFileName即可。

#include <windows.h>
#include<iostream>

int main()
{
    OPENFILENAME ofn{};
    TCHAR szFile[260]{};       //文件名缓冲区

    ofn.lStructSize = sizeof(ofn);
    ofn.hwndOwner = NULL; //设置对话框拥有者句柄
    ofn.lpstrFile = szFile; //设置文件名缓冲区
    ofn.lpstrFile[0] = '\0';
    ofn.nMaxFile = sizeof(szFile); //设置所选文件路径缓冲区最大长度
    ofn.lpstrFilter = L"全部文件\0*.*\0文本文件\0*.txt\0";  //指定文件类型
    ofn.nFilterIndex = 1;  //文件类型选中的索引 从1开始
    ofn.lpstrFileTitle = NULL;  //选中的文件名(不包含路径,包含扩展名)
    ofn.nMaxFileTitle = 0;  //选中的文件名缓冲区最大长度
    ofn.lpstrInitialDir = NULL;  //初始路径
    ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; //用于初始化对话框的标志位


    if (GetSaveFileName(&ofn) == TRUE)
        std::wcout << ofn.lpstrFile << std::endl;
}

选择文件夹对话框

#include <iostream>
#include<Windows.h>
#include<shlobj_core.h>

int main()
{
    TCHAR szBuffer[MAX_PATH]{};
    BROWSEINFO bi{};
    bi.hwndOwner = ::GetForegroundWindow(); //对话框的拥有者名柄
    bi.pszDisplayName = szBuffer;  //设置选中路径缓冲区
    bi.pidlRoot = NULL; //默认选中的根路径
    bi.lpszTitle = L"标题";  //标题
    bi.ulFlags = BIF_NEWDIALOGSTYLE;  //对话框的选项

    LPITEMIDLIST idl = SHBrowseForFolder(&bi);  //显示对话框,并获取快捷方式

    if (NULL == idl)
    {
        return 0;
    }

    SHGetPathFromIDList(idl, szBuffer);   //从快捷方式获取路径
    std::wcout << szBuffer << std::endl;

    return 0;
}

字体选择对话框

选择字体对话框主要用到ChooseFont函数,参数为指向CHOOSEFONTA结构体的指针。

 BOOL WINAPI ChooseFont(
   _Inout_ LPCHOOSEFONT lpcf
 );

使用方法如下:

CHOOSEFONT cf{};
    static LOGFONT lf{};        // 逻辑字体结构
    static DWORD rgbCurrent = 0;  // 当前字体颜色
    HFONT hfont;

    cf.lStructSize = sizeof(cf);
    cf.hwndOwner = NULL;
    cf.lpLogFont = &lf;  //指向一个逻辑 字体
    cf.rgbColors = rgbCurrent;
    cf.Flags = CF_SCREENFONTS | CF_EFFECTS; //设置字体对话框选项

    if (ChooseFont(&cf) == TRUE)
    {
        hfont = CreateFontIndirect(cf.lpLogFont);  //创建逻辑字体
        rgbCurrent = cf.rgbColors;  //保存字体颜色
    }

颜色选择对话框

颜色选择对话框主要用到ChooseColor函数,参数为指向CHOOSECOLOR 结构体的指针。

 BOOL WINAPI ChooseColor(
   _Inout_ LPCHOOSECOLOR lpcc
);
#include <windows.h>
#include<iostream>

int main()
{
    CHOOSECOLOR cc{};
    static COLORREF acrCustClr[16]; //颜色对话框下面的16个自定义颜色存储空间
    HBRUSH hbrush;
    static COLORREF rgbCurrent = 0;

    cc.lStructSize = sizeof(cc);
    cc.hwndOwner = NULL;
    cc.lpCustColors = (LPDWORD)acrCustClr;
    cc.rgbResult = rgbCurrent;
    cc.Flags = CC_FULLOPEN | CC_RGBINIT;

    if (ChooseColor(&cc) == TRUE)
    {
        hbrush = CreateSolidBrush(cc.rgbResult);
        rgbCurrent = cc.rgbResult;
    }
}

打印对话框

打印对话框主要用到PrintDlg函数,参数为指向PRINTDLG结构体的指针。

 BOOL WINAPI PrintDlg(
   _Inout_ LPPRINTDLG lppd
 );
PRINTDLG pd{};

    pd.lStructSize = sizeof(pd);
    pd.hwndOwner = NULL;
    pd.hDevMode = NULL;
    pd.hDevNames = NULL;
    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)
    {
        //打印操作

        //释放dc
        DeleteDC(pd.hDC);
    }

lzw1je2h.png
打印属性页对话框(打印对话框增强版)

主要用到PrintDlgEx函数,参数为指向PRINTDLGEX结构体的指针。

 HRESULT WINAPI PrintDlgEx(
   _Inout_ LPPRINTDLGEX lppd
 );
#include <windows.h>
#include<iostream>

int main()
{
    HRESULT hResult;
    PRINTDLGEX pdx = { 0 };
    LPPRINTPAGERANGE pPageRanges = NULL;

    //分配PRINTPAGERANGE结构体数组内存
    pPageRanges = (LPPRINTPAGERANGE)GlobalAlloc(GPTR, 10 * sizeof(PRINTPAGERANGE));

    if (!pPageRanges)
        return 0;

    // 初始化PRINTDLGEX结构体
    pdx.lStructSize = sizeof(PRINTDLGEX);
    pdx.hwndOwner = GetConsoleWindow();  //拥有者窗体句柄 不能为NULL (这里使用控制台程序测试,所以传入控制台窗体句柄)
    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;

    hResult = PrintDlgEx(&pdx);

    if ((hResult == S_OK) && pdx.dwResultAction == PD_RESULT_PRINT)
    {
        //打印操作
    }

    //资源释放
    if (pdx.hDevMode != NULL)
        GlobalFree(pdx.hDevMode);
    if (pdx.hDevNames != NULL)
        GlobalFree(pdx.hDevNames);
    if (pdx.lpPageRanges != NULL)
        GlobalFree(pPageRanges);

    //删除dc
    if (pdx.hDC != NULL)
        DeleteDC(pdx.hDC);

    return 0;
}

lzw1jynm.png

页面设置对话框

页面设置对话框主要用到PageSetupDlg函数,参数为指向PAGESETUPDLG结构体的指针。

 BOOL WINAPI PageSetupDlg(
   _Inout_ LPPAGESETUPDLG lppsd
 );

这里在进行页面预览时,需要设置一个钩子函数,用于对页面进行绘制。如下:

UINT_PTR CALLBACK PaintHook(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    LPRECT lprc;
    COLORREF crMargRect;
    HDC hdc, hdcOld;

    switch (uMsg)
    {
    case WM_PSD_MARGINRECT:
        hdc = (HDC)wParam;
        lprc = (LPRECT)lParam;

        // 获取系统High light颜色
        crMargRect = GetSysColor(COLOR_HIGHLIGHT);

        //创建系统突出显示颜色的点划线笔,然后将其选择到示例页面的DC中。
        hdcOld = (HDC)SelectObject(hdc, CreatePen(PS_DASHDOT, 1, crMargRect));

        //绘制Rectangle
        Rectangle(hdc, lprc->left, lprc->top, lprc->right, lprc->bottom);

        //还原dc
        SelectObject(hdc, hdcOld);
        return TRUE;

    default:
        return FALSE;
    }
    return TRUE;
}
PAGESETUPDLG psd{};

    psd.lStructSize = sizeof(psd);
    psd.hwndOwner = GetConsoleWindow(); // 演示使用控制台窗体
    psd.hDevMode = NULL;
    psd.hDevNames = NULL;
    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)
    {
        //获取纸张尺寸和边距值。

    }

lzw1kw6y.png
有趣的是,按照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)

C++
打赏
评论区
头像