Using a macro to sort data from instrumentation software - vba

So I use an instrumentation software at work that outputs readings to a csv excel file. Because of the length of the test and the readings every 30 seconds, I accumulate a few thousand rows for every 24 hours of the test. When the test runs, it reads things that I don't need readings of so I have to go through the sheet manually and replace the "false" readings with zeros.
What I would like to do is use a command button to prompt the user to select a column to sort and apply a range of values so if it falls within that range, it returns the value to the cell and if it doesn't fall within the range, it returns a 0. I have done this with smaller sheets with extra columns (see attached file) but I'm not super familiar with Macros or VBA so I'm not sure where to get started.
Can anyone give me a hand?

This can be done as follows.
1) Go to Developer tab in the Excel ribbon. Click Insert, choose a Command Button (ActiveX Control) and place it onto the sheet where you want to have it.
2) Double-click the button, this will open up the editor. You should see:
Private Sub CommandButton1_Click()
End Sub
3) Add the line UserForm1.Show inside of this block of code. This should now look like:
Private Sub CommandButton1_Click()
UserForm1.Show
End Sub
4) Now we will create the userform. On the left side of the editor you will see a section called "Projects - VBA Project", in this list you should see your Workbook. Right click the name of your workbook and click Insert -> UserForm.
5) Use the toolbox to drag the correct components into the Userform. You are free to customize this form as you see fit to add or remove functionality based on your needs. I made mine look like this:
6) In the projects tab you will see your userform named UserForm1. Right click this userform and click "View Code". Paste the following code:
Private Sub CommandButton1_Click()
Unload UserForm1
End Sub
Private Sub UserForm_Initialize()
Dim lastColumn As Long
lastColumn = Worksheets("Sheet1").Cells(1,Columns.Count).End(xlToLeft).Column
For i = 1 To lastColumn
UserForm1.ComboBox1.AddItem (Worksheets("Sheet1").Cells(1, i))
Next
End Sub
Private Sub CommandButton2_Click()
Dim columnName As String
Dim columnIndex As Integer
Dim min As Double
Dim max As Double
If Not (ComboBox1.SelText = "" And TextBox1.Text = "" And TextBox2.Text = "") Then
columnName = ComboBox1.SelText
min = TextBox1.Text
max = TextBox2.Text
Dim lastColumn As Long
lastColumn = Worksheets("Sheet1").Cells(1, Columns.Count).End(xlToLeft).Column
For i = 1 To lastColumn
If Worksheets("Sheet1").Cells(1, i).Value = columnName Then
columnIndex = i
End If
Next
Dim cellValue As Double
Dim lastRow As Long
lastRow = Worksheets("Sheet1").Cells(Rows.Count, 1).End(xlUp).Row
For i = 2 To lastRow
cellValue = Worksheets("Sheet1").Cells(i, columnIndex).Value
' MsgBox CStr(cellValue) + "--" + CStr(cellValue > min) + "--" + CStr(cellValue < max)
If Not (cellValue >= min And cellValue <= max) Then
Worksheets("Sheet1").Cells(i, columnIndex).Value = 0
End If
Next
End If
Unload UserForm1
End Sub
7) Change the component names such as CommandButton, ComboBox1, etc. to match your UserForm.
What does the code do?
Initializing: As soon as the UserForm is called it passes through the method UserForm_Initialize(). This method looks through your WorkSheet and determines the name of all the columns. It then adds these to the ComboBox.
Command Button 1: "Cancel", exits the UserForm without doing anything.
Command Button 2: "Confirm", this method goes to your selected column, checks within the desired range. If a value falls outside that range then it will set it to 0.
I hope this help!!

Related

VBA Several UserForms export to Sheet

In my Workbook i have several identical UserForms. Only the name is different.
For Example WKA1 / WKA2 / WKS1 / WKS2 / PM1 / PM2 and some more.
Now i want if i click on the CommandButton on the UserForm, that the Data in the TextBoxes will be saved on a extra Worksheet. I want that with a seperate Macro, so that i code for the CommandButton looks like this:
Private Sub CommandButton1_Click()
Call Save_UF_Data
[NameOfUF].Hide
End Sub
The Problem is, i donĀ“t know how to write in the Macro "Save_UF_Data" that it always takes the TextBox from the UF which is open.
I already tried it with:
Me.Controls("TextBox1")
I hope someone can show me how i have to write the code that my macro will work for every UserForm in my Workbook.
This is my Macro so far:
Public Sub Save_UF_Data()
Dim lastrow As Long
Dim a As Integer
Dim ws As Worksheet
Set ws = Worksheet("UserForm_Data")
lastrow = ActiveSheet.Cells(Rows.Count, "A").End(xlUp).Row
a = 1
Do
ws.Range("A" & lastrow).Value = Me.Controls("Label" & a) ' How do i have to change this part that it takes the value from the userform which is open?
a = a + 1
lastrow = lastrow + 1
Loop Until a = 25
End Sub
You could pass the calling form Object as Parameter to the Sub:
Private Sub CommandButton1_Click()
Call Save_UF_Data(Me)
[NameOfUF].Hide
End Sub
And the Sub would look like:
Public Sub Save_UF_Data(frm As UserForm)
Debug.Print frm.Controls("Textbox1")
(...)
End Sub
Have a look to How to loop through all controls in a form, including controls in a subform - Access 2007 to learn how to access the controls of a form

excel VBA how to make the code run automaticly when the user open the file

i have this code that check for date and fill the cells in colors based on the date.
what i need is that when the user open the file and write the date the system will check directly the date and fill in the right color.
what happen is that after the user write the date he needs to click on macro icon in order to the code take action.
code:
Sub test()
Dim i As Integer
Dim OfficerList(4) As String
For i = Range("C5000").End(xlUp).Row To 2 Step -1 'Range upto 5000, chnge this as per your requirment'
Select Case VBA.CDate(Cells(i, 3))
Case Is < VBA.Date()
Cells(i, 3).Interior.Color = vbGreen
Case Is = VBA.Date()
Cells(i, 3).Interior.Color = vbYellow
Case Is > VBA.Date()
Cells(i, 3).Interior.Color = vbRed
End Select
Next
End Sub
can anyone help me ?
or is there any better idea?
This code should get the job done.
'This function is called everytime a cell is edited in the worksheet
'NOTE: This macro should be placed in the same worksheet object of your VBA Project
'that has the same worksheet name as the worksheet with all the dates
Private Sub Worksheet_Change(ByVal Target As Range)
Dim DateCells As Range
Set DateCells = Range("C2:C5000")
'If the user changed one of the date cell run the macro, else do nothing
If (Not Application.Intersect(DateCells, Range(Target.Address)) Is Nothing) Then
test 'Call your macro here
End If
End Sub
'This function is called everytime the workbook is opened
'NOTE: This macro should be placed in the 'ThisWorkbook' object of your VBA
Project
Private Sub Workbook_Open()
test 'Call your macro here
End Sub

populating data from userform checkboxes & optional buttons

I am creating a userform that I want to be able to populate values in a data tab as well as default to certain values.
I think I have text boxes and combo boxes down, but cannot find info on using multiple optional buttons to generate data to one cell depending on the selection.
from the example, my criteria would be "secondary insurance" how do I go about linking them all so that, lets say cell b1 is populated with the selected option?
I'm completely guessing but I think checkboxes are a little more simple, true if checked and false if unchecked.
What I have so far is just a code I came across to fill in a cell with the value of the designated text/combo box and was just going to repeat for each column I need to set a criteria for.
Private Sub CommandButton1_Click()
Dim LastRow As Long, ws As Worksheet
Set ws = Sheets("Sheet1")
LastRow = ws.Range("A" & Rows.Count).End(xlUp).Row + 1 'Finds the last blank row
ws.Range("A" & LastRow).Value = TextBox1.Text 'Adds the TextBox1 into Col A & Last Blank Row
Me.Hide
End Sub
combobox list
Private Sub UserForm_Initialize()
ComboBox1.Value = ("N/A")
ComboBox1.List = Split("N/A Yes No")
End Sub
Please let me know if I lack information and or how to attach my test worksheet, hopefully you can see the picture (I can't on my work server).
Thanks in advance for any and all education.
If the caption of the option button is the same as you want as cell text, then something like this may be what you want to store it:
Private Sub CommandButton1_Click()
Dim LastRow As Range
With Sheets("Sheet1")
Set LastRow = .Rows(.Cells(Rows.Count, 1).End(xlUp).Row + 1).Cells
If OptionButton1 Then
LastRow(2).Value2 = Me.OptionButton1.Caption
ElseIf Me.OptionButton2 Then
LastRow(2).Value2 = Me.OptionButton2.Caption
Else
LastRow(2).Value2 = Me.OptionButton3.Caption
End If
End With
End Sub
This will set the desired cell to the value of the caption of the option button you have selected.
To load the data back in the userform, you could use something like this:
Sub Load_in(Row_To_Load As Long)
Dim MyRow As Range
With Sheets("Sheet1")
Set MyRow = .Rows(Row_To_Load).Cells
If MyRow(2).Value2 = OptionButton1.Caption Then
OptionButton1.Value = True
ElseIf MyRow(2).Value2 = OptionButton2.Caption Then
OptionButton2.Value = True
Else
OptionButton3.Value = True
End If
End With
End Sub
For this, I assumed that the names hasn't been changed. Also if nothing is selected, the third option (N/A) will be used. The same goes for loading it back. If you do not want that, simply change the Else part to ElseIf so it looks like the first 2 options.

VBA causing typed information to go to an incorrect worksheet

I am creating a spreadsheet that creates a reference number on the first worksheet (called database, to be used similarly to a database) and generates a new worksheet. This then gives a reference number on the new worksheet so that they are linked together. This is done by pressing "New Idea" on a UserForm.
Once this is completed it should then go to the newly created worksheet and highlight cell C7. Once this is complete it should close the UserForm and allow the user to be able to type in cell C7 on the new worksheet with no further steps needed.
This works fine if I use F8 to step through the process however if I close the code window and run through the process as a user would it doesn't work as it should.
C7 is highlighted but once you have typed in it and press enter to go to the cell below, what you've typed disappears completely, and whatever you type on the newly generated worksheet is actually entered on another worksheet.
I have a seperate worksheet that contains a button to open the UserForm and all data that is entered on the newly generated worksheet goes to this sheet incorrectly.
My code is below, and is all within the UserForm's code. I have left the ComboBox code below but this isn't relevant to the generation of the new worksheets. All that does is list the created tabs so the user can select a worksheet from the UserForm and go directly there rather than having to scroll sideways.
I'm using Excel 2013. I'm by no means a VBA veteran so any help would be greatly appreciated!
Thanks!
Private Sub UserForm_Initialize()
Me.ComboBox1.List = Worksheets("Database").Range("A2:A10000").Value
End Sub
Private Sub CreateNewIdea_Click()
CopySheet
End Sub
Sub CopySheet()
Dim LastRow As Long
NewReference
LastRow = Sheets("Database").Range("A" & Rows.Count).End(xlUp).Row - 1
ReturnValue = LastRow
Sheets("Idea Template").Copy After:=Sheets(Sheets.Count)
ActiveSheet.Name = LastRow
Range("C3").Value = LastRow
Me.ComboBox1.List = Worksheets("Database").Range("A2:A10000").Value
Range("C7").Select
Unload Home
End Sub
Sub NewReference()
Dim LastRow As Long
LastRow = Sheets("Database").Range("A" & Rows.Count).End(xlUp).Row
Sheets("Database").Cells(LastRow + 1, "A").Value = Sheets("Database").Cells(LastRow, "A").Value + 1
End Sub
Private Sub ComboBox1_Change()
Worksheets(ComboBox1.Text).Select
End Sub
I've taken the liberty to edit and rewrite the code you've written for greater flexibility.
Option Explicit 'Forces the variable to be declared, undeclared variables are not allowed
Dim DatabaseTable As ListObject 'Makes the variable usable for the entire module
Dim Lastrow As Long
Private Sub UserForm_Initialize()
Set DatabaseTable = ThisWorkbook.Worksheets("Database").ListObjects("References")
'I'm assuming you've formatted the data on the worksheet as a table and named the table "References"
Dim i As Long
Dim DatabaseRows As Long
DatabaseRows = DatabaseTable.ListRows.Count
With Me.ComboBox1
.Value = Empty
.Clear
For i = 1 To DatabaseRows
.AddItem DatabaseTable.DataBodyRange(i, 1)
Next i
End With
End Sub
Private Sub CreateNewIdea_Click()
Set DatabaseTable = ThisWorkbook.Worksheets("Database").ListObjects("References")
Call CopySheet
End Sub
Sub CopySheet() 'Are you calling Sub CopySheet() from other subs besides Private Sub CreateNewIdea_Click()?
Call NewReference
Dim ReturnValue As Long 'I'm declaring this variable because I'm using the option explicit and that doesn't allow undeclared variables
ReturnValue = Lastrow 'Unless ReturnValue is a public variable, it's not doing much here.
ThisWorkbook.Worksheets("Idea Template").Copy After:=ThisWorkbook.Worksheets(Worksheets.Count)
ThisWorkbook.Worksheets("Idea Template (2)").name = Lastrow
ThisWorkbook.Worksheets(CStr(Lastrow)).Cells(1, 3).Value = Lastrow 'Cstr(lastrow) is needed because we want the sheet with the name of the last row, not the nth sheet which is what happens with WorkSheets(Lastrow) as lastrow is a number
Call UserForm_Initialize 'Calls the procedure which fills ComboBox1, if the unload home refers to this form, then this line is redundant since the combobox is filled again when the form is initialized.
ThisWorkbook.Worksheets(CStr(Lastrow)).Cells(7, 3).Select
Unload Home 'If the name of this form is home, you can just 'Unload Me'
End Sub
Sub NewReference() 'Are you calling Sub NewReference from other subs besides Sub CopySheet()?
DatabaseTable.ListRows.Add AlwaysInsert:=False 'Adds a new row to the table on the worksheet "Database"
Lastrow = DatabaseTable.ListRows.Count
If Lastrow = 2 And IsEmpty(DatabaseTable.DataBodyRange(1, 1)) Then 'This if determines if a row was added while the first row does not contain a reference
DatabaseTable.DataBodyRange(Lastrow, 1).Value = 1 'First reference, can be anything you want really
DatabaseTable.ListRows(1).Delete 'First row is deleted, otherwise you'd have an empty first row
Lastrow = Lastrow - 1
Else
DatabaseTable.DataBodyRange(Lastrow, 1).Value = DatabaseTable.DataBodyRange(Lastrow - 1, 1) + 1
End If
End Sub
Private Sub ComboBox1_Change()
If Not Me.ComboBox1 = Empty Then
Worksheets(CStr(Me.ComboBox1)).Select
End If
End Sub
Revised answer
After looking at the document provided by #tomjo and trying to reporduce the problem I found that the problem was caused by the buttons on the sheets. The buttons used were the Form Controls rather than ActiveX Controls.
A macro was assigned to the Form Control The macro was defined in a module as you'd expect. The Macro only called to show the relevant form. It appeared as if the selected sheet, either by the menu on the form or after creating a new sheet from the form wasn't properly activated and the information entered in the sheet that showing was actually entered in the form which was last manually selected. Stepping through the code I found that the proper sheet and cell was active after the selection through the form through Debug.Print ThisWorkbook.ActiveSheet.Name, ThisWorkbook.ActiveSheet.ActiveCell.Address. I failed to discover why, while the correct sheet and cell were active, the information was entered in the last manually selected worksheet and cell.
To verify that the issue was not caused by the file somehow I tried to reproduce the problem with an entirely new file. Again the problem occurred that while the screen was showing the correct sheet and cell as selected (selected through a form, called by a sub in a module, called by a Form Control) the information was actually entered in the last manually selected sheet and cell.
----Edit----
Running the Showform macro (which calls the form to show) from the Macros button under the developer tab in the ribbon, instead of clicking the Form control button which has the ShowForm macro assigned to it, doesn't create the issue.
----End of Edit----
I then only removed the Form control, and the sub in the module which calls to show the form and placed an ActiveX Control (CommandButton) on the sheet and on the relevant Sheet module created:
Private Sub CommandButton1_Click()
Form.Show
End Sub
Without editing the code any further, there were no further issues regarding information being entered on the last manually selected sheet and cell instead of the sheet and cell the screen was showing as selected.
Edited file (The link will be active for a limited time)

VBA public variables

I am having trouble with the public i as intger portion of my code.
I am using i to keep the value of my current row so i can use this range across
my program. In my for loop it increments i so it will step through a column and search for v
however when i try using "i" in another set of code "i" no longer has a value.
I am not sure how global/public variables work in VBA or what is cause this error.
the problem occurs int Sub "yes" , and sub "no"
at the code
Cells(i,lcol).value=" ok "
and
Cells(i,lcol).value = " updated "
1st set of code is as follows, which gets my value for "i"
Public V As Integer
Public i As Integer
Private Sub Enter_Click()
Dim EmptyRow As Long
'Audit will only search Master Sheet
Worksheets("Master").Activate
'Find empty row value so we can use that for limit of search
With Sheets("Master")
EmptyRow = .Range("A" & Rows.Count).End(xlUp).Row + 1
End With
'i needs to be set to minimum limit
'Begin loop of search
For i = 12 To EmptyRow + 1
If Cells(i, 1).Value = V Then 'AssetNum.Value Then
'Go to compare userform to display
Compare.AssetDisplay.Value = AssetNum.Value
Compare.LocationDisply.Value = Cells(i - 1, 2).Value
Compare.Show
End If
Next i
'If i gets to emptyrow num then go to non found asset userform
Unload Me
NonFoundAsset.Show
End Sub
Private Sub UserForm_Initialize()
'Read in value from asset num to be comapre in loop
AssetNum.Value = V
End Sub
the second set of code im trying to call "i" using the public variable and it has no value
Private Sub No_Click()
Dim ws As Worksheet
Dim lcol As Long
'Make Master Sheet Active
Worksheets("Master").Activate
Set ws = ThisWorkbook.Sheets("Master")
'Finds next empty column
With ws
lcol = .Cells(11, .Columns.Count).End(xlToLeft).Column - 1
End With
'If the displayed location is not the same as the actual location "No" will be
'selected and the Change User Form will be displayed
'The value under the current audit column will be displayed as updated
Cells(i, lcol).Value = " Updated "
Unload Me
AuditChange.Show
End Sub
Private Sub Yes_Click()
Dim ws As Worksheet
Dim lcol As Long
'Make Master Sheet Active
Worksheets("Master").Activate
Set ws = ThisWorkbook.Sheets("Master")
'Finds next empty column
With ws
lcol = .Cells(11, .Columns.Count).End(xlToLeft).Column - 1
End With
'If the location displayed is correct "Yes" will be selected and
'The value "ok" will be displayed in the current audit column
Cells(i, lcol).Value = " Ok "
Unload Me
'Returns to Assetlookup to look for a new asset
Assetlookup.Show
End Sub
I appreciate any help, Im new to VBA and don't understand why this is not working.
I believe a public variabe in a UserForm is only available if the UserForm is running (loaded). To have a truely global variable, declare it in a normal module.
Probably the variable isn't available and VB can't find it in its scope. If Tools, Options, Require variable declarations is turned OFF, VB will create a new variable with that name in the current scope. Hence it looks as if it has "lost" its value.
Tip: don't call global variables something like i, j, n etc. These are typically used as local variables for loops and counters. Use a naming convention that makes clear the variable is global. I always prefix such a variable with g for 'global', e.g.:
Public giLoopCounter As Integer;
It depends where you declare it. You have to refer to that location. So if i is in UserForm1 and you are trying to use it from another form, reference it as.
Cells(UserForm1.i,lcol).value=" ok "
If you put
Option explicit
at the top of the form you are trying to call it from it would tell you that i by itself is not defined in that scope of you code.
EDIT: For additional comments from OP. Asked if i can be public in a click event.
To my knowledge, you can't have public/global variables in an event.
You will have to use a variable local
'Public variables are declared outside (above) all subs and functions
'This will be accessible by all subs functions and events in in the forms or sheets module or wherever it is
Public i As Integer
'This will be accessible by all subs functions and events in in the CURRENT sheet or form. It is private but to the current item
Private i As Integer
Private Sub CommandButton1_Click()
Dim j As count
'Do whatever it is to get that value.
j = 5
'You can access i to use it in you click event code
msgbox i * j
'Or you can set it in the event
i = j
End Sub