Hallo liebe Delphianer,
da ich selbst eine ganze Weile gebraucht habe eine Lösung zu o.g. Thema zu finden, möchte ich euch an meiner nun teilhaben lassen. Das Problem ist bekannt:
Ein TOpenDialog bzw. TSaveDialog läßt sich nicht positionieren und erscheint z.T. meilenweit entfernt von der aufrufenden Applikation. Das Event OnShow, das zunächst für diesen Zweck als hilfreich erscheint, liefert keine Möglichkeit die Position und Größe des Dialogs zu beeinflussen. Es fehlen einfach die entsprechenden Objekteigenschaften.
Nach langen (erfolglosen) Recherchen bin ich nun auf eine Idee gekommen, die die Positionierung nicht über das Fenster-
Handle, also SetWindowPos(...) macht. Dies ist nämlich zum Scheitern verurteilt, weil Windows die jeweils letzte Position und Größe in der Registry je Applikation speichert und diese, nach dem Zeitpunkt zu dem das OnShow-Event aufgerufen wird wiederherstellt. Alle Versuche mit SetWindowPos und Co. sind daher zum Scheitern verurteilt.
Die Lösung für das Problem lautet: Direkt nach TOpenDialog.Create setzen wir den entsprechenden Registry-Wert so wie wir es wünschen.
Folgende Procedure stellt einen TOpenDialog und TSaveDialog immer zentriert über das Application.MainForm, der Parameter "nVersatz" bestimmt, um wie viele Pixel das Fenster an jeder Ecke Kleiner sein soll, als das Application.MainForm:
Delphi-Quellcode:
uses Registry,Classes,Forms;
procedure SetRegPos(nVersatz: integer);
var reg: TRegistry;
buffer: pByteArray;
buflen: integer;
fn: WideString;
p,s,e: PWideChar;
appname: string;
tmplen: integer;
aValues: tstringlist;
n: integer;
r: TRect;
// little endian
procedure setInt(nValue,nOffset,nLen: integer);
var i,calcValue: integer;
nByte: byte;
begin
calcValue:=nValue;
for i:=0 to nLen-1 do
begin
nByte:=calcValue and 255;
buffer[nOffset+i]:=nByte;
calcValue:=calcValue shr 8;
end;
end;
begin
reg:=TRegistry.Create;
try
reg.RootKey:= HKEY_CURRENT_USER;
if not reg.OpenKey('Software\Microsoft\Windows\CurrentVersion\Explorer\ComDlg32\CIDSizeMRU',False) then exit;
aValues:=tstringlist.create;
reg.GetValueNames(aValues);
for n:=0 to aValues.count-1 do
begin
buflen:=reg.GetDataSize(aValues.strings[n]);
if buflen>0 then
begin
GetMem(buffer,buflen);
try
reg.ReadBinaryData(aValues.strings[n],pByte(buffer)^,buflen);
s:=PWideChar(buffer);
p:=s;
e:=s+buflen;
tmplen:=0;
while p<=e do
begin
if p^=#0 then
begin
tmplen:=(p-s);
Break;
end;
inc(p);
end;
if tmplen>0 then
begin
SetLength(fn,tmplen);
copymemory(@fn[1],s,tmplen*SizeOf(WideChar));
end;
appname:=WideCharToString(@fn[1]);
if appname=ExtractFilename(Application.Exename) then
begin
// Koordinaten unseres MainForms
r:=Rect(application.MainForm.Left,application.MainForm.Top,
application.MainForm.Left+application.MainForm.Width,application.MainForm.Top+application.MainForm.Height);
// jetzt Koordinaten des Dialogs setzen
// Left-X
setInt(r.Left+nVersatz,$218,4);
// Left-Y
setInt(r.Top+nVersatz,$218+4,4);
// Bottom-X
setInt(r.Right-nVersatz,$220,4);
// Bottom-Y
setInt(r.Bottom-nVersatz,$220+4,4);
reg.WriteBinaryData(aValues.strings[n],pByte(buffer)^,buflen);
break;
end;
finally
FreeMem(buffer,buflen);
end;
end;
end;
reg.CloseKey;
finally
aValues.Free;
reg.free;
end;
Aufgerufen wird die Procedure beispielhaft dann wie folgt:
Delphi-Quellcode:
with TOpenDialog.Create(Application) do
try
SetRegPos(80); // an allen Ecken 80 Pixel kleiner als das MainForm
DefaultExt := GetControlPanel.DefaultExt;
Filter := FilterString;
Options := [ofHideReadOnly, ofPathMustExist, ofFileMustExist, ofEnableSizing];
undsoweiter...
Hoffe das erspart einigen unter Euch das stundenlange Suchen nach einer entsprechenden Lösung.
Anzumerken wäre noch, daß beim ersten Aufruf eines solchen Dialogs noch keine Wirkung zu sehen ist - der Dialog wird auf Monitor 0 zentriert dargestellt, weil es ja noch keinen Registry-Eintrag gibt. Dies könnte man natürlich noch ergänzen. Für mich ist dies momentan nur ein Schönheitsfehler.
PS: Einen Teil des Codes habe ich von einer chinesischen Seite deren
URL ich leider nicht gespeichert habe und dessen Autor vermutlich in chinesischer Schrift genannt war. Dort wurde ein Beitrag zur MRU-Verwaltung mit der Funktion "GetLastVisitedMRU" gelistet. Einen Dank an den unbekannten chinesischen Autor.