AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein GUI-Design mit VCL / FireMonkey / Common Controls Fensterposition von TOpenDialog und TSaveDialog - Lösung
Thema durchsuchen
Ansicht
Themen-Optionen

Fensterposition von TOpenDialog und TSaveDialog - Lösung

Ein Thema von awk · begonnen am 28. Feb 2017 · letzter Beitrag vom 28. Feb 2017
 
awk

Registriert seit: 12. Sep 2007
3 Beiträge
 
#1

Fensterposition von TOpenDialog und TSaveDialog - Lösung

  Alt 28. Feb 2017, 19:22
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.
  Mit Zitat antworten Zitat
 


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 10:55 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz