Eine kleine C -Bibliothek, in der die native Datei portable geöffnet ist, die Dialoge aus dem Ordner auswählen und Datei speichern. Schreiben Sie einen Dialogcode einmal und lassen Sie ihn native Dialoge auf allen unterstützten Plattformen aufstellen. Vermeiden Sie es, große Abhängigkeiten wie WXWidgets und QT zu verbinden.
Diese Bibliothek basiert auf dem Dialogfeld "Native Datei" von Michael Labbe (MLABBE/NativeFiledialog).
Merkmale:
C/C++ Source files (*.c;*.cpp) anstelle von (*.c;*.cpp) ) auf Plattformen, die es unterstützenUntitled.c )wchar_t ) Unterstützung unter WindowsIFileDialog unter Windowsunique_ptr automatischer Semantik und optionalen Parametern für diejenigen, die diese Bibliothek von C ++ verwenden, für diejenigen, die diese Bibliothek verwendenVergleich mit dem Dialogfeld "Original native Datei":
Die Funktionsnamenfunktion ist der Hauptgrund für die Brechen der API -Kompatibilität mit der Bibliothek von Michael Labbe (und daher wird diese Bibliothek wahrscheinlich nie damit verschmolzen). Es gibt auch eine Reihe von Verbesserungen, die beobachtbare Unterschiede in dieser Bibliothek verursachen.
Funktionen im Dialogfeld "Native Datei" erweitert hinzugefügt:
wchar_t ) Unterstützung unter Windowsunique_ptr automatischer Semantik und optionalen ParameternEs gibt auch einen erheblichen Code -Refractoring, insbesondere für die Windows -Implementierung.
Das Wiki verfolgt bekannte Sprachbindungen und bekannte populäre Projekte, die von dieser Bibliothek abhängen.
#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 ;
} Der U8 / u8 in NFDE bezieht sich auf die API für UTF-8-Zeichen ( char ), die die meisten Verbraucher wahrscheinlich wollen. Eine N / n -Version ist ebenfalls verfügbar, die den nativen Zeichentyp verwendet ( wchar_t unter Windows und char auf anderen Plattformen).
Die vollständige Liste der Argumente, die Sie in der args -Struktur festlegen können, finden Sie im Abschnitt "Alle Optionen" unten.
Wenn Sie ein Plattformabstraktions -Framework wie SDL oder GLFW verwenden, siehe Abschnitt "Verwendung mit einem Plattformabstraktions -Framework" unten.






Wenn Ihr Projekt CMake verwendet, fügen Sie einfach die folgenden Zeilen zu Ihren cmakelists.txt hinzu:
add_subdirectory(path/to/nativefiledialog-extended)
target_link_libraries(MyProgram PRIVATE nfd)
Stellen Sie sicher, dass Sie auch die erforderlichen Abhängigkeiten haben.
Wenn als Unterprojekt eingeschlossen wird, werden Beispielprogramme nicht erstellt und das Installation Ziel standardmäßig deaktiviert. Fügen Sie -DNFD_BUILD_TESTS=ON , um Beispielprogramme und -DNFD_INSTALL=ON zu erstellen, um das Installationsziel zu aktivieren.
Wenn Sie die eigenständige statische Bibliothek erstellen möchten, führen Sie die folgenden Befehle aus (aus Beginn des Projektstammverzeichnisses):
Für GCC und Clang:
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Release ..
cmake --build .
Für MSVC:
mkdir build
cd build
cmake ..
cmake --build . --config Release
Die obigen Befehle erstellen ein build -Verzeichnis und erstellen dort das Projekt (im Release -Modus). Wenn Sie NFDE entwickeln, sollten Sie -DCMAKE_BUILD_TYPE=Debug / --config Debug erstellen, um stattdessen eine Debug -Version der Bibliothek zu erstellen.
Beim Erstellen einer eigenständigen Bibliothek werden Beispielprogramme erstellt und das Installation Ziel standardmäßig aktiviert. Fügen Sie -DNFD_BUILD_TESTS=OFF , um das Erstellen von Beispielprogrammen und -DNFD_INSTALL=OFF , um das Installationsziel zu deaktivieren.
Wenn Sie unter Linux das Flatpak -Desktop -Portal anstelle von GTK verwenden möchten, fügen Sie -DNFD_PORTAL=ON . (Andernfalls wird GTK verwendet.) Weitere Informationen finden Sie im Abschnitt "Nutzung" unten.
In der CI -Build -Datei finden Sie einige Beispiel -Build -Befehle.
In jüngsten Versionen von Visual Studio wird die CMake -Unterstützung in die IDE eingebaut. Sie sollten in der Lage sein, den Ordner im Projekt Root -Verzeichnis "zu öffnen", und Visual Studio erkennt das Projekt angemessen. Von dort aus können Sie Konfigurationen für Debug vs Release und für x86 vs x64 festlegen. Weitere Informationen finden Sie auf der Seite Microsoft Docs. Dies wurde getestet, um an Visual Studio 2019 zu arbeiten, und es funktioniert wahrscheinlich auch in Visual Studio 2017.
src/include zu Ihrem Suchpfad hinzu.nfd.lib oder nfd_d.lib zu der Liste der statischen Bibliotheken hinzu, die sich gegen (für die Veröffentlichung bzw. Debuggen) verlinken.build/<debug|release>/<arch> zum Bibliothekssuchpfad hinzu. Stellen Sie sicher, dass libgtk-3-dev in Ihrem System installiert ist.
Stellen Sie sicher, dass libdbus-1-dev in Ihrem System installiert ist.
Fügen Sie auf macOS AppKit und UniformTypeIdentifiers in die Liste der Frameworks hinzu.
Stellen Sie unter Windows (sowohl MSVC als auch Mingw) sicher, dass Sie gegen ole32.lib , uuid.lib und shell32.lib bauen.
Um einen Dialog zu öffnen, setzen Sie Optionen für eine Struktur und übergeben diese Struktur dann an eine NFDE -Funktion, z. B.:
nfdopendialogu8args_t args = { 0 };
args . filterList = filters ;
args . filterCount = 2 ;
nfdresult_t result = NFD_OpenDialogU8_With ( & outPath , & args ); Alle Optionen sind optional und können einzeln festgelegt werden (Null Initialisierungsstunde setzt alle Optionen auf angemessene Standardeinstellungen), mit Ausnahme von filterList und filterCount , die sowohl festgelegt als auch beide gelassen werden müssen.
Zukünftige Versionen von NFDE können zum Ende der Argumentestrukturen zusätzliche Optionen hinzufügen, ohne die Hauptversionsnummer zu erhöhen. Um die Rückwärts -API -Kompatibilität zu gewährleisten, sollten Sie nicht davon ausgehen, dass die Struktur eine bestimmte Länge oder Anzahl von Feldern hat. Sie können davon ausgehen, dass die Nullinitialisierung der Struktur weiterhin alle Optionen auf angemessene Standardeinstellungen einstellen wird, sodass die Zuweisung von {0} der Struktur zugewiesen wird. Für diejenigen, die freigegebene Bibliotheken von NFDE erstellen, wird die Rückwärts -Abi -Kompatibilität durch einen internen Versionsindex ( NFD_INTERFACE_VERSION ) gewährleistet, der für die Verbraucher voraussichtlich transparent ist.
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 ;Pickmolder / Pickfoldermultiple :
typedef struct {
const nfdu8char_t * defaultPath ;
nfdwindowhandle_t parentWindow ;
} nfdpickfolderu8args_t ;filterList und filterCount : Setzen Sie diese so ein, dass der Dateifilter anpassen (er wird als Dropdown -Menü unter Windows und Linux angezeigt. Versteckt jedoch einfach Dateien auf macOS). Stellen Sie filterList auf einen Zeiger auf den Start des Arrays von Filterelementen und filterCount an die Anzahl der Filterelemente in diesem Array. Weitere Informationen finden Sie im Abschnitt "Dateifiltersyntax" unten.defaultPath : Setzen Sie dies auf den Standardordner, für den das Dialogfeld geöffnet werden soll (unter Windows, wenn es einen kürzlich verwendeten Ordner gibt, öffnet es anstelle des Ordners, den Sie übergeben, es sei denn, die Option NFD_OVERRIDE_RECENT_WITH_DEFAULT wird auf eingestellt).defaultName : (Nur für gespeicherte) setzen Sie dies auf den Dateinamen, der im Dialog vorgefüllt werden sollte.parentWindow : Stellen Sie dies auf das native Fenstergriff des übergeordneten Dialogfelds dieses Dialogfelds ein. Weitere Informationen finden Sie im Abschnitt "Nutzung mit einem Plattformabstraktionsframework". Es ist auch möglich, einen Griff zu übergeben, auch wenn Sie kein Plattformabstraktionsframework verwenden. Siehe das test zum Beispiel Code (sowohl C- als auch C ++).
Wenn Sie die Option zum Erstellen des test ( -DNFD_BUILD_TESTS=ON ) eingeschaltet haben, enthält build/bin die kompilierten Testprogramme.
Es gibt auch ein SDL2 -Beispiel, das mit -DNFD_BUILD_SDL2_TESTS=ON getrennt aktiviert werden muss. SDL2 muss auf Ihrem Computer installiert werden.
Zusammenstellte Beispiele (einschließlich des SDL2 -Beispiels) werden ebenfalls als Artefakte auf Github -Aktionen hochgeladen und können von dort heruntergeladen werden.
Dateien können durch Dateierweiterungsgruppen gefiltert werden:
nfdu8filteritem_t filters [ 2 ] = { { "Source code" , "c,cpp,cc" }, { "Headers" , "h,hpp" } };Ein Dateifilter ist zwei Zeichenfolgen, die den freundlichen Namen und die Spezifikation umfassen (mehrere Dateierweiterungen sind von Comm-getrennten).
Eine Liste von Dateifiltern kann beim Aufrufen der Bibliothek als Argument übergeben werden.
In jedem Dialog wird immer ein Platzhalterfilter hinzugefügt.
Hinweis: Auf macOS haben die Dateidialoge keine freundlichen Namen und es gibt keine Möglichkeit, zwischen Filtern zu wechseln, sodass die Filterspezifikationen kombiniert werden (z. B. "C, CPP, CC, H, HPP"). Die Filterspezifikation wird dem Benutzer auch nie explizit angezeigt. Dies ist ein übliches MacOS -Verhalten und Benutzer erwarten es.
Hinweis 2: Sie müssen sicherstellen, dass die Spezifikationszeichenfolge nicht leer ist und dass jede Dateierweiterung mindestens ein Zeichen hat. Ansonsten könnten sich schlechte Dinge ergeben (dh undefiniertes Verhalten).
Hinweis 3: Unter Linux wird die Dateierweiterung angehängt (fehlt), wenn der Benutzer die Schaltfläche "Speichern" drückt. Die angehängte Dateierweiterung bleibt für den Benutzer sichtbar, auch wenn eine Überschreibungsaufforderung angezeigt wird und der Benutzer dann auf "Abbrechen" drückt.
Hinweis 4: Unter Windows wird der Standardordnerparameter nur dann verwendet, wenn kürzlich verwendeter Ordner nicht verfügbar ist, es sei denn, die Option NFD_OVERRIDE_RECENT_WITH_DEFAULT ist auf Ein festgelegt. Andernfalls ist der Standardordner der zuletzt verwendete Ordner. Innen ruft die Windows -Implementierung ifiledialog :: setDefaultFolder (iShellItem) auf. Dies ist ein übliches Windows -Verhalten und Benutzer erwarten es.
Ein geöffnetes Datei-Dialog, der mehrere Auswahl unterstützt, erzeugt ein Pfad, bei dem es sich um eine dünne Abstraktion über die plattformspezifische Sammlung handelt. Es gibt zwei Möglichkeiten, über einen Pfad zu iterieren:
Diese Methode hat Array-ähnlichen Zugriff auf dem Pfad und ist am einfachsten zu bedienen. Auf bestimmten Plattformen (Linux und möglicherweise Windows) benötigt es jedoch in der O (n 2 ) Zeit in der Gesamtzeit, um den gesamten Pfad zu iterieren, da die zugrunde liegende plattformspezifische Implementierung eine verknüpfte Liste verwendet.
Siehe test_opendialogmultiple.c.
Diese Methode verwendet ein Enumerator -Objekt, um die Pfade im Pfad zu iterieren. Insgesamt nimmt es garantiert O (n) Zeit, um den gesamten Pfad zu iterieren.
Siehe test_opendialogmultiple_enum.c.
Diese API ist experimentell und ändert sich.
Sie können die folgenden Makros definieren, bevor Sie nfd.h / nfd.hpp einbeziehen:
NFD_NATIVE : Definieren Sie dies vor NFD_OpenDialogN Einbeziehung nfd.h , NFD_OpenDialogU8 nicht senkten Funktionsnamen und Typedefs (z NFD_OpenDialog Dieses Makro wirkt sich nicht auf die C ++ - Wrapper nfd.hpp aus.NFD_THROWS_EXCEPTIONS : (nur c ++) definieren Sie dies vor der Einbeziehung nfd.hpp , um NFD::Guard Construction std::runtime_error zu machen, wenn NFD_Init fehlschlägt. Andernfalls gibt es keine Möglichkeit, ein Versagen bei NFD::Guard Construction zu erkennen. Makros, die durch nfd.h definiert werden könnten:
NFD_DIFFERENT_NATIVE_FUNCTIONS : definiert, wenn die nativen und utf-8-Versionen von Funktionen unterschiedlich sind (dh Kompilieren für Windows); sonst nicht definiert. Wenn NFD_DIFFERENT_NATIVE_FUNCTIONS nicht definiert ist, sind die UTF-8-Versionen von Funktionen Aliase für die nativen Versionen. Dies kann nützlich sein, wenn Sie eine Funktion schreiben, die Überladungen bereitstellen möchte, je nachdem, ob die nativen Funktionen und UTF-8-Funktionen gleich sind. (Native ist UTF-16 ( wchar_t ) für Windows und UTF-8 ( char ) für Mac/Linux.) Es ist bekannt, dass NFDE mit SDL2 und GLFW arbeitet und auch mit anderen Plattformabstraktionsframworks zusammenarbeiten sollte. In diesem Abschnitt wird erläutert, wie NFDE mit solchen Frameworks ordnungsgemäß verwendet wird.
Mit dem Argument parentWindow kann der Benutzer dem Dialog einen übergeordneten übergeben.
Wenn Sie SDL2 verwenden, geben Sie <nfd_sdl2.h> ein und rufen Sie die folgende Funktion auf, um das übergeordnete Fenstergriff festzulegen:
NFD_GetNativeWindowFromSDLWindow ( sdlWindow /* SDL_Window* */ , & args . parentWindow ); Wenn Sie GLFW3 verwenden, definieren Sie die entsprechenden GLFW_EXPOSE_NATIVE_* -Makros, die auf der Seite GLFW Native Access beschrieben werden, und geben Sie dann <nfd_glfw3.h> an und rufen Sie die folgende Funktion auf, um den übergeordneten Fenstergriff festzulegen:
NFD_GetNativeWindowFromGLFWWindow ( glfwWindow /* GLFWwindow* */ , & args . parentWindow ); Wenn Sie ein anderes Plattformabstraktionsframework verwenden oder kein solches Framework verwenden, können Sie args.parentWindow manuell festlegen.
Win32 (Windows), Kakao (MacOS) und X11 (Linux) werden unterstützt. Das Übergeben eines Wayland -Fensters (Linux) derzeit macht derzeit nichts (dh der Dialog wirkt so aus, als hätte es keinen Elternteil), aber es wird wahrscheinlich in Zukunft Unterstützung hinzugefügt.
Um ein Fenster zu erstellen (in diesem Fall der Dateidialog), bleiben wir über einem anderen Fenster, müssen wir das untere Fenster als übergeordnetes über das obere Fenster deklarieren. Dadurch wird verhindern, dass das Dialogfenster hinter dem übergeordneten Fenster verschwindet, wenn der Benutzer auf das übergeordnete Fenster klickt, während das Dialogfeld geöffnet ist. Wenn Sie den Dialog über dem Fenster behalten, das aufgerufen wurde, ist dies das erwartete Verhalten auf allen unterstützten Betriebssystemen, und so wird das Übergeben des übergeordneten Fenstergriffs nach Möglichkeit empfohlen.
Sie sollten NFDE nach der Initialisierung des Frameworks initialisieren und wahrscheinlich NFDE vor dem Deinitialisieren des Rahmens deeinitialisieren. Dies liegt daran, dass einige Frameworks erwarten, auf einem "sauberen Schiefer" initialisiert zu werden und das System möglicherweise auf eine andere Art und Weise konfigurieren als NFDE. NFD_Init ist im Allgemeinen sehr vorsichtig, die vorhandene Konfiguration nicht zu stören, sofern dies nicht erforderlich ist, und NFD_Quit stellt die Konfiguration genau auf das zurück, was sie vor der Initialisierung war.
Ein Beispiel mit 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
Unter Linux können Sie die Portal -Implementierung anstelle von GTK verwenden, die den vom Betriebssystem ausgewählten "nativen" Dateiauswahl öffnen oder vom Benutzer angepasst werden. Der Benutzer muss über xdg-desktop-portal und ein geeignetes Backend installiert sein (dies ist vorinstalliert mit den häufigsten Desktop-Distributionen), ansonsten wird NFD_ERROR zurückgegeben.
Um die Portal -Implementierung zu verwenden, fügen Sie den Befehl "Build" -DNFD_PORTAL=ON .
*Hinweis: Der Ordner-Picker wird nur auf org.freedesktop.portal.filechooser Interface-Version> = 3 unterstützt, was der XDG-Desktop-Portal-Version> = 1.7.1 entspricht. NFD_PickFolder() wird die Schnittstellenversion zur Laufzeit abfragen und NFD_ERROR zurückgeben, wenn die Version zu niedrig ist.
Im Gegensatz zu Windows und MacOS hat Linux keine Dateiauswahl in das Betriebssystem eingebacken. Linux -Anwendungen, die einen Dateiwähler haben möchten, verlinken normalerweise mit einer Bibliothek, die eine liefert (z. B. GTK, wie im obigen Linux -Screenshot). Dies ist eine meist akzeptable Lösung, die viele Anwendungen verwenden, die Datei jedoch auf Nicht-GTK-Distributionen fremd aussehen lassen.
Flatpak wurde 2015 vorgestellt und kam mit einer standardisierten Schnittstelle, um einen Dateiwähler zu öffnen. Anwendungen, die diese Schnittstelle verwenden, mussten nicht mit einem Dateiwähler geliefert werden und konnten die von Flatpak bereitgestellte verwenden. Diese Schnittstelle wurde als Desktop-Portal bekannt und wurde auf nicht-Flatpak-Anwendungen erweitert. Jetzt sind die meisten großen Desktop -Linux -Distributionen mit dem installierten Desktop -Portal ausgestattet, wobei Dateiwähler zum Thema der Distribution passen. Benutzer können bei Bedarf auch ein anderes Portal -Backend installieren. Derzeit gibt es drei bekannte Backends mit der Datei -Chooser -Unterstützung: GTK, KDE und LXQT; GNOME- und XAPP -Backends hängen von der GTK für diese Funktionalität ab. Das XApp -Backend wurde für Zimt, Mate und XFCE entwickelt. Andere Desktop -Umgebungen scheinen derzeit kein Portal -Backend zu haben.
Info.plist -Datei gemäß der Apple -Dokumentation definieren. (Es ist möglich, NFDE zu erzwingen, um erlaubte fileTypes zu verwenden, indem Sie -DNFD_USE_ALLOWEDCONTENTTYPES_IF_AVAILABLE=OFF zu Ihrem Befehl cMake Build hinzufügen. Dies ist jedoch nicht empfohlen. Wenn Sie ältere MacOS -Versionen unterstützen, sollten Sie stattdessen das richtige Bereitstellungsziel festlegen.))GetOpenFileName . (Es gibt keine Pläne, dies zu unterstützen. Sie sollten Windows XP sowieso nicht noch verwenden.)Bitte verwenden Sie den GitHub -Problem -Tracker, um Fehler zu melden oder zu diesem Repository beizutragen. Fühlen Sie sich frei, Fehlerberichte jeglicher Art einzureichen.
Bernard Teo (ME) und andere Mitwirkende für alles, was nicht aus dem Dialog der nativen Datei von Michael Labbe stand.
Michael Labbe für seine großartige Dialogbibliothek für native Datei und die anderen Mitwirkenden dieser Bibliothek.
Ein Großteil dieser Readme wurde auch aus dem Readme des ursprünglichen Dialogfelds natives Datei -Repository kopiert.
Alles in diesem Repository wird unter der ZLIB -Lizenz verteilt, ebenso wie die ursprüngliche Dialogbibliothek der nativen Datei.
Ich biete keine bezahlte Unterstützung. Michael Labbe scheint zum Zeitpunkt des Schreibens bezahlte Unterstützung für seine Bibliothek zu leisten.