I only have basic VBA knowledge. Trying to find a way to make the user choice between two value "internal" or "external" then depending on the results it would run one part of the code or another part.
What is the best way to achieve this?
I have started to create a user form, but how can get back the value type_trade back into the sub and then use it for a if then statement?
Private Sub External_Click()
Dim type_trade As String
type_trade = "external"
End Sub
Private Sub Internal_B2B_Click()
Dim type_trade As String
type_trade = "Internal_B2B"
End Sub
Private Sub UserForm_Click()
End Sub
One way to achieve this is as follows:
Private type_trade As String
Private Sub External_Click()
type_trade = "external"
End Sub
Private Sub Internal_B2B_Click()
type_trade = "Internal_B2B"
End Sub
Private Sub SomeOtherPoint()
If type_trade = "Internal_B2B" Then
'do something
End If
End Sub
Related
This question already has answers here:
Return a value from a userform
(2 answers)
Closed 23 days ago.
I am new to the board. I have a module in VBA for Excel and an associated user form with 4 CommandButtons. I call the user form with frmSelect.Show. The user is to pick on 1 of the 4 Command buttons and then a value is assigned to a variable that I want to pass to the module. This way I can tell which CommandButton was activated. I cannot seem to figure out how to pass a variable as the variable always comes back to the module as a null (0).
This is the module code:
Sub BumpGenerator()
Dim Pattern As Integer
frmSelect.Show
If Pattern = 1 then
Do some stuff
End If
If Pattern = 2 then
Do some other stuff
End If
If Pattern = 3 then
Do some other stuff
End If
If Pattern = 4 then
Do this stuff
End If
End Sub
This is the code in the user form:
Private Sub CommandButton1_Click()
Pattern = 1
frmSelect.Hide
End Sub
Private Sub CommandButton2_Click()
Pattern = 2
frmSelect.Hide
End Sub
Private Sub CommandButton3_Click()
Pattern = 3
frmSelect.Hide
End Sub
Private Sub CommandButton4_Click()
Pattern = 4
frmSelect.Hide
End Sub
I have tried using:
'Public Pattern As Integer' above my module
Passing Pattern as a variable using 'BumpGenerator(Pattern As Integer)'
Using 'Call BumpGenerator(Pattern)' in the user form
Using 'BumpGenerator Value:=Pattern'
but none of those options changed my null.
Thank you for any replies
Forms are just a special type of class so you can do with forms anything you can do with a class.
In your userform define a UDT which holds the values of you module level variables.
Private Type State
Pattern as Long
End Type
Private s as State
Private Sub CommandButton1_Click()
s.Pattern = 1
Me.Hide
End Sub
Private Sub CommandButton2_Click()
s.Pattern = 2
Me.Hide
End Sub
Private Sub CommandButton3_Click()
s.Pattern = 3
Me.Hide
End Sub
Private Sub CommandButton4_Click()
s.Pattern = 4
Me.Hide
End Sub
Public Property Get Pattern() as long
Pattern = s.Pattern
End Property
' and then in your module
Sub BumpGenerator()
frmSelect.Show
' You don't lose access to the form just because you've hidden it.
Select Case frmSelect.Pattern
Case 1
Do some stuff
Case 2
Do some other stuff
Case 3
Do some other stuff
Case 4
Do this stuff
End Select
End Sub
By the way, you should be aware that you are making a classic newbie mistake as you are using the default instance of frmSelect rather than creating a specific instance of the form. This is why you can use frmSelect.Hide rather than Me.Hide.
Its much better (in the longer run) to create your own instances of forms.
Dim mySelect as frmSelect
Set mySelect = New frmSelect
etc....
I'd also suggest that you install the free and fantastic Rubberduck addin for VBA and pay attention to the Code Inspections
If you declare the variable Pattern global than your code works.
I would also recommend to have a look at the scoping rules of vba.
User-Form modul
Option Explicit
Private Sub CommandButton1_Click()
Pattern = 1
BumpGenerator
End Sub
Private Sub CommandButton2_Click()
Pattern = 2
BumpGenerator
End Sub
Private Sub CommandButton3_Click()
Pattern = 3
BumpGenerator
End Sub
Private Sub CommandButton4_Click()
Pattern = 4
BumpGenerator
End Sub
Standard modul
Option Explicit
Global Pattern As Integer
Sub BumpGenerator()
Debug.Print Pattern
frmselect.Hide
End Sub
I have a userForm (mappingGuide) that allows user to pick a smartyTag from a list of more user-friendly names.
I have a second user-form (conditionalBuilder) that I would like to call this userForm upon double-clicking a text field so that a user can lookup which smartyTag to apply (in case they don't know).
So logic, is:
open conditionalBuilder
double-click Field text box
mappingGuide opens
pick a smartytag from listbox
fill smartytag value into field text-box in conditionalBuilder
unload mappingGuide
The issue I think I having with completing the requirement is that when I load the forms themselves I cannot find a way to set the text of the fieldName textbox of the loaded instance of conditionalBuilder (see last code block below). I've been searching around, but cannot figure it out.
Here is relevant code:
conditionalBuilder loads from Custom UI ribbon
Sub RunCode(ByVal Control As IRibbonControl)
Select Case Control.ID
Case Is = "mapper": LoadMappingGuide
Case Is = "conditional": LoadConditionalBuilder
End Select
End Sub
Sub LoadConditionalBuilder()
Dim conditionalForm As New conditionalBuilder
conditionalForm.Show False
End Sub
double-click event of fieldName then loads mappingGuide
Private Sub fieldName_DblClick(ByVal Cancel As MSForms.ReturnBoolean)
Me.hide
Dim pickField As New mappingGuide
pickField.Show False
End Sub
smartTag listbox click event then attempts to place selection into fieldName (or selection if form not loaded)
Private Sub smartTagList_Click()
If smartTagList.ListIndex > -1 And smartTagList.Selected(smartTagList.ListIndex) Then
Dim smartyTag As String
smartyTag = smartTagList.List(smartTagList.ListIndex, 2)
If isUserFormLoaded(conditionalBuilder.Name) Then
'*** ---> below is my issue how to reference instance of form
conditionalBuilder.fieldName.Text = smartyTag
conditionalBuilder.Show
Else
Selection.Range.Text = smartyTag
End If
End If
Unload Me
End Sub
If there is a better set-up that would be great to know too. I have the forms separate because there's a couple of levels a user can create tags with.
This is how I would do it, a bit of overkill but in case of multiple forms it will be beneficial.
Module 1:
Option Explicit
Sub test()
frmMaster.Show False
End Sub
Form 1 : frmMaster:
Option Explicit
'/ Declare with events
Dim WithEvents frmCh As frmChild
Private Sub TextBox1_DblClick(ByVal cancel As MSForms.ReturnBoolean)
handleDoubleClick
End Sub
Sub handleDoubleClick()
If frmCh Is Nothing Then
Set frmCh = New frmChild
End If
frmCh.Show False
End Sub
'/ Handle the event
Private Sub frmCh_cClicked(cancel As Boolean)
Me.TextBox1.Text = frmCh.bChecked
End Sub
Form 2: frmChild:
Option Explicit
Event cClicked(cancel As Boolean)
Private m_bbChecked As Boolean
Public Property Get bChecked() As Boolean
bChecked = m_bbChecked
End Property
Public Property Let bChecked(ByVal bNewValue As Boolean)
m_bbChecked = bNewValue
End Property
Private Sub CheckBox1_Click()
Me.bChecked = Me.CheckBox1.Value
'/ Raise an event when something happens.
'/ Caller will handle it.
RaiseEvent cClicked(False)
End Sub
You can do this with a presenter class which controls userform instances and pass values between them. I mocked up something similar to give you an idea.
Presenter. This is a class module which creates the userforms, controls their scope, and catches the event thrown by the
ConditionalBuilder. It makes it super easy to pass values between
userforms.
Private WithEvents CB As ConditionalBuilder
Private MG As MappingGuide
Public Sub ShowCB()
Set CB = New ConditionalBuilder
CB.Show vbModal
End Sub
Private Sub CB_ShowMappingGuide()
Set MG = New MappingGuide
MG.Show vbModal
CB.UpdateTB1 Value:=MG.SmartTag
End Sub
ConditionalBuilder.
This has a simple function to update your textbox and also an event which raises actions in the presenter.
Public Event ShowMappingGuide()
Public Function UpdateTB1(Value As String)
TextBox1.Value = Value
End Function
Private Sub TextBox1_DblClick(ByVal Cancel As MSForms.ReturnBoolean)
RaiseEvent ShowMappingGuide
End Sub
MappingGuide.
The Type and Property could be overkill since we just want one value from the mapping guide but it's still good practice.
Private Type TView
Tag As String
End Type
Private this As TView
Public Property Get SmartTag() As String
SmartTag = this.Tag
End Property
Private Sub UserForm_Initialize()
Tags.List = Array("a", "b", "c")
End Sub
Private Sub Tags_Click()
this.Tag = Tags.List(Tags.ListIndex, 0)
Me.Hide
End Sub
I have one final Standard Module which creates the Presenter. This is what you'd hook up to your ribbon.
Public Sub ShowProject()
With New Presenter
.ShowCB
End With
End Sub
Step 1 (double click text field)
Step 2 (selecting "b")
Step 3 (result)
I actually solved it by placing the below block inside the IF where I check for the form being loaded and I will leave open for better answers, if there are any.
Dim uForm As Object
For Each uForm In VBA.UserForms
If uForm.Name = conditionalBuilder.Name Then
uForm.fieldName.Text = smartyTag
uForm.Show
End If
Next
Prehistory
I have read the best practises for creating a form, concerning the fact that one should always refer to an object of the form and not the form itself. Thus, I have decided to build a boiler-plate form for myself.
The problem
Everything ran smoothly, until the moment I have decided to close the form with the top right red X. It closes ok. But then, when I try to open the form again, I get this runtime error:
The error is on objPresenter.Show (see the code below). Obviously, it does not enter in the if above. But the problem is that the closing from the X does not work fine. When I close the form from the End button, anything works. And even, if I copy the code for the closing from the btnEnd to UserForm_QueryClose it still does not work the same.
The form
Thus, I have a modMain, frmMain and clsSummaryPresenter, which all take care of the form. I start the code from modMain
My form looks like this:
It has btnRun, btnExit, lblInfo. The name of the class is frmMain.
The code
In frmMain:
Option Explicit
Public Event OnRunReport()
Public Event OnExit()
Public Property Get InformationText() As String
InformationText = lblInfo.Caption
End Property
Public Property Let InformationText(ByVal value As String)
lblInfo.Caption = value
End Property
Public Property Get InformationCaption() As String
InformationCaption = Caption
End Property
Public Property Let InformationCaption(ByVal value As String)
Caption = value
End Property
Private Sub btnRun_Click()
RaiseEvent OnRunReport
End Sub
Private Sub btnExit_Click()
RaiseEvent OnExit
End Sub
Private Sub UserForm_QueryClose(CloseMode As Integer, Cancel As Integer)
If CloseMode = vbFormControlMenu Then
Cancel = True
Hide
'Even if I change the two lines above with this the error happens:
'RaiseEvent OnExit
'However, if I simply write END in stead of those two lines
'anything works quite ok...
'but that is a bit brutal.
End If
End Sub
In clsSummaryPresenter
Option Explicit
Private WithEvents objSummaryForm As frmMain
Private Sub Class_Initialize()
Set objSummaryForm = New frmMain
End Sub
Private Sub Class_Terminate()
Set objSummaryForm = Nothing
End Sub
Public Sub Show()
If Not objSummaryForm.Visible Then
objSummaryForm.Show vbModeless
Call ChangeLabelAndCaption("Press Run to Start", "Starting")
End If
With objSummaryForm
.Top = CLng((Application.Height / 2 + Application.Top) - .Height / 2)
.Left = CLng((Application.Width / 2 + Application.Left) - .Width / 2)
End With
End Sub
Public Sub Hide()
If objSummaryForm.Visible Then objSummaryForm.Hide
End Sub
Public Sub ChangeLabelAndCaption(strLabelInfo As String, strCaption As String)
objSummaryForm.InformationText = strLabelInfo
objSummaryForm.InformationCaption = strCaption
objSummaryForm.Repaint
End Sub
Private Sub objSummaryForm_OnRunReport()
MainGenerateReport
Refresh
End Sub
Private Sub objSummaryForm_OnExit()
Hide
End Sub
Public Sub Refresh()
With objSummaryForm
.lblInfo = "Ready"
.Caption = "Task performed"
End With
End Sub
In modMain
Option Explicit
Private objPresenter As clsSummaryPresenter
Public Sub MainGenerateReport()
objPresenter.ChangeLabelAndCaption "Starting and running...", "Running..."
GenerateNumbers
End Sub
Public Sub GenerateNumbers()
Dim lngLong As Long
Dim lngLong2 As Long
tblMain.Cells.Clear
For lngLong = 1 To 4
For lngLong2 = 1 To 1
tblMain.Cells(lngLong, lngLong2) = lngLong * lngLong2
Next lngLong2
Next lngLong
End Sub
Public Sub ShowMainForm()
If (objPresenter Is Nothing) Then
Set objPresenter = New clsSummaryPresenter
End If
objPresenter.Show
End Sub
The question
Once again, why I cannot close the form with the red X? I can substitute the code in UserForm_QueryClose with End but that is a bit brutal. Any ideas?
Changing the form's mode from vbModeless to vbModal gives you an earlier and more informative failure:
The problem seems to be because the Cancel = True assignment in the QueryClose handler, isn't working for some reason.
The signature for the QueryClose handler is as follows:
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
Yours is:
Private Sub UserForm_QueryClose(CloseMode As Integer, Cancel As Integer)
You should never type these handler signatures manually yourself - instead, use the drop-down in the codepane's top-right corner, and have the VBE generate the handler stubs for you:
That way your handler signatures will always match the interface they're for.
VBA doesn't really care about parameter names in handlers: the way the runtime matches a handler signature is by matching the parameter indices and their types, against the expected ones. Since both QueryClose parameters are Integer values, inverting them compiles just fine - except when you set Cancel = True, what the runtime sees is that you've assigned CloseMode = -1 and left the Cancel parameter alone.
Which means your form doesn't cancel its close, and thus the object gets destroyed every time.
Invert the parameters in your QueryClose handler, and everything works perfectly fine and exactly as intended.
Calling the form like so works just fine for me:
Option Explicit
dim mfrmMain as ufMain
Sub ShowMainForm2()
If ufMain Is Nothing Then
Set ufMain = New mfrmMain
End If
mfrmMain.Show vbModeless
End Sub
I have created a TextBox1 within my UserForm.
I have create a Sub called
Sub TextBox1_Enter()
End Sub
where by clicking the textbox I want to open the DateTimePicker control to choose a date, and after the date is chosen the chosen date should be the TextBox1.Value
I have the DateTimePicker from mscomct2.ocx
I really don't figure out how to call the control; any tips with code and a good explanation anyone?
I'm not sure if this is exactly what you are looking for but you could take a look as this. It is very well explained.
My goal was to have an empty DatePicker at form startup, and was told to use a textbox to load the DTPicker upon clicking.
But I found this solution that keep the DTPicker Value empty as form startup
Private Sub DTPicker1_CloseUp()
FormatDTPicker
End Sub
Private Sub DTPicker1_Format(ByVal CallbackField As String, FormattedString As String)
If CallbackField = "X" Then FormattedString = ""
End Sub
Private Sub DTPicker1_MouseDown(ByVal Button As Integer, ByVal Shift As Integer, ByVal_
x As stdole.OLE_XPOS_PIXELS, ByValy As stdole.OLE_YPOS_PIXELS)
With DTPicker1
If .Value = vbNull Then
.Value = Now
End If
End With
End Sub
Private Sub UserForm_Initialize()
DTPicker1.Value = vbNull
FormatDTPicker
End Sub
Private Sub FormatDTPicker()
With DTPicker1
If .Value = vbNull Then
.Format = dtpCustom
.CustomFormat = "X"
Else
.Format = dtpShortDate
End If
End With
End Sub
http://www.mrexcel.com/forum/excel-questions/666685-dtpicker-value-null.html
I search about this in the forum and found some answers but did not work for me.
I have two UserForms.
In the first one, I give a value to a variable called Word.
In the second one, I have a Label that I need the caption to become the variable Word.
Example:
Public Word as String
Private Sub Userform1_Activate
Word = "Today Is Saturday"
End Sub
Private Sub Userform2_Activate
Label1.Caption = Word
End Sub
But this does not work. The Label caption gets Zero for value.
Could anybody help me on this?
Thanks.
First Form
Private Sub CommandButton5_Click()
Db = "C:\Users\Desktop\db.txt"
Set File1 = CreateObject("Scripting.FileSystemObject")
Set File2 = File1.OpenTextFile(Db, 1)
Do Until File2.AtEndOfStream
If (File2.Readline = TextBox1) Then Exit Do
If File2.AtEndOfStream Then WordNotFound.Show
If File2.AtEndOfStream Then TextBox1.Value = ""
If File2.AtEndOfStream Then Exit Sub
Loop
Word = File2.Readline
MsgBox Word
TextBox1.Value = ""
End Sub
Second Form
Private Sub UserForm_Click()
Label1.Caption = Word
End Sub
As I said in my comment, that your method should work. Here is the test code that I tried
1- In Module1
Public Word As String
2- Create 2 user forms - UserForm1 and UserForm2
2a- In UserForm1
Private Sub UserForm_Activate()
Word = "This is Saturday"
End Sub
2b- In UserForm2
Private Sub UserForm_Activate()
Label1.Caption = Word
End Sub
3- Then in ThisWorkbook
Private Sub Workbook_Open()
UserForm1.Show
UserForm2.Show
End Sub
So when you close UserForm1, the UserForm2 would be displayed as below