1
votes

I need help with this solution. There is application with several forms. One of this forms need to be opened on selected monitor. For example: Solution 1. OnCreate form cheks if there are more than one monitor used, and open on the last one. I try this code, but with no luck:

  Application.CreateForm(TfrmDashboard, frmDashboard);
  for I := 0 to Screen.MonitorCount -1 do
  begin
    // Checking Screen Position
    ShowMessageFmt('%d, %d, %d, %d',
              [Screen.Monitors[i].BoundsRect.Left,
              Screen.Monitors[i].BoundsRect.Top,
              Screen.Monitors[i].BoundsRect.Right,
              Screen.Monitors[i].BoundsRect.Bottom]);
  end;

  if Screen.MonitorCount > 1 then
  begin
      frmDashboard.Top:= Screen.Monitors[i].BoundsRect.Top;
      frmDashboard.Top:= Screen.Monitors[i].BoundsRect.Left;
  end;

Solution 2. Form is dragged to the selected monitor and OnDestroy event Top and Left position are written to the INI file. Next time form opens on the same monitor and same position. I try this code, but also with no luck:

procedure TfrmDashboard.FormCreate(Sender: TObject);
var
    ini: TIniFile;
begin
    ini:= TIniFile.Create(extractfilepath(paramstr(0))+'Dashboard.ini');
    Left:= StrToInt(ini.ReadString('Left', 'Form_Left', '0'));
    Top:= StrToInt(ini.ReadString('Top', 'Form_Top', '0'));
    ini.Free;
end;

procedure TfrmDashboard.FormDestroy(Sender: TObject);
var
    ini: TIniFile;
begin
    ini:= TIniFile.Create(extractfilepath(paramstr(0))+'Dashboard.ini');
    ini.WriteString('Left', 'Form_Left', IntToStr(Left));
    ini.WriteString('Top', 'Form_Top', IntToStr(Top));
    ini.Free;
end;
1
You need to be careful when creating INI files in the same directory as the app. If the app is in \program files, for instance, some versions of Windows create a temporary directory to store the ini file, which is then deleted on program exit, meaning it looks like a virgin implementation every time. Better to use the registry or store data or use documents directory, for instance. I may have the technical details wrong, but this is the effect.Dsm
In your first section of code inside the 'if' statement you mean Screen[ 1 ] not screen[ i ]. At the point you use it i is not defined and may contain any rubbish.Dsm

1 Answers

5
votes
frmDashboard.Top:= ...
frmDashboard.Top:= ...

This appears to be a simple copy paste error. You set Top both times. Presumably you mean:

frmDashboard.Top:= ...
frmDashboard.Left:= ...

This code makes the same mistake:

if Screen.MonitorCount > 1 then
begin
  frmDashboard.Top:= Screen.Monitors[i].BoundsRect.Top;
  frmDashboard.Top:= Screen.Monitors[i].BoundsRect.Left;
end;

Furthermore, it refers to i when it is ill-defined. The compiler will warn about this. I hope you have compiler warnings and hints enabled, and do take heed of them.


Your OnCreate event handler will raise an exception if the INI file contains invalid data. For instance, if the user edits the position values to be non-numeric, then StrToInt will raise an exception. Your program should be resilient to that.

Both the OnCreate and OnDestroy event handlers don't manage the lifetime of the INI file object correctly. If the INI file access fails, or the calls to StrToInt fail (see above) then you will leak the object. This is the pattern to be followed:

obj := TMyObject.Create;
try
  // do things with obj
finally
  obj.Free;
end;