Click here to Skip to main content
15,884,629 members
Articles / Programming Languages / Visual Basic

Saving and Restoring Form Location in a Multi-Monitor Environment

Rate me:
Please Sign up or sign in to vote.
4.68/5 (9 votes)
19 Feb 2009CPOL3 min read 36.8K   32   7
This article describes a method to save and restore form locations that will continue to work when display settings change.

Introduction

Many applications store the size and location of a form so that the next time it is opened it restores to the same size and location. This is a great feature, but can present a problem when the display environment is not always the same. For example, a notebook computer may be connected to a secondary monitor at the office, but not when on the road. A form that is set to load on the secondary monitor will be displayed off the visible screen when the notebook is on the road. The code in this article shows how to get the benefits of this feature without this problem.

A quick search of the Internet will find many ways to save the form position. None that I found seemed to take multiple monitors (or more precisely, an inconsistent monitor setup) into account. I also easily found a code example that allowed me to specify which monitor to start a form on. The problem with this code is that it assumes that the coordinate system is based on position 0,0 being the top left corner of the specified monitor, not necessarily the top left corner of the primary monitor, while the form coordinates are given based on the primary monitor. So, if I positioned the form in the middle of my left (secondary) monitor and exited, I would store an X position of -600 (600 pixels to the left of the primary monitor), but when loading the form and specifying the startup monitor, I need to tell it to move 424 pixels to the right from its origin on the secondary monitor. All very confusing.

The key was to determine the bounds of the monitor used. This uses the same coordinates referenced in the form's location, so a 1024×768 monitor to the left of the primary monitor (also 1024×768) would have its upper left corner be -1024,0. We can subtract the bounds coordinates from the saved coordinates to find the coordinates relative to the top left corner of the monitor used. I also check to verify that the position stored is within the bounds of the selected monitor, and if not, display the form in the upper left corner of the selected monitor. This way, the form is never displayed in a position where it can not be seen.

Another problem with the code I found for specifying which screen to start on was that it did not verify the existence of that screen before trying to change to it. So, if a monitor was disconnected, you would end up with an error. Storing the selected monitor also wound up being a bit more of a challenge than expected. The property Screen.DisplayName pads the end of the string with a number of hidden characters. Trimming off the extra characters solved my problems with this section, but it was annoying to track down.

Using the code

The code is in two segments. The first is placed in the Form_Load procedure, and the second in the Form_FormClosing procedure, as marked. The example shown stores the form position in an INI file. An XML file or the Registry could be used as easily. The ReadINI and WriteINI procedures referenced in the code are not shown here. There are many methods available for performing these functions.

The following code goes in the Form_Load procedure:

VB
'Multi Monitor Aware - Restore Postition to last Used
Dim posScreen As Integer
Dim posX As Integer
Dim posY As Integer
Dim screen As Screen
' Read the previous screen used from the INI file
posScreen = Val(ReadIni(File, "Main", "PosScreen"))
screen = screen.AllScreens(0)
' Verify the Specified screen exists, if so then use it
If screen.AllScreens.Length > posScreen + 1 Then
  screen = screen.AllScreens(0)
Else
  screen = screen.AllScreens(posScreen)
End If
' Read the Position from the INI File
posX = Val(ReadIni(File, "Main", "PosX"))
posY = Val(ReadIni(File, "Main", "PosY"))
Dim pt As New Point(posX, posY)
If screen.Bounds().Contains(pt) Then
  pt.X = posX - screen.Bounds().X
  pt.Y = posY - screen.Bounds().Y
Else
  pt.X = 0
  pt.Y = 0
End If
Me.StartPosition = FormStartPosition.Manual
Me.Location = screen.Bounds.Location + pt

The following code goes in the Form_FormClosing procedure:

VB
' Save Screen Position
For i As Integer = 0 To
screen.AllScreens().Length - 1
  If stringtoasc(screen.AllScreens(i).DeviceName.ToString) _
  = stringtoasc(screen.FromControl(Me).DeviceName.ToString) Then
    WriteIni(File, "Main", "PosScreen", i)
  End If
Next
WriteIni(File, "Main", "PosX", Me.Location.X)
WriteIni(File, "Main", "PosY", Me.Location.Y)

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
Questionsimplify/eliminate stringtoasc Pin
TomWpoint12-Oct-15 4:29
TomWpoint12-Oct-15 4:29 
BugBroken if Window is Maximized & missing code Pin
chrisf865723-Mar-15 22:37
chrisf865723-Mar-15 22:37 
GeneralMy vote of 4 Pin
Member 69720399-Nov-12 9:41
Member 69720399-Nov-12 9:41 
GeneralGreat topic Pin
scottb224-Feb-09 5:03
scottb224-Feb-09 5:03 
GeneralI have an alternative to this solution, please read further for more information Pin
PHenry20-Feb-09 17:16
PHenry20-Feb-09 17:16 
GeneralRe: I have an alternative to this solution, please read further for more information Pin
NealSchafer13-Mar-09 16:11
NealSchafer13-Mar-09 16:11 
GeneralRe: I have an alternative to this solution, please read further for more information Pin
Pete BSC9-Jun-09 5:31
Pete BSC9-Jun-09 5:31 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.