VBA Userform not filled when first opened (possible memory issues) - vba

VBA'ers,
I'll cut to the chase. I have a userform with all the bells and whistles(Label's,textboxes,listboxes,tabstrips,etc.). Currently I have three subs.
Here's my code. I know people only asked for the userform initialize but seeing all of it might help find the problem.
Private x As Single
Private y As Single
'------------------------------------------
Private Sub CommandButton1_Click()
Unload Me
End Sub
'------------------------------------------
Private Sub ListBox1_Click()
x = 2
y = 2
name = ListBox1.Value
'Loop to match names
Do Until name = Cells(x, y)
x = x + 1
Loop
'Changes lables on click <- I realize I can handle this better with listbox.values
Label2.Caption = Sheet2.Cells(x, 2) 'Name
Label5.Caption = Sheet2.Cells(x, 3) 'Current Positions
Label7.Caption = Sheet2.Cells(x, 4) 'Previous Positions
Label9.Caption = Sheet2.Cells(x, 5) 'DOB
Label11.Caption = Sheet2.Cells(x, 6) 'POB
Label13.Caption = Sheet2.Cells(x, 7) 'Party Affiliation
'Changes tab strip accordingly
Call TabStrip1_Change
'Handles Picture
If Cells(x, 8) <> "" Then
Image1.Picture = LoadPicture(ThisWorkbook.Path & Cells(x, 8))
Else
Image1.Picture = LoadPicture(ThisWorkbook.Path & "..\pics\nophoto.jpg")
End If
End Sub
'------------------------------------------
Private Sub TabStrip1_Change()
'Handle Tab Strip
If TabStrip1.Value = 0 Then
TextBox1.Value = Cells(x, 9)
ElseIf TabStrip1.Value = 1 Then
TextBox1.Value = Cells(x, 10)
Else
TextBox1.Value = Cells(x, 11)
End If
End Sub
'------------------------------------------
Private Sub UserForm_Initialize()
'Initialize global variables
x = 2
'Initialize lists within userform.
ListBox1.RowSource = "B2:B11"
'Set tab strip to first tab.
TabStrip1.Value = 0
TextBox1.Value = Sheet2.Cells(2, 9)
'Grab photo if path is in cell
If Cells(2, 8) <> "" Then
Image1.Picture = LoadPicture(ThisWorkbook.Path & Cells(2, 8))
Else
Image1.Picture = LoadPicture(ThisWorkbook.Path & "..\pics\nophoto.jpg")
End If
End Sub
The problem is that when I run the code, via vba or a commandButton (Userform1.show) its a coins flip on whether or not the userform populates the listbox. The labels are initialized correctly, but the listbox shows no text. If I continue to run and stop the macro, it will eventually work fine.
Is this a memory issue? Am I not activating the userform properly? Or is this due to sloppy coding?
Any suggestions would be appreciated.

Since we cannot see the full Userform_Initialize(), I assume you have only populated the list into listbox.
If you want a listbox to select something when it shows, you need to call something like ListBox1.ListIndex = 0 or the index of your default value. This must be after the list is populated.
UPDATE:
Thanks, I believe when it doesn't work, it's because the activesheet is not where you have the list items. Either put in full formula address or Range Name my test workbook is "Test.xlsm":
ListBox1.RowSource = "[Test.xlsm]Sheet1!B2:B11" ' Change Workbook and Sheet name to fit yours
or
ListBox1.RowSource = "Test.xlsm!MyListItems" ' Change Workbook name, Create and Change the name of the Range that contains the list items.

Related

VBA userform - Dynamic textbox default value

I have two TextBox in my userform. One is for entering the Name, and the other one is for entering the income.
Now I create a modeless userform, so that user can keep insert the data
Suppose I already have list of Name. For example: Marry, Jamie, Michael
Is it posible to set this list as a default value for Name TextBox?
For example:
After click the button, the userform Pop up and Shows as follow:
Name: Marry
Income: ""
After I enter the income, and click "OK" buttom, the userform will Pop up again.
This time it Shows like this:
Name: Jamie
Income: ""
If my question is not clear enough, please tell me and I will explain it more detailed. Thanks in advance.
Update:
I add my code here to make my question clearer. However, the "story" of my code is a Little bit different. The user will insert the Portfolio ID, Budget value and the date into userform. Then the macro will filter the table in sheet "ALL_List".
Based on Portfolio ID and date, there will be only one line data in that table after filtering. The Budget column for this line of data should be empty. The Macro should automatically insert the Budget value, which was recorded in userform, into Budget column.
There are, for example, 5 ID and 5 Budget value:
Date / ID / Budget
29/06/2018 / 12541 / 336521
29/06/2018 / 4521 / 658882
29/06/2018 / 44359 / 4587996
29/06/2018 / 10223 / 148665
29/06/2018 / 74 / 658324
So, when the first time userform Pop up. I hope there will be a Default ID value "12541" in the Portfolio ID TextBox. After I enter the date and Budget value and click the button "Enter", the Budget value will insert to the Budget column in sheet "ALL_List". Then the userform Pop up again. This time the Default value for ID will be 4521.
After the final Default ID (74) Show up and I enter the value and click Enter, I hope the userform will still Pop up and this time the value of Portfolio ID TextBox will be empty (because there could be other ID which the user wants to insert.)
Hope my descripition is clear. If there is any question, please don't hesitate to inform me. Much Thanks!
Sub Budget_Adjustment()
Dim frm As New UserFormBudget
frm.Show vbModeless
End Sub
Private Sub ButtonClose_Click()
Unload Me
End Sub
Private Sub ButtonEnter_Click()
InsertBudget
End Sub
Private Sub InsertBudget()
Dim UpdateDate As String
Dim PortfolioID, Budgetvalue As Long
UpdateDate = TextBoxDate.Value
PortfolioID = TextBoxID.Value
Budgetvalue = TextBoxBedget.Value
UpdateDate = CDate(UpdateDate)
Sheets("ALL_List").Activate
ActiveSheet.AutoFilterMode = False
Range(Cells(1, 1), Cells(Cells(Rows.Count, 7).End(xlUp).row, 7)).AutoFilter Field:=1, Criteria1:=UpdateDate
Range(Cells(1, 1), Cells(Cells(Rows.Count, 7).End(xlUp).row, 7)).AutoFilter Field:=3, Criteria1:=PortfolioID
Cells(Cells(Rows.Count, "A").End(xlUp).row, "F").Value = Budgetvalue
ActiveSheet.AutoFilterMode = False
TextBoxID.Value = ""
TextBoxBedget.Value = ""
TextBoxID.SetFocus
End Sub
Private Sub TextBoxBedget_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
If KeyCode = 13 Then
ButtonEnter_Click
End If
End Sub
Private Sub UserForm_Activate()
'Empty TextBoxID
TextBoxID.Value = ""
'Empty TextBoxBedget
TextBoxBedget.Value = ""
'Empty TextBoxDate
TextBoxDate.Value = ""
'Set Focus on NameTextBox
TextBoxDate.SetFocus
End Sub
...
EDIT:
Edited your code a little bit based on the new information you provided. Now, you just enter your ID's you want to edit before hand in the sheet named "list".
I added sheet named "List" :
This code goes in area when you right-click UserFormBudget > View Code:
Private Sub ButtonClose_Click()
Dim lastListRow As Long
With ThisWorkbook.Worksheets("List")
lastListRow = .Cells(.Rows.Count, 1).End(xlUp).row
.Range("A4:A" & lastListRow).Interior.ColorIndex = 0
End With
Unload Me
End Sub
Private Sub ButtonEnter_Click()
InsertBudget
End Sub
Private Sub InsertBudget()
Dim UpdateDate As String
Dim PortfolioID As Long
Dim Budgetvalue As Long
Dim lastListRow As Long
Dim row As Long
UpdateDate = TextBoxDate.Value
PortfolioID = TextBoxID.Value
Budgetvalue = TextBoxBedget.Value
If Len(UpdateDate) > 0 Then
UpdateDate = CDate(UpdateDate)
Else
MsgBox "Need to enter a date"
Exit Sub
End If
With Worksheets("ALL_List")
.Activate
.AutoFilterMode = False
.Range(.Cells(1, 1), .Cells(.Cells(.Rows.Count, 7).End(xlUp).row, 7)).AutoFilter Field:=1, Criteria1:=UpdateDate
.Range(.Cells(1, 1), .Cells(.Cells(.Rows.Count, 7).End(xlUp).row, 7)).AutoFilter Field:=3, Criteria1:=PortfolioID
.Cells(.Cells(.Rows.Count, "A").End(xlUp).row, "F").Value = Budgetvalue
.AutoFilterMode = False
End With
With ThisWorkbook.Worksheets("List")
lastListRow = .Cells(.Rows.Count, 1).End(xlUp).row
TextBoxID.Value = ""
For row = 5 To lastListRow
If .Cells(row, "A").Interior.Color <> RGB(255, 255, 0) Then
TextBoxID.Value = .Cells(row, "A").Value
.Cells(row, "A").Interior.Color = RGB(255, 255, 0)
Exit For
End If
If row = lastListRow Then
TextBoxDate.Value = ""
End If
Next
End With
TextBoxBedget.Value = ""
TextBoxID.SetFocus
End Sub
Private Sub TextBoxBedget_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
If KeyCode = 13 Then
ButtonEnter_Click
End If
End Sub
And add this code in a module, so right-click project and insert new module, then paste:
Sub Budget_Adjustment()
Dim frm As New UserFormBudget
Dim lastListRow As Long
With ThisWorkbook.Worksheets("List")
lastListRow = .Cells(.Rows.Count, 1).End(xlUp).row
If lastListRow = 3 Then
frm.TextBoxDate.Value = ""
frm.TextBoxID.Value = ""
frm.TextBoxBedget.Value = ""
Else
frm.TextBoxID.Value = .Cells(4, "A").Value
frm.TextBoxBedget.Value = .Cells(4, "B").Value
.Cells(4, "A").Interior.Color = RGB(255, 255, 0)
End If
End With
frm.TextBoxID.SetFocus
frm.Show vbModeless
End Sub
Now, just right-click on the button on List sheet and assign it the macro Budget_Adjustment

Loop counter in checkbox name

I am trying to create a sheet which will have a checkbox in each non-empty line. To automatically adjust the number of checkboxes I created this macro:
Sub checkboxes()
Dim i As Integer
For i = 9 To 200
Set CurCell = ActiveSheet.Cells(i, 3)
If CurCell.Value > 1 Then
ActiveSheet.Shapes("CheckBox" & CStr(i)).Visible = True
Else
ActiveSheet.Shapes("CheckBox" & CStr(i)).Visible = False
End If
Next i
End Sub
I expect number of potential rows with data not greater than 200. Macro checks if value in column C for each line is >1, if true checkbox is visible, else it's hidden.
My problem is that I don't know how to put the loop counter "i" into Shape name - I got an error using code above. Can someone help?
I think this would be a more elegant solution.
This loops through all shapes on ActiveSheet and checks if they are a msoOLEControlObject (see here for more information on that matter).
Sub checkboxes()
Dim curCellValue as Variant
Dim i As Long
For i = 1 To ActiveSheet.Shapes.Count
If ActiveSheet.Shapes(i).Type = msoOLEControlObject Then
curCellValue = ActiveSheet.Cells(i, 3).Value
If curCellValue <> "" Then
ActiveSheet.Shapes(i).Visible = True
Else
ActiveSheet.Shapes(i).Visible = False
End If
End If
Next i
End Sub
So why is this "better"?
You don't have to "guess" how many values there will be.
If you ever change a name of a CheckBox this script will still be working.
This checks for empty cells.
Also note that I replaced Set CurCell = ActiveSheet.Cells(i, 3) with curCellValue = ActiveSheet.Cells(i, 3).Value. You don't need to Set an object in every iteration. Filling the variable suffices.
But: this will check for all msoOLEControlObjects which includes checkboxes, textboxes and the like.
HTH.

Excel VBA increasing rows/columns

http://imgur.com/zEm7hT7
In my image I have my form which upon entering information into the text boxes and pressing enter will place the information into the correct places below the titles, what i'm wanting to do is either have a next button that will go down one row and a back button that will go up one row and allows me to enter information into a 'database' per say or i would like to have it automatically jump down one row upon clicking 'Enter'. I have looked and I can't find anything that is quite what i'm asking and response is great, thanks.
This is what i have so far.
Private Sub CommandButton1_Click()
Dim x As Integer
x = Cells(1, 1).End(xlDown).Row + 1
Cells(x, 1) = TextBox1.Value
Cells(x, 2) = TextBox2.Value
Cells(x, 3) = TextBox3.Value
Cells(x, 4) = TextBox4.Value
Cells(x, 5) = TextBox5.Value
End Sub
Replace x=2 with finding the next empty row
If Cells(2,1) = "" Then
x = 2
Else
x = Cells(1,1).End(xlDown).Row + 1
End If

Increase speed of changing Excell cell's value with just a mouse [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
I would like to increase the speed of changing Excel cell's value with a mouse only. I share my tool in hope that someone will like it and want to improve it.
This is an example. After clicking on a defined cell containing value, scrollbar appears on the right side of a cell. You can smoothly change its value with a mouse.
The tool is meant to change cells value and observe formulas values dynamically. You may simplify the code however some features should not be disabled. It should always stay dynamic, that is moving the srollbar should immediately influence other cells with formulas. The srollbar should not twinkle (changing colour grey and black).
You may simply download the scrollbar.xlsm file here and view the VBA code inside it.
Or you may put this code in your sheet where you want the scollbars to appear. The name of your sheet does not matter. Right click on the sheet's name and then click View Code. This is the place:
Insert there this code:
Option Explicit
Dim previousRow, c
Const scrlName As String = "scrlSh" ' the name of the scrollbar
Private Sub scrlSh_GotFocus()
ActiveSheet.Range(ActiveSheet.OLEObjects(scrlName).TopLeftCell.Offset(0, -1).Address).Activate
End Sub
Private Sub scrlSh_Scroll()
Dim rngCell As Range
Set rngCell = Sheets("Param").Range(ActiveSheet.OLEObjects(scrlName).LinkedCell)
ActiveSheet.OLEObjects(scrlName).TopLeftCell.Offset(0, -1).Value = _
rngCell.Offset(0, 1).Value + (ActiveSheet.OLEObjects(scrlName).Object.Value * rngCell.Offset(0, 3).Value)
Set rngCell = Nothing
End Sub
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
' Macro concept by Przemyslaw Remin, VBA code written by Jaroslaw Smolinski
' The Sub Worksheet_SelectionChange and function SearchAdr have to be on each sheet where scrollbars are to appear
' Sheet Param is one for all sheets, only the columns A-G are used, othre columns can be used for something else
' Do not change the layout of A-G columns unless you want to modify the code
' Addresses in Param have to be with dollars (i.e. $A$3) or it may be named ranges of single cells
' (if it starts with $ it is a cell, otherwise it is a named range)
' the lower or upper case in addresses does not matter
Dim SheetFly As String, adr As String
Dim cCell As Range
Dim actSheet As Worksheet
Dim shScroll As Object
Set actSheet = ActiveSheet
' checks if scrollbar exists
If actSheet.Shapes.Count > 0 Then
For Each shScroll In actSheet.Shapes
If shScroll.Type = msoOLEControlObject And shScroll.Name = scrlName Then
Exit For ' scrollbar found, and the variable is set
End If
Next shScroll
End If
' if scrollbar does not exists then it is created
If shScroll Is Nothing Then
Set shScroll = ActiveSheet.OLEObjects.Add(ClassType:="Forms.ScrollBar.1", Link:=False, _
DisplayAsIcon:=False, Left:=0, Top:=0, Width:=64 * 3, Height:=15)
' scrollbar length is set as three adjesent columns
shScroll.Visible = False
shScroll.Name = scrlName
shScroll.Placement = xlMoveAndSize
End If
shScroll.Visible = False
adr = Target.AddressLocal
SheetFly = actSheet.Name
' here we set up in which cells the scrollbar has to appear. We set up only the number of rows
Set cCell = SearchAdr(SheetFly, adr, Sheets("Param").Range("B2:B40")) ' If needed it can be longer i.e. B2:B400
If Not cCell Is Nothing Then
With ActiveSheet.OLEObjects(scrlName)
.LinkedCell = "" ' temporary turn off of the link to the cell to avoid stange behaviour
.Object.Min = 0 ' the scale begins from 0, not negative
.Object.Max = Abs((cCell.Offset(0, 4).Value - cCell.Offset(0, 3).Value) / cCell.Offset(0, 5).Value)
.Object.SmallChange = 10 ' single change by one step
.Object.LargeChange = 10 ' change by jumps after clicking on scrollbar bar ("page up", "page down")
If Target.Value <> cCell.Offset(0, 2).Value And Target.Value >= cCell.Offset(0, 3).Value And Target.Value <= cCell.Offset(0, 4).Value Then
' setting up the cells value as close as possible to the value of input by hand
' rounded by step
' if value is out of defined range then the last value will be used
cCell.Offset(0, 2).Value = Abs((Target.Value - cCell.Offset(0, 3).Value) / cCell.Offset(0, 5).Value)
End If
'Protection in case the value is out of min and max range
If cCell.Offset(0, 2).Value > .Object.Max Then
cCell.Offset(0, 2).Value = .Object.Max
ElseIf cCell.Offset(0, 2).Value < .Object.Min Then
cCell.Offset(0, 2).Value = .Object.Min
End If
Target.Value = cCell.Offset(0, 3).Value + (cCell.Offset(0, 5).Value * cCell.Offset(0, 2).Value)
.Object.Value = cCell.Offset(0, 2).Value
.LinkedCell = "Param!" & cCell.Offset(0, 2).Address 'setting up linked cell
End With
' Setting up the position and width of scrollbar with reference to the cell
shScroll.Top = Target.Top
shScroll.Left = Target.Offset(0, 1).Left + 2 'position to the right + small margin
shScroll.Width = Target.Offset(0, 5).Left - Target.Offset(0, 1).Left - 2 'width of 5 columns
shScroll.Visible = True
End If
Set actSheet = Nothing
Set shScroll = Nothing
Set cCell = Nothing
End Sub
Private Function SearchAdr(SheetFly As String, SearchCell As String, rng As Range) As Range
Dim cCell As Range
Dim oOOo As Name
' Searching for the row with parameter for chosen cell
' The parameter have to be in one, continouse range
For Each cCell In rng
If cCell.Text = "" Then ' check if parameters have not finished
Set SearchAdr = Nothing
Exit Function ' stop if you find first empty cell for speeding
ElseIf Left(cCell.Text, 1) = "$" Then ' normal address
If cCell.Offset(0, 1).Text & "!" & UCase(cCell.Text) = SheetFly & "!" & UCase(SearchCell) Then
Set SearchAdr = cCell
Exit Function ' exit if find proper row with parameters
End If
Else ' means that found is a name
For Each oOOo In ActiveWorkbook.Names
If (oOOo.RefersTo = "=" & SheetFly & "!" & UCase(SearchCell)) And (UCase(oOOo.Name) = UCase(cCell.Text)) Then
Set SearchAdr = cCell
Exit Function ' exit if find proper row with parameters
End If
Next oOOo
End If
Next cCell
End Function
In your workbook you have to make sheet named Param where the parameters of scrollbar are stored. In column A and C put the name of your sheet where you want scrollbars to appear. The sheet looks like this:
Now you can enjoy the scrollbar after clicking the cell in the model sheet.
Note that you can define different min, max ranges and step of scrollbar change separately for every cell. Moreover, the min and max range can be negative.
I'd prefer:
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If Intersect(Target, Range("A1:A10")) Is Nothing Then Exit Sub
If OLEObjects.Count = 0 Then OLEObjects.Add "Forms.ScrollBar.1", , , , , , , Target.Offset(, 1).Left, Target.Top, 199, 15
With OLEObjects(1)
.Top = Target.Top
.object.max=200
Target = Application.Max(Target, .Object.Min)
Target = Application.Min(Target, .Object.Max)
.LinkedCell = Target.Address
End With
End Sub
To make the value change when clicking on left/right arrow or inside the scrollbar, I'd rather add:
Private Sub scrlSh_Change()
If ActiveSheet.OLEObjects(scrlName).LinkedCell <> "" Then
scrlSh_Scroll
End If
End Sub
I'd prefer use typed function like UCase$, Left$, ... rather than their variant equivalent (UCase, Left, ...), but for this macro the "true" performance is not really required.
Within your Worksheet_SelectionChange sub, I've replaced the actSheet, SheetFly and adr variables by their original values (as there are used only once). No real big improvment yet.

Extract data from a two columned listbox to a sheet

I have a two-columned listbox, which I've manually added entries to using
.AddItem (potato)
.List(.ListCount - 1, 1) = bananaTbx.Text
When the user closes the userform all of the data is lost, so I want to have a save & exit button which saves the data to a sheet. However, it can't be saved to specific cells as the size of the list is dynamic and they will continually be adding to the master list in the sheet.
I tried to do something like this to extract the data:
Dim i As Integer
'loop through each row number in the list
For i = 0 To Userform1.Listbox1.ListCount - 1
'create sequence 1,1,2,2,3,3,4,4 ... to reference the current list row
j = Application.WorksheetFunction.RoundDown(i + 0.5, 0)
'create sequence 0,1,0,1,0,1,0,1 ... to reference current column in list
If Len(CStr(i / 2)) > 1 Then
k = 0
Else
k = 1
Sheets("Data").Range("A1" & ":" & "A" & i).Value = Userform1.ListBox1.List(j, k)
End If
Error:
1004 Object defined error
How can I do this properly or in a more efficient manner?
I have created a simple userform to demonstrate how to Extract Values / Data from a multi-column Listbox on a Userform
Start by creating a simple userform with a few controls
add a new Module1 to your Project and stick the below code in it
Sub TestUserForm()
UserForm1.Show
Unload UserForm1
End Sub
in Project Explorer (VBE) Right-click on the UserForm1 and hit View Code
Copy and paste the below code
Private Sub CommandButton1_Click()
With ListBox1
.AddItem TextBox1.Value
.List(.ListCount - 1, 1) = TextBox2.Value
End With
End Sub
Private Sub CommandButton2_Click()
Dim ws As Worksheet
' create a results sheets if you do not already have one
Set ws = Sheets("Results")
Dim nextAvailableRow As Long
Dim i As Long
For i = 0 To ListBox1.ListCount - 1
nextAvailableRow = ws.Range("A" & Rows.Count).End(xlUp).Row + 1
ws.Range("A" & nextAvailableRow) = ListBox1.Column(0, i)
ws.Range("B" & nextAvailableRow) = ListBox1.Column(1, i)
Next i
Me.Hide
End Sub
Create a new spreadsheet and name it Results
Run the TestUserForm macro
Add sample data to the list and click Save button