Public Sub ShowMainForm()
With frmMain
.Show vbModeless
End With
End Sub
You don't want that With
block, it's redundant.
Public Sub ShowMainForm()
With New frmMain
.Show vbModeless
End With
End Sub
You don't want to do that with a vbModeless
form either - the instance will be destroyed quite immediately after being created.
For an object-oriented approach that uses a modeless form, I'd suggest you make the form a member of a dedicated "presenter" class:
Option Explicit
Private WithEvents summaryForm As frmMain ' <~ notice WithEvents ..I'll get to it.
Private Sub Class_Initialize()
Set summaryForm = New frmMain
End Sub
Private Sub Class_Terminate()
Set summaryForm = Nothing
End Sub
Public Sub Show()
If Not summaryForm.Visible Then summaryForm.Show vbModeless
End Sub
Public Sub Hide()
If summaryForm.Visible Then summaryForm.Hide
End Sub
Now, this "presenter" class shall be responsible for accessing the form; notice how it already hides the implementation detail of the modeless-ness to the outside world.
When the user clicks the btnRun
button, the form itself shouldn't be responsible for anything - so instead of calling MainGenerateReport
directly, we'll fire an event to tell the presenter class that it needs to do something about it:
Option Explicit
Public Event OnRunReport()
Public Event OnExit()
Private Sub btnRun_Click()
RaiseEvent OnRunReport
End Sub
Private Sub btnExit_Click()
RaiseEvent OnExit
End Sub
That way the form has no dependencies to other modules, and pretty much zero responsibilities.
Back to the presenter, we can handle these events:
Private Sub summaryForm_OnRunReport()
MainGenerateReport
Refresh
End Sub
Private Sub summaryForm_OnExit()
Hide
End Sub
Public Sub Refresh()
'todo
End Sub
This leaves the problem of MakeLabel
/Refresh
. I don't know what tblInfo
is, but I'm pretty sure it's not the form's concern. Really all it needs is some Range
or ListObject
that contains whatever information needs to go into that list - and instead of looping to .AddItem
and explicitly set each .ListItem
, you could use the control's .RowSource
property and avoid looping altogether; this CR Q&A shows how.
Once the presenter class is capable of providing a data source for the form's ListBox
(you'll have to verify it it actually binds to the source; if that's the case then you won't even need a refresh button, the list would just update itself).
That would be the Refresh
implementation.
The last step is to instantiate the presenter; as long as the presenter instance is alive, the encapsulated form instance lives - there's no need to explicitly Unload Me
anywhere.
Say you named the class SummaryPresenter
, then you could have it exist in global scope:
Option Explicit
Private presenter As SummaryPresenter
Public Sub ShowMainForm() ' macro attached to shortcut key
If presenter Is Nothing Then Set presenter = New SummaryPresenter
presenter.Show
End Sub
Since we made the OnRunReport
handler call Refresh
after MainGenerateReport
runs, the procedure no longer needs to call it explicitly. Or, if it does need to (hard to tell with just a little 'other code;
comment to work with), then it can do so by calling the Presenter
object's Refresh
method:
Public Sub MainGenerateReport()
' other code;
presenter.Refresh
' other code;
End Sub
This makes your code use the same instance of frmMain
all the time, while separating responsibilities into different [class] modules... which isn't much different from working against the default instance in the first place.
But then, everything boils down to why you would want a new instance every time - IMO if the form is a modeless "toolwindow" that you can show/hide while working in Excel, then it's objectively better (more efficient) to avoid initializing it everytime you want to show it... just like it's more efficient to avoid initializing the listbox columns everytime you refresh it ;-)
MainGenerateReport
need to callfrmMain.MakeLabel
? What's theother code
doing? \$\endgroup\$MainGenerateReport
is uniting a few excel files together. In thefrm.MakeLabel
, there is information about the total number of rows of the newly created file and other relevant information, for the operation carried out. Something likeSuccessfully carried out
,1000 rows are added
etc. \$\endgroup\$MakeLabel
it would probably work. However, it will not work at the end, when the form stays and displays information. Then it is closed manually by the user - either through the X or through the escape key, which runs currently withbtnExit_Click
. \$\endgroup\$