一个小型库库,该库可随时调用本机文件打开,文件夹选择和文件保存对话框。一次编写对话框代码,然后在所有受支持的平台上弹出本机对话框。避免将诸如WXWIDGETS和QT之类的大依赖关系链接。
该库基于Michael Labbe的本机文件对话框(Mlabbe/nativalfiledialog)。
特征:
C/C++ Source files (*.c;*.cpp)而不是(*.c;*.cpp) )Untitled.c )wchar_t )支持IFileDialogunique_ptr自动释放语义和可选参数,适用于C ++使用此库的人与原始本机文件对话框进行比较:
友好名称功能是与Michael Labbe库中API兼容的主要原因(因此,该库可能永远不会与之合并)。也有许多调整在此库中引起可观察到的差异。
本机文件对话框中添加的功能扩展:
wchar_t )支持unique_ptr自动释放语义和可选参数还有重要的代码折射,尤其是对于Windows实现。
Wiki跟踪依赖该库的已知语言绑定和已知的流行项目。
#include <nfd.h>
#include <stdio.h>
#include <stdlib.h>
int main ( void )
{
NFD_Init ();
nfdu8char_t * outPath ;
nfdu8filteritem_t filters [ 2 ] = { { "Source code" , "c,cpp,cc" }, { "Headers" , "h,hpp" } };
nfdopendialogu8args_t args = { 0 };
args . filterList = filters ;
args . filterCount = 2 ;
nfdresult_t result = NFD_OpenDialogU8_With ( & outPath , & args );
if ( result == NFD_OKAY )
{
puts ( "Success!" );
puts ( outPath );
NFD_FreePathU8 ( outPath );
}
else if ( result == NFD_CANCEL )
{
puts ( "User pressed cancel." );
}
else
{
printf ( "Error: %sn" , NFD_GetError ());
}
NFD_Quit ();
return 0 ;
} NFDE中的U8 / u8是指大多数消费者可能想要的UTF-8字符( char )的API。还可以使用N / n版本,该版本使用本机字符类型(Windows上的wchar_t和其他平台上的char )。
有关您可以在args结构上设置的参数的完整列表,请参见下面的“所有选项”部分。
如果您使用的是平台抽象框架(例如SDL或GLFW),请参见下面的“使用平台抽象框架的使用”部分。






如果您的项目使用Cmake,只需将以下几行添加到您的cmakelists.txt:
add_subdirectory(path/to/nativefiledialog-extended)
target_link_libraries(MyProgram PRIVATE nfd)
确保您还具有所需的依赖关系。
当包含作为子标记时,未构建示例程序,并且默认情况下禁用了安装目标。添加-DNFD_BUILD_TESTS=ON构建示例程序, -DNFD_INSTALL=ON启用安装目标。
如果要构建独立的静态库,请执行以下命令(从项目root目录开始):
对于GCC和Clang:
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Release ..
cmake --build .
对于MSVC:
mkdir build
cd build
cmake ..
cmake --build . --config Release
以上命令将制作一个build目录,并在此处构建项目(以发布模式)。如果您正在开发NFDE,则可能需要执行-DCMAKE_BUILD_TYPE=Debug / --config Debug ,以构建库的调试版本。
当作为独立库构建时,会构建示例程序,并且默认情况下启用了安装目标。添加-DNFD_BUILD_TESTS=OFF禁用构建示例程序和-DNFD_INSTALL=OFF以禁用安装目标。
在Linux上,如果要使用FlatPak桌面门户而不是GTK,请添加-DNFD_PORTAL=ON 。 (否则,将使用GTK。)有关更多信息,请参见下面的“使用”部分。
有关一些示例构建命令,请参见CI构建文件。
Visual Studio的最新版本具有IDE中内置的CMAKE支持。您应该能够在项目根目录中“打开文件夹”,而Visual Studio将适当识别和配置项目。从那里,您将能够为Debug vs Release设置配置,以及X86与X64的配置。有关更多信息,请参见Microsoft文档页面。已经对此进行了测试以在Visual Studio 2019上工作,并且可能在Visual Studio 2017上工作。
src/include您的包含搜索路径。nfd.lib或nfd_d.lib添加到要链接的静态库列表(分别用于发布或调试)。build/<debug|release>/<arch>添加到库搜索路径。 确保系统上安装了libgtk-3-dev 。
确保系统上安装了libdbus-1-dev 。
在MacOS上,将AppKit和UniformTypeIdentifiers添加到框架列表中。
在Windows(MSVC和MINGW)上,确保您正在针对ole32.lib , uuid.lib和shell32.lib进行构建。
要打开对话框,您可以在结构上设置选项,然后将该结构传递给NFDE函数,例如:
nfdopendialogu8args_t args = { 0 };
args . filterList = filters ;
args . filterCount = 2 ;
nfdresult_t result = NFD_OpenDialogU8_With ( & outPath , & args );所有选项都是可选的,可以单独设置(零初始化设置所有选项以合理默认值),除了filterList和filterCount之外,必须设置或两者都不设置。
NFDE的未来版本可能会在参数结构的末尾添加其他选项,而不会撞击主要版本编号,因此为了确保向后API兼容性,您不应假设结构具有特定的长度或字段数。您可以假设结构的零限制将继续将所有选项设置为合理的默认设置,因此将{0}分配给结构是可以接受的。对于那些构建NFDE的共享库,内部版本索引( NFD_INTERFACE_VERSION )确保向后ABI兼容性,预计将对消费者透明。
opendialog / opendialogmultiph :
typedef struct {
const nfdu8filteritem_t * filterList ;
nfdfiltersize_t filterCount ;
const nfdu8char_t * defaultPath ;
nfdwindowhandle_t parentWindow ;
} nfdopendialogu8args_t ;Savedialog :
typedef struct {
const nfdu8filteritem_t * filterList ;
nfdfiltersize_t filterCount ;
const nfdu8char_t * defaultPath ;
const nfdu8char_t * defaultName ;
nfdwindowhandle_t parentWindow ;
} nfdsavedialogu8args_t ;PickFolder / PickFoldermultiple :
typedef struct {
const nfdu8char_t * defaultPath ;
nfdwindowhandle_t parentWindow ;
} nfdpickfolderu8args_t ;filterList和filterCount :将它们设置为自定义文件过滤器(它显示为Windows和Linux上的下拉菜单,但只是隐藏了MacOS上的文件)。将filterList设置为指针,以启用过滤器项目数组的开始,并将filterCount到该数组中的过滤器项目数量。有关详细信息,请参见下面的“文件过滤器语法”部分。defaultPath :将其设置为对话框应打开的默认文件夹(在Windows上,如果有最近使用的文件夹,则它将打开到该文件夹而不是您通过的文件夹,除非NFD_OVERRIDE_RECENT_WITH_DEFAULT build构建选项设置为ON)。defaultName :(仅适用于Savedialog)将其设置为应该在对话框上预先填充的文件名。parentWindow :将此设置为此对话框的父窗口的本机窗口句柄。有关详细信息,请参见“使用平台抽象框架的使用”部分。即使您不使用平台抽象框架,也可以通过手柄传递。 有关示例代码(C和C ++),请参见test目录。
如果打开构建test目录的选项( -DNFD_BUILD_TESTS=ON ),则build/bin将包含编译的测试程序。
还有一个SDL2示例,需要使用-DNFD_BUILD_SDL2_TESTS=ON分别启用。它需要安装在计算机上的SDL2。
编译的示例(包括SDL2示例)也被上传为github动作的手工艺品,可以从那里下载。
文件可以通过文件扩展程序组过滤:
nfdu8filteritem_t filters [ 2 ] = { { "Source code" , "c,cpp,cc" }, { "Headers" , "h,hpp" } };文件过滤器是一对包含友好名称和规范的字符串(多个文件扩展程序是逗号分隔的)。
调用库时,可以将文件过滤器的列表作为参数传递。
通配符滤波器总是添加到每个对话框中。
注意:在MACOS上,文件对话框没有友好的名称,也无法在过滤器之间切换,因此将过滤器规范组合在一起(例如“ C,CPP,CC,CC,H,HPP”)。过滤器规范也永远不会明确显示给用户。这是通常的MacOS行为,用户期望这一点。
注2:您必须确保规范字符串是非空字符串,并且每个文件扩展名至少具有一个字符。否则,可能会发生坏事(即不确定的行为)。
注3:在Linux上,当用户按下“保存”按钮时,将附加文件扩展名(如果丢失)。即使显示了覆盖提示,并且用户按“ CANCAL”显示了附加的文件扩展名,即使显示了覆盖提示。
注4:在Windows上,默认文件夹参数仅在没有最近使用的文件夹时才使用,除非NFD_OVERRIDE_RECENT_WITH_DEFAULT构建选项设置为ON。否则,默认文件夹将是上次使用的文件夹。在内部,Windows实现了IFILEDIALOG :: SETDEFAULTFOLDER(ISHELLITEM)。这是通常的Windows行为,用户期望它。
支持多个选择的文件打开对话框会产生一个路径集,这是平台特定集合的薄抽象。有两种方法可以迭代路径集:
此方法确实在路径集中确实像数组一样访问,并且最容易使用。但是,在某些平台(Linux,可能是Windows)上,总共需要O(n 2 )时间才能迭代整个路径集,因为基础平台特定的实现使用了链接列表。
参见test_opendialogmultiple.c。
该方法使用枚举对象来迭代路径集中的路径。保证总共需要O(n)时间才能迭代整个路径集。
请参阅test_opendialogmultiple_enum.c。
该API是实验性的,可能会改变。
您可以在包括nfd.h / nfd.hpp之前定义以下宏:
NFD_NATIVE :在包含nfd.h之前定义此问题以制作本机函数(例如NFD_OpenDialog )的非填充功能名称和Typedef(例如NFD_OpenDialogN )别名,而不是utf-8函数的别名(例如NFD_OpenDialogU8 )。该宏不影响C ++包装器nfd.hpp 。NFD_THROWS_EXCEPTIONS :(仅C ++)在包含nfd.hpp之前定义此问题,以使NFD::Guard Construction Throw Throw std::runtime_error如果NFD_Init失败。否则,将无法检测到NFD::Guard建筑中的故障。 nfd.h可能定义的宏:
NFD_DIFFERENT_NATIVE_FUNCTIONS :定义函数的本机和UTF-8版本不同(即windows编译);没有另外定义。如果未定义NFD_DIFFERENT_NATIVE_FUNCTIONS ,则功能的UTF-8版本是本机版本的别名。如果您正在编写想要根据本机函数和UTF-8函数相同的函数来提供过载的函数,这可能很有用。 (本机是Windows的UTF-16( wchar_t )和Mac/Linux的UTF-8( char )。) 众所周知,NFDE可以与SDL2和GLFW合作,还应与其他平台抽象的杂物合作。本节说明了如何在此类框架中正确使用NFDE。
parentWindow参数允许用户将对话框作为父。
如果使用SDL2,请包括<nfd_sdl2.h> ,并调用以下功能设置父窗口句柄:
NFD_GetNativeWindowFromSDLWindow ( sdlWindow /* SDL_Window* */ , & args . parentWindow );如果使用GLFW3,请定义GLFW本机访问页面上描述的适当的GLFW_EXPOSE_NATIVE_*宏,然后包含<nfd_glfw3.h>并调用以下功能以设置父窗口hander:
NFD_GetNativeWindowFromGLFWWindow ( glfwWindow /* GLFWwindow* */ , & args . parentWindow );如果您正在使用另一个平台抽象框架,或者不使用任何此类框架,则可以手动设置args.parentWindow 。
支持Win32(Windows),可可(MacOS)和X11(Linux)Windows。通过一个Wayland(Linux)窗口当前什么都不做(即对话框的作用,就好像没有父母一样),但是将来可能会添加支持。
要制作一个窗口(在这种情况下,文件对话框)停留在另一个窗口上方,我们需要将底部窗口声明为顶部窗口的父。如果用户在对话框打开时,用户单击“父”窗口,则可以防止对话框窗口在父窗口后面消失。将对话框保留在窗口上方调用的是所有受支持的操作系统上的预期行为,因此,如果可能的话,建议通过父窗口句柄。
您应该在初始化框架后初始化NFDE,并且可能在降低框架之前将NFDE降低。这是因为某些框架期望在“干净的板岩”上初始化,并且它们可能以与NFDE不同的方式配置系统。 NFD_Init通常非常小心,不要在必要时破坏现有配置,并且NFD_Quit将配置完全恢复到初始化之前的配置。
SDL2的示例:
// Initialize SDL2 first
if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO) != 0) {
// display some error here
}
// Then initialize NFDe
if (NFD_Init() != NFD_OKAY) {
// display some error here
}
/*
Your main program goes here
*/
NFD_Quit(); // deinitialize NFDe first
SDL_Quit(); // Then deinitialize SDL2
在Linux上,您可以使用门户实现,而不是GTK,该实现将打开由OS选择的“本机”文件选择器或用户自定义的。用户必须具有xdg-desktop-portal ,并安装了合适的后端(这是由最常见的桌面发行版预装),否则将返回NFD_ERROR 。
要使用门户实现,请添加-DNFD_PORTAL=ON to build命令。
*注意:仅在org.freedesktop.portal.filechooser接口版本> = 3上支持文件夹选择器,该版本对应于XDG-DESKTOP-PORTAL版本> = 1.7.1。 NFD_PickFolder()将在运行时查询接口版本,并在版本太低时返回NFD_ERROR 。
与Windows和MacOS不同,Linux没有将文件选择器烘烤到操作系统中。想要文件选择器的Linux应用程序通常与提供一个的库(例如GTK,如上面的Linux屏幕截图)链接。这是许多应用程序使用的最可接受的解决方案,但可能会使文件选择器在非GTK发行版上看起来外观。
Flatpak于2015年推出,随之而来的是一个标准化的接口来打开文件选择器。使用此接口的应用程序不需要随附文件选择器,并且可以使用Flatpak提供的应用程序。该界面被称为桌面门户,其使用扩展到非Flatpak应用程序。现在,大多数主要的桌面Linux发行版都安装了桌面门户,其中适合该发行版主题的文件选择器。如果需要,用户还可以安装其他门户后端。目前有三个已知的后端具有文件选择器支持:GTK,KDE和LXQT; GNOME和XAPP后端取决于GTK ONE的功能。 XAPP后端是为肉桂,伴侣和XFCE设计的。其他桌面环境似乎目前没有门户后端。
Info.plist文件中定义数据类型。 (可以通过添加-DNFD_USE_ALLOWEDCONTENTTYPES_IF_AVAILABLE=OFF来强迫NFDE使用允许的filetypes,但不建议您支持旧的macOS版本。GetOpenFileName 。 (没有计划支持这一点;无论如何您都不应该使用Windows XP。)请使用GitHub问题跟踪器报告错误或为此存储库做出贡献。随时提交任何类型的错误报告。
Bernard Teo(ME)和其他所有内容都不是Michael Labbe的本地文件对话框。
Michael Labbe的本机文件对话框以及该库的其他贡献者。
此读数的大部分也已从原始本机文件对话框存储库中复制。
此存储库中的所有内容均以ZLIB许可证分配,原始本机文件对话框也是如此。
我不提供任何付费支持。迈克尔·拉贝(Michael Labbe)在撰写本文时似乎为他的图书馆提供了付费支持。