-
making a form "always on top"
I am quite sure this issue has been addressed before, but the search feature for vbforums wasn't very helpful.
I just want to make it so my form will always be on top of any other programs (it doesn't have to have focus).
Thanks guys. Much appreciated. :)
-
Re: making a form "always on top"
SetWindowPos(0 api function may work for you:
Code:
Option Explicit
Private Const HWND_TOPMOST = -1
Private Const HWND_NOTOPMOST = -2
Private Const SWP_NOSIZE = &H1
Private Const SWP_NOMOVE = &H2
Private Const SWP_NOACTIVATE = &H10
Private Const SWP_SHOWWINDOW = &H40
Private Declare Sub SetWindowPos Lib "User32" _
(ByVal hWnd As Long, ByVal hWndInsertAfter As Long, ByVal X As Long, _
ByVal Y As Long, ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long)
Private Sub Form_Load()
SetWindowPos Me.hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE Or SWP_SHOWWINDOW Or SWP_NOMOVE Or SWP_NOSIZE
End Sub
-
Re: making a form "always on top"
I applied the code exactly as above. It seems to have the limitation that it only brings the form to the "front" at the moment the SetWindowPos command is called.
I tried applying the code to the Form_LostFocus sub which didn't work. I then threw it in a timer, which does seem to have the desired effect, but I would prefer to not have a short duration Timer spam-proc'ing 100% of the time when my program is running.
Any idea how I might be able to event-capture when my form is not on top? Or maybe another method?
Thanks tons. This is really a big help.
-
Re: making a form "always on top"
It stays on top forevermore after the call is made; it isn't just a one-time "bring to front" action. You can call it in the Form_Load() event.
Note that other "Always On Top" windows will obscure your window if they get the focus, but that's just how Windows works.
-
Re: making a form "always on top"
It's not working like that for me. After I call it, it is able to lose focus again.
Are we using different versions or something?
I am VB6, XP sp3.
-
Re: making a form "always on top"
There is no such thing as Always Has Focus. Always On Top is a different thing entirely, which isn't related to focus at all.
Any program that didn't let itself lose focus would be, IMO, an evil piece of malware.
-
Re: making a form "always on top"
I misspoke in my last post.
As I said in my original post:
"I just want to make it so my form will always be on top of any other programs (it doesn't have to have focus)."
What I meant to say in my last post was, after I call SetWindowPos, it is able to be "behind" other programs that do not have "always on top". Like notepad. The code was copied exactly as above into a blank project.
-
Re: making a form "always on top"
Okay, gotcha.
I've actually run into similar problems with a couple apps I want AlwaysOnTop, like for instance a WinAmp-style mp3 player. My best guess is that the window may not stay on top if it isn't fully loaded when the SetWindowPos call is made. Doesn't make a ton of sense since you can send a hwnd, but whatever.
My workaround was to set up a short timer to set the form AlwaysOnTop on startup. The timer gets some short delay, like half second or so. It gets Enabled at the end of Form_Load, and when it fires it disables itself and then calls SetWindowPos. End result is that it runs only once, but the form is likely to be fully loaded before it gets called.
This isn't a 100% guaranteed solution. That WinAmp-style program I wrote will occasionally still fail to be always on top if the system is very busy when the program is first run. Despite that, it works correctly the vast majority of the time, so that's the solution I've stuck with.
If anyone has any better ideas, I'm definitely interested.
-
Re: making a form "always on top"
Still isn't working for me. I started with a 500ms delay, and went up to 10000ms.
Still didn't work so I threw some DoEvents in the Timer sub just before the SetWindowPos command. None of the tests worked. No idea why. =/
-
Re: making a form "always on top"
Create a new project with nothing but the AlwaysOnTop logic implemented and see if that works. If it doesn't, attach that small test project here and I'll take a look.
-
1 Attachment(s)
Re: making a form "always on top"
Here ya go. Thanks tons.
Edit: Just for clarification, i've been doing these tests in a blank project. Also, it wouldn't let me upload a ".vbp" so I had to zip it. =P
-
Re: making a form "always on top"
Works fine for me. Are you not waiting 5 seconds?
I shortened the timer interval to 200 and it still works fine.
-
Re: making a form "always on top"
Works here (WinXP).
I've never seen on-top not work in a compiled project, but it does happen to me once in awhile when run from the IDE and set at the top of form load.
-
Re: making a form "always on top"
-
Re: making a form "always on top"
Yes, I was waiting until the command triggered. I have been programming in Visual Basic for 12 years. I frequently help people on this website, I just didn't know how to do this "always on top" thing.
ThEiMp, the Zorder command did nothing. Does that work for other people?
-
Re: making a form "always on top"
Zorder lets you move an object to the front or back of other objects (within your project), it's doesn't keep a form on top of other program windows.
Maybe you have a PC problem, open Task Manager, go to OPtions, set it to Always On Top, does it stay on top of other windows?
-
Re: making a form "always on top"
Winamp and the Task Manager are set to "Always On Top" and they work perfect.
The API command does bring the form to the front also, but it only does it when the command is called. I'm perplexed as to why it's not working.
Are there any other "Always On Top" methods?
-
Re: making a form "always on top"
Not sure, I been using that same code as post #2 for years without a problem, only difference is I don't think I've ever used SWP_SHOWWINDOW in mine.
-
Re: making a form "always on top"
In the interest of trying anything, as opposed to just giving up, here is the helper function I've been using since last year:
Code:
Private Declare Function SetWindowPos Lib "user32" (ByVal hwnd As Long, ByVal hWndInsertAfter As Long, ByVal X As Long, ByVal Y As Long, ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long
' Set/unset a form as AlwaysOnTop
Public Sub SetAlwaysOnTop(ByVal hwnd As Long, Optional ByVal AlwaysOnTop As Boolean = True)
Const SWP_NOSIZE = &H1
Const SWP_NOMOVE = &H2
Const SWP_SHOWWINDOW = &H40
Const HWND_NOTOPMOST = -2
Const HWND_TOPMOST = -1
If AlwaysOnTop Then
SetWindowPos hwnd, HWND_TOPMOST, 0&, 0&, 0&, 0&, SWP_NOMOVE Or SWP_NOSIZE Or SWP_SHOWWINDOW
Else
SetWindowPos hwnd, HWND_NOTOPMOST, 0&, 0&, 0&, 0&, SWP_NOMOVE Or SWP_NOSIZE Or SWP_SHOWWINDOW
End If
End Sub
Edge, maybe post your library function too, just so he can try it?
-
1 Attachment(s)
Re: making a form "always on top"
Mods, I'm intentionally violating an explicit board rule here, and for that I apologize. I've attached a bare-bones project that works for me, including the compiled exe it makes. I've reported this post.
deathfxu, run the exe on your computer and see if it works. (The delay is 200ms.) If so, I guess that means your compiler isn't working right. (?!)
-
Re: making a form "always on top"
Quote:
Originally Posted by
Ellis Dee
Edge, maybe post your library function too, just so he can try it?
K,
Code:
Option Explicit
'ModStayOnTop_No_Focus.bas
Private Declare Function SetWindowPos Lib "user32" (ByVal hwnd As Long, ByVal hWndInsertAfter As Long, ByVal x As Long, ByVal y As Long, ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long
Private Const HWND_TOPMOST = -1
Private Const HWND_NOTOPMOST = -2
Private Const SWP_NOSIZE = 1
Private Const SWP_NOMOVE = 2
Private Const SWP_NOACTIVATE = &H10
Private Const FLAGS = SWP_NOMOVE Or SWP_NOSIZE Or SWP_NOACTIVATE
Public Sub StayOnTop(LHwnd As Long, OnTop As Boolean)
If OnTop = True Then
SetWindowPos LHwnd, HWND_TOPMOST, 0, 0, 0, 0, FLAGS
Else
SetWindowPos LHwnd, HWND_NOTOPMOST, 0, 0, 0, 0, FLAGS
End If
End Sub
-
Re: making a form "always on top"
For me, I have found that the standard "always on top" code doesnt work if you minimize your "on top" form. So my solution was to place the api call in the forms "Form_Resize" event. No timer needed.
-
Re: making a form "always on top"
Well I didn't write this code to do this, that is why I cannot comment on this. But you can go and private message: Ellis Dee for the source code of the top most window.
-
Re: making a form "always on top"
How about reinstalling your version of VB6 that might probably work, even more so than the code we are giving you.
-
Re: making a form "always on top"
Ellis Dee, in the project you attached the timer was calling the command every 200ms, and did work just like the one I created the same way. When I made the Timer set it's Enabled to False after it proc'd once, it did not stay on top as desired.
But fascinating results here...
RobDog, I tried putting the code in the Form_Resize sub and it worked! But only after manually resizing the form.
So I also added the command to Form_Load again, and it still didn't work till I manually resized the form (I even tried manually calling Form_Resize in Form_Load, to no avail). It's as though the command only works "forever" if it triggers by me manually doing something while the program is running.
In all my years of programming i've never seen anything like this! This is crazy, lol.
-
Re: making a form "always on top"
Okay, this is pretty funny, but at the moment I have a timer on interval 100 that loops until the user does anything with the form, then whatever they do (click, dblclick, resize, etc) that sub calls the command and turns off the timer, lol.
Somehow it works perfect, lol. I wish I knew what is causing it to only work forever on manually triggered events though. :)
-
Re: making a form "always on top"
What I do in this kind of situation is have "Me.Show" then "Me.Refresh" (which could arguably be DoEvents) at the end of Form_Load, followed by the code that affects the form (in this case, the "always on top" code).
That way the visible aspect of the form will exist, and the hWnd should be valid.
-
Re: making a form "always on top"
Oddly enough, that didn't work.
The only thing we haven't ruled out at this point is if there is a full moon out. ><
Edit: I don't think it's just an issue of the hWnd being valid or the timer method would have worked. Not sure what it could be though.
-
Re: making a form "always on top"
Quote:
Originally Posted by
deathfxu
Ellis Dee, in the project you attached the timer was calling the command every 200ms, and did work just like the one I created the same way. When I made the Timer set it's Enabled to False after it proc'd once, it did not stay on top as desired.
But fascinating results here...
RobDog, I tried putting the code in the Form_Resize sub and it worked! But only after manually resizing the form.
So I also added the command to Form_Load again, and it still didn't work till I manually resized the form (I even tried manually calling Form_Resize in Form_Load, to no avail). It's as though the command only works "forever" if it triggers by me manually doing something while the program is running.
In all my years of programming i've never seen anything like this! This is crazy, lol.
Sorry, forgot to say that to initialize it, place another call in the Form_Load event. Then it will work like expected and when minimized/restored it will continue to work. :)
-
Re: making a form "always on top"
Quote:
Originally Posted by
deathfxu
Ellis Dee, in the project you attached the timer was calling the command every 200ms
Yeah, heh, oops. Like five lines of code in the whole project and I still forgot a major piece of the puzzle. Not my best effort.
-
Re: making a form "always on top"
RobDog, the problem is that for whatever reason the command only brings the window to the front the instant that I call the command SetWindowPos, except if it's in a subroutine of an event that is manually triggered by the user. (Yes, odd as it sounds.) Which means I can't put it in Form_Load, in a Timer, or anything else that triggers automatically.
Ellis Dee, no worries. :)
-
1 Attachment(s)
Re: making a form "always on top"
Maybe Im missing something but I whipped this up to show that if its automatically set or manually invoked it still works. Maybe you have a different scenerio?
Code:
Option Explicit
Private Declare Function SetWindowPos Lib "user32" ( _
ByVal hwnd As Long, _
ByVal hWndInsertAfter As Long, _
ByVal x As Long, _
ByVal y As Long, _
ByVal cx As Long, _
ByVal cy As Long, _
ByVal wFlags As Long _
) As Long
Private Const HWND_TOPMOST As Long = -1
Private Const HWND_NOTOPMOST As Long = -2
Private Const SWP_NOSIZE As Long = 1
Private Const SWP_NOMOVE As Long = 2
Private Const SWP_NOACTIVATE As Long = &H10
Private Const FLAGS As Long = SWP_NOMOVE Or SWP_NOSIZE Or SWP_NOACTIVATE
Private mlState As Long
Private Sub OnTop()
SetWindowPos Me.hwnd, mlState, 0, 0, 0, 0, FLAGS
End Sub
Private Sub Command1_Click()
If mlState = HWND_TOPMOST Then
mlState = HWND_NOTOPMOST
Else
mlState = HWND_TOPMOST
End If
OnTop
Me.Label1.Caption = "TopMost State: " & mlState
End Sub
Private Sub Form_Load()
mlState = HWND_TOPMOST
OnTop
Me.Label1.Caption = "TopMost State: " & mlState
End Sub
Private Sub Form_Resize()
OnTop
Me.Label1.Caption = "TopMost State: " & mlState
End Sub
-
Re: making a form "always on top"
The Form_Load call is not making it stay on top. When I resize the form, it does stay on top permanently. When I click on the button the first time, it continues not being on top. But when I click on it again, it will stay on top until I click the button again, at which point it loses "on top" again.
=P
-
Re: making a form "always on top"
Ok I started up the app. Its automatically set to topmost. I resized the form and brought other windows into active and the form remained topmost. I minimized it, restored it, resized it and it still remained topmost :confused:
Button first click is HWND_NOTOPMOST ;)
-
Re: making a form "always on top"
Yeah, my computer is possessed. "Yay" for workarounds. =P
Thanks tons guys.