Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to display user form in IDE instead of host app?

I created a userform in an *.xlam add-in and created a new commandbar and button in the IDE, but when I click the button, the user form is opened in Excel, and focus is forced away from the IDE. Is there a way to open the user form in the IDE instead of the host application without resorting to a .Net COM Add-in?

Here is the code that creates the commandbar and button and handles the button click event.

Option Explicit

Public WithEvents cmdBarEvents As VBIDE.CommandBarEvents

Private Sub Class_Initialize()
    CreateCommandBar
End Sub

Private Sub Class_Terminate()
    Application.VBE.CommandBars("VBIDE").Delete
End Sub

Private Sub CreateCommandBar()

    Dim bar As CommandBar
    Set bar = Application.VBE.CommandBars.Add("VBIDE", MsoBarPosition.msoBarFloating, False, True)
    bar.Visible = True

    Dim btn As CommandBarButton
    Set btn = bar.Controls.Add(msoControlButton, , , , True)
    btn.Caption = "Show Form"
    btn.OnAction = "ShowForm"
    btn.FaceId = 59

    Set cmdBarEvents = Application.VBE.Events.CommandBarEvents(btn)

End Sub

Private Sub cmdBarEvents_Click(ByVal CommandBarControl As Object, handled As Boolean, CancelDefault As Boolean)

    CallByName Me, CommandBarControl.OnAction, VbMethod

End Sub

Public Sub ShowForm()
    Dim frm As New UserForm1
    frm.Show
End Sub

P.S. You may need this line of code to remove the commandbar...

Application.VBE.CommandBars("VBIDE").Delete
like image 541
RubberDuck Avatar asked Nov 03 '14 20:11

RubberDuck


1 Answers

Here is an alternative.

Put a button on your user form. For demonstration purpose, I am using this

enter image description here

Next put this code in the userform

Private Sub CommandButton1_Click()
    Unload Me
    Application.Visible = True
End Sub

Next paste this on top of your class module

Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" _
(ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Dim Ret As Long, ChildRet As Long

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 SWP_NOACTIVATE = &H10
Private Const SWP_SHOWWINDOW = &H40

Finally change your Sub ShowForm() to this

Public Sub ShowForm()
    Dim frm As New UserForm1
    Dim Ret As Long

    frm.Show vbModeless

    Application.Visible = False

    Ret = FindWindow("ThunderDFrame", frm.Caption)

    SetWindowPos Ret, HWND_TOPMOST, 100, 100, 250, 200, _
    SWP_NOACTIVATE Or SWP_SHOWWINDOW
End Sub

This is what you get

enter image description here

EDIT

More thoughts. To prevent the user from creating more userforms when the user clicks on smiley, change the Sub ShowForm() to the below. (Alternative would be to disable the smiley and re enable it when the form unload?)

Public Sub ShowForm()
    Dim frm As New UserForm1
    Dim Ret As Long
    Dim formCaption As String

    '~~> Set Userform Caption
    formCaption = "Blah Blah"

    On Error Resume Next
    Ret = FindWindow("ThunderDFrame", formCaption)
    On Error GoTo 0

    '~~> If already there in an instance then exit sub
    If Ret <> 0 Then Exit Sub

    frm.Show vbModeless
    frm.Caption = formCaption

    Application.Visible = False

    Ret = FindWindow("ThunderDFrame", frm.Caption)

    SetWindowPos Ret, HWND_TOPMOST, 100, 100, 250, 200, _
    SWP_NOACTIVATE Or SWP_SHOWWINDOW
End Sub
like image 99
Siddharth Rout Avatar answered Oct 16 '22 10:10

Siddharth Rout