Robert Crandal said:
Sure, I'll try to explain.....
I was looking for a popup that: 1) Stays visible to the user
as they work on their excel spreadsheet, and 2) I also wanted
the userframe to still remain visible even if Excel is minimized
or if they switch to a different application.
Keep in mind, I want the two above conditions to happen
almost automatically, because I dont want my users to spend
time looking for the popup userform. (BTW, the
"ThunderDFrame" class popup is pushed to the background
as soon as editing occurs on the spreadsheet)
Let's clear this up, again. No need to call it a "ThunderDFrame class
popup". It's a Userfrom, it's always a Userform. The classname of a
Userform's window is "ThunderDFrame", it's always "ThunderDFrame", forget
about ThunderDFrame! The only thing that's ever changed in the previous
code examples is if the Userform-window is "attached" to Excel's main window
(default) or to nothing (or rather the desktop) and in effect free floating.
I think that's the 4th time, I'm running out of ideas !
Since Excel does not provide a Userform that has BOTH
of the above behaviors, I was going to try to invent a
work-around that involves using your code that toggles
the Userform "from the form's parent between Excel (default)
and the desktop".
So, if an edit occurs, I figured that I would add code to
Worksheet_Change() to show an "Excel default" Userframe,
because the default Userframe remains in the foreground
when editing happens on the spreadsheet. Once the edit is complete,
I figure that would be a good time to switch to the
"Desktop" userframe???
Is that a little bit more clear??
I think so!
OK, you want the form always displayed even if Excel is minimized. However
if the form is not attached to Excel, when user enters edit mode, or even
makes a new selection, Excel's window is brought to the front thereby hiding
the form (normal behaviour). Ideally it'd be handy if Excel exposed
Min/restore events, but it doesn't (actually there is a complex way but I
won't go into it here). So your idea to solve the dilema is to reset the
form's parent to Excel "before" going into edit mode, then set the form back
to the desktop again when user exits edit mode.
First problem, there is no direct way to trap in advance when user goes into
edit mode. And there are (at least?) three ways of doing that: key F2, just
start typing, or double click. Without going into very complicated
sub-classing of Windows events (risky in VBA) I can only think of trapping
the double-click.
Second problem, can only trap user exiting edit mode if user changes a cell
(pressing Enter without changing is enough). However if user presses Esc
there's no event.
With the above limitations in mind have a go with the following; code in
Thisworkbook module, a normal module, and a userform (no controls required)
Run ShowForm (ideally from Alt-F8 or a button)
Double click a cell to go into edit mode
Change a cell or just press Enter to trigger the change event
Minimizing Excel should leave the form still displayed
The code is quickly put together and no doubt many ways of improving it.
Overall though this is about as close as I think possible to having your
cake and eating it, in a clunky kind of way....
''' Thisworkbook module
Private mbExit As Boolean
Private Sub Workbook_SheetActivate(ByVal Sh As Object)
FormParent True, Sh.Name, True
End Sub
Private Sub Workbook_SheetBeforeDoubleClick(ByVal Sh As Object, _
ByVal Target As Range, Cancel As Boolean)
Call FormParent(bDesk:=False, sInfo:=Target.Address, bToFront:=True)
Application.SendKeys "{F2}"
End Sub
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
FormParent True, Target.Value
mbExit = True
End Sub
Private Sub Workbook_SheetDeactivate(ByVal Sh As Object)
FormParent True, ""
End Sub
Private Sub Workbook_SheetSelectionChange(ByVal Sh As Object, _
ByVal Target As Range)
If mbExit Then
mbExit = False
Else
FormParent True, Target.Address, True
End If
End Sub
''''''''''''' end Thisworkbook module
'' UserForm1 module
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
If CloseMode = 0 Or gbFrmLoaded Then
CloseForm
End If
End Sub
''''''''''''' end userform
''''' in a normal module
Option Explicit
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" ( _
ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function SetWindowLongA Lib "user32" _
(ByVal hwnd As Long, _
ByVal nIndex As Long, _
ByVal dwNewLong As Long) As Long
Private Declare Function SetForegroundWindow Lib "user32.dll" ( _
ByVal hwnd As Long) As Long
Private Declare Function GetForegroundWindow Lib "user32.dll" () As Long
Private Const GWL_HWNDPARENT As Long = -8
Private mhWndFrm As Long
Private mhWndApp As Long
Private mbDeskTop As Boolean
Public mFrm As UserForm1
Public gbFrmLoaded As Boolean
Sub ShowForm()
Set mFrm = UserForm1
gbFrmLoaded = True
mFrm.Caption = "UniqueCaption"
mhWndFrm = FindWindow("ThunderDFrame", mFrm.Caption)
mFrm.Caption = "Hello"
If Val(Application.Version) < 10 Then
mhWndApp = FindWindow("XLMAIN", Application.Caption)
Else
mhWndApp = Application.hwnd
End If
FormParent True, "New Form"
mFrm.Show vbModeless
End Sub
Sub CloseForm()
gbFrmLoaded = False
On Error Resume Next
Unload mFrm
On Error GoTo 0
Set mFrm = Nothing
mbDeskTop = False
mhWndFrm = 0
End Sub
Public Sub FormParent(bDesk As Boolean, sInfo As String, _
Optional bToFront As Boolean)
Dim h As Long, s As String
If gbFrmLoaded Then
On Error Resume Next
s = mFrm.Caption
If Err.Number Then
ShowForm
mbDeskTop = False
End If
On Error GoTo 0
Else
Exit Sub
End If
If mbDeskTop <> bDesk Then
mbDeskTop = bDesk
If mbDeskTop Then
h = 0&
Else
h = mhWndApp
End If
SetWindowLongA mhWndFrm, GWL_HWNDPARENT, h
End If
mFrm.Caption = IIf(mbDeskTop, "Desktop", "Excel") & " : " & sInfo
If bToFront Then
SetForegroundWindow mhWndFrm
End If
End Sub
'''' end normal module
Regards,
Peter T