AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Win32/Win64 API (native code) TFileOpenDialog öffnet immer auf MainMonitor
Thema durchsuchen
Ansicht
Themen-Optionen

TFileOpenDialog öffnet immer auf MainMonitor

Ein Thema von user69 · begonnen am 7. Sep 2020 · letzter Beitrag vom 9. Sep 2020
Antwort Antwort
Seite 1 von 2  1 2      
user69

Registriert seit: 11. Dez 2004
114 Beiträge
 
#1

TFileOpenDialog öffnet immer auf MainMonitor

  Alt 7. Sep 2020, 22:50
Hallo,

hat jemand eine Idee, wie ich den TFileOpenDialog bei PerMonitorDPIV2 immer auf dem Monitor meiner App öffne?
Bei mir öffnet der immer auf dem MainMonitor, egal ob er zuvor beim letzten Öffnen auf den Zweitmonitor verschoben wurde oder meine App auf dem Zweitmonitor ist.
Ergänzung: Dies passiert so, wenn die DPI des Monitore verschieden sind. Bei gleicher DPI öffnet der Dialog immer dort wo er zuvor geschlossen wurde (also auch nicht immer auf dem Moitor meiner App).
Dies ist besonders ärgerlich wenn meine App auf dem Zweitmonitor ist und das TFileOpenDialog Fenster einfach auf dem Hauptbildschirm aufgeht, wo man es nicht erwartet.

Ich weiß das Windows das automatisch speichert, aber Apps wie Chrome und Notepad funktionieren da ok, obwohl die auch PerMonitorDPIV2 sind.
In [HKEY_CURRENT_USER\Software\Microsoft\Windows\Curre ntVersion\Explorer\ComDlg32\CIDSizeMRU] sind die Positionen binär gespeichert, aber wie die kodiert sind ist mir unklar und eine Manipulation daran finde ich recht gewagt.
BTW: Ich nutze Delphi Sydney.

Hier finde ich die Windows Intelligenz nicht sinnvoll. Notepad macht es hier recht gut. Die Öffnen den Dialog immer relativ zur App (oder verschieben ihn, wenn er nicht auf den Bildschirm passt).

Ich hoffe ihr könnt mir da helfen.

Geändert von user69 ( 7. Sep 2020 um 23:21 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.184 Beiträge
 
Delphi 12 Athens
 
#2

AW: TFileOpenDialog öffnet immer auf MainMonitor

  Alt 7. Sep 2020, 23:47
Hast du mal versucht deinem Dialog eine GUID zu geben?
$2B or not $2B
  Mit Zitat antworten Zitat
user69

Registriert seit: 11. Dez 2004
114 Beiträge
 
#3

AW: TFileOpenDialog öffnet immer auf MainMonitor

  Alt 8. Sep 2020, 00:31
Ja, das ändert nichts an dem beschriebenen Verhalten.
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.184 Beiträge
 
Delphi 12 Athens
 
#4

AW: TFileOpenDialog öffnet immer auf MainMonitor

  Alt 8. Sep 2020, 04:17
Dann fallen mir nur noch die Kompatibilitätsmodi ein.
Ohne Kennzeichnung geht Windows davon aus, dein Programm ist alt, bzw. total unfähig, und macht dann blöde Dinge.

supportedOS
dpiAware
dpiAwareness per Monitor
usw.

https://docs.microsoft.com/en-us/win...-for-a-process
https://docs.microsoft.com/en-us/win...tion-manifests
$2B or not $2B
  Mit Zitat antworten Zitat
Alt 8. Sep 2020, 06:46     Erstellt von rohit1491
Dieser Beitrag wurde von TBx gelöscht. - Grund: Verdacht auf SPAM und den damit verbundenen verschwenderischen Umgang von wertvollen Bits und Bytes
Benutzerbild von Dalai
Dalai

Registriert seit: 9. Apr 2006
1.682 Beiträge
 
Delphi 5 Professional
 
#5

AW: TFileOpenDialog öffnet immer auf MainMonitor

  Alt 8. Sep 2020, 10:18
Wird denn das richtige Manifest verwendet (also steht wirklich die erwartete PerMonitorDPIV2 im richtigen Abschnitt/Tag), und ist das Manifest syntaktisch korrekt?

Grüße
Dalai
  Mit Zitat antworten Zitat
user69

Registriert seit: 11. Dez 2004
114 Beiträge
 
#6

AW: TFileOpenDialog öffnet immer auf MainMonitor

  Alt 8. Sep 2020, 10:46
Mein Manifest sollte auch ok sein.
Alternativ hab ich das Delphi Standard Manifest für MonitorDPIV2 verwendet => Keine Änderung.

Ich habe mal ein Demo angehängt (mit Source):
Einfach die Form nach dem Start auf einen Zweitmonitor (mit unterschiedlicher DPI Skalierung) schieben und "FileOpen" klicken.
Der Dialog geht immer auf dem Hauptmonitor auf.
Angehängte Dateien
Dateityp: zip _FileOpenDialogIssue.zip (1,35 MB, 6x aufgerufen)
  Mit Zitat antworten Zitat
Benutzerbild von KodeZwerg
KodeZwerg

Registriert seit: 1. Feb 2018
3.691 Beiträge
 
Delphi 11 Alexandria
 
#7

AW: TFileOpenDialog öffnet immer auf MainMonitor

  Alt 8. Sep 2020, 12:22
Warum nicht einfach die Position vom Formular auslesen und den Dialog "dahinführen" ?
Wie ich neulich gelernt habe gibts ja das Screen und das Desktop für x/y angaben mit den man wunderbar rumspielen kann.
Ich lade mal Projekt und passe es an wie beschrieben, vielleicht ist es ja genau das was Du wolltest.
Gruß vom KodeZwerg
  Mit Zitat antworten Zitat
user69

Registriert seit: 11. Dez 2004
114 Beiträge
 
#8

AW: TFileOpenDialog öffnet immer auf MainMonitor

  Alt 8. Sep 2020, 12:46
Ja, das wäre, was ich will.
Aber den Dialog zu verschieben ist tricky und mir bisher nicht optimal gelungen.
  Mit Zitat antworten Zitat
Benutzerbild von KodeZwerg
KodeZwerg

Registriert seit: 1. Feb 2018
3.691 Beiträge
 
Delphi 11 Alexandria
 
#9

AW: TFileOpenDialog öffnet immer auf MainMonitor

  Alt 9. Sep 2020, 08:32
Ich habe Dein Projekt "repariert".
Im Anhang ist Projekt Quelltext plus Kompilat zum sofort Testen, bei mir klappt es mit allen vier Knöpfe das der Dialog sich auf das Aufrufer-Formular legt.

3 x standard methoden, ich musste lediglich dem Execute() noch ein Handle mitgeben, schon war das Ziel erreicht.
Das war mir noch nicht genug, also forstete ich in meiner Sammlung nach brauchbaren und bin fündig geworden.
Ich war so frei TOpen-/SaveDialog zu intercepten, so das man nun auch X und Y koordinaten angeben kann.

Hier die Quelltexte falls der Anhang flöten geht:

Delphi-Quellcode:
unit TestForm;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Themes;

type
  TForm1 = class(TForm)
    FileOpenDialog1: TFileOpenDialog;
    Button1: TButton;
    Label1: TLabel;
    Button2: TButton;
    Label2: TLabel;
    Button3: TButton;
    Label3: TLabel;
    Label4: TLabel;
    Button4: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure Button4Click(Sender: TObject);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

(*
  Aufgabe: Dialog soll auf dem Formular plaziert sein.
  Lösung: Nutzung der Window-Handle im Execute() Aufruf.
  Notlösung: Nutzung einer frei wählbaren Position per x und y
  Alternativ: Auf passende Message reagieren?
              (evtl über WM_NOTIFY tiefer rein
              oder über WM_SHOWWINDOW eher global?
              dies sind nur vermutungen
              da die erste änderung bereits zum ziel führte.)
Bemerkungen: Alle varianten haben den gleichen Nachteil.
  Die positionierung funktioniert nur beim ersten Aufruf wie erwartet.
  Ab da an übernimmt BigBrother die automatik bis man das HauptFormular
  Fenster etwas verschiebt, dann geht das Spiel von vorne los.
*)


uses
// Winapi.CommDlg // for hacking into dialogs; bind and use this unit
  dlgPos // Positionierbarer Dialog rein-intercepted
  ;


// der hier benötigt eine handle angabe damit er sich gut dazu positionieren kann
procedure TForm1.Button1Click(Sender: TObject);
begin
// if FileOpenDialog1.Execute() then
  if FileOpenDialog1.Execute(Application.ActiveFormHandle) then
    Label1.Caption := FileOpenDialog1.FileName
    else
    Label1.Caption := 'canceled';
end;


(* Dynamisches Testen von Dialogen *)

// der hier erscheint immer gut positioniert bei mir ohne handle angabe
procedure TForm1.Button2Click(Sender: TObject);
var
  Dlg: TOpenDialog; // maintype probe
begin
  Dlg := TOpenDialog.Create(nil);
  // da Dein FileOpenDialog1 über keinerlei Grundeinstellungen verfügt
  // setze ich auch keine :-)
  // ansonsten hier so filter, folder, labels usw setzen
  // um letzendlich das hier machen zu dürfen:
  if Dlg.Execute() then
    Label2.Caption := Dlg.FileName
    else
    Label2.Caption := 'canceled';
  Dlg.Free;
end;


// der hier benötigt eine handle angabe damit er sich gut dazu positionieren kann
procedure TForm1.Button3Click(Sender: TObject);
var
  Dlg: TFileOpenDialog; // subtype testing
begin
  Dlg := TFileOpenDialog.Create(nil);
  if Dlg.Execute(Application.ActiveFormHandle) then
    Label3.Caption := Dlg.FileName
    else
    Label3.Caption := 'canceled';
  Dlg.Free;
end;


// dies hier arbeitet mit x und y
// und passt sich notfalls selbst an
procedure TForm1.Button4Click(Sender: TObject);
var
  Dlg: TOpenDialog;
begin
  Dlg := TOpenDialog.Create(Self);
  if Dlg.Execute((Left + (Width div 2)), (Top + (Height div 2))) then
    Label4.Caption := Dlg.FileName
    else
    Label4.Caption := 'canceled';
  Dlg.Free
end;

end.
Hier die Interceptor Unit:
Delphi-Quellcode:
unit dlgPos;

(*
Diese Unit erweitert den originalen TOpenDialog und TSaveDialog der Vcl.
Nun kann man auch X und Y Koordinaten im Execute() Aufruf verwenden.
Wer keinen Title setzt muss sich erstmal mit simplified English zufrieden geben.

Benutzung:
  Diese als letzte Unit einbinden und dynamisch einen Dialog erzeugen
  oder per Designer auf Form droppen und bei Ausführung halt die X/Y variante nutzen.
  Mit letzter Unit ist (falls überhaupt vorhanden) nach Unit Vcl.Dialogs gemeint.

Methodik:
  Diese Variante erzeugt einen Thread der wiederum auf ein Handle wartet.
  Sobald ein Handle vorliegt wird das Fenster vom Handle verschoben.

Beispiel dynamisch:
procedure TForm1.Button1Click(Sender: TObject);
var
  Dlg: TOpenDialog;
begin
  Dlg := TOpenDialog.Create(Self);
  if Dlg.Execute((Left + (Width div 2)), (Top + (Height div 2))) then
    Label1.Caption := Dlg.FileName
    else
    Label1.Caption := 'canceled';
  Dlg.Free
end;

Beispiel per Designer:
procedure TForm1.Button1Click(Sender: TObject);
begin
  if OpenDialog1.Execute((Left + (Width div 2)), (Top + (Height div 2))) then
    Label1.Caption := OpenDialog1.FileName
    else
    Label1.Caption := 'canceled';
  Dlg.Free
end;


gefunden auf stackoverflow.com
Autor und/oder Uploader: Peter Kapas
Lizenz: keine Angabe
Änderungen: code formatierung.
            methoden argumente sind nun const.
            umgeschrieben zu einer intercepted variante.
            bezeichner angepasst.

Kommentare und Änderungen von KodeZwerg.
*)


interface

uses
  Winapi.Windows, System.Classes, Vcl.Dialogs;

type
  TSetDialogPosition = class(TThread)
  private
    Title: string;
    XPos: Integer;
    YPos: Integer;
  protected
    procedure Execute; override;
  end;

  TOpenDialog = class(Vcl.Dialogs.TOpenDialog)
  private
    SDP: TSetDialogPosition;
  public
    function Execute(const X, Y: Integer): Boolean; overload;
  end;

  TSaveDialog = class(Vcl.Dialogs.TSaveDialog)
  private
    SDP: TSetDialogPosition;
  public
    function Execute(const X,Y: Integer): Boolean; overload;
  end;

implementation


// dieser thread wartet auf ein gefundenes handle.
// nach 5000 versuchen wird abgebrochen.
// wenn ein handle gefunden wurde,
// verschiebe das fenster.
// terminiere thread.
procedure TSetDialogPosition.Execute;
var
  hDlg: HWND; // handle des dialogs
  rDlg: TRect; // dimension des dialogs
  fuse: Integer; // endlos schleifen killer
begin
  hDlg := 0;
  fuse := 0;
  while ((hDlg = 0) and (fuse < 5000)) do
    begin
      hDlg := FindWindow(nil, PChar(Title));
      Inc(fuse, 1);
    end;
  if (hDlg <> 0) then
    if GetWindowRect(hDlg, rDlg) then
      begin
        XPos := (XPos - (rDlg.Right - rDlg.Left) div 2);
        YPos := (YPos - (rDlg.Bottom - rDlg.Top) div 2);
        if (MoveWindow(hDlg, XPos, YPos, (rDlg.Right - rDlg.Left), (rDlg.Bottom - rDlg.Top), True)) then
          SetWindowPos(hDlg, HWND_TOP, XPos, YPos, 0, 0, SWP_NOSIZE);
      end;
  DoTerminate;
end;


// erzeuge den wartethread
// übermittel aktuelle x und y werte
// setze title property
// rufe original dialog auf
// gebe wartethread wieder frei
function TOpenDialog.Execute(const X, Y : Integer): Boolean;
begin
  SDP := TSetDialogPosition.Create(False);
  SDP.XPos := X;
  SDP.YPos := Y;
  if Self.Title <> 'then
    SDP.Title := Self.Title
  else
  begin
    Self.Title := 'Open';
    SDP.Title := Self.Title;
  end;
  Result := inherited Execute;
  SDP.Free;
end;


// erzeuge den wartethread
// übermittel aktuelle x und y werte
// setze title property
// rufe original dialog auf
// gebe wartethread wieder frei
function TSaveDialog.Execute(const X, Y : Integer): Boolean;
begin
  SDP := TSetDialogPosition.Create(False);
  SDP.XPos := X;
  SDP.YPos := Y;
  if Self.Title <> 'then
    SDP.Title := Self.Title
  else
  begin
    Self.Title := 'Save';
    SDP.Title := Self.Title;
  end;
  Result := inherited Execute;
  SDP.Free;
end;

end.
Viel Spass damit.
Angehängte Dateien
Dateityp: 7z ComboBoxIssue.7z (765,5 KB, 5x aufgerufen)
Gruß vom KodeZwerg
  Mit Zitat antworten Zitat
Benutzerbild von dummzeuch
dummzeuch

Registriert seit: 11. Aug 2012
Ort: Essen
1.623 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#10

AW: TFileOpenDialog öffnet immer auf MainMonitor

  Alt 9. Sep 2020, 09:40
+1
Thomas Mueller
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


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 18:48 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