Небольшая библиотека C, которая портильно вызывает открытие собственного файла, выберите папки и сохранение файлов. Напишите диалоговый код один раз и включите его нативные диалоги на всех поддерживаемых платформах. Избегайте связывания больших зависимостей, таких как WXWIDGETS и QT.
Эта библиотека основана на диалоговом окне «Майкл Лаббе» (Mlabbe/Nativefiledialog).
Функции:
C/C++ Source files (*.c;*.cpp) вместо (*.c;*.cpp) ) на платформах, которые его поддерживаютUntitled.c )wchar_t ) поддержка в WindowsIFileDialog Vista в Windowsunique_ptr семантикой автоматической свободы и дополнительными параметрами для тех, кто использует эту библиотеку из C ++Сравнение с исходным диалогом нативного файла:
Функция дружественных имен является основной причиной разрыва совместимости API с библиотекой Майкла Лаббе (и, следовательно, эта библиотека, вероятно, никогда не будет объединена с ней). Есть также ряд изменений, которые вызывают наблюдаемые различия в этой библиотеке.
Функции, добавленные в диалоговое окно «Настоящий файл расширен:
wchar_t ) поддержка в Windowsunique_ptr семантикой автоматической бесплатной.Существует также значительный код ректоринг, особенно для реализации Windows.
Вики отслеживает известные языковые привязки и известные популярные проекты, которые зависят от этой библиотеки.
#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 ;
} U8 / u8 в NFDE относятся к API для символов UTF-8 ( char ), которых большинство потребителей, вероятно, хотят. Также доступна версия N / n , в которой используется собственный тип символа ( wchar_t в Windows и char на других платформах).
Полный список аргументов, которые вы можете установить на структуре args , см. Раздел «Все параметры» ниже.
Если вы используете структуру абстракции платформы, такую как SDL или GLFW, также см. В разделе «Использование с платформой Abstraction Framework».






Если ваш проект использует Cmake, просто добавьте следующие строки в свой cmakelists.txt:
add_subdirectory(path/to/nativefiledialog-extended)
target_link_libraries(MyProgram PRIVATE nfd)
Убедитесь, что у вас также есть необходимые зависимости.
При включении в качестве подпроекта программы выборки не создаются, а цель установки отключена по умолчанию. Добавить -DNFD_BUILD_TESTS=ON для создания образцов программ и -DNFD_INSTALL=ON , чтобы включить цель установки.
Если вы хотите построить автономную статическую библиотеку, выполните следующие команды (начиная с каталога Project 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 имеют поддержку Cmake, встроенную в IDE. Вы должны быть в состоянии «открыть папку» в каталоге Project Root, а Visual Studio распознает и настроит проект надлежащим образом. Оттуда вы сможете установить конфигурации для релиза от Debug VS и для x86 против X64. Для получения дополнительной информации см. Страницу Microsoft Docs. Это было протестировано для работы на 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 могут добавить дополнительные параметры к концу аргументов Struct без удара по основному номеру версии, поэтому для обеспечения обратной совместимости API вы не должны предполагать, что структура имеет определенную длину или количество полей. Вы можете предположить, что нулевая инициализация struct будет продолжать устанавливать все параметры для разумных по умолчанию, поэтому присвоение {0} struct является приемлемой. Для тех, кто строит общие библиотеки NFDE, обратная совместимость ABI обеспечивается индексом внутренней версии ( NFD_INTERFACE_VERSION ), который, как ожидается, будет прозрачна для потребителей.
Opendialog / opendialogmultiple :
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 ;Пиколдер / Пикфолмольмольдипле :
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 опция сборки не установлена).defaultName : (только для сохранения) Установите это на имя файла, которое должно быть предварительно заполнено в диалоге.parentWindow : установите это на нативную ручку окна родителя этого диалога. Для получения подробной информации см. Раздел «Использование с платформой абстракции». Также возможно передать ручку, даже если вы не используете структуру абстракции платформы. См. test каталог, например, код (как C, так и C ++).
Если вы включили опцию для построения 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, H, HPP»). Спецификация фильтра также никогда не отображается пользователю. Это обычное поведение macOS, и пользователи ожидают этого.
ПРИМЕЧАНИЕ 2: Вы должны убедиться, что строка спецификации не является пустой и что каждое расширение файла имеет хотя бы один символ. В противном случае могут возникнуть плохие вещи (т.е. неопределенное поведение).
Примечание 3: На Linux добавляется расширение файла (если отсутствует), когда пользователь нажимает кнопку «Сохранить». Докладываемое расширение файла останется видимым для пользователя, даже если отображается подсказка о перезаписи, а затем пользователь нажимает «Отмена».
ПРИМЕЧАНИЕ 4: В Windows параметр папки по умолчанию используется только в том случае, если в последнее время не доступна папка, если только NFD_OVERRIDE_RECENT_WITH_DEFAULT Опция сборки не установлена. В противном случае папка по умолчанию будет папкой, которая в последний раз использовалась. Внутренне, реализация 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 ) для нативных функций (например, NFD_OpenDialogN ) вместо псевдонимов для функций UTF-8 (например, NFD_OpenDialogU8 ). Этот макрос не влияет на обертку C ++ nfd.hpp .NFD_THROWS_EXCEPTIONS : (только C ++) Определите это, прежде чем включать nfd.hpp , чтобы сделать NFD::Guard Construction thress std::runtime_error если NFD_Init не удастся. В противном случае, в NFD::Guard Construction нет способа обнаружить сбой. Макросы, которые могут быть определены nfd.h :
NFD_DIFFERENT_NATIVE_FUNCTIONS : определено, если собственные версии функций UTF-8 различны (т.е. компиляция для Windows); не определено иным. Если NFD_DIFFERENT_NATIVE_FUNCTIONS не определена, то версии функций UTF-8 являются псевдонимом для нативных версий. Это может быть полезно, если вы пишете функцию, которая хочет обеспечить перегрузку в зависимости от того, одинаковы ли нативные функции и функции UTF-8. (Native IS UTF-16 ( wchar_t ) для Windows и UTF-8 ( char ) для Mac/linux.) Известно, что NFDE работает с SDL2 и GLFW, а также должен работать с другими Framworks FramWorks. В этом разделе объясняется, как правильно использовать NFDE с такими рамками.
Аргумент parentWindow позволяет пользователю дать диалогу родителя.
Если использовать SDL2, включите <nfd_sdl2.h> и вызовите следующую функцию, чтобы установить ручку родительского окна:
NFD_GetNativeWindowFromSDLWindow ( sdlWindow /* SDL_Window* */ , & args . parentWindow ); При использовании GLFW3, определите соответствующие макросы GLFW_EXPOSE_NATIVE_* описанные на странице нативного доступа GLFW, а затем включите <nfd_glfw3.h>
NFD_GetNativeWindowFromGLFWWindow ( glfwWindow /* GLFWwindow* */ , & args . parentWindow ); Если вы используете другую структуру абстракции платформы или не используете какую -либо такую структуру, вы можете установить args.parentWindow вручную.
Окна Win32 (Windows), Cocoa (MacOS) и X11 (Linux). Передача окна 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, которая откроет «нативный» выбор файла, выбранную ОС или настроенный пользователем. Пользователь должен иметь xdg-desktop-portal и подходящий бэкэнд (это предварительно установлен с наиболее распространенными настольными дистрибуциями), в противном случае будет возвращен NFD_ERROR .
Чтобы использовать реализацию портала, добавьте -DNFD_PORTAL=ON в команду сборки.
*Примечание. Сборник папок поддерживается только на 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. Этот интерфейс стал известен как настольный портал, и его использование расширилось до не-флатпаковских приложений. Теперь большинство крупных настольных дистрибутов Linux поставляются с установленным порталом настольного компьютера с выбором файлов, которые соответствуют теме дистрибуции. Пользователи также могут установить другой бэкэнд портала при желании. В настоящее время существует три известных бэкэнда с поддержкой выбора файлов: GTK, KDE и LXQT; Бэксины GNOME и XAPP зависят от GTK для этой функции. Бэкэнд XAPP был разработан для корицы, приятеля и XFCE. Другие настольные среды, похоже, в настоящее время не имеют бэкэнда портала.
Info.plist в соответствии с документацией Apple. (Можно заставить NFDE использовать AllfileTypes, добавив -DNFD_USE_ALLOWEDCONTENTTYPES_IF_AVAILABLE=OFF в свою команду Cmake Build, но это не рекомендуется. Если вам нужно поддерживать более старые версии MacOS, вы должны установить вместо этого целевую цель развертывания.).GetOpenFileName . (Нет никаких планов поддержать это; вы все равно не должны использовать Windows XP.)Пожалуйста, используйте трекер выпуска GitHub, чтобы сообщать об ошибках или внести свой вклад в этот репозиторий. Не стесняйтесь отправлять отчеты об ошибках любого рода.
Бернард Тео (я) и другие участники за все, что было не из диалога нативного файла Майкла Лабба.
Майкл Лаббе за его потрясающую библиотеку «Нативные файлы» и другие участники этой библиотеки.
Большая часть этого Readme также была скопирована из Readme исходного репозитория диалога нативного файла.
Все в этом хранилище распределено по лицензии Zlib, как и исходная библиотека диалога «Нативные файлы».
Я не оказываю никакой платной поддержки. Майкл Лаббе, кажется, оказывает платную поддержку своей библиотеке на момент написания статьи.