Autor Beitrag
Aton
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 125

Windows XP
D7 Enterprise
BeitragVerfasst: Mi 16.06.04 21:20 
Hallo Peter Lustig, Lucki und Co.

Erstmal, großen Respekt für die ganzen Tools hier. So zum Beispiel auch der Meisterschaft um den besten OpenDialog für Folder im Dateizugriffs-FAQ.

Eine Anregung für OpenDialog #5: :idea:

Eine Eigenschaft Filter, oder so, in der man Dateitypen angeben kann (z.B. *.dat). Nun kann der Benutzer des OpenDialogs nur Folder auswählen, in der mindestens eine dieser Datei vorhanden ist. Sonst ist der Button OK disabled.

Gruß Jens.
Christian S.
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 20451
Erhaltene Danke: 2264

Win 10
C# (VS 2019)
BeitragVerfasst: Mi 16.06.04 21:30 
Hallo!

Dies kannst Du über die bereits eingebaute CallBack-Funktion realisieren. Dort kannst Du auf die Nachricht BFFM_SELCHANGED reagieren, über den lParam den ausgewählten Ordner ermitteln. Dann schaust Du, ob in diesem Ordner eine .dat-Datei ist. Den Button aktivieren / deaktivieren kannst Du über die Nachricht BFFM_ENABLEOK (analog zum Senden der Nachricht BFFM_SETSELECTION im FAQ-Beitrag).

Ich habe das selbst nicht ausprobiert, aber auf diese Weise sollte das zu machen sein. Am Besten schaust Du Dir dazu die MSDN-Seite an, auf die ich oben verlinkt habe.

MfG
Peter

_________________
Zwei Worte werden Dir im Leben viele Türen öffnen - "ziehen" und "drücken".


Zuletzt bearbeitet von Christian S. am Mi 16.06.04 21:31, insgesamt 1-mal bearbeitet
Aton Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 125

Windows XP
D7 Enterprise
BeitragVerfasst: Mi 16.06.04 21:31 
Ich denke man müsste damit arbeiten, oder?

Zitat:
BrowseCallbackProc can also send messages to the dialog box through SendMessage, controlling these aspects of that dialog box.

OK button enabled/disabled


Leider habe ich keine Idee, wie ich eine CallBack Prozedure realisieren kann :?: :?:

Gruß Jens.

----- oops, du warst schneller. OK, ich probiere das mal... ----


Zuletzt bearbeitet von Aton am Mi 16.06.04 21:32, insgesamt 1-mal bearbeitet
Christian S.
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 20451
Erhaltene Danke: 2264

Win 10
C# (VS 2019)
BeitragVerfasst: Mi 16.06.04 21:31 
@Aton: Wird doch in dem FAQ-Beitrag schon verwendet!

_________________
Zwei Worte werden Dir im Leben viele Türen öffnen - "ziehen" und "drücken".
Aton Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 125

Windows XP
D7 Enterprise
BeitragVerfasst: Mi 16.06.04 21:42 
Hallo,

ich habe folgendes in den CallBack-Procedure eingebaut:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
  if uMsg = BFFM_SELCHANGED then
  begin
    // Wie komme ich an den aktuellen Ordner ran???
    SendMessage(theHandle, BFFM_ENABLEOK, 00);  // 0: disabled, 1: enabled
  end;


Woher bekomme ich nun den aktuell gesetzten Ordner als String?
Danke, Gruß Jens.
Christian S.
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 20451
Erhaltene Danke: 2264

Win 10
C# (VS 2019)
BeitragVerfasst: Mi 16.06.04 21:46 
Hallo!

Im Link zum MSDN steht auch etwas darüber. Dort sind nämlich die lParams für die Botschaften aufgelistet. BFFM_SELCHANGE liefert Dir den ausgewählten Ordner im lParam in der Form einer IDList. Wie man die verwurstet, bis dann den Ordner hat, steht auch in dem FAQ-Beitrag.

Stichwort: "SHGetPathFromIDList"

MfG
Peter

_________________
Zwei Worte werden Dir im Leben viele Türen öffnen - "ziehen" und "drücken".
Aton Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 125

Windows XP
D7 Enterprise
BeitragVerfasst: Mi 16.06.04 21:50 
Danke soweit,
mache morgen weiter.

Nicht verraten, wie!
So lernt man am meisten :wink:

Gruß Jens.
Christian S.
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 20451
Erhaltene Danke: 2264

Win 10
C# (VS 2019)
BeitragVerfasst: Mi 16.06.04 22:03 
Aton hat folgendes geschrieben:
Nicht verraten, wie!
So lernt man am meisten :wink:
Super! Eine solche Einstellung lobe ich mir! :-)

_________________
Zwei Worte werden Dir im Leben viele Türen öffnen - "ziehen" und "drücken".
Aton Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 125

Windows XP
D7 Enterprise
BeitragVerfasst: Mi 16.06.04 22:42 
Fett!!!
Es klappt.

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
var Path: Array [0..MAX_PATH+1Of Char;
    sFilter: String;
    sr: TSearchRec;

...

  if uMsg = BFFM_SELCHANGED then
  begin
    SHGetPathFromIDList(PItemIDList(lParam), Path);
    sFilter:= String(Path)+ '\*.dat';
    if FindFirst(sFilter, faAnyFile, sr)= 0  then
      SendMessage(theHandle, BFFM_ENABLEOK, 01)
    else
      SendMessage(theHandle, BFFM_ENABLEOK, 00);
    FindClose(sr);
  end;


Fettes Danke.
Gruß Jens. :lol:
Aton Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 125

Windows XP
D7 Enterprise
BeitragVerfasst: Do 17.06.04 08:21 
Hallo nochmal,

ich wollte jetzt mal eine Eigenschaft Filter in die Klasse einfügen, um das universell nutzbar zu machen, bin aber auf folgendes Problem gestossen:

1. von FolderCallBack aus komme ich nicht an
sFilter:= String(Path)+ '\'+ FFilter;

2. wenn ich FolderCallBack in die Klasse aufnehme, komme ich zwar
an FFilter ran, bekomme aber hier einen Fehler:
lpfn := @FolderCallBack; --> Variable erforderlich

3. wenn ich schreibe lpfn := @TFolderBrowser.FolderCallBack; übersetzt
der Compiler es zwar, aber es kommt während der Laufzeit zu einem
Zugriffsfehler.

Jetzt weiß ich nicht weiter?? :shock:

ausblenden Delphi-Quelltext
1:
//..					


--> Edit: Alten Sourcecode entfernt.


Zuletzt bearbeitet von Aton am Do 17.06.04 12:59, insgesamt 1-mal bearbeitet
smiegel
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 992
Erhaltene Danke: 1

WIN 7
D7 Prof., C#, RAD XE Prof.
BeitragVerfasst: Do 17.06.04 08:51 
Hallo,

die Callback des BrowseDialogs darf nicht Bestandteil einer Objektdeklaration bzw. darf keine Objektmethode sein.

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
...
TFolderBrowser = class 
...
public 
...
// die hat hier nichts zu suchen
// function FolderCallBack(theHandle: HWND; uMsg: UINT; lParam: lParam; lpData : lParam): lresult; stdcall;
end;
...
...
implementation 
// statt
//function TFolderBrowser.FolderCallBack (theHandle: HWND; uMsg: UINT; lParam: lParam; lpData : lParam): lresult; stdcall;
function FolderCallBack (theHandle: HWND; uMsg: UINT; lParam: lParam; lpData : lParam): lresult; stdcall;
...


...
function TFolderBrowser.execute: Boolean; 
  ...
  lpfn:=@FolderCallBack; 
  ...
end;

_________________
Gruß Smiegel
Ich weiß, daß ich nichts weiß, aber ich weiß mehr als die, die nicht wissen, daß sie nichts wissen. (Sokrates)
Aton Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 125

Windows XP
D7 Enterprise
BeitragVerfasst: Do 17.06.04 09:08 
Hallo smiegel,

alles klar. Und wie kann ich dann von meiner Funktion FolderCallBack auf die Eigenschaft FFilter meiner Klasse TFolderBrowser zugreifen??

Ich muss doch in FolderCallBack FindFirst mit dem jeweiligen Filter aufrufen.

Gruß Jens.
MathiasSimmack
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Do 17.06.04 09:27 
Aton hat folgendes geschrieben:
Jetzt weiß ich nicht weiter?? :shock:

Ich schon. ;)

Die einfachste Variante ist, dass du a) "FolderCallback" aus der Klasse herausnimmst und wie ursprünglich als interne Funktion verwendest. Damit du dann aber Zugriff auf den Filter hast, benutzt du eine Unit-interne globale Variable, die du vor dem Aufruf des Dialogs entsprechend setzt. Voilà.

Für nonVCL-Fans ist sicher noch die Methode ohne "SysUtils"-Unit interessant. So gesehen kannst du auch deine Prüffunktion etwas optimieren.

Edit: Quellcode entfernt, weil inzwischen integriert.


Zuletzt bearbeitet von MathiasSimmack am Do 17.06.04 11:46, insgesamt 1-mal bearbeitet
Aton Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 125

Windows XP
D7 Enterprise
BeitragVerfasst: Do 17.06.04 10:13 
Danke für die Tipps,

jetzt läuft es. Übrigens, ohne ZeroMemory gehts auch. Ich habe es aber sicherheitshalber drin gelassen:

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
unit fldbrows;

{ +-------------------------------------------------------------------------+ }
{ |                                                                         | }
{ |  Klasse zum Öffnen von Ordnern                                          | }
{ |  Quelle: http://www.delphi-forum.de/viewtopic.php?t=25302               | }
{ |  erweitert mit Filter...                                                | }
{ |  Autoren: halbes Delphi-Forum                                           | }
{ |           (Peter Lustig, MathiasSimmack, Tino, Lucki, ...)              | }
{ |                                                                         | }
{ +-------------------------------------------------------------------------+ }

interface

uses
  ShlObj, ActiveX, Windows;

type
  TFolderBrowser = class
  private
    // Luckie
    // alles private gemacht, geht niemanden was an da nachträglicher Zugriff
    // sinnlos
    FHandle: THandle;
    FCaption: string;
    FShowFiles: Boolean;
    FNewFolder: Boolean;
    FInitFolder: string;
    FSelected: string;
    FFilter: String;
  public
    // im Konstruktor gleich alles initialisieren (ist geschmackssache)
    constructor create(Handle: THandle; const Caption: stringconst InitFolder: string = '';
      ShowFiles: Boolean = False; NewFolder: Boolean = False);
    function execute: Boolean;
    property Filter: String read FFilter write FFilter;
    property SelFolder: string read FSelected;
  end;

implementation

var szCallbackFilter: String'';

function FileExists(const szFilename: string): boolean;
var
  Handle   : THandle;
  FindData : TWin32FindData;
begin
  Handle := FindFirstFile(pchar(szFilename),FindData);
  Result := (Handle <> INVALID_HANDLE_VALUE);
  if(Result) then Windows.FindClose(Handle);
end;

function FolderCallBack (theHandle: HWND; uMsg: UINT; lParam: lParam; lpData : lParam): lresult; stdcall;
var Path: Array [0..MAX_PATH+1Of Char;
begin
  //Dialog wurde initialisiert
  if uMsg = BFFM_INITIALIZED then
    //Ordner auswählen
    SendMessage(theHandle, BFFM_SETSELECTION, Ord(TRUE), lpData);
  if uMsg = BFFM_SELCHANGED then
  begin
    if (szCallbackFilter<> ''then
    begin
      ZeroMemory(@path,sizeof(path));
      SHGetPathFromIDList(PItemIDList(lParam), Path);
      SendMessage(theHandle, BFFM_ENABLEOK, 0,
                  Integer(FileExists(string(path) + '\' + szCallbackFilter)));
    end;
  end;
  result := 0//von Luckie hinzugefügt, hatte ich vergessen (oops)
end;

 
constructor TFolderBrowser.create(Handle: THandle; const Caption: stringconst InitFolder: string
  = ''; ShowFiles: Boolean = False; NewFolder: Boolean = False);
begin
  FHandle := Handle;
  FCaption := Caption;
  FInitFolder := InitFolder;
  FShowFiles := ShowFiles;
  FNewFolder := NewFolder;
  FFilter:= '';
end;


//Original:        Tino in den Delphi-Forum FAQs
//Modifiziert von: Christian "Peter Lustig" Stelzmann
// Luckie: Bug ("neuer Ordner" wird immer angezeigt) gefixed
function TFolderBrowser.execute: Boolean;
    Procedure FreeItemIDList (Var aPIdL: pItemIDList);
    Var
      ppMalloc: iMalloc;
    Begin
      SHGetMalloc (ppMalloc);
      ppMalloc.Free (aPIdL);
      aPIdL := nil;
      ppMalloc := nil;
    End;


const
  BIF_NEWDIALOGSTYLE = $40;
  BIF_NONEWFOLDERBUTTON = $200;

Var  
  BrowseInfo: TBrowseInfo;
  pidlResult: PItemIDList;  
  DisplayName,  
  Path: Array [0..MAX_PATH+1Of Char;
begin
  // BrowseInfo mit Werten füllen
  FillChar (BrowseInfo, SizeOf (BrowseInfo), 0);
  CoInitialize(nil);
  With BrowseInfo Do
  Begin
    hwndOwner := 0;  
    pszDisplayName := @DisplayName;
    lpszTitle := PChar (Fcaption) ;

    //Callback-Funktion zur Auswahl des Startverzeichnisses verwenden und ...
    lpfn := @FolderCallBack;
    //... das entsprechende Verzeichnis als lParam verwenden.
    lParam := Integer(Pchar(FinitFolder));


   // Luckie - BIF_USENEWUI sorgt dafür dass besagter Button immer angezeigt wird,
   //          egal, ob BIF_BROWSEINCLUDEFILES gesetzt wird oder nicht, daher rausgenommen
   if FShowFiles then
      ulFlags := ulFlags or BIF_BROWSEINCLUDEFILES;


    //Button zum Erstellen neuer Ordner anzeigen?  
    // Luckie - ergänzt / geändert
    // PL - nochmals geändert  
    if FNewFolder then
      ulFlags := ulFlags or BIF_NEWDIALOGSTYLE  
    else
      ulFlags := ulFlags or BIF_NONEWFOLDERBUTTON;  
  End;

  { weil ich von FolderCallBack nicht auf FFilter zugreifen kann ... }
  szCallbackFilter:= FFilter;

  // Dialog aufrufen
  pidlResult := SHBrowseForFolder (BrowseInfo);
  // Prüfen ob ein Verzeichnis ausgewählt wurde
  If pidlResult <> nil Then
  Begin
    SHGetPathFromIDList (pidlResult, Path);
    FSelected := Path;
    FreeItemIDList (pidlResult);

    Result := True;
  End Else Result := False;
end;

end.


Aufruf:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
  bff:= TFolderBrowser.Create(Handle, 'TurboDB Datenbank Ordner:',
                              EVerzeichnis.Text, False, False);
  bff.Filter:= '*.dat';                            
  try
    if bff.Execute then
      EVerzeichnis.Text:= bff.SelFolder;
  finally
    FreeAndNil(bff);
  end;


Für Anregungen bin ich immer offen.
Gruß Jens.
MathiasSimmack
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Do 17.06.04 10:23 
Okay, hier sind Anregungen:
  1. Versuche einen eigenen Stil in deinem Quellcode zu benutzen. Im Moment merkt man sehr deutlich, dass du dir die Teile ... äh ... na, sagen wir mal: zusammengesucht hast. ;) Das ist erkennbar an der oft unterschiedlichen Schreibweise von Schlüsselworten, usw.
  2. Versuche den rechten Rand des Quellcode-Editors zu respektieren. Soll heißen: Überschreite diesen Rand nach Möglichkeit nicht. Das hat positive Auswirkungen auf jeden Ausdruck und auch auf das Forum hier, weil man dann nicht seitwärts scrollen muss. (Sorry, aber ich bin immer noch mit 1025x768 unterwegs.)
  3. Biete noch ein paar Flags an, die man über Properties einstellen kann.
  4. Und zu guter Letzt: Schreib eine überladene (overload) Version von "Execute", bei der man den Root-Ordner wählen kann. Im Normalfall siehst du ja den Desktop als Root im Dialog. Aber mit "BrowseInfo.pidlRoot" kannst du auch einen anderen Ordner einstellen.
    Beachten musst du dabei allerdings, dass dies eine PItemIdList-Variable ist. Bei speziellen Ordnern (Startmenü, Netzwerkumgebung, usw.) kannst du mit "SHGetSpecialFolderLocation" an die entsprechende ID herankommen. Für normale Ordner könnte ich dir eine Funktion zur Verfügung stellen, die ich mal im Netz gefunden habe.
Christian S.
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 20451
Erhaltene Danke: 2264

Win 10
C# (VS 2019)
BeitragVerfasst: Do 17.06.04 10:35 
Globale Variablen kann ja jeder! :-) Aber die sollte man vermeiden. Daher würde ich folgendes vorschlagen:
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
type
  TFolderBrowser = class
  private
    // Luckie
    // alles private gemacht, geht niemanden was an da nachträglicher Zugriff
    // sinnlos
    FHandle: THandle;
    FCaption: string;
    FShowFiles: Boolean;
    FNewFolder: Boolean;
    FInitFolder: string;
    FSelected: string;
    //Added by Aton --->
    FFilter: String;
    //<----
  public
    // im Konstruktor gleich alles initialisieren (ist geschmackssache)
    constructor create(Handle: THandle; const Caption: stringconst InitFolder: string = '';
      ShowFiles: Boolean = False; NewFolder: Boolean = False);
    function execute: Boolean;
    //Added by Aton --->
    property Filter: String read FFilter write FFilter;
    //<----
    property SelFolder: string read FSelected;
  end;

implementation


//by MathiasSimmack --->
function FileExists(const szFilename: string): boolean;
var
  Handle   : THandle;
  FindData : TWin32FindData;
begin
  Handle := FindFirstFile(pchar(szFilename),FindData);
  Result := (Handle <> INVALID_HANDLE_VALUE);
  if(Result) then Windows.FindClose(Handle);
end;
//<---


function FolderCallBack (theHandle: HWND; uMsg: UINT; lParam: lParam; lpData : lParam): lresult; stdcall;
var Path: Array [0..MAX_PATH+1Of Char;
    fb : TFolderBrowser;
    initFolder : PChar;
    szCallbackFilter : String;
begin
//  initFolder :=
  fb := TFolderBrowser(lpData);

  szCallbackFilter := fb.FFilter;
  initFolder := PChar(fb.FInitFolder);

  //Dialog wurde initialisiert
  if uMsg = BFFM_INITIALIZED then
    //Ordner auswählen
    SendMessage(theHandle, BFFM_SETSELECTION, Ord(TRUE), lpData);

  //Added by Aton ---->
  if uMsg = BFFM_SELCHANGED then
  begin
    if (szCallbackFilter<> ''then
    begin
      ZeroMemory(@path,sizeof(path));
      SHGetPathFromIDList(PItemIDList(lParam), Path);
      SendMessage(theHandle, BFFM_ENABLEOK, 0,
                  Integer(FileExists(string(path) + '\' + szCallbackFilter)));
    end;
  end;
  //<-----

  result := 0//von Luckie hinzugefügt, hatte ich vergessen (oops)
end;


constructor TFolderBrowser.create(Handle: THandle; const Caption: stringconst InitFolder: string
  = ''; ShowFiles: Boolean = False; NewFolder: Boolean = False);
begin
  FHandle := Handle;
  FCaption := Caption;
  FInitFolder := InitFolder;
  FShowFiles := ShowFiles;
  FNewFolder := NewFolder;
  FFilter:= '';
end;


//Original:        Tino in den Delphi-Forum FAQs
//Modifiziert von: Christian "Peter Lustig" Stelzmann
// Luckie: Bug ("neuer Ordner" wird immer angezeigt) gefixed
function TFolderBrowser.execute: Boolean;
    Procedure FreeItemIDList (Var aPIdL: pItemIDList);
    Var
      ppMalloc: iMalloc;
    Begin
      SHGetMalloc (ppMalloc);
      ppMalloc.Free (aPIdL);
      aPIdL := nil;
      ppMalloc := nil;
    End;


const
  BIF_NEWDIALOGSTYLE = $40;
  BIF_NONEWFOLDERBUTTON = $200;

Var  
  BrowseInfo: TBrowseInfo;
  pidlResult: PItemIDList;
  DisplayName,  
  Path: Array [0..MAX_PATH+1Of Char;
begin
  // BrowseInfo mit Werten füllen
  FillChar (BrowseInfo, SizeOf (BrowseInfo), 0);
  CoInitialize(nil);
  With BrowseInfo Do
  Begin
    hwndOwner := 0;
    pszDisplayName := @DisplayName;
    lpszTitle := PChar (Fcaption) ;

    //Callback-Funktion zur Auswahl des Startverzeichnisses verwenden und ...
    lpfn := @FolderCallBack;
    //... sich selbst als Parameter übergeben, damit auf alle Eigenschaften zugegriffen
    //werden kann
    lParam := Integer(self);


   // Luckie - BIF_USENEWUI sorgt dafür dass besagter Button immer angezeigt wird,
   //          egal, ob BIF_BROWSEINCLUDEFILES gesetzt wird oder nicht, daher rausgenommen
   if FShowFiles then
      ulFlags := ulFlags or BIF_BROWSEINCLUDEFILES;


    //Button zum Erstellen neuer Ordner anzeigen?
    // Luckie - ergänzt / geändert
    // PL - nochmals geändert
    if FNewFolder then
      ulFlags := ulFlags or BIF_NEWDIALOGSTYLE
    else
      ulFlags := ulFlags or BIF_NONEWFOLDERBUTTON;
  End;

  // Dialog aufrufen
  pidlResult := SHBrowseForFolder (BrowseInfo);
  // Prüfen ob ein Verzeichnis ausgewählt wurde
  If pidlResult <> nil Then
  Begin
    SHGetPathFromIDList (pidlResult, Path);
    FSelected := Path;
    FreeItemIDList (pidlResult);

    Result := True;
  End Else Result := False;
end;


Auf diese Weise kannst Du Dein gesamtes Objekt mit allen Eigenschaften benutzen!

MfG
Peter

//edit: Ach ja, die Funktion FileExists solltest Du noch als class funtion in den TFolderBrowser packen, dann hast Du die auch schon mal in dem Objekt, welches sie verwendet.

_________________
Zwei Worte werden Dir im Leben viele Türen öffnen - "ziehen" und "drücken".


Zuletzt bearbeitet von Christian S. am Do 17.06.04 13:23, insgesamt 2-mal bearbeitet
MathiasSimmack
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Do 17.06.04 11:18 
Peter Lustig hat folgendes geschrieben:
//edit: Ach ja, die Funktion FileExists solltest Du noch als class funtion in den TFolderBrowser packen, dann hast Du die auch schon mal in dem Objekt, welches sie verwendet.

Wozu? Gebraucht wird sie nur Unit-intern, und da spielt es keine Rolle ob sie Teil der Klasse ist oder nicht. Aber egal -

Als weitere Anregung: Unterstütze mehr Filter, indem du sie durch #0 voneinander trennst. Dadurch brauchst du dich dann nicht mit Stringlisten oder dynamischen Stringarrays herumschlagen, und das Prinzip entspricht den API-Dialogen Speichern/Öffnen. Dafür brauchst du dann aber idealerweise eine eigene Funktion, die die Filter überprüft:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
function CheckFilter(const szPath, szFilter: string): boolean;
var
  p      : pchar;
begin
  Result := false;
  if(szPath = ''or (szFilter = ''then exit;

  // zur Sicherheit zwei #0-Zeichen anhängen, damit das Ende
  // des Strings in jedem Fall richtig erkannt wird
  p      := pchar(szFilter + #0#0);
  while(p[0] <> #0do
  begin
    if(fileexists(szPath + '\' + p)) then
    begin
      Result := true;
      break;
    end;

    // und zum nächsten Filter
    inc(p,lstrlen(p) + 1);
  end;
end;

Die musst du dann anstelle der "fileexist" in der Prüfung unterbringen. Aber dafür könnte der Filter hinterher so aussehen:
ausblenden Delphi-Quelltext
1:
bf.Filter := '*.txt'#0'*.*htm*'#0'*.xml';					

und der OK-Button würde bei TXT-, HTM/HTML/SHTML- (und diverse andere Varianten mit HTM im Namen) und bei XML-Dateien freigegeben werden.
MathiasSimmack
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Do 17.06.04 11:26 
Oh, eine kleine Wanze ist da noch drin, @Pjotr:
Peter Lustig hat folgendes geschrieben:
ausblenden Delphi-Quelltext
1:
2:
3:
  if uMsg = BFFM_INITIALIZED then
    //Ordner auswählen
    SendMessage(theHandle, BFFM_SETSELECTION, Ord(TRUE), lpData);

weil "lpData" nun ja den kompletten TFolderBrowser enthält. ;) Auf die Strings könntest du übrigens bei der Idee verzichten. Wenn du das Objekt selbst schon hast, dann kannst du auch gleich auf die entsprechenden Properties zugreifen.
Christian S.
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 20451
Erhaltene Danke: 2264

Win 10
C# (VS 2019)
BeitragVerfasst: Do 17.06.04 11:26 
MathiasSimmack hat folgendes geschrieben:
Peter Lustig hat folgendes geschrieben:
//edit: Ach ja, die Funktion FileExists solltest Du noch als class funtion in den TFolderBrowser packen, dann hast Du die auch schon mal in dem Objekt, welches sie verwendet.

Wozu? Gebraucht wird sie nur Unit-intern, und da spielt es keine Rolle ob sie Teil der Klasse ist oder nicht. Aber egal -


Es bringt ansich keine weiteren Änderungen mitsich, ist aber von der Struktur her logischer. Man hat alles, was zu der Klasse gehört, auch in ihr drin. (Soweit das eben geht, bei der CallBack-Funktion geht es halt nicht.)

_________________
Zwei Worte werden Dir im Leben viele Türen öffnen - "ziehen" und "drücken".
MathiasSimmack
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Do 17.06.04 11:44 
Peter Lustig hat folgendes geschrieben:
Es bringt ansich keine weiteren Änderungen mitsich, ist aber von der Struktur her logischer.

Es mag evtl. von der Struktur logischer sein, nicht aber von der Anwendung (im Sinne von Gebrauch/Benutzung). Du brauchst "fileexists" doch nur Klassen-intern zum Prüfen ob es eine Datei mit dem gewünschten Filter gibt.
Eine andere Aufgabe erfüllt diese Funktion nicht. Daher spielt sie auch außerhalb der Klasse keine Rolle. Wenn es denn sein muss, dann kann man sie als private Funktion deklarieren. Das wäre noch logisch, denn zum Prüfen ob irgendwelche Dateien existieren, hat man sicher eine Toolbox (nonVCL) bzw. die "SysUtils" (standardmäßig bei VCL-Apps eingebunden).

Evtl. sehe ich das aber auch unter dem Blickpunkt, dass eine Unit nicht zwangsläufig nur eine Klasse enthalten muss. Es wäre ja denkbar, dass du noch eine zweite Klasse mit einer passenden ähnlichen Aufgabe wie "TFolderBrowser" hast, die selbst auch "fileexists" benötigt. In dem Fall wäre es IMHO effizienter, solche kleinen Hilfsroutinen Unit- aber eben nicht Klassen-bezogen zu schreiben.

Wobei es in meinem Fall sogar so ist, dass ich meine "Toolbox" (SysUtils.inc) einfach einbinde. Wenn ich etwas ergänze oder erweitere, dann wirkt sich das natürlich auch gleich auf die Unit auf, und ich muss nicht ggf. alle Klassenunits absuchen um evtl. Fehler zu beheben. ;)


btw: @Aton, wäre es möglich, dass du ein paar deiner alten Quellcodes wieder entfernst? Dann würde der Beitrag schneller laden. Eine aktuelle Version deiner Unit reicht ja IMHO auch. Danke.