Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations John Tel on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Making a form active 2

Status
Not open for further replies.

krinid

Programmer
Jun 10, 2003
356
CA
How can I make a form active? It's already on screen and visible, just not the active control. In particular, I don't want the current position or size of the form to change. But forms don't seem to have an activate method.

I tried:

Code:
ThisWorkbook.VBProject.VBComponents.Item (frmVariable.name).Activate
but for some reason this actually halts code execution, and on some occasions crashes Excel.

I suppose I could save the .left, .top, .height and .width values for the form, then do a .show and then restore them, but even with Application.ScreenUpdating = False is still shows the form in the middle of the screen for a instant or two before putting it back to where it belongs.
 
Well, the last is easiest. When StartUp property is set to 0 (manual), it is possible first set left/top and next show the form.
Afaik, you can activate window (also Userform window, FindWindow("ThunderXFrame",caption) to find it) with API.
When using VBIDE, UserForm's designer and module windows are objects, but for running VBA excel application they are a class used to instantiate userform objects. Some programmers suggest that the best way to run userform is to create an instance and refer to it: Dim oForm As UserForm1:Set oForm=New UserForm1,oForm.Show. oForm is a reference to this instance (if visible) in the program. There is no problem to create another instance, customize and show as a second form. When you refer in the form's module using 'Me', it always means current instance. Private (or public) variables in the form's module, work like form's properties, in the same way you can use them with Me.VarX (maybe some of that will be useful in solving the problem from the second thread, hope that this is only a question of proper refering to the userform instance - "dynamic" form. BTW, I wrote a FAQ on events, including simulation of control array, a little more consistent that in my other answer here).

combo
 
Chance,
Couldn't find the SetFocus property - where can it be found? I couldn't find in the property window, and get an error trying to access it directly from VBA.

combo,
1) What's the API call to activate a form? Is it ShowWindow ? Where can I find a list of available API calls?
2) You're a genius yet again! For some reason I've never noticed the StartUp property and that it can be set to manual and the position can be set before .show activates!
3) Your FAQ's are great! You should write one last one (Understand Events. V: Dynamic controls and their events) to touch on the dynamic stuff with a good example (like the one you showed me for dynamic buttons and forms). The example you included uses static buttons, which is also useful, but by including a dynamic example, that would put the icing on the cake.
 
Thanks, Krinid.

A code to moving focus between forms; 'Userform1' form and a commandbutton 'cmd1' with:

[tt]Public SecondForm As String

Private Sub cmd1_Click()
Putfocus FindWindow("ThunderDFrame", Me.SecondForm)
End Sub[/tt]

and a standard module:
[tt]Dim oForm1 As UserForm1, oForm2 As UserForm1

Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Declare Function Putfocus Lib "user32" Alias "SetFocus" (ByVal hwnd As Long) As Long

Sub ShowForms()
Set oForm1 = New UserForm1
With oForm1
.Caption = "First form"
.SecondForm = "Second form"
.Show vbModeless
End With
Set oForm2 = New UserForm1
With oForm2
.Caption = "Second form"
.SecondForm = "First form"
.Show vbModeless
End With
End Sub[/tt]

One of good places with API (API-guide to download):
combo
 
combo,
Works great. One question - what's "ThunderDFrame" refer to?
 
'ThunderDFrame' is a class name for VBA 6 userforms ('ThunderXFrame' for VBA5, in office 97).

BTW, you can also consider using:
[tt]Declare Function SetActiveWindow Lib "user32.dll" (ByVal hwnd As Long) As Long[/tt]
to activate form.

combo
 
This is fantastic combo! Wd!

I would like to take it one step further... Do you know of an API to force the userform to be SystemModal once it is active?

Or alternatively, to set the Form as Application Modal but attached to another application - perhaps Adobe Acrobat Reader or something?

I would be eternally grateful as i have been searching the forums for ages!!

Thanks
sugarflux
 
Sugarflux,
what is your goal? Userforms as a part of office application, can be shown as application modal (without argument or with vbModal) or modeless. You can emulate standalone application, you can add hWnd property for better window (API) management:

Private Declare Function FindWindow Lib "User32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long

Public hWnd As Long

Private Sub UserForm_Initialize()
Application.Visible = False
hWnd = FindWindow("ThunderDFrame", Me.Caption)
End Sub

Private Sub UserForm_Terminate()
Application.Visible = True
End Sub

AFAIK, system modal is not available in multitasking 32 bit environment. Without access to acrobat reader objects, only SendKeys and low level windows messaging can be available.

It would be easier to find answer by starting a new thread in this forum or API Forum711.

combo
 
Thanks Combo
Sorry - i should have started a new thread. In case similar minded individuals stumble across this thread while looking for this solution, i shall post what i have used...

PutFocus and SetActiveWindow were good to "select" the form, but as soon as the user clicks elsewhere the form is deactivated - and therefore, hidden behind other applications. This was proving difficult as the code i am using is run from an "invisible" window.

I wanted either System Modal (which isn't possible in Win2000+) or to be able to attach my form to other applications. The solution i have used isn't perfect - but does the job well enough (and flexible enough) for me. It sets the form as the Foreground Window and then sets it permanently as the Top Level window to disable other applications stealing focus.

I've broken this down to make it easier for beginners.

Here are the API calls to place outside of the procedure but in the same Window as the 'MakeFormActive' procedure below

Private Declare Function GetForegroundWindow Lib "user32" _
() As Integer

Private Declare Function GetWindowText Lib "user32" _
Alias "GetWindowTextA" _
(ByVal hwnd As Integer, _
ByVal lpString As String, _
ByVal nMaxCount As Integer) _
As Integer

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 Declare Function SetForegroundWindow Lib "user32" ( _
ByVal hwnd As Long _
) As Long

Private Declare Function GetWindow Lib "user32" _
(ByVal hwnd As Integer, _
ByVal uCmd As Integer) _
As Integer


Private Const SWP_NOMOVE = &H2
Private Const SWP_NOSIZE = &H1
Private Const HWND_TOPMOST = -1

'Here is the procedure to make your form active and "almost" system modal
Sub MakeFormActive()

Dim hWndApp As Long
Dim appCaption As String
Dim lngAppCap As Long

'First get the activewindow
hWndApp = GetForegroundWindow

'Loop through all active processes by starting with _
the active window and then going to the next
Do While hWndApp <> 0

'Set a blank string to extract the window caption _
into
appCaption = Space(255)

'Fill this blank string with the current window _
caption
lngAppCap = GetWindowText(hWndApp, appCaption, 255)

'Check there is a valid window caption to test
If Len(Trim(appCaption)) <> 0 And Asc(Trim(appCaption)) <> 0 Then

'Check if this is the window you're searching for
If Left(appCaption, 17) = "My Window Caption" Then

'Activate your form as "almost" system modal
SetWindowPos hWndApp, HWND_TOPMOST, myForm.Top, myForm.Left, 10, 10, SWP_NOMOVE + SWP_NOSIZE

'Set form as the foreground window
SetForegroundWindow hWndApp

End IF
End If

hWndApp = GetWindow(hWndApp, 2)
Loop

End Sub

'Add the below call to the Initialise or Activate section of your form
Sub Form_Activate()
MakeFormActive
End Sub

I hope this helps someone!

sugarflux
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top