JLI Spieleprogrammierung Foren-Übersicht JLI Spieleprogrammierung

 
 FAQFAQ   SuchenSuchen   MitgliederlisteMitgliederliste   BenutzergruppenBenutzergruppen 
 medals.php?sid=3d96b4f084f21decc988ecd0fb29485bMedaillen   RegistrierenRegistrieren   ProfilProfil   Einloggen, um private Nachrichten zu lesenEinloggen, um private Nachrichten zu lesen   LoginLogin 

[Win API] Standard-Dateidialoge
Gehe zu Seite 1, 2  Weiter
 
Neues Thema eröffnen   Neue Antwort erstellen    JLI Spieleprogrammierung Foren-Übersicht -> Tutorials
Vorheriges Thema anzeigen :: Nächstes Thema anzeigen  
Autor Nachricht
Jonathan_Klein
Living Legend


Alter: 36
Anmeldedatum: 17.02.2003
Beiträge: 3431
Wohnort: Siegerland
Medaillen: Keine

BeitragVerfasst am: 19.04.2006, 20:17    Titel: [Win API] Standard-Dateidialoge Antworten mit Zitat

Wenn man einen Leveleditor oder ähnliches mit der Win-API programmieren möchte, ist es sehr praktisch wenn man den Windowsstandard Dateidialog benutzen kann. Der Aufwand ist realtiv gering, aber das Ergebnis wirkt professionell.

Hier mal ein Beispiel um Dateien zu laden:
CPP:
char Dir[128], Name[128];
ZeroMemory(Name, sizeof(Name));
GetModuleFileName(NULL, Dir, 128);

OPENFILENAME Filename;
ZeroMemory(&Filename, sizeof(OPENFILENAME));
Filename.lStructSize=sizeof(OPENFILENAME);
Filename.lpstrInitialDir=Dir;
Filename.lpstrFile=Name;
Filename.nMaxFile=128;
if(GetSaveFileName(&Filename))
   SaveFile(Filename.lpstrFile);


Man ruft also einfach die Funktion GetSaveFileName auf und übergibt als Parameter einen Zeiger auf eine OPENFILENAME-Struktur. Diese hat ziemlich viele Elemente, weswegen hier mehr oder weniger eine Minimallösung vorgestellt wird.

Wichtig ist hier der Name-String, der hinterher den Dateinamen enthält. Man muss in der Openfilename Struktur vorher den Speicherort und die Größe des Buffers angeben, damit das ganze funktioniert.
Der Dir-String dient hier lediglich dazu, das der Dateidialog dort startet, wo sich die exe-Datei befindet. Man kann auch jedes andere Verzeichnis angeben das einem passt.
Der Rückgabewert gibt an ob auch eine Datei ausgewählt wurde. Man kann ja schließlich auch auf "Abbrechen" klicken, und dann darf natürlich nichts gespeichert oder geladen werden.

Für das Laden von Dateine benutzt man exakt die selbe Struktur, nur heißt die Funktion jetzt GetOpenFileName. Die unterschiede sind minimal, beide geben schließlich einen Dateinamen zurück, nur will man beim öffnen von Dateien vieleicht nicht auf einen "Speichern"-Button klicken.

Detailiertere Beschreibungen findet man in der MSDN, einfach "OPENFILENAME", "GetOpenFileName" oder "GetSaveFileName" eingeben.
_________________
https://jonathank.de/games/
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden Website dieses Benutzers besuchen
Dragon
Super JLI'ler


Alter: 37
Anmeldedatum: 24.05.2004
Beiträge: 340
Wohnort: Sachsen
Medaillen: Keine

BeitragVerfasst am: 19.04.2006, 20:28    Titel: Antworten mit Zitat

etwas kurz für ein Tutorial, vieleicht könntest du es noch etwas mehr ausbauen Wink
_________________
Nur wenn man ein Ziel sieht, kann man es auch treffen.
___________
Mein Leben, Freunde und die Spieleentwicklung
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden Website dieses Benutzers besuchen
Jonathan_Klein
Living Legend


Alter: 36
Anmeldedatum: 17.02.2003
Beiträge: 3431
Wohnort: Siegerland
Medaillen: Keine

BeitragVerfasst am: 19.04.2006, 20:44    Titel: Antworten mit Zitat

Jo, das ist so ein wenig zwischen FAQ/Tutorial. Ich werd bei Gelegenheit mal ein paar mehr Sachen erläutern, zum Beispiel Standarddateiendung, und Filter zur Dateiauswahl, was beides relativ nützlich ist.
_________________
https://jonathank.de/games/
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden Website dieses Benutzers besuchen
FH
Super JLI'ler


Alter: 36
Anmeldedatum: 16.10.2004
Beiträge: 437

Medaillen: Keine

BeitragVerfasst am: 26.04.2006, 18:52    Titel: Antworten mit Zitat

/me erweiteret das jetzt mal ein bisschen:
Die Struktur OPENFILENAME kann aber noch mehr:
Zum Beispiel kann man einen Filter definieren, dass z.B. nur Dateien mit der Endung .txt angezeigt werden. Man kann auch mehrere solcher Filter definieren. Der User kann dann zwischen der verschiedenen Filtern wählen.
Den Filter gibt man folgendermaßen an:
CPP:
Filename.lpstrFilter="Text-Dateien\0*.txt\0Alle Dateien\0*.*\0";

Es ist eigentlich ganz simpel: Man hängt die verschiedenen Filter einfach hintereinander, und trennt sie durch Null-Zeichen. Zuerst kommt eine Beschreibung des Filters (die kriegt der User angezeigt), dann folgt ein Nullzeichen, und nun kommt der String, nach dem gesucht wird. Ein "*" steht dabei allgemein für eine beliebige Zeichenkombination. Zum Abschluss kommt wieder ein Nullzeichen.
Wir haben hier im Beispiel also zwei Filter: Erstmal einen Filter, der alle Text-Dateien anzeigt, und dann einen Filter, der alle Dateien anzeigt. Ihr könnt auch gerne noch mehr Filter deklarieren, und diese einfügen.
Gruß

FH
_________________
goto work, send your kids to school
follow fashion, act normal
walk on the pavement, watch T.V.
save for your old age, obey the law
Repeat after me: I am free
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
FH
Super JLI'ler


Alter: 36
Anmeldedatum: 16.10.2004
Beiträge: 437

Medaillen: Keine

BeitragVerfasst am: 26.04.2006, 19:15    Titel: Antworten mit Zitat

Wenn wir schon beim Thema Standard-Datei-Dialoge sind:
Man kann auch nur nach Ordner suchen lassen.
Ihr müsst dazu die Datei "shlobj.h" includen.
Nun zum eigentlichen Code für das Suchen nach Ordnern:
CPP:
BROWSEINFO bi;
LPITEMIDLIST pItemIDList;
char Path[MAX_PATH+1];
ZeroMemory(&bi,sizeof(BROWSEINFO));

bi.lpszTitle="Bitte wählen sie einen Ordner aus.";
pItemIDList=SHBrowseForFolder(&bi);
SHGetPathFromIDList(pItemIDList,Path);

Man macht also folgendes: Man nutzt die Struktur BROWSEINFO. Deren Member lpszTitle übergibt man einen Text, der über dem eigentlich Feld zur Suche nach den Ordnern angezeigt wird.
Dann ruft ihr SHBrowseForFolder auf. Dies gibt einen Zeiger auf ein ITEMIDLIST-Objekt zurück, oder 0 falls der User abbrechen gedrückt hat. Mit diesem Zeiger auf ein ITEMIDLIST-Objekt können wir vorerst mal überhaupt nix anfangen. Deshalb werfen wir es erstmal der Funktion SHGetPathFromIDList vor. Diese Funktion übernimmt noch einen Zeiger auf ein char-Array. Dieses Array enthält danach die Pfadangabe zum vom User ausgewählten Ordner. Das char-Array muss mindestens MAX_PATH lang sein (das ist eine in den untiefen der Windows-include-Dateien definierte Konstante).
Der Dialog sieht dann im Endeffekt so aus:

So, dass wars erstmal.
Wer jetzt noch etwas daran zu meckern hat, dass ich Ordner statt Verzeichniss schreibe: Verzeichniss is so lang, und ich bin schlichtweg tippfaul. Wink
Gruß

FH
_________________
goto work, send your kids to school
follow fashion, act normal
walk on the pavement, watch T.V.
save for your old age, obey the law
Repeat after me: I am free


Zuletzt bearbeitet von FH am 23.07.2011, 23:01, insgesamt 3-mal bearbeitet
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
fast hawk
Senior JLI'ler



Anmeldedatum: 15.07.2005
Beiträge: 237
Wohnort: Freiburg
Medaillen: Keine

BeitragVerfasst am: 27.04.2006, 17:53    Titel: Antworten mit Zitat

\me gibt auch noch seinen senf dazu:

Wenn man bei GetSaveFileName Filter benutzt wird in Filename.nFilterIndex der Filter gespeichert.
d.h.:

wenn der Filter so aus sieht:
CPP:
Filename.lpstrFilter="Text-Dateien\0*.txt\0Alle Dateien\0*.*\0";


und nacher Filename.nFilterIndex == 2 ist, hat derjenige "Alle Dateien" ausgwählt,
wenn Filename.nFilterIndex == 1 ist "Text-Dateien".
Für wenn es verwireen sollte es beginnt hier wirklich mit 1 nicht wie sonst oft mit 0. Ebenso wird der Dateityp nicht automatisch hinten angehenkt das muss händisch gemacht werden.

siehe auch: http://msdn.microsoft.com/library/en-us/winui/winui/windowsuserinterface/userinput/commondialogboxlibrary/aboutcommondialogboxes/openandsaveasdialogboxes.asp?frame=true
_________________
Jetziges Projekt: The Ring War
Status: 40%
-----------------------------------
Nicht weil es schwer ist, wagen wir es nicht, sondern weil wir es nicht wagen, ist es schwer.
--
Lucius Annaeus Seneca (4)
röm. Philosoph, Dramatiker und Staatsmann
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden Website dieses Benutzers besuchen
Jonathan_Klein
Living Legend


Alter: 36
Anmeldedatum: 17.02.2003
Beiträge: 3431
Wohnort: Siegerland
Medaillen: Keine

BeitragVerfasst am: 30.04.2006, 18:14    Titel: Antworten mit Zitat

Hinweis: GetOpenFilename scheint den Standadrpfad fürs laden von Dateien zu verändern. Siehe dazu folgenden Thread:
http://www.jliforum.de/board/viewtopic.php?p=59173#59173
_________________
https://jonathank.de/games/
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden Website dieses Benutzers besuchen
fast hawk
Senior JLI'ler



Anmeldedatum: 15.07.2005
Beiträge: 237
Wohnort: Freiburg
Medaillen: Keine

BeitragVerfasst am: 30.04.2006, 18:52    Titel: Antworten mit Zitat

Nein macht es nicht es setzt nur den aktullen pfad auf deinen Auswahl Pfad so wie er bei jedem Start deines Programmes auf deinen Programmpfad gesetzt wird. Den kannst du auch über die Eingabeaufforderung umsetzen(D:,C:,I:,E;(darf leider keinen Doppelpunkt machen weil es sonst ein Smile wird Wink ). Wurd aber in dem anderen thread ja auch schon gesagt!!
_________________
Jetziges Projekt: The Ring War
Status: 40%
-----------------------------------
Nicht weil es schwer ist, wagen wir es nicht, sondern weil wir es nicht wagen, ist es schwer.
--
Lucius Annaeus Seneca (4)
röm. Philosoph, Dramatiker und Staatsmann
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden Website dieses Benutzers besuchen
FH
Super JLI'ler


Alter: 36
Anmeldedatum: 16.10.2004
Beiträge: 437

Medaillen: Keine

BeitragVerfasst am: 01.05.2006, 09:38    Titel: Antworten mit Zitat

Allerdings hat die Struktur OPENFILENAME einen Member namens Flags. Wenn man ihn auf OFN_NOCHANGEDIR setzt, wird der Pfad nicht verändert.
Es gibt da übrigens ebenfalls noch ein paar sehr schöne andere Flags!
Gruß

FH
_________________
goto work, send your kids to school
follow fashion, act normal
walk on the pavement, watch T.V.
save for your old age, obey the law
Repeat after me: I am free
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
Jonathan_Klein
Living Legend


Alter: 36
Anmeldedatum: 17.02.2003
Beiträge: 3431
Wohnort: Siegerland
Medaillen: Keine

BeitragVerfasst am: 09.08.2006, 12:45    Titel: Antworten mit Zitat

Laut MSDN muss bei Filtern der letze Filter mit zwei NULL zeichen abgeschlossen werden. Ist ja auch logsich, woher sollte Windows sonst wissen, wo der String aufhört, wenn es nach einem NULL-Zeichen noch weiter geht?
MSDN hat Folgendes geschrieben:

lpstrFilter
Pointer to a buffer containing pairs of null-terminated filter strings. The last string in the buffer must be terminated by two NULL characters.

_________________
https://jonathank.de/games/
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden Website dieses Benutzers besuchen
User_User
JLI'ler



Anmeldedatum: 05.08.2004
Beiträge: 137

Medaillen: Keine

BeitragVerfasst am: 25.02.2007, 20:24    Titel: Antworten mit Zitat

Wenn ich den Dateidialog in einem Programm verwende, welches 3D-Grafik verwendet (z.B. Kapitel 27 Triangle3D, muss ich das Programm im Ordner Debug direkt mittels Doppelklick starten.

Beweg ich das Fenster des Dateidialogs, dann werden freigewordene Flächen des darunterliegenden Fensters mit einer einheitlichen Hintergrundfarbe dargestellt.

Wir erreiche ich es, dass die ursprüngliche 3D-Hintergrundgrafik wiederhergestellt wird?
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden Website dieses Benutzers besuchen
Jonathan_Klein
Living Legend


Alter: 36
Anmeldedatum: 17.02.2003
Beiträge: 3431
Wohnort: Siegerland
Medaillen: Keine

BeitragVerfasst am: 25.02.2007, 21:10    Titel: Antworten mit Zitat

WM_PAINT bearbeiten.
_________________
https://jonathank.de/games/
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden Website dieses Benutzers besuchen
Otscho
Super JLI'ler


Alter: 35
Anmeldedatum: 31.08.2006
Beiträge: 338
Wohnort: Gummibären-Gasse
Medaillen: Keine

BeitragVerfasst am: 28.01.2009, 18:25    Titel: Antworten mit Zitat

Ich hab mal nach Petzold folgende OPENFILENAME implementierung ausprobiert:

Das erstellen einer Struktur:

CPP:
static OPENFILENAME ofn;
static TCHAR szFilter[] =   __TEXT("MelioRay Xml Dateien (*.mrx)\0*.MRX\0") \
                        __TEXT("Alle Dateien (*.*)\0*.*\0\0");


static TCHAR Dir[128], Name[128];

GetModuleFileName(NULL, Dir, 128);

ofn.lStructSize         = sizeof(OPENFILENAME);
ofn.hwndOwner           = hwnd;
ofn.hInstance           = globalInstance;
ofn.lpstrFilter         = szFilter;
ofn.lpstrCustomFilter   = NULL;
ofn.nMaxCustFilter      = 0;
ofn.nFilterIndex        = 0;
ofn.lpstrFile           = NULL;
ofn.nMaxFile            = MAX_PATH;
ofn.lpstrFileTitle      = NULL;
ofn.nMaxFileTitle       = MAX_PATH;
ofn.lpstrInitialDir     = Dir;
ofn.lpstrTitle          = NULL;
ofn.Flags               = 0;
ofn.nFileOffset         = 0;
ofn.nFileExtension      = 0;
ofn.lpstrDefExt         = TEXT("mrx");
ofn.lCustData           = 0L;
ofn.lpfnHook            = NULL;
ofn.lpTemplateName      = NULL;


Und dann der Aufruf des Dialogfensters zum öffnen einer Datei:
CPP:
ofn.hwndOwner        = hwnd;
ofn.lpstrFile        = Name;
ofn.lpstrFileTitle   = TEXT("mrx");
ofn.Flags            = OFN_HIDEREADONLY | OFN_CREATEPROMPT;

GetOpenFileName(&ofn);


Leider kommt es bei mir hier immer zu einem Programmabsturz, wegen eines ungültigen Speicherzugriffs.


Weiß jemand, was ich falsch gemacht habe ?
Ich verwende Windows Vista und bin mir nicht sicher, welche Dinge der Struktur ich hier mit einer "NULL" abfertigen darf.

Das Debuggen hat mir leider auch Nichts gebracht.
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden
FH
Super JLI'ler


Alter: 36
Anmeldedatum: 16.10.2004
Beiträge: 437

Medaillen: Keine

BeitragVerfasst am: 28.01.2009, 19:36    Titel: Antworten mit Zitat

Otscho hat Folgendes geschrieben:
CPP:
ofn.lpstrFile           = NULL;
ofn.nMaxFile            = MAX_PATH;

lpstrFile darf nicht NULL sein, denn in den Buffer, den du da angibst, wird Pfad der Datei reingeschrieben. Sozusagen die Rückgabe. Wink
Und nMaxFile sollte die Länge des Buffers in lpstrFile enthalten.
Nebenbei sollte der Buffer für lpstrFile mit einem \0 beginnen.

Ansonsten würde ich dir noch empfehlen, OFN_NOCHANGEDIR in den Flags zu setzen, denn sonst verändert GetOpenFileName den aktuellen Pfad zu dem Pfad, der geöffnet wurde, was später (z.B. beim nachladen von DLLs) gerne zu sehr merkwürdigem Verhalten führt.
Überhaupt würde ich dir wegen den Flags noch zu einem Blick in die Doku raten, je nachdem, ob man ein File zum lesen oder zum schreiben öffnen will, gibt es da noch einige nette Flags.
Gruß

FH
_________________
goto work, send your kids to school
follow fashion, act normal
walk on the pavement, watch T.V.
save for your old age, obey the law
Repeat after me: I am free
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
Otscho
Super JLI'ler


Alter: 35
Anmeldedatum: 31.08.2006
Beiträge: 338
Wohnort: Gummibären-Gasse
Medaillen: Keine

BeitragVerfasst am: 29.01.2009, 17:37    Titel: Antworten mit Zitat

Ich hab mal deinen Ratschlag befolgt FH. und für nMaxFile = 128 eingesetzt. lpstrFile hab ich ja vor dem Öffnen auf den Buffer "Name" gesetzt. Wobei ich das erste Zeichen auf \0 gestzt habe, hat das nichts bewirkt als dass ein komisches Zeichen am als vorwahl datei angezeigt wurde.

Leider hat das alles nichts gebracht.

Kann es was ausmachen, dass ich den "Datentyp" TCHAR verwende ?
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden
Beiträge der letzten Zeit anzeigen:   
Neues Thema eröffnen   Neue Antwort erstellen    JLI Spieleprogrammierung Foren-Übersicht -> Tutorials Alle Zeiten sind GMT
Gehe zu Seite 1, 2  Weiter
Seite 1 von 2

 
Gehe zu:  
Du kannst keine Beiträge in dieses Forum schreiben.
Du kannst auf Beiträge in diesem Forum nicht antworten.
Du kannst deine Beiträge in diesem Forum nicht bearbeiten.
Du kannst deine Beiträge in diesem Forum nicht löschen.
Du kannst an Umfragen in diesem Forum nicht mitmachen.


Powered by phpBB © 2001, 2005 phpBB Group
Deutsche Übersetzung von phpBB.de

Impressum