I have a UserForm DataInput in the same VBA project as the module RunOB. These are in the Excel Project Benchmarking.xlsx. I have a command button on the DataInput form in which I would like the module RunOB to run when pressed. Additionally I am passing String arguments from the form to the module.
'Header of 'Run OB' Module
Sub OrganizeBenchmarks(bidNum As String, name As String, _
state As String, year As String, category As String)
The button click method is:
Private Sub CommandButton1_Click()
'...'
End Sub
If possible, it would also be helpful if I could set up a keyboard shortcut to open the DataInput UserForm while I was in the Excel project.
Seems pretty straightforward?
Private Sub CommandButton1_Click()
OrganizeBenchmarks "your", "arguments", "would", "go", "here"
End Sub
Something for you to help developing your own code .........
'Public enum type to add a set of particular vbKeys to the standard key set
Public Enum typePressKeys
vbNoKey = 0
vbExitTrigger = -1
vbAnswerKey = 100
vbLaunchKey = 102
vbPrevious = 104
vbNext = 106
vbSpecialAccessKey = 108
End Enum
Public Sub OrganizeBenchmarks()
Dim stopLoop As Boolean, listOfYears As Variant, bidNum As String, name As String, state As String, year As String, category As String
'For example
listOfYears = Array(2017, 2018, 2019, 2020, 2021, 2022)
stopLoop = False
Load DataInputForm 'Assuming this is the name of your UserForm
With DataInputForm 'Assuming that this name would be an input control in your UserForm
.yearCB.List = listOfYears 'comboboxList control
.yearCB.ListIndex = 2
.Tag = vbNoKey
End With
DataInputForm.Show
Do
If DataInputForm.Tag = vbOK Then
'I have assumed you would use these names for input controls on your UserForm
bidNum = DataInputForm.bidNum_TextBox.Value
name = DataInputForm.name_TextBox.Value
state = DataInputForm.state_TextBox.Value
year = CStr(DataInputForm.yearCB.Value)
category = DataInputForm.category_TextBox.Value
Unload DataInputForm
stopLoop = True
ElseIf DataInputForm.Tag = vbCancel Then
Unload DataInputForm
Exit Sub
Else
stopLoop = False
End If
Loop Until stopLoop = True
'Place additional code here to take whatever actions
End Sub
Related
In the code I am posting, I am using a check box called "ACDS Test" and whenever it is checked it creates a sheet, then when it becomes unchecked it calls the upper function and deletes the sheet.
I am trying to add a message box that essentially works like a fail safe to ensure they want to delete the page. If they say they do not want to delete the page then I want the checkbox to stay checked.
For some reason I am getting this error message when I try to pass the value to make sure the checkbox stays checked and I cannot figure out why.
The error comes up on the line:
Sub ACDSTest_Click(CorrectValue As Integer)
And the specific error is: "Compile error: Procedure Declaration does not match description of event or procedure having the same name".
Any help is much appreciated! IF any more clarification is needed please feel free to ask!
Sub DeleteWorksheet(NameSheet As String)
Dim Ans As Long
Dim t As String
Dim CorrectValue As Integer
Dim i As Long, k As Long
k = Sheets.Count
Ans = MsgBox("Would you like to take this test off of the form?", vbYesNo)
Select Case Ans
Case vbYes
'Code reads through each page and finds one with corresponding name to string t
'Once it finds the correct page, it deletes it
For i = k To 1 Step -1
t = Sheets(i).Name
If t = NameSheet Then
Sheets(i).Delete
End If
Next i
CorrectValue = 0
Case vbNo
CorrectValue = 1
End Select
End Sub
Sub ACDSTest_Click(CorrectValue As Integer)
Dim NameSheet As String
Dim NameValue As String
NameSheet = "ACDS"
NameValue = "ACDS Test"
If ACDSTest.Value = True Then
CreateWorksheet (NameSheet), (NameValue)
Worksheets("Sheet1").Activate
Else
DeleteWorksheet (NameSheet)
If CorrectValue = 1 Then
ActiveSheet.Shapes("ACDS Test").ControlFormat.Value = 1
End If
End If
End Sub
The issue here is that the CorrectValue variable as you define it in DeleteWorksheet does not exist in the context of the
variable does not exist in context of the ACDSTest_Click subroutine. This is because variables defined within subroutines or functions are local to those functions. To correct this I would convert DeleteWorksheet to a function such as the below.
Further, the event that fires Private Sub ACDSTest_Click() cannot handle passing a value to that function, so changing it to Sub ACDSTest_Click(CorrectValue As Integer) causes an error.
Function DeleteWorksheet(ByVal SheetName As String) As Boolean
On Error GoTo SheetDNE
SheetName = Sheets(SheetName).Name 'Check if sheet exists w/o other objects
On Error GoTo 0
Select Case MsgBox("Would you like to take this test off of the form?", vbYesNo)
Case vbYes
Application.DisplayAlerts = False
Sheets(SheetName).Delete
Application.DisplayAlerts = True
DeleteWorksheet = True
Case Else: DeleteWorksheet = False
End Select
Exit Function 'Exit The Function w/o error
SheetDNE: 'Sheet Does Not Exist
MsgBox "The indicated sheet, " & SheetName & ", does not exist", vbOKOnly
End Function
And
Private Sub ACDSTest_Click()
Dim NameSheet As String
Dim NameValue As String
NameSheet = "ACDS"
NameValue = "ACDS Test"
If ACDSTest.Value = True Then
CreateWorksheet (NameSheet), (NameValue)
Worksheets("Sheet1").Activate
Else
If Not DeleteWorksheet(NameSheet) Then _
ActiveSheet.Shapes("ACDS Test").ControlFormat.Value = 1
End If
End Sub
I have a macro which run function (clear each named range depend ot application.caller.name) if radio button was clicked
Sub Clear_Click()
Dim s, f, arr
s = ActiveSheet.Shapes(Application.Caller).Name
arr = Array("NamedArray1", "NamedArray2", "NamedArray3", "NamedArray4")
Select Case s
Case "Clear7"
For i = LBound(arr) To UBound(arr)
ThisWorkbook.Worksheets("info").Range(arr(i)).value = ""
Next i
Case Else
f = arr(Right(s, 1) - 1)
ThisWorkbook.Worksheets("info").Range(f).value = ""
End Select
End Sub
It works ok.
Now i need to click Clear7 radio button from other function
So if i do
Sub test()
Application.Run ActiveSheet.Shapes("Clear7").OnAction
End Sub
I got error on s = ActiveSheet.Shapes(Application.Caller).Name as there are no Application.Caller i think.
So how to click radio button from other function?
If you're using Application.Caller but you want to run the code without someone needing to click the button then here's how you can do it.
NOTE: since Clear_Click has an argument, it won't show up in the "assign macro" list when attaching it to a button, but you can type its name directly in the box and that will work fine.
Sub Clear_Click(Optional callerName As String = "")
Dim s, f, arr, cn As String, i
Dim sht As Worksheet
cn = IIf(Len(callerName) > 0, callerName, Application.Caller)
'Debug.Print cn
Set sht = ThisWorkbook.Worksheets("info")
arr = Array("NamedArray1", "NamedArray2", "NamedArray3", "NamedArray4")
Select Case cn
Case "Clear7"
For i = LBound(arr) To UBound(arr)
sht.Range(arr(i)).Value = ""
Next i
Case Else
f = arr(Right(s, 1) - 1)
sht.Range(f).Value = ""
End Select
End Sub
Sub test()
ClickIt "Clear7"
End Sub
'run a macro attached to a shape and pass its name as a parameter
Sub ClickIt(sName As String)
Application.Run ActiveSheet.Shapes(sName).OnAction, sName
End Sub
I have 2 forms. Lets call the FormA and FormB. When a button is pressed in FormA I open formB from FormA. Then I call a function inside FormB that is supposed to update the text fields. When I do this none of the textboxes are filled with values, even though values are being assigned to them ( i can see this in debug mode).
But when I put the same code in the form_load event handler it works fine. Any ideas?
This is FormAs code:
Private Sub btnNew_Click()
[Form_Client Info].Modal = False
Call DoCmd.OpenForm("Client Info")
Call [Form_Client Info].SetValues(lstClients.Column(0, intIndex))
End Sub
and this is FormBs:
Public Sub SetValues(ByVal intID As Long)
Dim arrFields(0 To 8) As Variant
Dim arrValues(0 To 8) As Variant
For i = 1 To 9
arrFields(i - 1) = General.GetField(i, "Clients")
Next i
Call General.GetRecord2(arrFields, arrValues, "Clients")
txtPOBOX.Value = 3434 'arrValues(0)
txtFirstName.Value = arrValues(1)
txtLastName.Value = arrValues(2)
txtPhoneNumber.Value = arrValues(3)
txtStartDate.Value = arrValues(4)
txtEndDate.Value = arrValues(5)
cmbPlan.Value = arrValues(6)
cmbDuration.Value = arrValues(7)
txtPhoneBalance.Value = arrValues(8)
End Sub
As you have this line:
[Form_Client Info].Modal = False
it sounds like your form is saved as modal.
Try to specify the non-modal status when opening it:
Call DoCmd.OpenForm("Client Info", , , , , acWindowNormal)
I have a form named FrmDrvouchers. It contains some public subprocedures.
I call these subs from another form which opens from a form which is opened from FrmDrVouchers as a dialog.
When I open FrmDrvouchers directly, everything works. But when I call FrmDrvouchers from another project which is also part of this solution, its public subs don't work when I call them from another (dialog) form.
Here is the code of the Button Click from which I open FrmDrvouchers:
Dim FrmDrv As FrmDrVouchers = New FrmDrVouchers()
FrmDrv.Show()
This works, but those public subs don't. Why?
Thanks For ur response,
It just skip what i want to do, but not throws any Exceptions,
Now I m posting my Code,,, plz have a look on that,,
Here is my Main form's MenuStrip Button Click code :
Private Sub CashPaymentToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles CashPaymentToolStripMenuItem.Click
Dim DrVouchers As Transactions.FrmDebitVouchers = Transactions.New FrmDebitVouchers()
DrVouchers.Show()
End Sub
Here is the FrmDebitVouchers's Public Subs which are not working,,, in the sense that they skip the function which i have written but not throwing any Exception,,
Public Sub DrVoucherOPen(ByVal VoucherNo As Integer)
'Filling the Dataset with selected Voucher No to OPen the record
DebitVouchersTableAdapter.FillByVoucher(Flr12131DataSet.DebitVouchers, VoucherNo)
VoucherDateDateTimePicker.Enabled = False
End Sub
Public Sub DrVoucherBodyOPen(ByVal VoucherNo As Integer)
'---------Procedure to Open DrVouchersBody And to OPen it in Datagridview-------------'
'Getting the User No, and if it is admin then load fill dataset and allow user to edit the record
If GetUserNumber() = 1 Then
'Filling the dataset
DebitVouchersBodyTableAdapter.FillByVoucher(Flr12131DataSet.DebitVouchersBody, VoucherNo)
DrBodyDGV.DataSource = Nothing
Dim Sum As New Decimal
'Initializing the SerialNumbers variable
SerialNumbers = New List(Of Integer)
'Setting datagridview to opend record
For i = 0 To Flr12131DataSet.DebitVouchersBody.Rows.Count - 1
DrBodyDGV.Rows.Add()
DrBodyDGV.Rows(i).Cells(0).Value = Flr12131DataSet.DebitVouchersBody.Rows(i).Item("SerialNo")
DrBodyDGV.Rows(i).Cells(3).Value = Flr12131DataSet.DebitVouchersBody.Rows(i).Item("AccountNo")
DrBodyDGV.Rows(i).Cells(6).Value = Flr12131DataSet.DebitVouchersBody.Rows(i).Item("Debit")
DrBodyDGV.Rows(i).Cells(7).Value = Flr12131DataSet.DebitVouchersBody.Rows(i).Item("Narration")
'Getting serial No into List
SerialNumbers.Add(Flr12131DataSet.DebitVouchersBody.Rows(i).Item("SerialNo"))
'Getting Account Name into Datagridview
If Not Not IsNumeric(DrBodyDGV.Rows(i).Cells(3).Value) Then
Dim Qa As New Flr12131DataSetTableAdapters.QueriesTableAdapter
Dim StrAccountName = Qa.GetAccountName(DrBodyDGV.Rows(i).Cells(3).Value)
DrBodyDGV.Rows(i).Cells(5).Value = StrAccountName
Else
End If
Sum += DrBodyDGV.Rows(i).Cells(6).Value
Next
TxtTotal.Text = Sum
'Setting the controls properties for admin
DrBodyDGV.AllowUserToAddRows = True
DrBodyDGV.AllowUserToDeleteRows = True
DrBodyDGV.ReadOnly = False
BtnSave.Enabled = True
BtnDelete.Enabled = True
BtnPrint.Enabled = True
ToUpdate = True
Else
'If user is not admin then load all record and not allow user to modify it or delete
' Bounding the datagridview
Dim Sum As Decimal = 0
BtnSave.Enabled = False
DebitVouchersBodyTableAdapter.FillByVoucher(Flr12131DataSet.DebitVouchersBody, VoucherNo)
DrBodyDGV.DataSource = Flr12131DataSet.DebitVouchersBody
For i = 0 To DrBodyDGV.Rows.Count - 1
If Not Not IsNumeric(DrBodyDGV.Rows(i).Cells(3).Value) Then
Dim Qa As New Flr12131DataSetTableAdapters.QueriesTableAdapter
Dim StrAccountName = Qa.GetAccountName(DrBodyDGV.Rows(i).Cells(3).Value)
DrBodyDGV.Rows(i).Cells(5).Value = StrAccountName
Else
End If
Sum += DrBodyDGV.Rows(i).Cells(6).Value
Next
TxtTotal.Text = Sum
DrBodyDGV.AllowUserToAddRows = False
DrBodyDGV.AllowUserToDeleteRows = False
' DrBodyDGV.edit()
DrBodyDGV.ReadOnly = True
BtnSave.Enabled = False
BtnDelete.Enabled = False
BtnPrint.Enabled = True
End If
End Sub
Here is another the DrVouchersRecord form from which I call Public Subs:
Private Sub DrVouchersRecordDataGridView_CellDoubleClick(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) Handles DrVouchersRecordDataGridView.CellDoubleClick
Dim FrmDrVouchers As FrmDebitVouchers = New FrmDebitVouchers()
If FrmDrVouchers.DrBodyDGV.Rows.Count > 1 Then
Dim Ans As Integer
Ans = MsgBox("Unsaved changes will be lost, want to proceed", vbYesNo + vbInformation, "Alert")
If Ans = vbYes Then
Dim VoucherNo As New Integer
VoucherNo = DrVouchersRecordDataGridView.CurrentRow.Cells(0).Value
FrmDrVouchers.DrVoucherOPen(VoucherNo)
FrmDrVouchers.DrVoucherBodyOPen(VoucherNo)
Me.Close()
End If
Else
Dim VoucherNo As New Integer
VoucherNo = DrVouchersRecordDataGridView.CurrentRow.Cells(0).Value
FrmDrVouchers.DrVoucherOPen(VoucherNo)
FrmDrVouchers.DrVoucherBodyOPen(VoucherNo)
Me.Close()
End If
End Sub
My forms sequence is:
FrmMain is my main startUp form
After that FrmDebitVouchers Open on menustripButtonclick
After that DebitVouchersRecord is Open as Dialog from DrmDebitVouchers,,, and from these Public Subs are called
I Have added Refrence also
Waiting for ur answers,
This problem has hit many programmers coming from VB6 to VB.NET.
In your DataGridView_DoubleCellClick event you create a NEW instance of FrmDebitVouchers.
Then your code refers to property/methods/objects of this new INSTANCE, not of the original one created via CashPaymentToolStripMenuItem_Click. (Also note that this new instance is never showed on the screen, so you are sending/requesting changes to an hidden form instance)
Of course, the DrBodyDGV.Rows.Count is zero on this INSTANCE (referenced as FrmDrVouchers) because probably this INSTANCE has never been intialized like the first one.
Try to add a FrmDrVouchers.Show() after the creation and you will see the hidden SECOND INSTANCE of the form class FrmDebitVouchers.
To solve your problem, you need to pass the reference of the first FrmDebitVouchers instance to the DrVouchersRecord form (for example in the constructor or via a public property) and then use that reference instead of creating FrmDrVouchers
I'm using a large validation list on which a couple of vlookup() functions depend. This list is getting larger and larger. Is there a way to type the first letters of the list item I'm looking for, instead of manually scrolling down the list searching for the item?
I've done some Googling but this suggests that this is indeed possible in earlier versions of Excel, but not in Excel 2010. Hope you guys can help.
Here is a very good way to handle this (found on ozgrid):
Let's say your list is on Sheet2 and you wish to use the Validation List with AutoComplete on Sheet1.
On Sheet1 A1 Enter =Sheet2!A1 and copy down including as many spare rows as needed (say 300 rows total). Hide these rows and use this formula in the Refers to: for a dynamic named range called MyList:
=OFFSET(Sheet1!$A$1,0,0,MATCH("*",Sheet1!$A$1:$A$300,-1),1)
Now in the cell immediately below the last hidden row use Data Validation and for the List Source use =MyList
[EDIT] Adapted version for Excel 2007+ (couldn't test on 2010 though but AFAIK, there is nothing really specific to a version).
Let's say your data source is on Sheet2!A1:A300 and let's assume your validation list (aka autocomplete) is on cell Sheet1!A1.
Create a dynamic named range MyList that will depend on the value of the cell where you put the validation
=OFFSET(Sheet2!$A$1,MATCH(Sheet1!$A$1&"*",Sheet2!$A$1:$A$300,0)-1,0,COUNTA(Sheet2!$A:$A))
Add the validation list on cell Sheet1!A1 that will refert to the list =MyList
Caveats
This is not a real autocomplete as you have to type first and then click on the validation arrow : the list will then begin at the first matching element of your list
The list will go till the end of your data. If you want to be more precise (keep in the list only the matching elements), you can change the COUNTA with a SUMLPRODUCT that will calculate the number of matching elements
Your source list must be sorted
Here's another option. It works by putting an ActiveX ComboBox on top of the cell with validation enabled, and then providing autocomplete in the ComboBox instead.
Option Explicit
' Autocomplete - replacing validation lists with ActiveX ComboBox
'
' Usage:
' 1. Copy this code into a module named m_autocomplete
' 2. Go to Tools / References and make sure "Microsoft Forms 2.0 Object Library" is checked
' 3. Copy and paste the following code to the worksheet where you want autocomplete
' ------------------------------------------------------------------------------------------------------
' - autocomplete
' Private Sub Worksheet_SelectionChange(ByVal Target As Range)
' m_autocomplete.SelectionChangeHandler Target
' End Sub
' Private Sub AutoComplete_Combo_KeyDown(ByVal KeyCode As msforms.ReturnInteger, ByVal Shift As Integer)
' m_autocomplete.KeyDownHandler KeyCode, Shift
' End Sub
' Private Sub AutoComplete_Combo_Click()
' m_autocomplete.AutoComplete_Combo_Click
' End Sub
' ------------------------------------------------------------------------------------------------------
' When the combobox is clicked, it should dropdown (expand)
Public Sub AutoComplete_Combo_Click()
Dim ws As Worksheet: Set ws = ActiveSheet
Dim cbo As OLEObject: Set cbo = GetComboBoxObject(ws)
Dim cb As ComboBox: Set cb = cbo.Object
If cbo.Visible Then cb.DropDown
End Sub
' Make it easier to navigate between cells
Public Sub KeyDownHandler(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
Const UP As Integer = -1
Const DOWN As Integer = 1
Const K_TAB_______ As Integer = 9
Const K_ENTER_____ As Integer = 13
Const K_ARROW_UP__ As Integer = 38
Const K_ARROW_DOWN As Integer = 40
Dim direction As Integer: direction = 0
If Shift = 0 And KeyCode = K_TAB_______ Then direction = DOWN
If Shift = 0 And KeyCode = K_ENTER_____ Then direction = DOWN
If Shift = 1 And KeyCode = K_TAB_______ Then direction = UP
If Shift = 1 And KeyCode = K_ENTER_____ Then direction = UP
If Shift = 1 And KeyCode = K_ARROW_UP__ Then direction = UP
If Shift = 1 And KeyCode = K_ARROW_DOWN Then direction = DOWN
If direction <> 0 Then ActiveCell.Offset(direction, 0).Activate
AutoComplete_Combo_Click
End Sub
Public Sub SelectionChangeHandler(ByVal Target As Range)
On Error GoTo errHandler
Dim ws As Worksheet: Set ws = ActiveSheet
Dim cbo As OLEObject: Set cbo = GetComboBoxObject(ws)
Dim cb As ComboBox: Set cb = cbo.Object
' Try to hide the ComboBox. This might be buggy...
If cbo.Visible Then
cbo.Left = 10
cbo.Top = 10
cbo.ListFillRange = ""
cbo.LinkedCell = ""
cbo.Visible = False
Application.ScreenUpdating = True
ActiveSheet.Calculate
ActiveWindow.SmallScroll
Application.WindowState = Application.WindowState
DoEvents
End If
If Not HasValidationList(Target) Then GoTo ex
Application.EnableEvents = False
' TODO: the code below is a little fragile
Dim lfr As String
lfr = Mid(Target.Validation.Formula1, 2)
lfr = Replace(lfr, "INDIREKTE", "") ' norwegian
lfr = Replace(lfr, "INDIRECT", "") ' english
lfr = Replace(lfr, """", "")
lfr = Application.Range(lfr).Address(External:=True)
cbo.ListFillRange = lfr
cbo.Visible = True
cbo.Left = Target.Left
cbo.Top = Target.Top
cbo.Height = Target.Height + 5
cbo.Width = Target.Width + 15
cbo.LinkedCell = Target.Address(External:=True)
cbo.Activate
cb.SelStart = 0
cb.SelLength = cb.TextLength
cb.DropDown
GoTo ex
errHandler:
Debug.Print "Error"
Debug.Print Err.Number
Debug.Print Err.Description
ex:
Application.EnableEvents = True
End Sub
' Does the cell have a validation list?
Function HasValidationList(Cell As Range) As Boolean
HasValidationList = False
On Error GoTo ex
If Cell.Validation.Type = xlValidateList Then HasValidationList = True
ex:
End Function
' Retrieve or create the ComboBox
Function GetComboBoxObject(ws As Worksheet) As OLEObject
Dim cbo As OLEObject
On Error Resume Next
Set cbo = ws.OLEObjects("AutoComplete_Combo")
On Error GoTo 0
If cbo Is Nothing Then
'Dim EnableSelection As Integer: EnableSelection = ws.EnableSelection
Dim ProtectContents As Boolean: ProtectContents = ws.ProtectContents
Debug.Print "Lager AutoComplete_Combo"
If ProtectContents Then ws.Unprotect
Set cbo = ws.OLEObjects.Add(ClassType:="Forms.ComboBox.1", Link:=False, DisplayAsIcon:=False, _
Left:=50, Top:=18.75, Width:=129, Height:=18.75)
cbo.name = "AutoComplete_Combo"
cbo.Object.MatchRequired = True
cbo.Object.ListRows = 12
If ProtectContents Then ws.Protect
End If
Set GetComboBoxObject = cbo
End Function
Building on the answer of JMax, use this formula for the dynamic named range to make the solution work for multiple rows:
=OFFSET(Sheet2!$A$1,MATCH(INDIRECT("Sheet1!"&ADDRESS(ROW(),COLUMN(),4))&"*",Sheet2!$A$1:$A$300,0)-1,0,COUNTA(Sheet2!$A:$A))
Excel automatically does this whenever you have a vertical column of items. If you select the blank cell below (or above) the column and start typing, it does autocomplete based on everything in the column.
As other people suggested, you need to use a combobox. However, most tutorials show you how to set up just one combobox and the process is quite tedious.
As I faced this problem before when entering a large amount of data from a list, I can suggest you use this autocomplete add-in . It helps you create the combobox on any cells you select and you can define a list to appear in the dropdown.
=OFFSET(NameList!$A$2:$A$200,MATCH(INDIRECT("FillData!"&ADDRESS(ROW(),COLUMN(),4))&"*",NameList!$A$2:$A$200,0)-1,0,COUNTIF($A$2:$A$200,INDIRECT("FillData!"&ADDRESS(ROW(),COLUMN(),4))&"*"),1)
Create sheet name as Namelist. In column A fill list of data.
Create another sheet name as FillData for making data validation list as you want.
Type first alphabet and select, drop down menu will appear depend on you type.