* * *

Author Topic: [SOLVED]: TOpenDialog Screen Position  (Read 2638 times)

Troodon

  • Sr. Member
  • ****
  • Posts: 485
Re: TOpenDialog Screen Position
« Reply #15 on: January 24, 2012, 01:11:09 am »
Decided to post it here instead. The main form contains Button1, Label1, and OpenDialog1. This is the code for the main form.

Code: [Select]
unit Unit1;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls;

type

  { TForm1 }

  TForm1 = class(TForm)
    Button1: TButton;
    Label1: TLabel;
    OpenDialog1: TOpenDialog;
    procedure Button1Click(Sender: TObject);
  private
    { private declarations }
  public
    { public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.lfm}

{ TForm1 }

procedure TForm1.Button1Click(Sender: TObject);
begin
  if OpenDialog1.Execute() then
    label1.Caption := OpenDialog1.FileName
  else
    label1.Caption := '';
end;

end.
« Last Edit: January 24, 2012, 01:14:00 am by Troodon »
Lazarus/FPC on Linux

Pascaluvr

  • Full Member
  • ***
  • Posts: 142
Re: TOpenDialog Screen Position
« Reply #16 on: January 24, 2012, 06:38:20 am »
Hi Troodon,

Thanks - Partially solved.

I had used:
  var  OFN: TOpenDialog;

instead of adding TOpenDialog to my Form.  (I copied a Delphi example).

BUT -

If i OpenDialog while my application is still in Screen1, it behaves.

If I then OpenDialog after I move my application to Screen2 - it still behaves.

If I then OpenDialog after I move my application back to Screen1, the dialog still opens in Screen2.    This happens in your test program as well.

So, I say its partially solved - as it only works if I only move my application ONE time.

I accept that this is a little unusual to have this requirement, but without giving a detailed description, I assure you I do need to move my application around the screens.

Thanks for you assistance thus far.
« Last Edit: January 24, 2012, 06:49:40 am by Pascaluvr »

User137

  • Hero Member
  • *****
  • Posts: 503
Re: TOpenDialog Screen Position
« Reply #17 on: January 24, 2012, 08:56:55 am »
Ah, a custom TForm as a dialog. That goes in between screens only if its position property is set to DesktopCenter. It should be ScreenCenter.

Pascaluvr

  • Full Member
  • ***
  • Posts: 142
Re: TOpenDialog Screen Position
« Reply #18 on: January 24, 2012, 09:12:27 am »
Ah, a custom TForm as a dialog. That goes in between screens only if its position property is set to DesktopCenter. It should be ScreenCenter.
=======================================================

Nope, that makes no difference to the scenario I previously posted.

Thanks anyways.

Pascaluvr

  • Full Member
  • ***
  • Posts: 142
Re: TOpenDialog Screen Position
« Reply #19 on: January 25, 2012, 09:52:23 pm »
Hi Ludob,

I've had some time to try your suggestion and I still have problems.

Start my program and click OFN and it works fine.
or
Start my program and move it to the 2nd screen and click OFN - works fine.

but in either case, if I then move my application to another position, and click OFN, the dialog opens in the same position as the first time.

In other words, The SetWindowPos only seems to work for the first time the callback is raised, although I know the Callback is being executed as I put in a ShowMessage with NewLeft and NewTop being displayed and that came up each time.

Any more ideas?

Thabnks for your help to date.

ludob

  • Hero Member
  • *****
  • Posts: 623
Re: TOpenDialog Screen Position
« Reply #20 on: January 26, 2012, 09:15:21 am »
Did some further testing with opening a dialog for a second time. Windows seems to store the first position of the dialog and restore it the second time. SetWindowPos doesn't return an error but the position is overridden somewhat later by windows. The fact that windows stores some settings is somewhat confirmed by the following:
- create a TOpenDialog at run time and destroy. The first time, on my slow computer, there is a fair delay before the dialog is opened the first time. The second time, the dialog opens immediately. This corresponds with the loading of the common dialogs library. Repositioning doesn't work for the second dialog.
- execute a TSaveDialog after the TOpenDialog and the position is the same as for the TOpenDialog although the LCL tries to put it in the middle.

Another problem I found, in the LCL this time, but not related to positioning of the dialog is that OnShow is called twice. I'll raise a bug report for that.

The following workaround is working for me but, on my slow computer, you notice the repositioning of the screen as a short flash:

Code: [Select]
function OpenFileDialogCallBack(Wnd: HWND; uMsg: UINT; wParam: WPARAM;
  lParam: LPARAM): UINT_PTR; stdcall;
begin
  Result := 0;
  if uMsg = WM_INITDIALOG then
    begin
    SetWindowPos(GetParent(Wnd), HWND_TOP, Form1.Left, Form1.Top, 0, 0, SWP_NOSIZE);
    end
  else if (uMsg = WM_NOTIFY) and (lParam<>0) and (LPOFNOTIFY(lParam)^.hdr.code= CDN_SELCHANGE) then
    begin
    SetWindowPos(GetParent(Wnd), HWND_TOP, Form1.Left, Form1.Top, 0, 0, SWP_NOSIZE);
    result:=Form1.OldHook(Wnd,uMsg,wParam,lParam);
    end
  else
    result:=Form1.OldHook(Wnd,uMsg,wParam,lParam);
end;

procedure TForm1.OpenDialog1Show(Sender: TObject);
begin
  if LPOPENFILENAME(OpenDialog1.Handle)^.lpfnHook<>@OpenFileDialogCallBack then
    begin
    OldHook:=LPOPENFILENAME(OpenDialog1.Handle)^.lpfnHook;
    LPOPENFILENAME(OpenDialog1.Handle)^.lpfnHook:=@OpenFileDialogCallBack;
    end
  else
    LPOPENFILENAME(Form1.OpenDialog1.Handle)^.lpfnHook:=Form1.OldHook;
end;
The dialog is positioned here to match the upper left corner of the form. Change to your own liking.

The CDN_SELCHANGE command is sent when the dialog is fully populated and shown. Thereafter it will be triggered every time you change the file selected. As a result, when you manually move the dialog to another position, it will re-position whenever you change the selection.  If this is too annoying just use a flag that is set in OpenDialog1Show and cleared after the first CDN_SELCHANGE. Call SetWindowPos only when flag is set.

I tried other events and commands but they all happen before windows repositions the dialog to the old position.

The code change in OpenDialog1Show is to work around the LCL double Onshow issue.

Pascaluvr

  • Full Member
  • ***
  • Posts: 142
Solved: TOpenDialog Screen Position
« Reply #21 on: January 26, 2012, 07:13:30 pm »
Wow Ludob, thank you so much for going the extra mile and actually finding a solution for me.  It is truly appreciated.

I made all your changes including setting a flag to avoid flicker.  It all works perfectly.

Many thanks for all your efforts.

 

Recent

Get Lazarus at SourceForge.net. Fast, secure and Free Open Source software downloads