Button to add column? - vba

In excel 2013 I was hoping if someone can make a code for adding 1 blank column to a spreadsheet based on the user input after they click this button that is an activex control. The column will end based on how many rows there are in my table, meaning if there are 10 rows I should not see a column on line 11 of the spreadsheet.
I keep getting an error saying application defined or object error after I put in the column I want to add, I even tried both caps an lowercase and the same error comes up.
Private Sub CommandButton2_Click()
Dim x As String
x = InputBox("Enter a column that you want to add: ", "What column?")
If x = "" Then Exit Sub
ColumnNum = x
Columns(ColumnNum & ":" & ColumnNum).Insert shift:=xlShiftRight
Columns(ColumnNum - 1 & ":" & ColumnNum - 1).Copy Range("A1" & ColumnNum)
Columns(ColumnNum & ":" & ColumnNum).ClearContents
End Sub

This will get you started:
Dim x As Variant
Dim ColumnNum%
x = InputBox("Enter a column that you want to add: ", "What column?")
If x = "" Then Exit Sub
ColumnNum = x
ThisWorkbook.Sheets("Sheet1").Columns(ColumnNum).Insert shift:=xlRight
ThisWorkbook.Sheets("Sheet1").Columns(ColumnNum - 1).Copy
'THe line above doesnt make any sense whatsoever.
'Im not going to try and trouble shoot it but it seems like you dont understand how to
' properly scuplt things. Youll notice i changed how you strucutred the .copy part.
'THe part that doesnt make sense to me is the Range section.
ThisWorkbook.Sheets("Sheet1").Columns(ColumnNum).ClearContents
There were a few things wrong with your code.
You need to put Option Explicit at the top of your code. You didnt declare your variables.
you inpout box needs to be declared as variant
When i played around with this its clear you didnt fully reference what columns in what sheets need to be inserted. Notice my "ThisWorkbook....."
Your if statement is structured incorrectly as well.
I suggest you spend some time reading up on the basics some more :)

Related

Vlookup to a table on a different user selected file VBA Macro

I am trying to enter a Vlookup formula into Column S of a worksheet named "FY_16". I need the user to select the file (which changes each month) that the "table array" for the formula is in.
Each month the file changes, but the column I want to look up to will always be the same - Column W (but have varying number of rows). The "table array" that the formula will look up to is part of a table.
My code at this point is below:
Private Function UseFileDialogOpen()
MsgBox ("When the browse window opens: please select the previous months published FY16 Consulting SKU File")
Dim myString As String
' Open the file dialog
With Application.FileDialog(msoFileDialogFilePicker)
.AllowMultiSelect = False
.Show
If .SelectedItems.Count = 1 Then
myString = .SelectedItems(1)
'MsgBox myString
UseFileDialogOpen = myString
Else
MsgBox ("Failed to properly open file")
myString = "fail"
UseFileDialogOpen = myString
End If
End With
End Function
Sub Vlookup
Dim filelocation 'as what?????
filelocation = UseFileDialogOpen()
Worksheets("FY_16").Range("T2:T" & LastRow).FormulaR1C1 = "=vlookup(RC[-3], [" & myString & "] PA Rev!R1C23:R900000C23,1,false)"
My issue occurs on the final line of code. I receive a "run time error 1004 : application defined or object defined" message.
I know my syntax is incorrect for the vlookup in a few ways. I am not sure the "& myString & " is correct, perhaps this should be "filelocation"?
I also don't believe R1C1 can be used to name a range like I have in the vlookup. I typically would use
.Range(Cells(2,23), Cells(90000,23))
But I am not sure how to use that with the variable that holds the selected file name.
Also, I am using the 90000 row because this will go past my data each month (usually row count is around 75000). I would much rather find the exact row number but I don't believe this can be done without opening the "target file" selected by the user. If there is a way to achieve this, please offer any advice!
I am wondering if there is a way to use the Table Names to set the table array?
The non-VBA vlookup is as follows:
=VLOOKUP(Q2,'TargetFile.xlsb'!REV[[#All],[Net New Match]],1,FALSE)
TargetFile is the user selected file
REV is the worksheet the table array is on
Net New Match is the column I want to look up to (the entire column)
I played around with using these table names but couldn't get the syntax correct (possibly because the rest of the formula code is incorrect also).
Any help will be greatly appreciated. Let me know if any clarification is needed.
Mike
The correct syntax for accessing a range in an unopened workbook would be something that looks like 'C:\Temp\[Book2.xlsx]PA Rev'!R1C23:R900000C23. That won't be the same format that comes from the UseFileDialogOpen function.
You also can't use myString within your Vlookup subroutine because you defined that variable to be local to UseFileDialogOpen - but you can use filelocation which you have used to store the result from UseFileDialogOpen. But, as I said, it won't be in the right format anyway, so it will require a bit of reformatting.
The following command should do the necessary reformatting:
Worksheets("FY_16").Range("T2:T" & LastRow).FormulaR1C1 = _
"=vlookup(RC[-3],'" & Left(fileLocation, InStrRev(fileLocation, "\")) & _
"[" & Mid(fileLocation, InStrRev(fileLocation, "\") + 1) & _
"]PA Rev'!R1C23:R90000C23,1,false)"

Excel/VBA do not know where to begin

So I made a simple user form that will allow people to sign out equipment easily. I would like to make it so if something in the "Equipment" column is out, it will say out in the "In/Out" column. But otherwise say in. So if Equipment says "Laptop 1" and Last "Date & Time" Column is empty, then it would say out beside Laptop 1 in the "IN/OUT" column. The equipment column is multiselect with a "," between equipment options.
I have no idea where to start with this. What I have done so far minus populating the listbox and dropdown for the user form entry.
Private Sub cmdout_Click()
Set ws = ThisWorkbook.Worksheets("SignOut")
Dim sh As Worksheet
Dim LastRow As Long
Dim i As Integer
For i = 0 To equip.ListCount - 1
If equip.Selected(i) Then
Msg = Msg & equip.List(i) & ", "
End If
Next i
Msg = Left(Msg, Len(Msg) - 2)
Dim rngFound As Range
Dim strFirst As String
Dim strID As String
Dim strDay As String
Dim taken As Integer
strID = gov.Value
strDay = ""
Set rngFound = Columns("C").Find(strID, Cells(Rows.Count, "C"), xlValues, xlWhole)
If Not rngFound Is Nothing Then
strFirst = rngFound.Address
Do
If LCase(Cells(rngFound.Row, "G").Text) = LCase(strDay) Then
MsgBox "GOV is still signed out."
taken = 1
End If
Set rngFound = Columns("C").Find(strID, rngFound, xlValues, xlWhole)
Loop While rngFound.Address <> strFirst
End If
If taken = 0 Then
Application.Worksheets("SignOut").Range("A" & Rows.Count).End(xlUp).Offset(1).Value = Now()
Application.Worksheets("SignOut").Range("B" & Rows.Count).End(xlUp).Offset(1).Value = techname.Value
Application.Worksheets("SignOut").Range("C" & Rows.Count).End(xlUp).Offset(1).Value = gov.Value
Application.Worksheets("SignOut").Range("D" & Rows.Count).End(xlUp).Offset(1).Value = Msg
Application.Worksheets("SignOut").Range("E" & Rows.Count).End(xlUp).Offset(1).Value = otherequip.Value
End If
Set rngFound = Nothing
End Sub
Sign in form:
Private Sub CommandButton1_Click()
Dim rngFound As Range
Dim strFirst As String
Dim strID As String
Dim strDay As String
strID = techname1.Value
strDay = ""
Set rngFound = Columns("B").Find(strID, Cells(Rows.Count, "B"), xlValues, xlWhole)
If Not rngFound Is Nothing Then
strFirst = rngFound.Address
Do
Application.Worksheets("SignOut").Cells(rngFound.Row, "G").Value = Now()
Set rngFound = Columns("B").Find(strID, rngFound, xlValues, xlWhole)
Loop While rngFound.Address <> strFirst
End If
Set rngFound = Nothing
End Sub
1) A "form" is a specific coding construct in VBA. Based on what you posted, I assume that you aren't referring to it, but instead are just calling this sheet a form? If not, then please post the VBA code that you have tried.
2) Assuming that the list of equipment is in the "Tracker" column, you should use that list to populate a dropdown list in the equipment column to ensure that they match. I am also assuming that your extra equipment column won't have anything in the dropdown list and if people check out 2 tracked items, there will be a line entry for each item. (I'd recommend getting rid of that column if you get users that misuse it)
3) Since you asked where to start, I'll give you that. You'll learn much more by figuring out the exact syntax yourself. You can google "Excel VBA X" where X is basically any of these lines.
Pseudocode - (will not run, needs to be replaced with actual code - also ignore the colored words, they don't mean anything in pseudocode)
Phase 1:
trigger event on save (event handler is another search term for trigger events)
Change all equipment values to In
loop through first date/time column
IF there is a value in that column and there is not a value in the second date/time column get the name of the equipment from the equipment column
Find equipment from tracker column change In/Out value on that row to Out
continue the loop until the next row is blank
Alternate:
remove code to check everything in
add on-edit trigger to equipment column
add row that was edited to array
add on-edit trigger to check in date column
store row number to array
change loop so it only goes through rows in array
change if so that if something is checked out but not in, it is set out
(You will want to do this in case someone selects the wrong thing and then changes it - don't change it to out immediately or you will need logic to realize what was changed to out the previous time and change it back to in.)
else if something is checked out and has a value in check in date column then set it to in
Phase 2:
Implement an actual form that people use to fill in the sheet and check things in and out
Reuse relevant code from above but eliminate human error on dates and other things
(I suggest this as phase 2 as you can do this without a form and you will be using less new code. I would definitely use a form myself but it would be better if you wade into the pool instead of diving in. Unless you have coding experience and just need to learn syntax and vocab, then dive away.)
There are a lot of other things I would do if this was a form I was making, but this should get you started in terms of what to search for to build this project. I tried to make it as simple as possible so that it isn't overwhelming. There are better ways to do it but these methods should be ones that you can grasp quickly and then improve upon later after you learn more. Good luck with your equipment tracking!
Edit: after code posted
Ok, with the code you posted, go all the way to the top before the sub line and put in:
Option Explicit
This will cause the VBE editor to give you more meaningful feedback in quite a few instances. For example, you have your set line before your dim line. Without Option Explicit, when the editor comes to a variable that has not been declared with a Dim statement, it just makes it on the fly and sets it as a variant type. That uses up extra memory and means that typos get variables created on the fly. So when you are doing what you have done here, you end up with
Dim sh As Worksheet ' your sh variable is your worksheet variable. It never gets used again.
Set ws = ThisWorkbook.Worksheets("SignOut")' the ws here should likely be sh to match the Dim statement ... or the sh in the Dim should be a ws. Except it doesn't ever get used again either.
Neither of those matter in this case since you aren't reusing them but if you had code that was referring to one or the other, you would want the compiler to tell you that you are trying to use a variable that hasn't been declared instead of creating a new one.
Generally you want to put your Dim statements all at the top of the sub or function. 1) It is easier to find them and debug or check spelling. 2) It ensures that they are all declared before the script tries to reference them.
Your code here isn't populating the variables before it is referencing them. Pretty much any time that you have a variable you need to populate it before you can do anything with it. There are a number of ways to populate variables with data from the sheet. If you get comfortable with arrays sooner rather than latter (or collections instead of arrays) then you will have a much easier time with a task like this.
Some specific lines:
Dim LastRow as Long 'you have this declared but you need to put in code to get the last row, which will be handy for populating variables later in your code. Do this right after declaring variables. Google excel vba find last row.
For i = 0 To equip.ListCount - 1 ' you need to populate equip before doing this. Lookup excel vba how to copy a range into variable. Then lookup how to loop through range. You can start it at your first line of data and go down to the LastRow to grab them all into the same array (which will basically be a table).
msg = Left(msg, Len(msg) - 2) 'lookup excel vba string manipulations if this isn't doing what you want
'these next lines all have <Variable Name>.value which won't work for you. If those variables are supposed to be things that the sheet prompts someone to enter and then they get populated here you can see how to do that here-> http://www.excel-vba-easy.com/vba-userform-excel-vba.html
Application.Worksheets("SignOut").Range("B" & Rows.Count).End(xlUp).Offset(1).Value = techname.Value
Application.Worksheets("SignOut").Range("C" & Rows.Count).End(xlUp).Offset(1).Value = gov.Value
Application.Worksheets("SignOut").Range("D" & Rows.Count).End(xlUp).Offset(1).Value = msg
Application.Worksheets("SignOut").Range("E" & Rows.Count).End(xlUp).Offset(1).Value = otherequip.Value
With your loop untils you will want to ensure that you test with a short loop and step through it over and over. If you do the logic wrong and end up looping infinitely you can easily stop stepping through and fix it (or fix it while stepping through, then stop and retest,) but if you just hit play then excel will freeze up on you.
If you run into an issue with a specific step you can probably find lots of existing things on SO. If not, post a new thread with the specifics of that step. This posting will be down a few pages by then and people likely won't see your question if you put it here. Also, it will deserve its own thread since you will have moved past the "where to start" stage at that point.
Good luck!

VBA: Invalid Next Control Variable Reference

Basically, i'm trying to mimic a concatenate result using code i stripped apart and recycled for my purposes. But i'm having problems when the script attempts to process "Next T" idk, but i already indicated as a Dim - Integer, and that still didnt seem to do the trick.
Original source of code:
Concatenate multiple ranges using vba
I've been having a lot of problems with this one piece, cause it seems to be the only thing i've actually been trying to include in my script for a long time now. Had compile errors with closing the If, adjusting the Then, and even Exiting the loop.
I think the Next should be my final worries.
Btw, rnumbers is supposed to hold the place of a value/integer, but i'm not entirely sure if that was done correctly either.
rnumbers = Rows(ActiveCell.Range("A3").End(xlDown)) + 3
'or CellCount = ActiveCell.Range("A" & Rows.Count).End(xldown).Row
Do While Rows(ActiveCell.Range("A3").End(xlDown)) > 3
'For Q = 1 To 10 'This provides a column reference to concatenate - Outer For statement
For T = 3 To rnumbers 'This provides a rows reference to concatenate - Inner for statement
For Each Cell In Cells("A" & T) 'provides rows and column reference
If Cell.Value = "" Then
GoTo Line1 'this tells the macro to continue until a blank cell is reached
Exit For
End If
x = x & Cell.Value & Chr(10) 'This provides the concatenated cell value and comma separator
'Next ' this loops the range
Next T 'This is the inner loop which dynamically changes the number of rows to loop until a blank cell is reached
Line1:
On Error GoTo Terminate 'Terminates if there are less columns (max 10) to concatenate
ActiveCell.Value = Mid(x, 1, Len(x) - 1) 'This basically removes the last comma from the last concatenated cell e.g. you might get for a range 2,3,4, << this formula removes the last comma to
'give 2,3,4
ActiveCell.Offset(1, 0).Select 'Once the concatenated result is pasted into the cell this moves down to the next cell, e.g. from F1 to F2
x = "" 'The all important, clears x value after finishing concatenation for a range before moving on to another column and range
'Next Q 'After one range is done the second column loop kicks in to tell the macro to move to the next column and begin concatenation range again
'rnumbers = 0
'Next
Exit Do
'Resume
Terminate:'error handler
Trying again... when I took a closer look at your code I actually used a Bad Word.
You have been hanging with the wrong crowd, and are picking up some really bad code structure ideas. A GoTo followed by an Exit For? The latter statement can never be reached! And jumping out of a For loop is a dangerous (if not wrong) thing to do. And yes, you still needed a Next for the For Each statement (with a matching control argument - the Next T belonged with a different For loop, not the innermost one).
Anyway - I felt like the Cat In The Hat: "This mess is so big and so deep and so tall - we cannot pick it up, there is No Way At All!". So I decided to build you a new house instead.
I think the following does what you want to do, and quite elegantly. See if it makes sense, and if you can adapt it for your purpose. I need to go to sleep but will take a look in the morning to see if you figured it out from here.
Sub concAll()
Dim allRows As Range, target as range
Dim oneRow
Dim nc as Integer
Set allRows = Range("A3", "J10") ' pick the real range here - dynamically, probably
nc = allRows.Columns.Count ' need this number later to know where to put result
For Each oneRow In allRows.Rows ' loop over one row of the range at a time
Dim s As String
s = "" ' start with empty string
For Each c In oneRow.Cells ' loop over all the cells in the row
If Not IsEmpty(c) Then
s = s & "," & c.Text
Else
Exit For ' done with this row: found empty cell
End If
Next c ' keep looping over the cells...
Set target = oneRow.Cells(1).Offset(0, oneRow.Cells.Count) ' cell where we put result
target.Value = Mid(s, 2) ' put the concatenated value to the right of everything;
' skipping first comma (which came before first text)
Next oneRow ' repeat for all rows in source range
End Sub
I'm sorry, i shouldve explained what i was trying to produce than asking to fix something i wanted to do. My experience in vba has been self-taught, and i'm a little new to asking for help.
The script Floris produced seemed to have function but not as intended. Turns out what i wrote is a little outdated, and needs to be wiped and restarted. This was actually an old script i started a few months back that worked off of a web-query. But the website went thru some changes and now the script is all over the place.
the main issue i was having was a compile-error "Invalid Next Control Variable Reference" Which turns out to be caused by an open 'Do while' loop, that doesnt seem to have much of an exit point from the research i looked up. Was supposed to have used another 'If' command instead. At the same time, when attempting to solve that 'Do While' i added an extra 'Next' (cause i thought they were compatible), and it screwed with the script.
Hard to explain.. But the 'Do While' i used, i wanted it to combine the values only if the number of values were greater
rnumbers = Rows(ActiveCell.Range("A3").End(xlDown)) + 3
'or CellCount = ActiveCell.Range("A" & Rows.Count).End(xldown).Row
Do While Rows(ActiveCell.Range("A3").End(xlDown)) > 3
But instead it was supposed to be
Dim CellCount As Range
CellCount = ActiveCell.Range("A" & Rows.Count).End(xlDown).Row + 2
'cause its the active cell + two additional cells
If CellCount > 3
Which then opens up into the script Floris submitted. (But that failed too, because of what was stated above).
Thanks again, hope that it explains everything... Sorry if i wasted your time with that one Floris, really do appreciate the assistance. Just wish i had asked for the help sooner, would have saved me a lot of frustration that i'm dealing with now. >_>

Type Mismatch error in function using DateValue(), how to troubleshoot?

Warning: I'm a noob.
I've written a Sub to find cells with red text and alter them.
#ThinkerIV gave me a great function to put in a cell and drag the formula out into adjoining cells, but that won't work due to the number of sheets to work on.
So I wrote my Sub, calling his function (see code below). I passed it a Range of one cell, so it seems to me it should work?
But, it keeps throwing out Type Mismatch (run-time error code 13) on the line where the function calls the DateValue()! The passed range shows a value of 1 (which is the number in the cell it refers to) when I hover over it in the editor, but I don'rt know if that's the cell's contents or some other value 1 being shown.
So, I really don't know how to find out exactly why this is happening. Is it that the range I passed is somehow not the right kind? Please inform me of why this code won't work!
I tried to change that line to the comment line below it (and a couple other blind-guess changes), but that has the same error.
Thanks in advance!
Sub redTextToRealDates()
Dim dateTemp As Date
Dim redCell As Range
Dim foundCell As Range
Dim thisSheetsRange As Range
Dim busyCell As Range
Dim redTextCells As Range
Set thisSheetsRange = ActiveSheet.usedRange
'Build a range containing all the cells in a sheet containing red text.
' well... all cells formatted to HAVE red text, anyway.
' Anyone want to tell me how to write this to skip empty cells?
' Because I don't need to grab empty cells into this range...
For Each busyCell In thisSheetsRange
If (busyCell.Font.ColorIndex()) = 3 Then
If redTextCells Is Nothing Then
Set redTextCells = busyCell
Else: Set redTextCells = Union(redTextCells, busyCell)
End If
End If
Next busyCell
'Change unknown format cells to date cells populated with concantenated
'string of original contents and the active sheet's name.
For Each foundCell In redTextCells
foundCell.NumberFormat = "#"
foundCell = GetConcantDate(foundCell)
Next foundCell
redTextCells.NumberFormat = "dd/mm/yy"
On Error Resume Next
End Sub
Function GetConcantDate(rng As Range) As Date
'Original code supplied by ThinkerIV on StackOverflow.com
Dim dtTemp As Date
dtTemp = DateValue(rng.Range("A1").Value & " " & rng.Parent.Name)
'dateTemp = DateValue(foundCell.Value & " " & ActiveSheet.Name)
GetConcantDate = dtTemp
End Function
EDIT
I cant post my own answer yet, so I am adding this solution:
When feeding data to Format(), the contents of the first cell formatted for red were NOT in text form. I had not put in place any way to ensure that I passed the proper data type. So, the line to format the cell as text (foundCell.NumberFormat = "#") before passing it to the function is what fixed it.
The solution was actually already written when I copy/pasted the code into the question - I just wasn't aware that it had fixed it because of another error on a different Sub. (I'm a noob and was confused dealing with multiple errors in multiple subs) I thought I had tried it again with that new line, but HADN'T, so still thought it was not working.
Thanks to all who helped. I feel a bit of a fool now, having found it like that. Hope you forgive me for my rookie flubber - too many Subs and Functions in a huge list in the editor and I got 'dizzy'... At least I can post a solution in case some other noob needs it!
Ok, I think there are two things here. Firstly, the DateValue function takes a string representation of a date, e.g. "01/01/2013", when you pass through an excel date from a range, you are passing through a number, like 41275. This throws the run time error 13.
However, if you already have a date, why bother converting it? You seem to want all red cells to be converted to a date + the sheetname. To do this you'll have to have strings e.g. "01/01/2013 Sheet1", so you couldn't use DateValue here. Instead perhaps try something like this:
Public Function GetConcatDate(rng As Range) As String
Dim dtTemp As String
dtTemp = Format(rng.Range("A1").Value, "dd/mm/yyyy") & " " & rng.Parent.Name
GetConcatDate = dtTemp
End Function

excel vba activating a tab by name using a variable string

Can someone please help? I have a feeling that this type of issue is a simple one and has been answered many times but I can't seem to find a solution that works. Getting hit by error 9: subscript out of range.
A good part of the frustration is due to the simplicity of the code that works. I have a spreadsheet with tabs named like "Dist.12345-Store.67890". I have VBA code that will successfully open that tab if I use:
Sub test()
Worksheets("Dist.12345-Store.67890").visible = true
End sub
But rather than hard code this string in the code 31 times in 31 different subs I want to put a string together as a variable storeselect2, and refer to this string as the worksheet to appear. But I get that error 9...
Sub test()
Dim storeselect2 As String
storeselect2 = "Dist." & ActiveCell.Offset(0, -1).Value & "-Store." & ActiveCell.Value
` the storeselect2 is now = "Dist.12345-Store.67890" `
Sheets(storeselect2).Visible = True `this is where error 9 occurs`
End Sub
How can I get an existing tab to come up when using a string to refer to the tab name in the code? Is it due to the string coming from one tab and trying to open another?
Thanks!!
This what you need to write
Dim storeselect2 As String
Dim pig, dog, cat, bird As String
pig = "Dist."
dog = ActiveCell.Offset(0, -1).Value
cat = "-Store."
bird = ActiveCell.Value
storeselect2 = pig & dog & cat & bird
Sheets(storeselect2).Visible = False
For those arriving at this question (from Google?) seeking the straight-forward answer for how to activate a tab by name using a variable string:
Sheets(23).Activate
or
Worksheets(1).Select
or
Sheets("mytabname").Activate
It is not necessary to activate a worksheet in order to manipulate it programmatically, you can also just select it:
Sheets("mytabname").Select
This answer explains that it is not necessary to either select or activate a worksheet before manipulating it. Doing either one slows down the code. However, I (and others) have run into situations where first selecting or activating the sheet we want to manipulate seems to be necessary to avoid an error.
References:
https://www.automateexcel.com/vba/activate-select-sheet/
Excel Select vs Activate