-
[RESOLVED] [2008] Multiple monitors - keep form uppermost on secondary screen
I have 2 forms. ControlForm and displayForm.
On a single monitor system
- I need controlForm to always be on top of displayForm.
On a multiple monitor system :
- controlForm must be on primary screen
- displayForm must be maximized, unmovable and uppermost on secondary screen.
Please can someone show me how to code this and which events to use ?
Thanks !
-
Re: [2008] Multiple monitors - keep form uppermost on secondary screen
-
Re: [2008] Multiple monitors - keep form uppermost on secondary screen
1. Create a new WinForms application project.
2. Add a second form to the project.
3. Set the ControlBox and ShowInTaskbar properties of the second form to False.
4. Add a Button to the first form.
5. Double-click the Button to create a Click event handler.
6. Add the following code to the event handler:
vb.net Code:
Dim f2 As New Form2
If Screen.AllScreens.Length = 0 Then
'There is only one monitor so display this
'form as a modeless dialogue of the new form.
Me.Owner = f2
Else
'There are multiple monitors so disply the form maximised
'over all other windows on the second monitor.
With f2
.StartPosition = FormStartPosition.Manual
.Bounds = Screen.AllScreens(1).Bounds
.WindowState = FormWindowState.Maximized
.TopMost = True
End With
End If
f2.Show()
7. Run the project and click the Button.
-
Re: [2008] Multiple monitors - keep form uppermost on secondary screen
jmc, thanks, you are most helpful.
Is there any way can I use your immovable forms code to forbid Form1 from being dragged to secondary Screen/Monitor ?
-
Re: [2008] Multiple monitors - keep form uppermost on secondary screen
You can use my immovable form code to make Form1 immovable. If you want it the form to be movable but not able to be moved off the first screen then you'd have to handle the LocationChanged event, check whether it's on the primary monitor and move there if it's not.
-
Re: [2008] Multiple monitors - keep form uppermost on secondary screen
Just a theory question... Doesn't locationchanged fire after location has been changed ?
Code:
Quote MSDN: Occurs when the Location property value has changed.
What I'm trying to avoid is the peekaboo that occurs on secondary screen when form1 is dragged to secondary screen.
What I'm trying to achieve is while it is being dragged, for form1 to bang into it's primary screen rectangle and refuse to budge beyond. Scratching head
-
Re: [2008] Multiple monitors - keep form uppermost on secondary screen
What you ask for is not trivial but it isn't too difficult either. What you need to do is override the WndProc method and trap the WM_MOVING message, which is received before the window moves. You can get the RECT structure from the e.LParam property and determine whether it is partially outside the bounds of the primary screen. If it is then you can edit it before passing the message on.
I don't have time to write a code example at the moment but if you haven't figured it out for yourself or had someone else show you how by the next time I'm online I'll give it a go.
-
Re: [2008] Multiple monitors - keep form uppermost on secondary screen
Thanks for the hint. I do some research...
-
Re: [2008] Multiple monitors - keep form uppermost on secondary screen
Well I found the wm_moving msdn info with no sample code (as usual)
and I found exactly what I want to do but in Delphi
and I found the correct code for wpf
and I finally found C# code.
I have sort of understood but am having problems converting code from C#. So I'd appreciate any help and/or explanation on this.
Readers, please don't use this code as is:
Code:
Private Declare Function GetSystemMenu(ByVal hWnd As IntPtr, ByVal bRevert As Boolean) As IntPtr
Private Declare Function EnableMenuItem Lib "user32.dll" (ByVal hMenu As IntPtr, ByVal uIDEnableItem As Integer, ByVal uEnable As Integer) As Boolean
Public Declare Function RemoveMenu Lib "user32.Dll" (ByVal hMenu As IntPtr, ByVal nPosition As Integer, ByVal wFlags As Integer) As IntPtr
Public Declare Function GetMenuItemCount Lib "User32.Dll" (ByVal hMenu As IntPtr) As Integer
Public Declare Function DrawMenuBar Lib "User32.Dll" (ByVal hwnd As IntPtr) As IntPtr
Protected Overrides Function ProcessCmdKey(ByRef msg As System.Windows.Forms.Message, ByVal keyData As System.Windows.Forms.Keys) As Boolean
If (msg.Msg = WM_SYSKEYDOWN) Then
Select Case (keyData)
Case (System.Windows.Forms.Keys.Alt Or System.Windows.Forms.Keys.F4)
Return handleAltF4
End Select
End If
' process all others as normal
Return false
End Function
Protected Overrides Sub WndProc(ByRef m As Message)
Select Case (m.Msg)
Case WM_NCLBUTTONDOWN
' Title bar left clicked so set mouse cursor rectangle based on current position
ClipRectangle = New Rectangle((RectangleLimit.X _
+ (Cursor.Position.X - Location.X)), (RectangleLimit.Y _
+ (Cursor.Position.Y - Location.Y)), (RectangleLimit.Width - Width), (RectangleLimit.Height - Height))
Case WM_ENTERSIZEMOVE
' Move or size event so clip the mouse cursor
Cursor.Clip = ClipRectangle
Case WM_MOVING
' Form has moved so get current form rectangle
Dim rectangle As RECT = CType(Marshal.PtrToStructure(m.LParam, GetType(RECT)),RECT)
' Compare form rectangle position and marshal allowed position if necessary
If (rectangle.Left < RectangleLimit.Left) Then
rectangle.Right = (RectangleLimit.Left + Width)
rectangle.Left = RectangleLimit.Left
Marshal.StructureToPtr(rectangle, m.LParam, true)
End If
If (rectangle.Top < RectangleLimit.Top) Then
rectangle.Bottom = (RectangleLimit.Top + Height)
rectangle.Top = RectangleLimit.Top
Marshal.StructureToPtr(rectangle, m.LParam, true)
End If
If (rectangle.Right > RectangleLimit.Right) Then
rectangle.Left = (RectangleLimit.Right - Width)
rectangle.Right = RectangleLimit.Right
Marshal.StructureToPtr(rectangle, m.LParam, true)
End If
If (rectangle.Bottom > RectangleLimit.Bottom) Then
rectangle.Top = (RectangleLimit.Bottom - Height)
rectangle.Bottom = RectangleLimit.Bottom
Marshal.StructureToPtr(rectangle, m.LParam, true)
End If
End Select
MyBase.WndProc(m)
End Sub
-
Re: [2008] Multiple monitors - keep form uppermost on secondary screen
OK, I was incorrect about the message to trap. The correct message is WM_WINDOWPOSCHANGING. Try creating a new project and replace your form's code with the following:
Code:
Option Strict On
Imports System.Runtime.InteropServices
Public Class Form1
Private Structure WINDOWPOS
Public hwnd As IntPtr
Public hwndInsertAfter As IntPtr
Public x As Integer
Public y As Integer
Public cx As Integer
Public cy As Integer
Public flags As Flags
End Structure
<Flags()> _
Private Enum Flags As UInteger
NoSize = &H1
NoMove = &H2
NoZOrder = &H4
NoRedraw = &H8
NoActivate = &H10
FrameChanged = &H20
ShowWindow = &H40
HideWindow = &H80
NoCopyBits = &H100
NoOwnerZOrder = &H200
NoSendChanging = &H400
End Enum
Private Const WM_WINDOWPOSCHANGING As Integer = &H46
Private Const DRAGGING As Flags = Flags.NoZOrder Or Flags.NoActivate Or Flags.NoOwnerZOrder
Private Const DRAGGED As Flags = Flags.NoSize
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
If m.Msg = WM_WINDOWPOSCHANGING Then
Dim pos As WINDOWPOS = DirectCast(Marshal.PtrToStructure(m.LParam, GetType(WINDOWPOS)), WINDOWPOS)
Console.WriteLine(pos.flags.ToString())
If pos.flags = DRAGGING OrElse pos.flags = DRAGGED Then
If pos.x < 0 Then
pos.x = 0
End If
If pos.y < 0 Then
pos.y = 0
End If
Dim workingArea As Rectangle = Screen.PrimaryScreen.WorkingArea
Dim xMax As Integer = workingArea.Width - Me.Width
Dim yMax As Integer = workingArea.Height - Me.Height
If pos.x > xMax Then
pos.x = xMax
End If
If pos.y > yMax Then
pos.y = yMax
End If
Marshal.StructureToPtr(pos, m.LParam, True)
End If
End If
MyBase.WndProc(m)
End Sub
End Class
Run the project and try dragging the form of the screen. You'll find that it will not go beyond the bounds of the screen's working area. You can then transfer the appropriate code from that test project.
Note that another option would be to createw a class that inherits NativeWindow. You can then use that class with any existing form without having to change its code.
-
Re: [2008] Multiple monitors - keep form uppermost on secondary screen
There is a very very simple way of doing what you want to do. In the design view, set your FormBorderStyle to None. Since you want it maximised anyway, it doesn't really make any difference, and you can manually put a close button on it. The point is, when you put FormBorderStyle to None, the form cannot be moved, period.
-
1 Attachment(s)
Re: [2008] Multiple monitors - keep form uppermost on secondary screen
jmc I am most grateful for the example code. It very gently returns the window to it's screen. But it seems to allow form to be dragged beyond screen rectangle and allows form1 to peekaboo on secondary screen.
I'd like to refer to my C# codeproject code link above and sample attached. Running that C# project show how form1 can be physically limited and it literally bangs into owner screen rectangle. I'm having trouble converting the code to work in vb.net
How can I mimic that behaviour ? Thanks
-
Re: [2008] Multiple monitors - keep form uppermost on secondary screen
Quote:
Originally Posted by Xancholy
form1 can be physically limited and it literally bangs into owner screen rectangle.
That's exactly what my code in post #10 does, or at least it certainly did for me.
-
Re: [2008] Multiple monitors - keep form uppermost on secondary screen
Quote:
Originally Posted by jmcilhinney
That's exactly what my code in post #10 does, or at least it certainly did for me.
Hmmm, jmc, just to double-check, you're running this code on a multiple monitor setup ?:sick:
-
Re: [2008] Multiple monitors - keep form uppermost on secondary screen
I didn't originally but that's irrelevant anyway. The code uses Screen.PrimaryScreen.WorkingArea, which is the available area of the primary monitor, regardless of whether there is a secondary monitor or even a hundred other monitors. That said, I just tested it on a mulit-head system and it worked as expected.
Both systems I tested on were Vista, but I can't see why that would make a difference. I'll test it on XP at work tomorrow to see though.
Just for me to make sure, you did create a new project right, and you did replace the code of the default for with my entire code from post #10?
-
Re: [2008] Multiple monitors - keep form uppermost on secondary screen
Yes, I created a new project and replaced all form1's code with your code.
I will also test it again on another multiple monitor system(XP) at work tomorrow.
Is there any way your code can be a reusable function which can be called from any form ? eg: LimitME(form2)
-
Re: [2008] Multiple monitors - keep form uppermost on secondary screen
I just tested the code from post #10 on a dual-head XP system and it worked perfectly.
Quote:
Is there any way your code can be a reusable function which can be called from any form ?
Strictly speaking, no it can't. You need to hook into the form's message queue so a function is not enough. As I also said in post #10:
Code:
Note that another option would be to create a class that inherits NativeWindow. You can then use that class with any existing form without having to change its code.
If you read the documentation for the NativeWindow class you'll see the code example provided that shows you how to do that.
I should point out that if you ask a question and someone answers it, it's your responsibility to make sure you read the answer. If I tell you that you can do this for any existing form by creating a class that inherits NativeWindow, I would expect that, if you want to do this for any existing form, that you would have read my answer and then immediately gone to the MSDN Library to find out everything you could about the NativeWindow class.
-
Re: [2008] Multiple monitors - keep form uppermost on secondary screen
Quote:
Originally Posted by jmcilhinney
Note that another option would be to createw a class that inherits NativeWindow.
I did read your post and you said "another option" and I'm not in a position to do msdn research today. That's why I said I would further test your solution tomorrow at work. Hope you read my post ?:wave:
Quote:
Originally Posted by jmcilhinney
Strictly speaking, no it can't.
Fair enough, thanks. Shall report back tomorrow.
-
Re: [2008] Multiple monitors - keep form uppermost on secondary screen
Code:
Imports System.Runtime.InteropServices
Public Class FormLocationRestrictor
Inherits NativeWindow
Private Structure WINDOWPOS
Public hwnd As IntPtr
Public hwndInsertAfter As IntPtr
Public x As Integer
Public y As Integer
Public cx As Integer
Public cy As Integer
Public flags As Flags
End Structure
<Flags()> _
Private Enum Flags As UInteger
NoSize = &H1
NoMove = &H2
NoZOrder = &H4
NoRedraw = &H8
NoActivate = &H10
FrameChanged = &H20
ShowWindow = &H40
HideWindow = &H80
NoCopyBits = &H100
NoOwnerZOrder = &H200
NoSendChanging = &H400
End Enum
Private Const WM_WINDOWPOSCHANGING As Integer = &H46
Private Const DRAGGING As Flags = Flags.NoZOrder Or Flags.NoActivate Or Flags.NoOwnerZOrder
Private Const DRAGGED As Flags = Flags.NoSize
Private target As Form
Public Sub New(ByVal target As Form)
AddHandler target.HandleCreated, AddressOf Me.OnHandleCreated
AddHandler target.HandleDestroyed, AddressOf Me.OnHandleDestroyed
Me.target = target
End Sub
' Listen for the control's window creation and hook into it.
Private Sub OnHandleCreated(ByVal sender As Object, ByVal e As EventArgs)
' Window is now created, assign handle to NativeWindow.
AssignHandle(CType(sender, Form).Handle)
End Sub
Private Sub OnHandleDestroyed(ByVal sender As Object, ByVal e As EventArgs)
' Window was destroyed, release hook.
ReleaseHandle()
End Sub
<System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.Demand, Name:="FullTrust")> _
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
If m.Msg = WM_WINDOWPOSCHANGING Then
Dim pos As WINDOWPOS = DirectCast(Marshal.PtrToStructure(m.LParam, GetType(WINDOWPOS)), WINDOWPOS)
Console.WriteLine(pos.flags.ToString())
If pos.flags = DRAGGING OrElse pos.flags = DRAGGED Then
If pos.x < 0 Then
pos.x = 0
End If
If pos.y < 0 Then
pos.y = 0
End If
Dim workingArea As Rectangle = Screen.PrimaryScreen.WorkingArea
Dim xMax As Integer = workingArea.Width - Me.target.Width
Dim yMax As Integer = workingArea.Height - Me.target.Height
If pos.x > xMax Then
pos.x = xMax
End If
If pos.y > yMax Then
pos.y = yMax
End If
Marshal.StructureToPtr(pos, m.LParam, True)
End If
End If
MyBase.WndProc(m)
End Sub
End Class
-
Re: [2008] Multiple monitors - keep form uppermost on secondary screen
Just note that the code from post #10 and the reusable class from post #19 both will behave slightly oddly if the user resizes the form past the bounds of the primary monitor, rather than moving it. I'm sure that can be sorted out but I'll leave it up to you to do so.
-
Re: [2008] Multiple monitors - keep form uppermost on secondary screen
What is the correct way to make a call to your reusable class in posting#19 ?
-
Re: [2008] Multiple monitors - keep form uppermost on secondary screen
Quote:
Originally Posted by Xancholy
What is the correct way to make a call to your reusable class in posting#19 ?
Still haven't bothered... I mean, haven't had enough time... to read the documentation for the NativeWindow class huh? Well, when you do, then you'll know.
-
Re: [2008] Multiple monitors - keep form uppermost on secondary screen
Quote:
Originally Posted by jmcilhinney
Still haven't bothered... I mean, haven't had enough time... to read the documentation for the NativeWindow class huh? Well, when you do, then you'll know.
All in good time jmc, thanks for the reply. What I have just made :) time to do is test your code in posting #10 on a true dual head system and happy to confirm back that it works perfectly. :thumb: Thank God we now have a working code sample because I (spell it now) I asked for it :bigyello:
Next on my to-do list for today is to do some suggested nativewindow reading. Which will no doubt result in further questions being asked and further snide remarks. The joys of learning.
-
Re: [2008] Multiple monitors - keep form uppermost on secondary screen
Can i ask why your bothering with this. I use two monitors and any software that wouldn't allow me to move around both monitors was immediately scrapped. The idea of both monitors is so I have the choice where applications go.
-
Re: [2008] Multiple monitors - keep form uppermost on secondary screen
Make your philosophy "look first, ask questions later" and we'll get on fine. Ask others to do for you when you haven't done for yourself and the odd snide(ish) remark is a given.
-
Re: [2008] Multiple monitors - keep form uppermost on secondary screen
Quote:
Originally Posted by jmcilhinney
and the odd snide(ish) remark is a given.
come now jmc, those remarks have become your trademark! ;) And I've explained that I only come to these forums after much error because of trial.
-
Re: [2008] Multiple monitors - keep form uppermost on secondary screen
Quote:
Originally Posted by Xancholy
come now jmc, those remarks have become your trademark! ;) And I've explained that I only come to these forums after much error because of trial.
Everyone needs an angle.:thumb:
-
Re: [2008] Multiple monitors - keep form uppermost on secondary screen
Quote:
Originally Posted by CodedFire
Can i ask why your bothering with this. I use two monitors and any software that wouldn't allow me to move around both monitors was immediately scrapped. The idea of both monitors is so I have the choice where applications go.
Pretend you are a teacher and you have your laptop connected to a projector.
Laptop=Primary monitor. Projector=secondary monitor.
You have your control form on laptop and you want your audience to only see the results of your twiddling, not the twiddling itself.
Agreed this is a special-case scenario, not the norm. And jmc has stolen the thunder again with this solution. Cheers jmc.
-
Re: [2008] Multiple monitors - keep form uppermost on secondary screen
@jmcilhinney: That question wasn't directed at you man. Got nothing but respect for ya, personally i don't know how you do it to such a level as your currently at. It was for the OP. Still cant understand why you would need to make the application restricted in terms of screen real estate like that. But anyhow like you jmc i think il just answer the question that is at hand instead of the one that should be at hand.
-
Re: [2008] Multiple monitors - keep form uppermost on secondary screen
Opps, sorry you where directing that at the OP not me. Yeah i really should look first too.
-
Re: [2008] Multiple monitors - keep form uppermost on secondary screen
This is what happens when there are multiple people posting to a thread and they (I :() fail to quote the post they're (I'm :() replying to. I have nothing but respect for me too... and a little envy.
-
Re: [2008] Multiple monitors - keep form uppermost on secondary screen
Personally I envy my intelligent questions and fierce resolve! Am I the OP then ? :)
-
Re: [2008] Multiple monitors - keep form uppermost on secondary screen
All right jmc, it's been 2 minutes and time for your next remark.
I've been through the nativewindow class, trial, and here's the error. I'm adding the FormRestrictor class to my project and trying to apply it to form1. form1 scoobies right across both screens.
Code:
Private formLock As FormLocationRestrictor
formLock = New FormLocationRestrictor(Me)
What am I missing ?
-
Re: [2008] Multiple monitors - keep form uppermost on secondary screen
Again, I just have to point out, why not simply make your form borderless in the event that there are two screens? It isn't difficult to do, and it eliminates all that code you've been posting.
-
Re: [2008] Multiple monitors - keep form uppermost on secondary screen
What if you want a border?
-
Re: [2008] Multiple monitors - keep form uppermost on secondary screen
Quote:
Originally Posted by MaximilianMayrhofer
Again, I just have to point out, why not simply make your form borderless in the event that there are two screens? It isn't difficult to do, and it eliminates all that code you've been posting.
MM, form1 has to be sizable and movable only within primary screen. Therefore no borderless.
That's what all this code is about. jmc understands me.
-
Re: [2008] Multiple monitors - keep form uppermost on secondary screen
I do this:
Code:
Public Class Form1
Private flr As FormLocationRestrictor
Public Sub New()
' This call is required by the Windows Form Designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
Me.flr = New FormLocationRestrictor(Me)
End Sub
End Class
and I get no scoobying.
-
Re: [2008] Multiple monitors - keep form uppermost on secondary screen
Cool. Thanks ! I'll give this a go.
-
Re: [2008] Multiple monitors - keep form uppermost on secondary screen
Quote:
Originally Posted by jmcilhinney
Just note that the code from post #19 will behave slightly oddly if the user resizes the form past the bounds of the primary monitor, rather than moving it.
I still haven't figured how to restrict the form when the form is resized... appreciate any help with this
-
Re: [RESOLVED] [2008] Multiple monitors - keep form uppermost on secondary screen
jmc, if you're still following this thread, here's a good one to scratch the old noggin...
How can I limit the mouse cursor to the bounds of the primary screen rectangle...
Great question, eh ? But seriously now I need help with the answer. Do you have a MOUSERESTRICTOR up your sleeve ?
I do know that we have to trap WM_MOUSEMOVE
Something like...
Code:
Private Const WM_MOUSEMOVE As Integer = &H201
-
Re: [RESOLVED] [2008] Multiple monitors - keep form uppermost on secondary screen
Just wanted to chime in and say thanks for the code sniplet which works great.