Currently I have three fields of data. Two are data validation lists and another is just a normal cell where I input a number value. Once I've selected the data I want, I press an ActiveX button which copies the data into another spreadsheet. What it currently looks like:
The issue I have is I want on the button press for the fields to clear but retain their information. I've tried both .Clear and .ClearContents but they completely remove my data validation lists. I just want them to go back to a blank state for the next time.
What I want it to reset to:
Is there any way of doing this or do I need to rethink the entire spreadsheet and use VBA?
VBA : If myCell is the cell which you want to clear, use
myCell.FormulaR1C1 = ""
Edit: after comments below and assuming that the 3 fields from the screenshots above are c4, c7 and c10 I would recommend to change your sub like this:
Private Sub Command5Button21_Click()
Dim s1, s2
Set s1 = Worksheets("Master")
Set s2 = Worksheets("Sheet1")
With s1.Cells(Rows.Count, 1).End(xlUp).Offset(1, 0).EntireRow
.Cells(, "a").Value = s2.Range("p20").Value
.Cells(, "b").Value = s2.Range("p21").Value
.Cells(, "c").Value = s2.Range("c4").Value
.Cells(, "d").Value = s2.Range("c7").Value
.Cells(, "e").Value = s2.Range("c10").Value
s2.Range("c4").FormulaR1C1 = ""
s2.Range("c7").FormulaR1C1 = ""
s2.Range("c10").FormulaR1C1 = ""
End With
End Sub
Related
Can anyone help with the following.
Working in excel. Have created a table that is filled using a form. Cells in range a:1 to J:31 (Table1).
The form auto completes the table, however when an entry is deleted (anywhere) in the table I need the form to fill those empty spcaes. At the moment once the table is complete even when information I deleted no new entries can be entered using the form. In addition i need the form to fill the first empty cell.
Lets say that the only space available that I have is row 12, I want to be able to put the information there using my userform.
The table is an admissions to a hospital sheet including name, number, bedroom, date of arrival, doctor and other such info, filled across. The main point is that I don't want to create another row to enter data, the data should be just in the range of the table a:1 to J:31
I have this code in vba
Private Sub CommandButtonSave_Click()
Dim fill As Lonng
Sheets("Ward Planner").Activate
fill = WorksheetFunction.CountA(Range("Table1")) + 1
Cells(fill, 1).Value = ComboBoxBed
Cells(fill, 2).Value = TextBoxName.Text
Cells(fill, 3).Value = ComboBoxConsultant
Cells(fill, 4).Value = TextBoxPcn.Text
Cells(fill, 5).Value = TextBoxDoa.Text
Cells(fill, 6).Value = ComboBoxGender
Cells(fill, 7).Value = ComboBoxStatus
Cells(fill, 8).Value = ComboBoxDiet
Cells(fill, 9).Value = TextBoxComments.Text
End Sub
It looks like you need a test to see whether a blank row is available or not - then some code to find that row (based on column A) before pasting your data to it. The following code is untested but should work given the description in your question. Please try it & let me know how it goes.
Private Sub CommandButtonSave_Click()
Dim c As Range, fill As Long, ws As Worksheet
Set ws = Sheets("Ward Planner")
If Application.WorksheetFunction.CountBlank(ws.Range("A1:A31")) = 0 Then
MsgBox "No available rows"
Exit Sub
End If
For Each c In ws.Range("A1:A31")
If c.Value = "" Then
fill = c.Row
'ws.Cells(fill, 1).Value...etc" code goes here
'copy your current code - but please note the "ws." prefix
Exit Sub
End If
Next c
End Sub
I found that this code works too, just in case someone would like to try both.
Dim fill As Long
Sheets("Ward_Planner").Activate
On Error Resume Next
fill = Range("A2:A29").SpecialCells(xlBlanks)(1).Row
On Error GoTo 0
If fill = 0 Then
MsgBox "all beds are filled"
Exit Sub
End If
Cells(fill, 1).Value = ComboBoxBed.Value
Cells(fill, 2).Value = TextBoxName.Value***
I created a code that get user inputs and outputs a '2 by n' array from cell X33. n varies. Hence I set the VBA code to select this:
lastCol = Cells(34, Columns.Count).End(xlToLeft).Column
Range(Range("X33"), Cells(34, lastCol)).Select
I am attempting to assign the above selected range into an existing Array2 via Name Manager. When I try record macro via name manager, I am forced to use
With ActiveWorkbook.Names("Array2")
.Name = "Array2"
.RefersToR1C1 = "=Sheet1!R33C24:R34C100"
.Comment = ""
End With
I've attempted by changing C100 above to &lastCol , since the last column in the output can be any number, but the recorded code is fixed and would not assign the array to the selected range I want. Is there any way I may change this code so it would directly take the range selected in the top code instead of a fixed value.
I'm still learning VBA basics as I'm mostly attempting manual edits via recording. Thanks and much appreciated.
dim lastCol as long
lastCol = Cells(34, Columns.Count).End(xlToLeft).Column
With ActiveWorkbook.Names("Array2")
.Name = "Array2"
'written directly
.RefersToR1C1 = "=Sheet1!R33C24:R34C" & lastCol
'or from the selected cells
.RefersToR1C1 = selection.address(1, 1, ReferenceStyle:=xlr1c1, external:=true)
.Comment = ""
End With
Range(Range("X33"), Cells(34, lastCol)).Name = "Array2"
I have a macro that inserts 2 columns on my current sheet and pastes information from another sheet.
I want to create 2 variables that are assigned to each column that would change the next time I run the macro to paste the information in the next two columns.
Columns("BO:BO").Select
Selection.Insert Shift:=xlToRight
Range("BO2").Select
ActiveCell.FormulaR1C1 = "Feb weekly-wk 2"
Range("BO19").Select
ActiveCell.FormulaR1C1 = _
"=VLOOKUP(Comparison!RC2,'Jan16 wk4'!R3C15:R34C24,9,FALSE)"
Range("BO19").Select
Selection.AutoFill Destination:=Range("BO19:BO47"), Type:=xlFillDefault
Range("BO19:BO47").Select
Columns("BP:BP").Select
Selection.Insert Shift:=xlToRight
Range("BP2").Select
Selection.Style = "20% - Accent6"
Range("BP2").Select
ActiveCell.FormulaR1C1 = "Diff"
Range("BP19").Select
ActiveCell.FormulaR1C1 = "=RC[-2]-RC[-1]"
My idea is to set up a variable that I would replace my current "BO" and "BP" code with.
Dim X as String, Y as String
X = "BO"
y = "BP"
When I run the macro it would change the variable for this example "BO" to "BQ" and "BP" to "BR". Next time I run the macro would change the "BQ" to "BS" and "BR" to "BT".
I just cleaned your code a little:
Dim ColBO As Integer
Dim ColBP As Integer
Dim StrBO As String
Dim StrBP As String
StrBO = "BO"
StrBP = "BP"
ColBO = ActiveWorkbook.Range(StrBO & 1).Column 'instead of StrBO you could directly write ("BO" & 1)
ColBP = ActiveWorkbook.Range(StrBP & 1).Column 'Then you wouldnt need these two variables
Columns(ColBO).Insert Shift:=xlToRight
'Columns(ColBO).Select ' Trying to avoid selection but not sure if this works here...
'Selection.Insert Shift:=xlToRight
Range(1, ColBO).FormulaR1C1 = "Feb weekly-wk 2"
Range(19, ColBO).FormulaR1C1 = "=VLOOKUP(Comparison!RC2,'Jan16 wk4'!R3C15:R34C24,9,FALSE)"
Range(19, ColBO).AutoFill Destination:=Range("BO19:BO47"), Type:=xlFillDefault
Columns(ColBP).Insert Shift:=xlToRight 'Same here as above
Range(2, ColBP).Style = "20% - Accent6"
Range(2, ColBP).FormulaR1C1 = "Diff"
Range(19, ColBP).FormulaR1C1 = "=RC[-2]-RC[-1]"
For the future: If you can, try to avoid .Select/Selection/.Activate if possible. The code can mostly run without such commands and without activating a cell. ;)
If you are not actually writing BO/BP to the range you are transforming I would go with two ints, stored in a hidden sheet. Read/write each time you run the macro.
This is, in my opinion, the easier solution, other places to go would be global variables or storing it to a file.
If you want to use numeric variables you can change approach and use Cells instead of Range:
'You can use the rows below to know the column number
Range("BO1").Activate
ActiveCell.Value = ActiveCell.Column 'This way you get the column number into the cell
ColNum = ActiveCell.Column 'This way you get the column number into the variable
'So now you know that BO column number is 67 and you can use
Cells(1, 67) = "OK"
'Or, using variables:
RowNum = 1
ColNum = 67
Cells(RowNum, ColNum) = "You Got It!"
This makes you able to loop columns simply using a for ... next
If you need to loop from BO to BR you can use
For ColNum = 67 To 70
Cells(1, ColNum) = "OK"
Next ColNum
Hope it helps.
Please be aware that I am working with a series of ~1000 line medical information databases. Due to the size of the databases, manual manipulation of the data is too time consuming. As such, I have attempted to learn VBA and code an Excel 2010 macro using VBA to help me accomplish parsing certain data. The desired output is to split certain characters from a provided string on each line of the database as follows:
99204 - OFFICE/OUTPATIENT VISIT, NEW
will need to be split into
Active Row Active Column = 99204 ActiveRow Active Column+3 = OFFICE/OUTPATIENT VISIT, NEW
I have researched this topic using Walkenbach's "Excel 2013: Power Programming with VBA" and a fair amount of web resources, including this awesome site, but have been unable to develop a fully-workable solution using VBA in Excel. The code for my current macro is:
Sub EasySplit()
Dim text As String
Dim a As Integer
Dim name As Variant
text = ActiveCell.Value
name = Split(text, "-", 2)
For a = 0 To 1
Cells(1, a + 3).Value = Trim(name(a))
Next a
End Sub
The code uses the "-" character as a delimiter to split the input string into two substrings (I have limited the output strings to 2, as there exists in some input strings multiple "-" characters). I have trimmed the second string output to remove leading spaces.
The trouble that I am having is that the output is being presented at the top of the activesheet, instead of on the activerow.
Thank you in advance for any help. I have been working on this for 2 days and although I have made some progress, I feel that I have reached an impasse. I think that the issue is somewhere in the
Cells(1, a + 3).Value = Trim(name(a))
code, specifically with "Cells()".
Thank you Conrad Frix!
Yah.. funny enough. Just after I post I have a brainstorm.. and modify the code to read:
Sub EasySplit()
Dim text As String
Dim a As Integer
Dim name As Variant
text = ActiveCell.Value
name = Split(text, "-", 2)
For a = 0 To 1
ActiveCell.Offset(0, 3 + a).Value = Trim(name(a))
Next a
End Sub
Not quite the colkumn1,column4 output that I want (it outputs to column3,column4), but it will work for my purpose.
Now I need to incorporate a loop so that the code runs on each successive cell in the column (downwards, step 1) skipping all bolded cells, until it hits an empty cell.
Modified answer to modified request.
This will start on row 1 and continue until a blank cell is found in column A. If you would like to start on a different row, perhaps row 2 if you have headers, change the
i = 1
line to
i = 2
I added a check on the upper bound of our variant before doing the output writes, in case the macro is run again on already formatted cells. (Does nothing instead of erroring out)
Sub EasySplit()
Dim initialText As String
Dim i As Double
Dim name As Variant
i = 1
Do While Trim(Cells(i, 1)) <> ""
If Not Cells(i, 1).Font.Bold Then
initialText = Cells(i, 1).text
name = Split(initialText, "-", 2)
If Not UBound(name) < 1 Then
Cells(i, 1) = Trim(name(0))
Cells(i, 4) = Trim(name(1))
End If
End If
i = i + 1
Loop
End Sub
just add a variable to keep track of the active row and then use that in place of the constant 1.
e.g.
Dim iRow as Integer = ActiveCell.Row
For a = 0 To 1
Cells(iRow , a + 3).Value = Trim(name(a))
Next a
Alternate method utilizing TextToColumns. This code also avoids using a loop, making it more efficient and much faster. Comments have been added to assist with understanding the code.
EDIT: I have expanded the code to make it more versatile by using a temp worksheet. You can then output the two columns to wherever you'd like. As stated in your original question, the output is now to columns 1 and 4.
Sub tgr()
Const DataCol As String = "A" 'Change to the correct column letter
Const HeaderRow As Long = 1 'Change to be the correct header row
Dim rngOriginal As Range 'Use this variable to capture your original data
'Capture the original data, starting in Data column and the header row + 1
Set rngOriginal = Range(DataCol & HeaderRow + 1, Cells(Rows.Count, DataCol).End(xlUp))
If rngOriginal.Row < HeaderRow + 1 Then Exit Sub 'No data
'We will be using a temp worksheet, and to avoid a prompt when we delete the temp worksheet we turn off alerts
'We also turn off screenupdating to prevent "screen flickering"
Application.DisplayAlerts = False
Application.ScreenUpdating = False
'Move the original data to a temp worksheet to perform the split
'To avoid having leading/trailing spaces, replace all instances of " - " with simply "-"
'Lastly, move the split data to desired locations and remove the temp worksheet
With Sheets.Add.Range("A1").Resize(rngOriginal.Rows.Count)
.Value = rngOriginal.Value
.Replace " - ", "-"
.TextToColumns .Cells, xlDelimited, Other:=True, OtherChar:="-"
rngOriginal.Value = .Value
rngOriginal.Offset(, 3).Value = .Offset(, 1).Value
.Worksheet.Delete
End With
'Now that all operations have completed, turn alerts and screenupdating back on
Application.DisplayAlerts = True
Application.ScreenUpdating = True
End Sub
You can do this in a single shot without looping using the VBA equivalent of entering this formula, then taking values only
as a formula
=IF(NOT(ISERROR(FIND("-",A1))),RIGHT(A1,LEN(A1)-FIND("-",A1)-1 ),A1)
code
Sub Quicker()
Dim rng1 As Range
Set rng1 = Range([a1], Cells(Rows.Count, "A").End(xlUp))
With rng1.Offset(0, 3)
.FormulaR1C1 = "=IF(NOT(ISERROR(FIND(""-"",RC[-3]))),RIGHT(RC[-3],LEN(RC[-3])-FIND(""-"",RC[-3])-1 ),RC[-3])"
.Value = .Value
End With
End Sub
I want to check:
IF cells (i,"A") contains the text 'Miami' AND (i,"D") contains the text 'Florida' THEN change value of cell (i,"C") to BA.
Sub ABC()
Dim wsh As Worksheet, i As Long, lngEndRowInv As Long
Set wsh = ActiveSheet
i = 2
lngEndRowInv = wsh.Range("A" & wsh.Rows.Count).End(xlUp).Row
While i <= lngEndRowInv
If Cells(i, "A") like "*Miami*" And Cells(i, "D") like "*Florida*" Then
Cells(i, "C").Value = "BA"
End If
i = i + 1
Wend
End Sub
Brief syntax lesson
Cells(Row, Column) identifies a cell. Row must be an integer between 1 and the maximum for version of Excel you are using. Column must be a identifier (for example: "A", "IV", "XFD") or a number (for example: 1, 256, 16384)
.Cells(Row, Column) identifies a cell within a sheet identified in a earlier With statement:
With ActiveSheet
:
.Cells(Row,Column)
:
End With
If you omit the dot, Cells(Row,Column) is within the active worksheet. So wsh = ActiveWorkbook wsh.Range is not strictly necessary. However, I always use a With statement so I do not wonder which sheet I meant when I return to my code in six months time. So, I would write:
With ActiveSheet
:
.Range.
:
End With
Actually, I would not write the above unless I really did want the code to work on the active sheet. What if the user has the wrong sheet active when they started the macro. I would write:
With Sheets("xxxx")
:
.Range.
:
End With
because my code only works on sheet xxxx.
Cells(Row,Column) identifies a cell. Cells(Row,Column).xxxx identifies a property of the cell. Value is a property. Value is the default property so you can usually omit it and the compiler will know what you mean. But in certain situations the compiler can be confused so the advice to include the .Value is good.
Cells(Row,Column) like "*Miami*" will give True if the cell is "Miami", "South Miami", "Miami, North" or anything similar.
Cells(Row,Column).Value = "Miami" will give True if the cell is exactly equal to "Miami". "MIAMI" for example will give False. If you want to accept MIAMI, use the lower case function:
Lcase(Cells(Row,Column).Value) = "miami"
My suggestions
Your sample code keeps changing as you try different suggestions which I find confusing. You were using Cells(Row,Column) <> "Miami" when I started typing this.
Use
If Cells(i, "A").Value like "*Miami*" And Cells(i, "D").Value like "*Florida*" Then
Cells(i, "C").Value = "BA"
if you want to accept, for example, "South Miami" and "Miami, North".
Use
If Cells(i, "A").Value = "Miami" And Cells(i, "D").Value like "Florida" Then
Cells(i, "C").Value = "BA"
if you want to accept, exactly, "Miami" and "Florida".
Use
If Lcase(Cells(i, "A").Value) = "miami" And _
Lcase(Cells(i, "D").Value) = "florida" Then
Cells(i, "C").Value = "BA"
if you don't care about case.
If there are no typos in the question, you got the conditions wrong:
You said this:
IF cells (i,"A") contains the text 'Miami'
...but your code says:
If Cells(i, "A") <> "Miami"
--> <> means that the value of the cell is not equal to "Miami", so you're not checking what you think you are checking.
I guess you want this instead:
If Cells(i, "A") like "*Miami*"
EDIT:
Sorry, but I can't really help you more. As I already said in a comment, I'm no Excel VBA expert.
Normally I would open Excel now and try your code myself, but I don't even have Excel on any of my machines at home (I use OpenOffice).
Just one general thing: can you identify the row that does not work?
Maybe this helps someone else to answer the question.
Does it ever execute (or at least try to execute) the Cells(i, "C").Value = "BA" line?
Or is the If Cells(i, "A") like "*Miami*" stuff already False?
If yes, try checking just one cell and see if that works.
If you are simply looking for the occurrence of "Miami" or "Florida" inside a string (since you put * at both ends), it's probably better to use the InStr function instead of Like. Not only are the results more predictable, but I believe you'll get better performance.
Also, VBA is not short-circuited so when you use the AND keyword, it will test both sides of the AND, regardless if the first test failed or not. In VBA, it is more optimal to use 2 if-statements in these cases, that way you aren't checking for "Florida" if you don't find "Miami".
The other advice I have is that a for-each loop is faster than a for-loop. Using .offset, you can achieve the same thing, but with better effeciency. Of course there are even better ways (like variant arrays), but those will add a layer of complexity not needed in this example.
Here is some sample code:
Sub test()
Application.ScreenUpdating = False
Dim lastRow As Long
Dim cell As Range
lastRow = Range("A" & Rows.Count).End(xlUp).Row
For Each cell In Range("A1:A" & lastRow)
If InStr(1, cell.Value, "Miami") <> 0 Then
If InStr(1, cell.Offset(, 3).Value, "Florida") <> 0 Then
cell.Offset(, 2).Value = "BA"
End If
End If
Next
Application.ScreenUpdating = True
End Sub
I hope you find some of this helpful, and keep at it with VBA! ^^
I think you should append .value in IF statement:
If Cells(i, "A").Value <> "Miami" And Cells(i, "D").Value <> "Florida" Then
Cells(i, "C").Value = "BA"
End IF