Uma pequena biblioteca C que chama portável o arquivo nativo aberto, a pasta Selecion e o arquivo Salvar diálogos. Escreva o código de diálogo uma vez e faça com que apareça diálogos nativos em todas as plataformas suportadas. Evite vincular grandes dependências como WxWidgets e Qt.
Esta biblioteca é baseada na caixa de diálogo Native Arquivo de Michael Labbe (MLABBE/NativeFiledialog).
Características:
C/C++ Source files (*.c;*.cpp) em vez de (*.c;*.cpp) ) em plataformas que o suportamUntitled.c )wchar_t ) Suporte no WindowsIFileDialog do Vista no Windowsunique_ptr auto-isolamento automático e parâmetros opcionais, para aqueles que usam esta biblioteca de C ++Comparação com a caixa de diálogo de arquivo nativo original:
O recurso de nomes amigáveis é o principal motivo para quebrar a compatibilidade da API com a biblioteca de Michael Labbe (e, portanto, essa biblioteca provavelmente nunca será fundida com ela). Há também vários ajustes que causam diferenças observáveis nesta biblioteca.
Recursos adicionados na caixa de diálogo de arquivo nativo estendido:
wchar_t ) Suporte no Windowsunique_ptr e parâmetros opcionais isentos de automóveis e parâmetros opcionaisTambém há refratamento significativo de código, especialmente para a implementação do Windows.
O wiki acompanha as ligações de idiomas conhecidas e projetos populares conhecidos que dependem desta biblioteca.
#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 ;
} O U8 / u8 no NFDE consulte a API para caracteres UTF-8 ( char ), que a maioria dos consumidores provavelmente deseja. Também está disponível uma versão N / n , que usa o tipo de caractere nativo ( wchar_t no Windows e char em outras plataformas).
Para obter a lista completa de argumentos que você pode definir na estrutura args , consulte a seção "All Options" abaixo.
Se você estiver usando uma estrutura de abstração da plataforma, como SDL ou GLFW, consulte também o "uso com uma estrutura de abstração da plataforma" abaixo.






Se o seu projeto usar cmake, basta adicionar as seguintes linhas aos seus cmakelists.txt:
add_subdirectory(path/to/nativefiledialog-extended)
target_link_libraries(MyProgram PRIVATE nfd)
Certifique -se de que você também tenha as dependências necessárias.
Quando incluídos como subproject, os programas de amostra não são construídos e o destino de instalação é desativado por padrão. Adicionar -DNFD_BUILD_TESTS=ON para criar programas de amostra e -DNFD_INSTALL=ON para ativar o destino de instalação.
Se você deseja construir a biblioteca estática independente, execute os seguintes comandos (a partir do diretório raiz do projeto):
Para GCC e Clang:
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Release ..
cmake --build .
Para MSVC:
mkdir build
cd build
cmake ..
cmake --build . --config Release
Os comandos acima farão um diretório build e criarão o projeto (no modo de liberação) lá. Se você estiver desenvolvendo NFDE, convém fazer -DCMAKE_BUILD_TYPE=Debug / --config Debug para criar uma versão de depuração da biblioteca.
Ao criar como uma biblioteca independente, os programas de amostra são criados e o destino de instalação é ativado por padrão. Adicionar -DNFD_BUILD_TESTS=OFF para desativar programas de amostra de construção e -DNFD_INSTALL=OFF para desativar o destino de instalação.
No Linux, se você deseja usar o portal de desktop Flatpak em vez de GTK, adicione -DNFD_PORTAL=ON . (Caso contrário, o GTK será usado.) Consulte a seção "Uso" abaixo para obter mais informações.
Consulte o arquivo de construção do CI para obter alguns comandos de compilação de exemplo.
Versões recentes do Visual Studio têm suporte ao CMake incorporado ao IDE. Você deve poder "abrir a pasta" no diretório raiz do projeto, e o Visual Studio reconhecerá e configurará o projeto adequadamente. A partir daí, você poderá definir configurações para depuração versus lançamento e para x86 vs x64. Para mais informações, consulte a página da Microsoft Docs. Isso foi testado para funcionar no Visual Studio 2019 e provavelmente também funciona no Visual Studio 2017.
src/include ao seu caminho de pesquisa de incluir.nfd.lib ou nfd_d.lib à lista de bibliotecas estáticas a serem vinculadas (para liberação ou depuração, respectivamente).build/<debug|release>/<arch> ao caminho de pesquisa da biblioteca. Verifique se libgtk-3-dev está instalado no seu sistema.
Verifique se libdbus-1-dev está instalado no seu sistema.
No MacOS, adicione AppKit e UniformTypeIdentifiers à lista de estruturas.
No Windows (MSVC e Mingw), verifique se você está construindo contra ole32.lib , uuid.lib e shell32.lib .
Para abrir uma caixa de diálogo, você define opções em uma estrutura e depois passa essa estrutura para uma função NFDE, por exemplo:
nfdopendialogu8args_t args = { 0 };
args . filterList = filters ;
args . filterCount = 2 ;
nfdresult_t result = NFD_OpenDialogU8_With ( & outPath , & args ); Todas as opções são opcionais e podem ser configuradas individualmente (zero de inicialização define todas as opções para padrões razoáveis), exceto para filterList e filterCount que devem ser definidos ou ambos não.
As versões futuras do NFDE podem adicionar opções adicionais ao final dos argumentos Struct sem aumentar o número da versão principal; portanto, para garantir a compatibilidade da API reversa, você não deve assumir que a estrutura possui um comprimento ou número específico de campos. Você pode assumir que a inicialização zero da estrutura continuará definindo todas as opções para padrões razoáveis; portanto, atribuir {0} à estrutura é aceitável. Para aqueles que construem bibliotecas compartilhadas da NFDE, a compatibilidade com a ABI reversa é garantida por um índice de versão interna ( NFD_INTERFACE_VERSION ), que deve ser transparente para os consumidores.
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 ;PickFolder / PickFoldermultiple :
typedef struct {
const nfdu8char_t * defaultPath ;
nfdwindowhandle_t parentWindow ;
} nfdpickfolderu8args_t ;filterList e filterCount : Defina -os para personalizar o filtro de arquivo (ele aparece como um menu suspenso no Windows e Linux, mas simplesmente oculta arquivos no macOS). Defina filterList como um ponteiro para o início da matriz de itens de filtro e filterCount para o número de itens de filtro nessa matriz. Consulte a seção "Sintaxe do filtro de arquivo" abaixo para obter detalhes.defaultPath : Defina isso na pasta padrão em que a caixa de diálogo deve abrir (no Windows, se houver uma pasta usada recentemente, ele abre para essa pasta em vez da pasta que você passa, a menos que a opção NFD_OVERRIDE_RECENT_WITH_DEFAULT esteja definida).defaultName : (apenas para savedialog) Defina-o como o nome do arquivo que deve ser preenchido na caixa de diálogo.parentWindow : defina isso como a alça da janela nativa do pai desta caixa de diálogo. Consulte a seção "Uso com uma estrutura de abstração da plataforma" para obter detalhes. Também é possível passar uma alça, mesmo que você não use uma estrutura de abstração da plataforma. Consulte o diretório test para exemplo, código (C e C ++).
Se você ativou a opção de criar o diretório test ( -DNFD_BUILD_TESTS=ON ), o build/bin conterá os programas de teste compilados.
Há também um exemplo SDL2, que precisa ser ativado separadamente com -DNFD_BUILD_SDL2_TESTS=ON . Requer que o SDL2 seja instalado em sua máquina.
Exemplos compilados (incluindo o exemplo SDL2) também são enviados como artefatos para ações do GitHub e podem ser baixados a partir daí.
Os arquivos podem ser filtrados por grupos de extensão de arquivo:
nfdu8filteritem_t filters [ 2 ] = { { "Source code" , "c,cpp,cc" }, { "Headers" , "h,hpp" } };Um filtro de arquivo é um par de strings que compreende o nome amigável e a especificação (várias extensões de arquivo são separadas por vírgula).
Uma lista de filtros de arquivo pode ser passada como um argumento ao invocar a biblioteca.
Um filtro curinga é sempre adicionado a cada caixa de diálogo.
Nota: No macOS, as caixas de diálogo de arquivo não têm nomes amigáveis e não há como alternar entre os filtros, portanto as especificações do filtro são combinadas (por exemplo, "C, CPP, CC, H, HPP"). A especificação do filtro também nunca é mostrada explicitamente ao usuário. Este é o comportamento comum do macOS e os usuários esperam.
Nota 2: você deve garantir que a sequência de especificação não esteja vazia e que cada extensão de arquivo tenha pelo menos um caractere. Caso contrário, coisas ruins podem ocorrer (ou seja, comportamento indefinido).
Nota 3: No Linux, a extensão do arquivo é anexada (se estiver ausente) quando o usuário pressiona o botão "Salvar". A extensão de arquivo anexada permanecerá visível ao usuário, mesmo que um prompt de substituição seja mostrado e o usuário pressione "Cancelar".
Nota 4: No Windows, o parâmetro da pasta padrão é usado apenas se não houver pasta usada recentemente, a menos que a opção NFD_OVERRIDE_RECENT_WITH_DEFAULT esteja definida como ativada. Caso contrário, a pasta padrão será a pasta usada pela última vez. Internamente, a implementação do Windows chama o ifiledialog :: setDefaultFolder (ishellitem). Este é o comportamento usual do Windows e os usuários esperam.
Uma caixa de diálogo aberta de arquivo que suporta seleção múltipla produz um Pathset, que é uma abstração fina sobre a coleção específica da plataforma. Existem duas maneiras de iterar sobre um pathset:
Este método faz acesso semelhante a uma matriz no Pathset e é o mais fácil de usar. No entanto, em certas plataformas (Linux e possivelmente Windows), leva o tempo O (n 2 ) no total para iterar todo o Pathset, porque a implementação subjacente específica da plataforma usa uma lista vinculada.
Consulte test_opendialogmultiple.c.
Este método usa um objeto enumerador para iterar os caminhos no PathSet. É garantido que o tempo de O (n) é total para iterar todo o Pathset.
Consulte test_opendialogmultiple_enum.c.
Esta API é experimental e sujeita a alterações.
Você pode definir as seguintes macros antes de incluir nfd.h / nfd.hpp :
NFD_NATIVE : defina isso antes de incluir nfd.h para fazer nomes de funções e typedefs não sufocados (por exemplo, NFD_OpenDialog ) para as funções nativas (por exemplo, NFD_OpenDialogN ) em vez de aliases para as funções UTF-8 (gestão NFD_OpenDialogU8 ). Esta macro não afeta o wrapper C ++ nfd.hpp .NFD_THROWS_EXCEPTIONS : (somente C ++) Defina isso antes de incluir nfd.hpp para fazer NFD::Guard Construction Throw std::runtime_error se NFD_Init falhar. Caso contrário, não há como detectar falha na construção de NFD::Guard . Macros que podem ser definidas por nfd.h :
NFD_DIFFERENT_NATIVE_FUNCTIONS : definido se as versões nativas e UTF-8 das funções forem diferentes (ou seja, compilando para Windows); não definido de outra forma. Se NFD_DIFFERENT_NATIVE_FUNCTIONS não for definido, as versões UTF-8 das funções são aliases para as versões nativas. Isso pode ser útil se você estiver escrevendo uma função que deseja fornecer sobrecarga, dependendo se as funções nativas e as funções UTF-8 são as mesmas. (O nativo é UTF-16 ( wchar_t ) para Windows e UTF-8 ( char ) para Mac/Linux.) Sabe -se que a NFDE trabalha com SDL2 e GLFW e também deve trabalhar com outras pistas de abstração da plataforma. Esta seção explica como usar o NFDE corretamente com essas estruturas.
O argumento parentWindow permite que o usuário forneça um pai a um pai.
Se estiver usando o SDL2, inclua <nfd_sdl2.h> e chame a seguinte função para definir o identificador da janela pai:
NFD_GetNativeWindowFromSDLWindow ( sdlWindow /* SDL_Window* */ , & args . parentWindow ); Se estiver usando GLFW3, defina as macros apropriadas GLFW_EXPOSE_NATIVE_* descritas na página de acesso nativo do GLFW e inclua <nfd_glfw3.h> e chame a seguinte função para definir o identificador da janela pai:
NFD_GetNativeWindowFromGLFWWindow ( glfwWindow /* GLFWwindow* */ , & args . parentWindow ); Se você estiver usando outra estrutura de abstração da plataforma ou não estiver usando essa estrutura, poderá definir manualmente args.parentWindow .
As janelas Win32 (Windows), Cacau (MacOS) e X11 (Linux) são suportadas. Atualmente, passar uma janela Wayland (Linux) não faz nada (ou seja, a caixa de diálogo atua como se não tivesse pai), mas é provável que o suporte seja adicionado no futuro.
Para fazer uma janela (nesse caso, a caixa de diálogo Arquivo) fique acima de outra janela, precisamos declarar a janela inferior como pai da janela superior. Isso impede que a janela de diálogo desapareça atrás da janela dos pais se o usuário clicar na janela do pai enquanto a caixa de diálogo estiver aberta. Manter a caixa de diálogo acima da janela que invocou é o comportamento esperado em todos os sistemas operacionais suportados e, portanto, a passagem do identificador da janela dos pais é recomendada, se possível.
Você deve inicializar o NFDE após a inicialização da estrutura e provavelmente deve desinitalizar o NFDE antes de desinacionar a estrutura. Isso ocorre porque algumas estruturas esperam ser inicializadas em uma "lousa limpa" e podem configurar o sistema de uma maneira diferente da NFDE. NFD_Init geralmente é muito cuidadoso para não interromper a configuração existente, a menos que seja necessário, e NFD_Quit restaura a configuração de volta exatamente ao que era antes da inicialização.
Um exemplo com 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
No Linux, você pode usar a implementação do portal em vez do GTK, que abrirá o escolhido de arquivo "nativo" selecionado pelo sistema operacional ou personalizado pelo usuário. O usuário deve ter xdg-desktop-portal e um back-end adequado (isso vem pré-instalado com as distritos de desktop mais comuns), caso contrário, NFD_ERROR será retornado.
Para usar a implementação do portal, adicione -DNFD_PORTAL=ON ao comando de compilação.
*Nota: o seletor de pasta é suportado apenas no org.freedesktop.portal.FileChooser Interface Version> = 3, que corresponde à versão XDG-DESKTOP-portal> = 1.7.1. NFD_PickFolder() consultará a versão da interface no tempo de execução e retornará NFD_ERROR se a versão estiver muito baixa.
Ao contrário do Windows e MacOS, o Linux não possui um escolhido de arquivo assado no sistema operacional. Aplicativos Linux que desejam um escolhedor de arquivos geralmente se vincula a uma biblioteca que fornece uma (como o GTK, como na captura de tela do Linux acima). Esta é uma solução principalmente aceitável que muitos aplicativos usam, mas podem fazer com que o selecionador de arquivos pareça estranho nas distros não-GTK.
O FlatPak foi introduzido em 2015 e, com ele, veio uma interface padronizada para abrir um selecionador de arquivos. Os aplicativos usando essa interface não precisavam vir com um escolhedor de arquivos e poderiam usar o fornecido pelo Flatpak. Essa interface ficou conhecida como Portal de Desktop e seu uso expandido para aplicativos que não são flatpak. Agora, a maioria dos principais distritos do Linux de desktop vem com o portal de desktop instalado, com os escolhidos de arquivos que se encaixam no tema da distro. Os usuários também podem instalar um back -end de portal diferente, se desejar. Atualmente, existem três back -ends conhecidos com suporte ao selecionador de arquivos: GTK, KDE e LXQT; Os backnds do GNOME e XAPP dependem do GTK One para essa funcionalidade. O back -end do XAPP foi projetado para canela, companheiro e XFCE. Outros ambientes de desktop não parecem ter um back -end de portal.
Info.plist conforme a documentação da Apple. (É possível forçar o NFDE a usar o AllowFiletypes, adicionando -DNFD_USE_ALLOWEDCONTENTTYPES_IF_AVAILABLE=OFF ao seu comando CMake Build, mas isso não é recomendado.GetOpenFileName . (Não há planos de apoiar isso; você ainda não deve usar o Windows XP.)Use o rastreador de problemas do GitHub para relatar bugs ou para contribuir com este repositório. Sinta -se à vontade para enviar relatórios de bug de qualquer tipo.
Bernard Teo (ME) e outros colaboradores para tudo o que não era da caixa de diálogo Native Arquivo de Michael Labbe.
Michael Labbe para sua incrível biblioteca de diálogo de arquivo nativo e os outros colaboradores dessa biblioteca.
Grande parte deste ReadMe também foi copiada do Readme do repositório de caixa de arquivo nativo original.
Tudo neste repositório é distribuído pela licença ZLIB, assim como a biblioteca de diálogo de arquivo nativo original.
Não forneço nenhum apoio pago. Michael Labbe parece fornecer apoio remunerado à sua biblioteca no momento da redação.